annotate interfaces/discrete.js @ 22:1f375b7d75fd tip

updated warning for breaks during test
author Giulio Moro <giuliomoro@yahoo.it>
date Fri, 13 May 2016 19:01:08 +0100
parents f63604ce8f21
children
rev   line source
giuliomoro@0 1 // Once this is loaded and parsed, begin execution
giuliomoro@0 2 loadInterface();
giuliomoro@0 3
giuliomoro@0 4 function loadInterface() {
giuliomoro@0 5 // Use this to do any one-time page / element construction. For instance, placing any stationary text objects,
giuliomoro@0 6 // holding div's, or setting up any nodes which are present for the entire test sequence
giuliomoro@0 7
giuliomoro@0 8 // The injection point into the HTML page
giuliomoro@0 9 interfaceContext.insertPoint = document.getElementById("topLevelBody");
giuliomoro@0 10 var testContent = document.createElement('div');
giuliomoro@0 11 testContent.id = 'testContent';
giuliomoro@0 12
giuliomoro@0 13 // Create the top div for the Title element
giuliomoro@0 14 var titleAttr = specification.title;
giuliomoro@0 15 var title = document.createElement('div');
giuliomoro@0 16 title.className = "title";
giuliomoro@0 17 title.align = "center";
giuliomoro@0 18 var titleSpan = document.createElement('span');
giuliomoro@0 19
giuliomoro@0 20 // Set title to that defined in XML, else set to default
giuliomoro@0 21 if (titleAttr != undefined) {
giuliomoro@0 22 titleSpan.textContent = titleAttr;
giuliomoro@0 23 } else {
giuliomoro@0 24 titleSpan.textContent = 'Listening test';
giuliomoro@0 25 }
giuliomoro@0 26 // Insert the titleSpan element into the title div element.
giuliomoro@0 27 title.appendChild(titleSpan);
giuliomoro@0 28
giuliomoro@0 29 var pagetitle = document.createElement('div');
giuliomoro@0 30 pagetitle.className = "pageTitle";
giuliomoro@0 31 pagetitle.align = "center";
giuliomoro@0 32 var titleSpan = document.createElement('span');
giuliomoro@0 33 titleSpan.id = "pageTitle";
giuliomoro@0 34 pagetitle.appendChild(titleSpan);
giuliomoro@0 35
giuliomoro@0 36 // Create Interface buttons!
giuliomoro@0 37 var interfaceButtons = document.createElement('div');
giuliomoro@0 38 interfaceButtons.id = 'interface-buttons';
giuliomoro@0 39 interfaceButtons.style.height = '25px';
giuliomoro@0 40
giuliomoro@0 41 // Create playback start/stop points
giuliomoro@0 42 var playback = document.createElement("button");
giuliomoro@0 43 playback.innerHTML = 'Stop';
giuliomoro@0 44 playback.id = 'playback-button';
giuliomoro@0 45 playback.style.float = 'left';
giuliomoro@0 46 // onclick function. Check if it is playing or not, call the correct function in the
giuliomoro@0 47 // audioEngine, change the button text to reflect the next state.
giuliomoro@0 48 playback.onclick = function() {
giuliomoro@0 49 if (audioEngineContext.status == 1) {
giuliomoro@0 50 audioEngineContext.stop();
giuliomoro@0 51 this.innerHTML = 'Stop';
giuliomoro@0 52 var time = audioEngineContext.timer.getTestTime();
giuliomoro@0 53 console.log('Stopped at ' + time); // DEBUG/SAFETY
giuliomoro@0 54 }
giuliomoro@0 55 };
giuliomoro@0 56 // Create Submit (save) button
giuliomoro@0 57 var submit = document.createElement("button");
giuliomoro@10 58 submit.innerHTML = 'Submit';
giuliomoro@0 59 submit.onclick = buttonSubmitClick;
giuliomoro@0 60 submit.id = 'submit-button';
giuliomoro@0 61 // Append the interface buttons into the interfaceButtons object.
giuliomoro@0 62 interfaceButtons.appendChild(playback);
giuliomoro@0 63 interfaceButtons.appendChild(submit);
giuliomoro@0 64
giuliomoro@0 65 // Create a slider box
giuliomoro@0 66 var sliderBox = document.createElement('div');
giuliomoro@0 67 sliderBox.style.width = "100%";
giuliomoro@0 68 sliderBox.style.height = window.innerHeight - 200+12 + 'px';
giuliomoro@0 69 sliderBox.style.marginBottom = '10px';
giuliomoro@0 70 sliderBox.id = 'slider';
giuliomoro@0 71 var scaleHolder = document.createElement('div');
giuliomoro@0 72 scaleHolder.id = "scale-holder";
giuliomoro@0 73 scaleHolder.style.marginLeft = "107px";
giuliomoro@0 74 sliderBox.appendChild(scaleHolder);
giuliomoro@0 75 var scaleText = document.createElement('div');
giuliomoro@0 76 scaleText.id = "scale-text-holder";
giuliomoro@0 77 scaleText.style.height = "70px";
giuliomoro@0 78 scaleText.style.width = "100%";
giuliomoro@0 79 scaleHolder.appendChild(scaleText);
giuliomoro@0 80 var scaleCanvas = document.createElement('canvas');
giuliomoro@0 81 scaleCanvas.id = "scale-canvas";
giuliomoro@0 82 scaleCanvas.style.marginLeft = "150px";
giuliomoro@0 83 scaleHolder.appendChild(scaleCanvas);
giuliomoro@0 84 var sliderObjectHolder = document.createElement('div');
giuliomoro@0 85 sliderObjectHolder.id = 'slider-holder';
giuliomoro@0 86 sliderObjectHolder.align = "center";
giuliomoro@0 87 sliderBox.appendChild(sliderObjectHolder);
giuliomoro@0 88
giuliomoro@0 89 // Global parent for the comment boxes on the page
giuliomoro@0 90 var feedbackHolder = document.createElement('div');
giuliomoro@0 91 feedbackHolder.id = 'feedbackHolder';
giuliomoro@0 92
giuliomoro@0 93 testContent.style.zIndex = 1;
giuliomoro@0 94 interfaceContext.insertPoint.innerHTML = null; // Clear the current schema
giuliomoro@0 95
giuliomoro@0 96 // Inject into HTML
giuliomoro@0 97 testContent.appendChild(title); // Insert the title
giuliomoro@0 98 testContent.appendChild(pagetitle);
giuliomoro@0 99 testContent.appendChild(sliderBox);
giuliomoro@0 100 testContent.appendChild(feedbackHolder);
giuliomoro@10 101 testContent.appendChild(interfaceButtons);
giuliomoro@0 102 interfaceContext.insertPoint.appendChild(testContent);
giuliomoro@0 103
giuliomoro@0 104 // Load the full interface
giuliomoro@0 105 testState.initialise();
giuliomoro@0 106 testState.advanceState();
giuliomoro@0 107 };
giuliomoro@0 108
giuliomoro@0 109 function loadTest(page)
giuliomoro@0 110 {
giuliomoro@0 111 // Called each time a new test page is to be build. The page specification node is the only item passed in
giuliomoro@0 112 var id = page.id;
giuliomoro@0 113
giuliomoro@0 114 var feedbackHolder = document.getElementById('feedbackHolder');
giuliomoro@0 115 feedbackHolder.innerHTML = null;
giuliomoro@0 116 var interfaceObj = page.interfaces;
giuliomoro@0 117 if (interfaceObj.length > 1)
giuliomoro@0 118 {
giuliomoro@0 119 console.log("WARNING - This interface only supports one <interface> node per page. Using first interface node");
giuliomoro@0 120 }
giuliomoro@0 121 interfaceObj = interfaceObj[0];
giuliomoro@0 122 if(interfaceObj.title != null)
giuliomoro@0 123 {
giuliomoro@0 124 document.getElementById("pageTitle").textContent = interfaceObj.title;
giuliomoro@0 125 }
giuliomoro@0 126
giuliomoro@0 127 var interfaceOptions = specification.interfaces.options.concat(interfaceObj.options);
giuliomoro@0 128 for (var option of interfaceOptions)
giuliomoro@0 129 {
giuliomoro@0 130 if (option.type == "show")
giuliomoro@0 131 {
giuliomoro@0 132 switch(option.name) {
giuliomoro@0 133 case "playhead":
giuliomoro@0 134 var playbackHolder = document.getElementById('playback-holder');
giuliomoro@0 135 if (playbackHolder == null)
giuliomoro@0 136 {
giuliomoro@0 137 playbackHolder = document.createElement('div');
giuliomoro@0 138 playbackHolder.style.width = "100%";
giuliomoro@0 139 playbackHolder.align = 'center';
giuliomoro@0 140 playbackHolder.appendChild(interfaceContext.playhead.object);
giuliomoro@0 141 feedbackHolder.appendChild(playbackHolder);
giuliomoro@0 142 }
giuliomoro@0 143 break;
giuliomoro@0 144 case "page-count":
giuliomoro@0 145 var pagecountHolder = document.getElementById('page-count');
giuliomoro@0 146 if (pagecountHolder == null)
giuliomoro@0 147 {
giuliomoro@0 148 pagecountHolder = document.createElement('div');
giuliomoro@0 149 pagecountHolder.id = 'page-count';
giuliomoro@0 150 }
giuliomoro@0 151 pagecountHolder.innerHTML = '<span>Page '+(testState.stateIndex+1)+' of '+testState.stateMap.length+'</span>';
giuliomoro@0 152 var inject = document.getElementById('interface-buttons');
giuliomoro@0 153 inject.appendChild(pagecountHolder);
giuliomoro@0 154 break;
giuliomoro@0 155 case "volume":
giuliomoro@0 156 if (document.getElementById('master-volume-holder') == null)
giuliomoro@0 157 {
giuliomoro@0 158 feedbackHolder.appendChild(interfaceContext.volume.object);
giuliomoro@0 159 }
giuliomoro@0 160 break;
giuliomoro@0 161 }
giuliomoro@0 162 }
giuliomoro@0 163 }
giuliomoro@0 164
giuliomoro@0 165 // Delete outside reference
giuliomoro@0 166 var outsideReferenceHolder = document.getElementById('outside-reference');
giuliomoro@0 167 if (outsideReferenceHolder != null) {
giuliomoro@0 168 document.getElementById('interface-buttons').removeChild(outsideReferenceHolder);
giuliomoro@0 169 }
giuliomoro@0 170
giuliomoro@0 171 var sliderBox = document.getElementById('slider-holder');
giuliomoro@0 172 sliderBox.innerHTML = null;
giuliomoro@0 173
giuliomoro@0 174 var commentBoxPrefix = "Comment on track";
giuliomoro@0 175 if (interfaceObj.commentBoxPrefix != undefined) {
giuliomoro@0 176 commentBoxPrefix = interfaceObj.commentBoxPrefix;
giuliomoro@0 177 }
giuliomoro@0 178 var loopPlayback = page.loop;
giuliomoro@0 179
giuliomoro@0 180 $(page.commentQuestions).each(function(index,element) {
giuliomoro@0 181 var node = interfaceContext.createCommentQuestion(element);
giuliomoro@0 182 feedbackHolder.appendChild(node.holder);
giuliomoro@0 183 });
giuliomoro@0 184
giuliomoro@0 185 // Find all the audioElements from the audioHolder
giuliomoro@0 186 var index = 0;
giuliomoro@0 187 var interfaceScales = testState.currentStateMap.interfaces[0].scales;
giuliomoro@0 188 $(page.audioElements).each(function(index,element){
giuliomoro@0 189 // Find URL of track
giuliomoro@0 190 // In this jQuery loop, variable 'this' holds the current audioElement.
giuliomoro@0 191
giuliomoro@0 192 var audioObject = audioEngineContext.newTrack(element);
giuliomoro@0 193 if (element.type == 'outside-reference')
giuliomoro@0 194 {
giuliomoro@0 195 // Construct outside reference;
giuliomoro@0 196 var orNode = new outsideReferenceDOM(audioObject,index,document.getElementById('interface-buttons'));
giuliomoro@0 197 audioObject.bindInterface(orNode);
giuliomoro@0 198 } else {
giuliomoro@0 199 // Create a slider per track
giuliomoro@0 200 switch(audioObject.specification.parent.label) {
giuliomoro@0 201 case "none":
giuliomoro@0 202 label = "";
giuliomoro@0 203 break;
giuliomoro@0 204 case "letter":
giuliomoro@0 205 label = String.fromCharCode(97 + index);
giuliomoro@0 206 break;
giuliomoro@0 207 case "capital":
giuliomoro@0 208 label = String.fromCharCode(65 + index);
giuliomoro@0 209 break;
giuliomoro@0 210 default:
giuliomoro@10 211 label = ""+(index+1);
giuliomoro@0 212 break;
giuliomoro@0 213 }
giuliomoro@0 214 var sliderObj = new discreteObject(audioObject,label,interfaceScales);
giuliomoro@0 215 sliderBox.appendChild(sliderObj.holder);
giuliomoro@0 216 audioObject.bindInterface(sliderObj);
giuliomoro@0 217 interfaceContext.commentBoxes.createCommentBox(audioObject);
giuliomoro@0 218 index += 1;
giuliomoro@0 219 }
giuliomoro@0 220
giuliomoro@0 221 });
giuliomoro@0 222
giuliomoro@0 223 if (page.showElementComments)
giuliomoro@0 224 {
giuliomoro@0 225 interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder,true);
giuliomoro@0 226 }
giuliomoro@0 227
giuliomoro@0 228 // Auto-align
giuliomoro@0 229 resizeWindow(null);
giuliomoro@0 230 }
giuliomoro@0 231
giuliomoro@0 232 function discreteObject(audioObject,label,interfaceScales)
giuliomoro@0 233 {
giuliomoro@0 234 // An example node, you can make this however you want for each audioElement.
giuliomoro@0 235 // However, every audioObject (audioEngineContext.audioObject) MUST have an interface object with the following
giuliomoro@0 236 // You attach them by calling audioObject.bindInterface( )
giuliomoro@0 237 if (interfaceScales == null || interfaceScales.length == 0)
giuliomoro@0 238 {
giuliomoro@0 239 console.log("WARNING: The discrete radio's are built depending on the number of scale points specified! Ensure you have some specified. Defaulting to 5 for now!");
giuliomoro@0 240 numOptions = 5;
giuliomoro@0 241 }
giuliomoro@0 242 this.parent = audioObject;
giuliomoro@0 243
giuliomoro@0 244 this.holder = document.createElement('div');
giuliomoro@0 245 this.title = document.createElement('div');
giuliomoro@0 246 this.discreteHolder = document.createElement('div');
giuliomoro@0 247 this.discretes = [];
giuliomoro@0 248 this.play = document.createElement('button');
giuliomoro@0 249
giuliomoro@0 250 this.holder.className = 'track-slider';
giuliomoro@0 251 this.holder.style.width = window.innerWidth-200 + 'px';
giuliomoro@0 252 this.holder.appendChild(this.title);
giuliomoro@0 253 this.holder.appendChild(this.discreteHolder);
giuliomoro@0 254 this.holder.appendChild(this.play);
giuliomoro@0 255 this.holder.setAttribute('trackIndex',audioObject.id);
giuliomoro@0 256 this.title.textContent = label;
giuliomoro@0 257 this.title.className = 'track-slider-title';
giuliomoro@0 258
giuliomoro@0 259 this.discreteHolder.className = "track-slider-range";
giuliomoro@0 260 this.discreteHolder.style.width = window.innerWidth-500 + 'px';
giuliomoro@0 261 for (var i=0; i<interfaceScales.length; i++)
giuliomoro@0 262 {
giuliomoro@0 263 var node = document.createElement('input');
giuliomoro@0 264 node.setAttribute('type','radio');
giuliomoro@0 265 node.className = 'track-radio';
giuliomoro@0 266 node.disabled = true;
giuliomoro@0 267 node.setAttribute('position',interfaceScales[i].position);
giuliomoro@0 268 node.setAttribute('name',audioObject.specification.id);
giuliomoro@0 269 node.setAttribute('id',audioObject.specification.id+'-'+String(i));
giuliomoro@0 270 this.discretes.push(node);
giuliomoro@0 271 this.discreteHolder.appendChild(node);
giuliomoro@0 272 node.onclick = function(event)
giuliomoro@0 273 {
giuliomoro@0 274 if (audioEngineContext.status == 0)
giuliomoro@0 275 {
giuliomoro@0 276 event.currentTarget.checked = false;
giuliomoro@0 277 return;
giuliomoro@0 278 }
giuliomoro@0 279 var time = audioEngineContext.timer.getTestTime();
giuliomoro@0 280 var id = Number(event.currentTarget.parentNode.parentNode.getAttribute('trackIndex'));
giuliomoro@0 281 var value = event.currentTarget.getAttribute('position') / 100.0;
giuliomoro@0 282 audioEngineContext.audioObjects[id].metric.moved(time,value);
giuliomoro@0 283 console.log('slider '+id+' moved to '+value+' ('+time+')');
giuliomoro@0 284 };
giuliomoro@0 285 }
giuliomoro@0 286
giuliomoro@0 287 this.play.className = 'track-slider-button';
giuliomoro@0 288 this.play.textContent = "Loading...";
giuliomoro@0 289 this.play.value = audioObject.id;
giuliomoro@0 290 this.play.disabled = true;
giuliomoro@0 291 this.play.setAttribute("playstate","ready");
giuliomoro@0 292 this.play.onclick = function(event)
giuliomoro@0 293 {
giuliomoro@0 294 var id = Number(event.currentTarget.value);
giuliomoro@0 295 //audioEngineContext.metric.sliderPlayed(id);
giuliomoro@0 296 if (event.currentTarget.getAttribute("playstate") == "ready")
giuliomoro@0 297 audioEngineContext.play(id);
giuliomoro@0 298 else if (event.currentTarget.getAttribute("playstate") == "playing")
giuliomoro@0 299 audioEngineContext.stop();
giuliomoro@0 300 };
giuliomoro@0 301 this.resize = function(event)
giuliomoro@0 302 {
giuliomoro@0 303 this.holder.style.width = window.innerWidth-200 + 'px';
giuliomoro@0 304 this.discreteHolder.style.width = window.innerWidth-500 + 'px';
giuliomoro@0 305 //text.style.left = (posPix+150-($(text).width()/2)) +'px';
giuliomoro@0 306 for (var i=0; i<this.discretes.length; i++)
giuliomoro@0 307 {
giuliomoro@0 308 var width = $(this.discreteHolder).width() - 20;
giuliomoro@0 309 var node = this.discretes[i];
giuliomoro@0 310 var nodeW = $(node).width();
giuliomoro@0 311 var position = node.getAttribute('position');
giuliomoro@0 312 var posPix = Math.round(width * (position / 100.0));
giuliomoro@0 313 node.style.left = (posPix+10 - (nodeW/2)) + 'px';
giuliomoro@0 314 }
giuliomoro@0 315 };
giuliomoro@0 316 this.enable = function()
giuliomoro@0 317 {
giuliomoro@0 318 // This is used to tell the interface object that playback of this node is ready
giuliomoro@0 319 this.play.disabled = false;
giuliomoro@0 320 this.play.textContent = "Play";
giuliomoro@0 321 $(this.slider).removeClass('track-slider-disabled');
giuliomoro@0 322 for (var radio of this.discretes)
giuliomoro@0 323 {
giuliomoro@0 324 radio.disabled = false;
giuliomoro@0 325 }
giuliomoro@0 326 };
giuliomoro@0 327 this.updateLoading = function(progress)
giuliomoro@0 328 {
giuliomoro@0 329 // progress is a value from 0 to 100 indicating the current download state of media files
giuliomoro@0 330 if (progress != 100)
giuliomoro@0 331 {
giuliomoro@0 332 progress = String(progress);
giuliomoro@0 333 progress = progress.split('.')[0];
giuliomoro@0 334 this.play.textContent = progress+'%';
giuliomoro@0 335 } else {
giuliomoro@0 336 this.play.textContent = "Play";
giuliomoro@0 337 }
giuliomoro@0 338 };
giuliomoro@0 339
giuliomoro@0 340 this.startPlayback = function()
giuliomoro@0 341 {
giuliomoro@0 342 // Called by audioObject when playback begins
giuliomoro@0 343 this.play.setAttribute("playstate","playing");
giuliomoro@0 344 $(".track-slider").removeClass('track-slider-playing');
giuliomoro@0 345 $(this.holder).addClass('track-slider-playing');
giuliomoro@0 346 var outsideReference = document.getElementById('outside-reference');
giuliomoro@0 347 this.play.textContent = "Listening";
giuliomoro@0 348 if (outsideReference != null) {
giuliomoro@0 349 $(outsideReference).removeClass('track-slider-playing');
giuliomoro@0 350 }
giuliomoro@0 351 }
giuliomoro@0 352 this.stopPlayback = function()
giuliomoro@0 353 {
giuliomoro@0 354 // Called by audioObject when playback stops
giuliomoro@0 355 this.play.setAttribute("playstate","ready");
giuliomoro@10 356 // $(this.holder).removeClass('track-slider-playing');
giuliomoro@0 357 this.play.textContent = "Play";
giuliomoro@0 358 }
giuliomoro@0 359
giuliomoro@0 360 this.getValue = function()
giuliomoro@0 361 {
giuliomoro@0 362 // Return the current value of the object. If there is no value, return -1
giuliomoro@0 363 var value = -1;
giuliomoro@0 364 for (var i=0; i<this.discretes.length; i++)
giuliomoro@0 365 {
giuliomoro@0 366 if (this.discretes[i].checked == true)
giuliomoro@0 367 {
giuliomoro@0 368 value = this.discretes[i].getAttribute('position') / 100.0;
giuliomoro@0 369 break;
giuliomoro@0 370 }
giuliomoro@0 371 }
giuliomoro@0 372 return value;
giuliomoro@0 373 };
giuliomoro@0 374 this.getPresentedId = function()
giuliomoro@0 375 {
giuliomoro@0 376 // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale
giuliomoro@0 377 return this.title.textContent;
giuliomoro@0 378 };
giuliomoro@0 379 this.canMove = function()
giuliomoro@0 380 {
giuliomoro@0 381 // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale.
giuliomoro@0 382 // These are checked primarily if the interface check option 'fragmentMoved' is enabled.
giuliomoro@0 383 return true;
giuliomoro@0 384 };
giuliomoro@0 385 this.exportXMLDOM = function(audioObject) {
giuliomoro@0 386 // Called by the audioObject holding this element to export the interface <value> node.
giuliomoro@0 387 // If there is no value node (such as outside reference), return null
giuliomoro@0 388 // If there are multiple value nodes (such as multiple scale / 2D scales), return an array of nodes with each value node having an 'interfaceName' attribute
giuliomoro@0 389 // Use storage.document.createElement('value'); to generate the XML node.
giuliomoro@0 390 var node = storage.document.createElement('value');
giuliomoro@0 391 node.textContent = this.getValue();
giuliomoro@0 392 return node;
giuliomoro@0 393 };
giuliomoro@0 394 this.error = function() {
giuliomoro@0 395 // audioObject has an error!!
giuliomoro@0 396 this.playback.textContent = "Error";
giuliomoro@0 397 $(this.playback).addClass("error-colour");
giuliomoro@0 398 }
giuliomoro@0 399 };
giuliomoro@0 400
giuliomoro@0 401 function outsideReferenceDOM(audioObject,index,inject)
giuliomoro@0 402 {
giuliomoro@0 403 this.parent = audioObject;
giuliomoro@0 404 this.outsideReferenceHolder = document.createElement('button');
giuliomoro@0 405 this.outsideReferenceHolder.id = 'outside-reference';
giuliomoro@0 406 this.outsideReferenceHolder.className = 'outside-reference';
giuliomoro@0 407 this.outsideReferenceHolder.setAttribute('track-id',index);
giuliomoro@0 408 this.outsideReferenceHolder.textContent = "Play Reference";
giuliomoro@0 409 this.outsideReferenceHolder.disabled = true;
giuliomoro@0 410
giuliomoro@0 411 this.outsideReferenceHolder.onclick = function(event)
giuliomoro@0 412 {
giuliomoro@0 413 if (event.currentTarget.textContent == "Play Reference") {
giuliomoro@0 414 audioEngineContext.play(event.currentTarget.getAttribute('track-id'));
giuliomoro@0 415 } else {
giuliomoro@0 416 audioEngineContext.stop();
giuliomoro@0 417 }
giuliomoro@0 418 };
giuliomoro@0 419 inject.appendChild(this.outsideReferenceHolder);
giuliomoro@0 420 this.enable = function()
giuliomoro@0 421 {
giuliomoro@0 422 if (this.parent.state == 1)
giuliomoro@0 423 {
giuliomoro@0 424 this.outsideReferenceHolder.disabled = false;
giuliomoro@0 425 }
giuliomoro@0 426 };
giuliomoro@0 427 this.updateLoading = function(progress)
giuliomoro@0 428 {
giuliomoro@0 429 if (progress != 100)
giuliomoro@0 430 {
giuliomoro@0 431 progress = String(progress);
giuliomoro@0 432 progress = progress.split('.')[0];
giuliomoro@0 433 this.outsideReferenceHolder.textContent = progress+'%';
giuliomoro@0 434 } else {
giuliomoro@0 435 this.outsideReferenceHolder.textContent = "Play Reference";
giuliomoro@0 436 }
giuliomoro@0 437 };
giuliomoro@0 438 this.startPlayback = function()
giuliomoro@0 439 {
giuliomoro@0 440 // Called when playback has begun
giuliomoro@0 441 this.outsideReferenceHolder.style.backgroundColor = "rgb(255,100,100)";
giuliomoro@0 442 this.outsideReferenceHolder.textContent = "Stop";
giuliomoro@0 443 };
giuliomoro@0 444 this.stopPlayback = function()
giuliomoro@0 445 {
giuliomoro@0 446 // Called when playback has stopped. This gets called even if playback never started!
giuliomoro@0 447 $(this.outsideReferenceHolder).removeClass('track-slider-playing');
giuliomoro@0 448 this.outsideReferenceHolder.style.backgroundColor = "";
giuliomoro@0 449 this.outsideReferenceHolder.textContent = "Play Reference";
giuliomoro@0 450 };
giuliomoro@0 451 this.exportXMLDOM = function(audioObject)
giuliomoro@0 452 {
giuliomoro@0 453 return null;
giuliomoro@0 454 };
giuliomoro@0 455 this.getValue = function()
giuliomoro@0 456 {
giuliomoro@0 457 return 0;
giuliomoro@0 458 };
giuliomoro@0 459 this.getPresentedId = function()
giuliomoro@0 460 {
giuliomoro@0 461 return 'reference';
giuliomoro@0 462 };
giuliomoro@0 463 this.canMove = function()
giuliomoro@0 464 {
giuliomoro@0 465 return false;
giuliomoro@0 466 };
giuliomoro@0 467 this.error = function() {
giuliomoro@0 468 // audioObject has an error!!
giuliomoro@0 469 this.outsideReferenceHolder.textContent = "Error";
giuliomoro@0 470 $(this.outsideReferenceHolder).addClass("error-colour");
giuliomoro@0 471 }
giuliomoro@0 472 }
giuliomoro@0 473
giuliomoro@0 474 function resizeWindow(event)
giuliomoro@0 475 {
giuliomoro@0 476 // Called on every window resize event, use this to scale your page properly
giuliomoro@0 477 var numObj = document.getElementsByClassName('track-slider').length;
giuliomoro@0 478 var totalHeight = (numObj * 66)-30;
giuliomoro@0 479 document.getElementById('scale-holder').style.width = window.innerWidth-220 + 'px';
giuliomoro@0 480 var canvas = document.getElementById('scale-canvas');
giuliomoro@0 481 canvas.width = window.innerWidth-520;
giuliomoro@0 482 canvas.height = totalHeight;
giuliomoro@0 483 for (var i in audioEngineContext.audioObjects)
giuliomoro@0 484 {
giuliomoro@0 485 if (audioEngineContext.audioObjects[i].specification.type != 'outside-reference'){
giuliomoro@0 486 audioEngineContext.audioObjects[i].interfaceDOM.resize(event);
giuliomoro@0 487 }
giuliomoro@0 488 }
giuliomoro@0 489 document.getElementById('slider-holder').style.height = totalHeight + 'px';
giuliomoro@0 490 document.getElementById('slider').style.height = totalHeight + 70 + 'px';
giuliomoro@0 491 drawScale();
giuliomoro@0 492 }
giuliomoro@0 493
giuliomoro@0 494 function drawScale()
giuliomoro@0 495 {
giuliomoro@0 496 var interfaceObj = testState.currentStateMap.interfaces[0];
giuliomoro@0 497 var scales = testState.currentStateMap.interfaces[0].scales;
giuliomoro@0 498 scales = scales.sort(function(a,b) {
giuliomoro@0 499 return a.position - b.position;
giuliomoro@0 500 });
giuliomoro@0 501 var canvas = document.getElementById('scale-canvas');
giuliomoro@0 502 var ctx = canvas.getContext("2d");
giuliomoro@0 503 var height = canvas.height;
giuliomoro@0 504 var width = canvas.width;
giuliomoro@0 505 var textHolder = document.getElementById('scale-text-holder');
giuliomoro@0 506 textHolder.innerHTML = null;
giuliomoro@0 507 ctx.fillStyle = "#000000";
giuliomoro@0 508 ctx.setLineDash([1,4]);
giuliomoro@0 509
giuliomoro@0 510 var scaleTextWidthPercent = 100/scales.length - 2;
giuliomoro@0 511 var scaleTextMaxHeight = 0;
giuliomoro@0 512 var scaleTextDivs = [];
giuliomoro@0 513 for (var scale of scales)
giuliomoro@0 514 {
giuliomoro@0 515 var posPercent = scale.position / 100.0;
giuliomoro@0 516 var posPix = Math.round(width * posPercent);
giuliomoro@0 517 if(posPix<=0){posPix=1;}
giuliomoro@0 518 if(posPix>=width){posPix=width-1;}
giuliomoro@0 519 ctx.moveTo(posPix,0);
giuliomoro@0 520 ctx.lineTo(posPix,height);
giuliomoro@0 521 ctx.stroke();
giuliomoro@0 522
giuliomoro@0 523 var text = document.createElement('div');
giuliomoro@0 524 text.align = "center";
giuliomoro@0 525 var textC = document.createElement('span');
giuliomoro@0 526 textC.textContent = scale.text;
giuliomoro@0 527 text.appendChild(textC);
giuliomoro@0 528 text.className = "scale-text";
giuliomoro@0 529 textHolder.appendChild(text);
giuliomoro@0 530 // text.style.width = $(text.children[0]).width()+'px';
giuliomoro@0 531 text.style.width = scaleTextWidthPercent+"%";
giuliomoro@0 532 text.style.left = (posPix+150-($(text).width()/2)) +'px';
giuliomoro@0 533 scaleTextMaxHeight = text.offsetHeight > scaleTextMaxHeight ? text.offsetHeight : scaleTextMaxHeight;
giuliomoro@0 534 scaleTextDivs[scaleTextDivs.length] = text;
giuliomoro@0 535 }
giuliomoro@0 536 var newHeight = scaleTextMaxHeight+"px";
giuliomoro@0 537 for(var scaleTextDiv of scaleTextDivs){
giuliomoro@0 538 scaleTextDiv.style.height = newHeight;
giuliomoro@0 539 }
giuliomoro@0 540 textHolder.style.height = newHeight;
giuliomoro@0 541 var sliderHolder = document.getElementById("slider-holder");
giuliomoro@0 542 sliderHolder.style.marginTop = newHeight;
giuliomoro@0 543 }
giuliomoro@0 544
giuliomoro@0 545 function buttonSubmitClick() // TODO: Only when all songs have been played!
giuliomoro@0 546 {
giuliomoro@0 547 var checks = [];
giuliomoro@14 548 //checks = checks.concat(testState.currentStateMap.interfaces[0].options);
giuliomoro@0 549 checks = checks.concat(specification.interfaces.options);
giuliomoro@0 550 var canContinue = true;
giuliomoro@0 551
giuliomoro@0 552 // Check that the anchor and reference objects are correctly placed
giuliomoro@0 553 if (interfaceContext.checkHiddenAnchor() == false) {return;}
giuliomoro@0 554 if (interfaceContext.checkHiddenReference() == false) {return;}
giuliomoro@0 555
giuliomoro@0 556 for (var i=0; i<checks.length; i++) {
giuliomoro@0 557 if (checks[i].type == 'check')
giuliomoro@0 558 {
giuliomoro@0 559 switch(checks[i].name) {
giuliomoro@0 560 case 'fragmentPlayed':
giuliomoro@0 561 // Check if all fragments have been played
giuliomoro@0 562 var checkState = interfaceContext.checkAllPlayed();
giuliomoro@0 563 if (checkState == false) {canContinue = false;}
giuliomoro@0 564 break;
giuliomoro@0 565 case 'fragmentFullPlayback':
giuliomoro@0 566 // Check all fragments have been played to their full length
giuliomoro@0 567 var checkState = interfaceContext.checkAllPlayed();
giuliomoro@0 568 if (checkState == false) {canContinue = false;}
giuliomoro@0 569 console.log('NOTE: fragmentFullPlayback not currently implemented, performing check fragmentPlayed instead');
giuliomoro@0 570 break;
giuliomoro@0 571 case 'fragmentMoved':
giuliomoro@0 572 // Check all fragment sliders have been moved.
giuliomoro@0 573 var checkState = interfaceContext.checkAllMoved();
giuliomoro@0 574 if (checkState == false) {canContinue = false;}
giuliomoro@0 575 break;
giuliomoro@0 576 case 'fragmentComments':
giuliomoro@0 577 // Check all fragment sliders have been moved.
giuliomoro@0 578 var checkState = interfaceContext.checkAllCommented();
giuliomoro@0 579 if (checkState == false) {canContinue = false;}
giuliomoro@0 580 break;
giuliomoro@0 581 //case 'scalerange':
giuliomoro@0 582 // Check the scale is used to its full width outlined by the node
giuliomoro@0 583 //var checkState = interfaceContext.checkScaleRange();
giuliomoro@0 584 //if (checkState == false) {canContinue = false;}
giuliomoro@0 585 // break;
giuliomoro@0 586 default:
giuliomoro@0 587 console.log("WARNING - Check option "+checks[i].check+" is not supported on this interface");
giuliomoro@0 588 break;
giuliomoro@0 589 }
giuliomoro@0 590
giuliomoro@0 591 }
giuliomoro@0 592 if (!canContinue) {break;}
giuliomoro@0 593 }
giuliomoro@0 594
giuliomoro@0 595 if (canContinue) {
giuliomoro@0 596 if (audioEngineContext.status == 1) {
giuliomoro@0 597 var playback = document.getElementById('playback-button');
giuliomoro@0 598 playback.click();
giuliomoro@0 599 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options
giuliomoro@0 600 } else
giuliomoro@0 601 {
giuliomoro@0 602 if (audioEngineContext.timer.testStarted == false)
giuliomoro@0 603 {
giuliomoro@0 604 alert('You have not started the test! Please press start to begin the test!');
giuliomoro@0 605 return;
giuliomoro@0 606 }
giuliomoro@0 607 }
giuliomoro@0 608 testState.advanceState();
giuliomoro@0 609 }
giuliomoro@0 610 }
giuliomoro@0 611
giuliomoro@0 612 function pageXMLSave(store, pageSpecification)
giuliomoro@0 613 {
giuliomoro@0 614 // MANDATORY
giuliomoro@0 615 // Saves a specific test page
giuliomoro@0 616 // You can use this space to add any extra nodes to your XML <audioHolder> saves
giuliomoro@0 617 // Get the current <page> information in store (remember to appendChild your data to it)
giuliomoro@0 618 // pageSpecification is the current page node configuration
giuliomoro@0 619 // To create new XML nodes, use storage.document.createElement();
giuliomoro@0 620 }