annotate ape.js @ 892:6922eac3b945

Ready for merge into main.
author Nicholas Jillings <nicholas.jillings@eecs.qmul.ac.uk>
date Wed, 17 Jun 2015 16:42:57 +0100
parents 8c44e2d0d6c4
children a049c6cf7eb3
rev   line source
nicholas@886 1 /**
nicholas@886 2 * ape.js
nicholas@886 3 * Create the APE interface
nicholas@886 4 */
nicholas@886 5
nicholas@886 6 // preTest - In preTest state
nicholas@886 7 // testRun-ID - In test running, test Id number at the end 'testRun-2'
nicholas@886 8 // testRunPost-ID - Post test of test ID
nicholas@886 9 // testRunPre-ID - Pre-test of test ID
nicholas@886 10 // postTest - End of test, final submission!
nicholas@886 11
nicholas@886 12
nicholas@886 13 // Once this is loaded and parsed, begin execution
nicholas@886 14 loadInterface();
nicholas@886 15
nicholas@886 16 function loadInterface() {
nicholas@886 17
nicholas@886 18 // Get the dimensions of the screen available to the page
nicholas@886 19 var width = window.innerWidth;
nicholas@886 20 var height = window.innerHeight;
nicholas@886 21
nicholas@886 22 // The injection point into the HTML page
nicholas@886 23 interfaceContext.insertPoint = document.getElementById("topLevelBody");
nicholas@886 24 var testContent = document.createElement('div');
nicholas@886 25
nicholas@886 26 testContent.id = 'testContent';
nicholas@886 27
nicholas@886 28
nicholas@886 29 // Create APE specific metric functions
nicholas@886 30 audioEngineContext.metric.initialiseTest = function()
nicholas@886 31 {
nicholas@886 32 };
nicholas@886 33
nicholas@886 34 audioEngineContext.metric.sliderMoved = function()
nicholas@886 35 {
nicholas@886 36
nicholas@886 37 var id = this.data;
nicholas@886 38 this.data = -1;
nicholas@886 39 var position = convSliderPosToRate(id);
nicholas@886 40 console.log('slider ' + id + ': '+ position + ' (' + time + ')'); // DEBUG/SAFETY: show position and slider id
nicholas@886 41 if (audioEngineContext.timer.testStarted)
nicholas@886 42 {
nicholas@886 43 audioEngineContext.audioObjects[id].metric.moved(time,position);
nicholas@886 44 }
nicholas@886 45 };
nicholas@886 46
nicholas@886 47 audioEngineContext.metric.sliderPlayed = function(id)
nicholas@886 48 {
nicholas@886 49 var time = audioEngineContext.timer.getTestTime();
nicholas@886 50 if (audioEngineContext.timer.testStarted)
nicholas@886 51 {
nicholas@886 52 if (this.lastClicked >= 0)
nicholas@886 53 {
nicholas@886 54 audioEngineContext.audioObjects[this.lastClicked].metric.listening(time);
nicholas@886 55 }
nicholas@886 56 this.lastClicked = id;
nicholas@886 57 audioEngineContext.audioObjects[id].metric.listening(time);
nicholas@886 58 }
nicholas@886 59 console.log('slider ' + id + ' played (' + time + ')'); // DEBUG/SAFETY: show played slider id
nicholas@886 60 };
nicholas@886 61
nicholas@887 62 // Bindings for interfaceContext
nicholas@887 63 Interface.prototype.checkAllPlayed = function()
nicholas@887 64 {
nicholas@887 65 hasBeenPlayed = audioEngineContext.checkAllPlayed();
nicholas@887 66 if (hasBeenPlayed.length > 0) // if a fragment has not been played yet
nicholas@887 67 {
nicholas@887 68 str = "";
nicholas@887 69 if (hasBeenPlayed.length > 1) {
nicholas@887 70 for (var i=0; i<hasBeenPlayed.length; i++) {
nicholas@887 71 str = str + hasBeenPlayed[i];
nicholas@887 72 if (i < hasBeenPlayed.length-2){
nicholas@887 73 str += ", ";
nicholas@887 74 } else if (i == hasBeenPlayed.length-2) {
nicholas@887 75 str += " or ";
nicholas@887 76 }
nicholas@887 77 }
nicholas@887 78 alert('You have not played fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.');
nicholas@887 79 } else {
nicholas@887 80 alert('You have not played fragment ' + hasBeenPlayed[0] + ' yet. Please listen, rate and comment all samples before submitting.');
nicholas@887 81 }
nicholas@887 82 return false;
nicholas@887 83 }
nicholas@887 84 return true;
nicholas@891 85 };
nicholas@887 86
nicholas@887 87 Interface.prototype.checkAllMoved = function() {
nicholas@887 88 var audioObjs = audioEngineContext.audioObjects;
nicholas@887 89 var state = true;
nicholas@887 90 var strNums = [];
nicholas@887 91 for (var i=0; i<audioObjs.length; i++)
nicholas@887 92 {
nicholas@887 93 if (audioObjs[i].metric.wasMoved == false) {
nicholas@887 94 state = false;
nicholas@887 95 strNums.push(i);
nicholas@887 96 }
nicholas@887 97 }
nicholas@887 98 if (state == false) {
nicholas@887 99 if (strNums.length > 1) {
nicholas@887 100 var str = "";
nicholas@887 101 for (var i=0; i<strNums.length; i++) {
nicholas@887 102 str = str + strNums[i];
nicholas@887 103 if (i < strNums.length-2){
nicholas@887 104 str += ", ";
nicholas@887 105 } else if (i == strNums.length-2) {
nicholas@887 106 str += " or ";
nicholas@887 107 }
nicholas@887 108 }
nicholas@887 109 alert('You have not moved fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.');
nicholas@887 110 } else {
nicholas@887 111 alert('You have not moved fragment ' + strNums[0] + ' yet. Please listen, rate and comment all samples before submitting.');
nicholas@887 112 }
nicholas@887 113 }
nicholas@887 114 return state;
nicholas@891 115 };
nicholas@887 116
nicholas@887 117 Interface.prototype.checkAllCommented = function() {
nicholas@887 118 var audioObjs = audioEngineContext.audioObjects;
nicholas@887 119 var audioHolder = testState.stateMap[testState.stateIndex];
nicholas@887 120 var state = true;
nicholas@887 121 if (audioHolder.elementComments) {
nicholas@887 122 var strNums = [];
nicholas@887 123 for (var i=0; i<audioObjs.length; i++)
nicholas@887 124 {
nicholas@887 125 if (audioObjs[i].commentDOM.trackCommentBox.value.length == 0) {
nicholas@887 126 state = false;
nicholas@887 127 strNums.push(i);
nicholas@887 128 }
nicholas@887 129 }
nicholas@887 130 if (state == false) {
nicholas@887 131 if (strNums.length > 1) {
nicholas@887 132 var str = "";
nicholas@887 133 for (var i=0; i<strNums.length; i++) {
nicholas@887 134 str = str + strNums[i];
nicholas@887 135 if (i < strNums.length-2){
nicholas@887 136 str += ", ";
nicholas@887 137 } else if (i == strNums.length-2) {
nicholas@887 138 str += " or ";
nicholas@887 139 }
nicholas@887 140 }
nicholas@887 141 alert('You have not commented on fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.');
nicholas@887 142 } else {
nicholas@887 143 alert('You have not commented on fragment ' + strNums[0] + ' yet. Please listen, rate and comment all samples before submitting.');
nicholas@887 144 }
nicholas@887 145 }
nicholas@887 146 }
nicholas@887 147 return state;
nicholas@891 148 };
nicholas@887 149
nicholas@886 150 // Bindings for audioObjects
nicholas@886 151
nicholas@886 152 // Create the top div for the Title element
nicholas@886 153 var titleAttr = specification.title;
nicholas@886 154 var title = document.createElement('div');
nicholas@886 155 title.className = "title";
nicholas@886 156 title.align = "center";
nicholas@886 157 var titleSpan = document.createElement('span');
nicholas@886 158
nicholas@886 159 // Set title to that defined in XML, else set to default
nicholas@886 160 if (titleAttr != undefined) {
nicholas@886 161 titleSpan.textContent = titleAttr;
nicholas@886 162 } else {
nicholas@886 163 titleSpan.textContent = 'Listening test';
nicholas@886 164 }
nicholas@886 165 // Insert the titleSpan element into the title div element.
nicholas@886 166 title.appendChild(titleSpan);
nicholas@886 167
nicholas@886 168 var pagetitle = document.createElement('div');
nicholas@886 169 pagetitle.className = "pageTitle";
nicholas@886 170 pagetitle.align = "center";
nicholas@886 171 var titleSpan = document.createElement('span');
nicholas@886 172 titleSpan.id = "pageTitle";
nicholas@886 173 pagetitle.appendChild(titleSpan);
nicholas@886 174
nicholas@886 175 // Create Interface buttons!
nicholas@886 176 var interfaceButtons = document.createElement('div');
nicholas@886 177 interfaceButtons.id = 'interface-buttons';
nicholas@886 178
nicholas@886 179 // Create playback start/stop points
nicholas@886 180 var playback = document.createElement("button");
nicholas@886 181 playback.innerHTML = 'Stop';
nicholas@886 182 playback.id = 'playback-button';
nicholas@886 183 // onclick function. Check if it is playing or not, call the correct function in the
nicholas@886 184 // audioEngine, change the button text to reflect the next state.
nicholas@886 185 playback.onclick = function() {
nicholas@886 186 if (audioEngineContext.status == 1) {
nicholas@886 187 audioEngineContext.stop();
nicholas@886 188 this.innerHTML = 'Stop';
nicholas@886 189 var time = audioEngineContext.timer.getTestTime();
nicholas@886 190 console.log('Stopped at ' + time); // DEBUG/SAFETY
nicholas@886 191 }
nicholas@886 192 };
nicholas@886 193 // Create Submit (save) button
nicholas@886 194 var submit = document.createElement("button");
nicholas@886 195 submit.innerHTML = 'Submit';
nicholas@886 196 submit.onclick = buttonSubmitClick;
nicholas@886 197 submit.id = 'submit-button';
nicholas@886 198 // Append the interface buttons into the interfaceButtons object.
nicholas@886 199 interfaceButtons.appendChild(playback);
nicholas@886 200 interfaceButtons.appendChild(submit);
nicholas@886 201
nicholas@886 202 // Now create the slider and HTML5 canvas boxes
nicholas@886 203
nicholas@886 204 // Create the div box to center align
nicholas@886 205 var sliderBox = document.createElement('div');
nicholas@886 206 sliderBox.className = 'sliderCanvasDiv';
nicholas@886 207 sliderBox.id = 'sliderCanvasHolder';
nicholas@886 208
nicholas@886 209 // Create the slider box to hold the slider elements
nicholas@886 210 var canvas = document.createElement('div');
nicholas@886 211 canvas.id = 'slider';
nicholas@886 212 canvas.align = "left";
nicholas@886 213 canvas.addEventListener('dragover',function(event){
nicholas@886 214 event.preventDefault();
nicholas@886 215 return false;
nicholas@886 216 },false);
nicholas@886 217 var sliderMargin = document.createAttribute('marginsize');
nicholas@886 218 sliderMargin.nodeValue = 42; // Set default margins to 42px either side
nicholas@886 219 // Must have a known EXACT width, as this is used later to determine the ratings
nicholas@886 220 var w = (Number(sliderMargin.nodeValue)+8)*2;
nicholas@886 221 canvas.style.width = width - w +"px";
nicholas@886 222 canvas.style.marginLeft = sliderMargin.nodeValue +'px';
nicholas@886 223 canvas.setAttributeNode(sliderMargin);
nicholas@886 224 sliderBox.appendChild(canvas);
nicholas@886 225
nicholas@886 226 // Create the div to hold any scale objects
nicholas@886 227 var scale = document.createElement('div');
nicholas@886 228 scale.className = 'sliderScale';
nicholas@886 229 scale.id = 'sliderScaleHolder';
nicholas@886 230 scale.align = 'left';
nicholas@886 231 sliderBox.appendChild(scale);
nicholas@886 232
nicholas@886 233 // Global parent for the comment boxes on the page
nicholas@886 234 var feedbackHolder = document.createElement('div');
nicholas@886 235 feedbackHolder.id = 'feedbackHolder';
nicholas@886 236
nicholas@886 237 testContent.style.zIndex = 1;
nicholas@886 238 interfaceContext.insertPoint.innerHTML = null; // Clear the current schema
nicholas@886 239
nicholas@886 240 // Inject into HTML
nicholas@886 241 testContent.appendChild(title); // Insert the title
nicholas@886 242 testContent.appendChild(pagetitle);
nicholas@886 243 testContent.appendChild(interfaceButtons);
nicholas@886 244 testContent.appendChild(sliderBox);
nicholas@886 245 testContent.appendChild(feedbackHolder);
nicholas@886 246 interfaceContext.insertPoint.appendChild(testContent);
nicholas@886 247
nicholas@886 248 // Load the full interface
nicholas@886 249 testState.initialise();
nicholas@886 250 testState.advanceState();
nicholas@886 251
nicholas@886 252 }
nicholas@886 253
nicholas@886 254 function loadTest(audioHolderObject)
nicholas@886 255 {
nicholas@886 256
nicholas@886 257 // Reset audioEngineContext.Metric globals for new test
nicholas@886 258 audioEngineContext.newTestPage();
nicholas@886 259
nicholas@886 260 var id = audioHolderObject.id;
nicholas@886 261
nicholas@886 262 var feedbackHolder = document.getElementById('feedbackHolder');
nicholas@886 263 var canvas = document.getElementById('slider');
nicholas@886 264 feedbackHolder.innerHTML = null;
nicholas@886 265 canvas.innerHTML = null;
nicholas@886 266
nicholas@892 267 //var playbackHolder = document.createElement('div');
nicholas@892 268 //playbackHolder.style.width = "100%";
nicholas@892 269 //playbackHolder.align = 'center';
nicholas@892 270 //playbackHolder.appendChild(interfaceContext.playhead.object);
nicholas@892 271 //feedbackHolder.appendChild(playbackHolder);
nicholas@886 272 // Setup question title
nicholas@886 273 var interfaceObj = audioHolderObject.interfaces;
nicholas@886 274 var commentBoxPrefix = "Comment on track";
nicholas@886 275 if (interfaceObj.length != 0) {
nicholas@886 276 interfaceObj = interfaceObj[0];
nicholas@886 277 var titleNode = interfaceObj.title;
nicholas@886 278 if (titleNode != undefined)
nicholas@886 279 {
nicholas@886 280 document.getElementById('pageTitle').textContent = titleNode;
nicholas@886 281 }
nicholas@886 282 var positionScale = canvas.style.width.substr(0,canvas.style.width.length-2);
nicholas@886 283 var offset = Number(document.getElementById('slider').attributes['marginsize'].value);
nicholas@886 284 var scale = document.getElementById('sliderScaleHolder');
nicholas@886 285 scale.innerHTML = null;
nicholas@886 286 $(interfaceObj.scale).each(function(index,scaleObj){
nicholas@886 287 var value = document.createAttribute('value');
nicholas@886 288 var position = Number(scaleObj[0])*0.01;
nicholas@886 289 value.nodeValue = position;
nicholas@886 290 var pixelPosition = (position*positionScale)+offset;
nicholas@886 291 var scaleDOM = document.createElement('span');
nicholas@886 292 scaleDOM.textContent = scaleObj[1];
nicholas@886 293 scale.appendChild(scaleDOM);
nicholas@886 294 scaleDOM.style.left = Math.floor((pixelPosition-($(scaleDOM).width()/2)))+'px';
nicholas@886 295 scaleDOM.setAttributeNode(value);
nicholas@886 296 });
nicholas@886 297
nicholas@886 298 if (interfaceObj.commentBoxPrefix != undefined) {
nicholas@886 299 commentBoxPrefix = interfaceObj.commentBoxPrefix;
nicholas@886 300 }
nicholas@886 301 }
nicholas@886 302
nicholas@886 303 /// CHECK FOR SAMPLE RATE COMPATIBILITY
nicholas@886 304 if (audioHolderObject.sampleRate != undefined) {
nicholas@886 305 if (Number(audioHolderObject.sampleRate) != audioContext.sampleRate) {
nicholas@886 306 var errStr = 'Sample rates do not match! Requested '+Number(audioHolderObject.sampleRate)+', got '+audioContext.sampleRate+'. Please set the sample rate to match before completing this test.';
nicholas@886 307 alert(errStr);
nicholas@886 308 return;
nicholas@886 309 }
nicholas@886 310 }
nicholas@886 311
nicholas@886 312 var commentShow = audioHolderObject.elementComments;
nicholas@886 313
nicholas@886 314 var loopPlayback = audioHolderObject.loop;
nicholas@886 315
nicholas@886 316 audioEngineContext.loopPlayback = loopPlayback;
nicholas@886 317 // Create AudioEngine bindings for playback
nicholas@886 318 audioEngineContext.selectedTrack = function(id) {
nicholas@886 319 console.log('Deprecated');
nicholas@886 320 };
nicholas@886 321
nicholas@886 322 currentTestHolder = document.createElement('audioHolder');
nicholas@886 323 currentTestHolder.id = audioHolderObject.id;
nicholas@886 324 currentTestHolder.repeatCount = audioHolderObject.repeatCount;
nicholas@886 325
nicholas@886 326 var randomise = audioHolderObject.randomiseOrder;
nicholas@886 327
nicholas@886 328 var audioElements = audioHolderObject.audioElements;
nicholas@886 329 currentTrackOrder = [];
nicholas@886 330 if (randomise) {
nicholas@886 331 audioHolderObject.audioElements = randomiseOrder(audioHolderObject.audioElements);
nicholas@886 332 }
nicholas@886 333
nicholas@886 334 // Delete any previous audioObjects associated with the audioEngine
nicholas@886 335 audioEngineContext.audioObjects = [];
nicholas@886 336 interfaceContext.deleteCommentBoxes();
nicholas@886 337
nicholas@886 338 // Find all the audioElements from the audioHolder
nicholas@886 339 $(audioHolderObject.audioElements).each(function(index,element){
nicholas@886 340 // Find URL of track
nicholas@886 341 // In this jQuery loop, variable 'this' holds the current audioElement.
nicholas@886 342
nicholas@886 343 // Now load each audio sample. First create the new track by passing the full URL
nicholas@886 344 var trackURL = audioHolderObject.hostURL + element.url;
nicholas@886 345 var audioObject = audioEngineContext.newTrack(element);
nicholas@886 346
nicholas@886 347 var node = interfaceContext.createCommentBox(audioObject);
nicholas@886 348
nicholas@886 349 // Create a slider per track
nicholas@886 350 audioObject.interfaceDOM = new sliderObject(audioObject);
nicholas@886 351
nicholas@886 352 // Distribute it randomnly
nicholas@886 353 var w = window.innerWidth - (offset+8)*2;
nicholas@886 354 w = Math.random()*w;
nicholas@886 355 w = Math.floor(w+(offset+8));
nicholas@886 356 audioObject.interfaceDOM.trackSliderObj.style.left = w+'px';
nicholas@886 357
nicholas@886 358 canvas.appendChild(audioObject.interfaceDOM.trackSliderObj);
nicholas@886 359 audioObject.metric.initialised(convSliderPosToRate(audioObject.interfaceDOM.trackSliderObj));
nicholas@886 360
nicholas@886 361 });
nicholas@886 362 if (commentShow) {
nicholas@886 363 interfaceContext.showCommentBoxes(feedbackHolder,true);
nicholas@886 364 }
nicholas@886 365
nicholas@886 366 $(audioHolderObject.commentQuestions).each(function(index,element) {
nicholas@886 367 var node = interfaceContext.createCommentQuestion(element);
nicholas@886 368 feedbackHolder.appendChild(node.holder);
nicholas@886 369 });
nicholas@886 370
nicholas@886 371
nicholas@886 372 testWaitIndicator();
nicholas@886 373 }
nicholas@886 374
nicholas@886 375 function sliderObject(audioObject) {
nicholas@886 376 // Create a new slider object;
nicholas@886 377 this.parent = audioObject;
nicholas@886 378 this.trackSliderObj = document.createElement('div');
nicholas@886 379 this.trackSliderObj.className = 'track-slider';
nicholas@886 380 this.trackSliderObj.id = 'track-slider-'+audioObject.id;
nicholas@886 381
nicholas@886 382 this.trackSliderObj.setAttribute('trackIndex',audioObject.id);
nicholas@886 383 this.trackSliderObj.innerHTML = '<span>'+audioObject.id+'</span>';
nicholas@886 384 this.trackSliderObj.draggable = true;
nicholas@886 385 this.trackSliderObj.ondragend = dragEnd;
nicholas@886 386
nicholas@886 387 // Onclick, switch playback to that track
nicholas@886 388 this.trackSliderObj.onclick = function() {
nicholas@886 389 // Start the test on first click, that way timings are more accurate.
nicholas@886 390 audioEngineContext.play();
nicholas@886 391 if (audioEngineContext.audioObjectsReady) {
nicholas@886 392 // Cannot continue to issue play command until audioObjects reported as ready!
nicholas@886 393 // Get the track ID from the object ID
nicholas@886 394 var element;
nicholas@886 395 if (event.srcElement.nodeName == "SPAN") {
nicholas@886 396 element = event.srcElement.parentNode;
nicholas@886 397 } else {
nicholas@886 398 element = event.srcElement;
nicholas@886 399 }
nicholas@886 400 var id = Number(element.attributes['trackIndex'].value);
nicholas@886 401 //audioEngineContext.metric.sliderPlayed(id);
nicholas@886 402 audioEngineContext.play(id);
nicholas@886 403 // Currently playing track red, rest green
nicholas@886 404
nicholas@886 405 //document.getElementById('track-slider-'+index).style.backgroundColor = "#FF0000";
nicholas@886 406 $('.track-slider').removeClass('track-slider-playing');
nicholas@886 407 $(element).addClass('track-slider-playing');
nicholas@886 408 $('.comment-div').removeClass('comment-box-playing');
nicholas@886 409 $('#comment-div-'+id).addClass('comment-box-playing');
nicholas@886 410 }
nicholas@886 411 };
nicholas@886 412
nicholas@891 413 this.exportXMLDOM = function(audioObject) {
nicholas@886 414 // Called by the audioObject holding this element. Must be present
nicholas@886 415 var node = document.createElement('value');
nicholas@886 416 node.textContent = convSliderPosToRate(this.trackSliderObj);
nicholas@886 417 return node;
nicholas@886 418 };
nicholas@891 419 this.getValue = function() {
nicholas@891 420 return convSliderPosToRate(this.trackSliderObj);
nicholas@892 421 };
nicholas@886 422 }
nicholas@886 423
nicholas@886 424 function dragEnd(ev) {
nicholas@886 425 // Function call when a div has been dropped
nicholas@886 426 var slider = document.getElementById('slider');
nicholas@886 427 var marginSize = Number(slider.attributes['marginsize'].value);
nicholas@886 428 var w = slider.style.width;
nicholas@886 429 w = Number(w.substr(0,w.length-2));
nicholas@886 430 var x = ev.x;
nicholas@886 431 if (x >= marginSize && x < w+marginSize) {
nicholas@886 432 this.style.left = (x)+'px';
nicholas@886 433 } else {
nicholas@886 434 if (x<marginSize) {
nicholas@886 435 this.style.left = marginSize+'px';
nicholas@886 436 } else {
nicholas@886 437 this.style.left = (w+marginSize) + 'px';
nicholas@886 438 }
nicholas@886 439 }
nicholas@886 440 var time = audioEngineContext.timer.getTestTime();
nicholas@886 441 var id = Number(ev.srcElement.getAttribute('trackindex'));
nicholas@886 442 audioEngineContext.audioObjects[id].metric.moved(time,convSliderPosToRate(ev.srcElement));
nicholas@886 443 }
nicholas@886 444
nicholas@886 445 function buttonSubmitClick() // TODO: Only when all songs have been played!
nicholas@886 446 {
nicholas@887 447 var checks = specification.commonInterface.options;
nicholas@887 448 var canContinue = true;
nicholas@891 449
nicholas@891 450 // Check that the anchor and reference objects are correctly placed
nicholas@891 451 var audioObjs = audioEngineContext.audioObjects;
nicholas@891 452 var audioHolder = testState.stateMap[testState.stateIndex];
nicholas@891 453 var anchorId = null;
nicholas@891 454 var referenceId = null;
nicholas@891 455 for (var i=0; i<audioObjs.length; i++) {
nicholas@891 456 if (audioObjs[i].specification.anchor == true && anchorId == null) {anchorId = i;}
nicholas@891 457 if (audioObjs[i].specification.reference == true && referenceId == null) {referenceId = i;}
nicholas@891 458 }
nicholas@891 459 if (anchorId != null) {
nicholas@891 460 if (audioObjs[anchorId].specification.marker != null) {
nicholas@891 461 if (audioObjs[anchorId].interfaceDOM.getValue() > audioObjs[anchorId].specification.marker)
nicholas@891 462 {
nicholas@891 463 // Anchor is not set below
nicholas@891 464 console.log('Anchor node not below marker value');
nicholas@891 465 alert('Please keep listening');
nicholas@891 466 return;
nicholas@891 467 }
nicholas@891 468 } else {
nicholas@891 469 // No marker value given, ensure it is the minimum value
nicholas@891 470 var anchorVal = audioObjs[anchorId].interfaceDOM.getValue();
nicholas@891 471 for (var i=0; i<audioObjs.length; i++) {
nicholas@891 472 if (i != anchorId) {
nicholas@891 473 if (anchorVal > audioObjs[i].interfaceDOM.getValue()) {
nicholas@891 474 // Anchor not the minimum
nicholas@891 475 console.log('No marker set, anchor node not the minimum');
nicholas@891 476 alert('Please keep listening');
nicholas@891 477 return;
nicholas@891 478 }
nicholas@891 479 }
nicholas@891 480 }
nicholas@891 481 }
nicholas@891 482 }
nicholas@891 483 if (referenceId != null) {
nicholas@891 484 if (audioObjs[referenceId].specification.marker != null) {
nicholas@891 485 if (audioObjs[referenceId].interfaceDOM.getValue() < audioObjs[referenceId].specification.marker)
nicholas@891 486 {
nicholas@891 487 // Anchor is not set below
nicholas@891 488 console.log('Reference node not above marker value');
nicholas@891 489 alert('Please keep listening');
nicholas@891 490 return;
nicholas@891 491 }
nicholas@891 492 } else {
nicholas@891 493 // No marker value given, ensure it is the minimum value
nicholas@891 494 var referenceVal = audioObjs[referenceId].interfaceDOM.getValue();
nicholas@891 495 for (var i=0; i<audioObjs.length; i++) {
nicholas@891 496 if (i != referenceId) {
nicholas@891 497 if (referenceVal > audioObjs[i].interfaceDOM.getValue()) {
nicholas@891 498 // Anchor not the minimum
nicholas@891 499 console.log('No marker set, reference node not the maximum');
nicholas@891 500 alert('Please keep listening');
nicholas@891 501 return;
nicholas@891 502 }
nicholas@891 503 }
nicholas@891 504 }
nicholas@891 505 }
nicholas@891 506 }
nicholas@891 507
nicholas@887 508 for (var i=0; i<checks.length; i++) {
nicholas@887 509 if (checks[i].type == 'check')
nicholas@887 510 {
nicholas@887 511 switch(checks[i].check) {
nicholas@887 512 case 'fragmentPlayed':
nicholas@887 513 // Check if all fragments have been played
nicholas@887 514 var checkState = interfaceContext.checkAllPlayed();
nicholas@887 515 if (checkState == false) {canContinue = false;}
nicholas@887 516 break;
nicholas@887 517 case 'fragmentFullPlayback':
nicholas@887 518 // Check all fragments have been played to their full length
nicholas@887 519 var checkState = interfaceContext.checkAllPlayed();
nicholas@887 520 if (checkState == false) {canContinue = false;}
nicholas@887 521 console.log('NOTE: fragmentFullPlayback not currently implemented, performing check fragmentPlayed instead');
nicholas@887 522 break;
nicholas@887 523 case 'fragmentMoved':
nicholas@887 524 // Check all fragment sliders have been moved.
nicholas@887 525 var checkState = interfaceContext.checkAllMoved();
nicholas@887 526 if (checkState == false) {canContinue = false;}
nicholas@887 527 break;
nicholas@887 528 case 'fragmentComments':
nicholas@887 529 // Check all fragment sliders have been moved.
nicholas@887 530 var checkState = interfaceContext.checkAllCommented();
nicholas@887 531 if (checkState == false) {canContinue = false;}
nicholas@887 532 break;
nicholas@887 533 }
nicholas@887 534
nicholas@887 535 }
nicholas@887 536 }
nicholas@887 537
nicholas@887 538 if (canContinue) {
nicholas@886 539 if (audioEngineContext.status == 1) {
nicholas@886 540 var playback = document.getElementById('playback-button');
nicholas@886 541 playback.click();
nicholas@886 542 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options
nicholas@886 543 } else
nicholas@886 544 {
nicholas@886 545 if (audioEngineContext.timer.testStarted == false)
nicholas@886 546 {
nicholas@886 547 alert('You have not started the test! Please press start to begin the test!');
nicholas@886 548 return;
nicholas@886 549 }
nicholas@886 550 }
nicholas@886 551 testState.advanceState();
nicholas@887 552 }
nicholas@886 553 }
nicholas@886 554
nicholas@886 555 function convSliderPosToRate(slider)
nicholas@886 556 {
nicholas@886 557 var w = document.getElementById('slider').style.width;
nicholas@886 558 var marginsize = Number(document.getElementById('slider').attributes['marginsize'].value);
nicholas@886 559 var maxPix = w.substr(0,w.length-2);
nicholas@886 560 var pix = slider.style.left;
nicholas@886 561 pix = pix.substr(0,pix.length-2);
nicholas@886 562 var rate = (pix-marginsize)/maxPix;
nicholas@886 563 return rate;
nicholas@886 564 }
nicholas@886 565
nicholas@886 566 function resizeWindow(event){
nicholas@886 567 // Function called when the window has been resized.
nicholas@886 568 // MANDATORY FUNCTION
nicholas@886 569
nicholas@886 570 // Store the slider marker values
nicholas@886 571 var holdValues = [];
nicholas@886 572 $(".track-slider").each(function(index,sliderObj){
nicholas@886 573 holdValues.push(convSliderPosToRate(index));
nicholas@886 574 });
nicholas@886 575
nicholas@886 576 var width = event.target.innerWidth;
nicholas@886 577 var canvas = document.getElementById('sliderCanvasHolder');
nicholas@886 578 var sliderDiv = canvas.children[0];
nicholas@886 579 var sliderScaleDiv = canvas.children[1];
nicholas@886 580 var marginsize = Number(sliderDiv.attributes['marginsize'].value);
nicholas@886 581 var w = (marginsize+8)*2;
nicholas@886 582 sliderDiv.style.width = width - w + 'px';
nicholas@886 583 var width = width - w;
nicholas@886 584 // Move sliders into new position
nicholas@886 585 $(".track-slider").each(function(index,sliderObj){
nicholas@886 586 var pos = holdValues[index];
nicholas@886 587 var pix = pos * width;
nicholas@886 588 sliderObj.style.left = pix+marginsize+'px';
nicholas@886 589 });
nicholas@886 590
nicholas@886 591 // Move scale labels
nicholas@886 592 $(sliderScaleDiv.children).each(function(index,scaleObj){
nicholas@886 593 var position = Number(scaleObj.attributes['value'].value);
nicholas@886 594 var pixelPosition = (position*width)+marginsize;
nicholas@886 595 scaleObj.style.left = Math.floor((pixelPosition-($(scaleObj).width()/2)))+'px';
nicholas@886 596 });
nicholas@886 597 }
nicholas@886 598
nicholas@886 599 function pageXMLSave(store, testXML)
nicholas@886 600 {
nicholas@886 601 // Saves a specific test page
nicholas@886 602 var xmlDoc = store;
nicholas@886 603 // Check if any session wide metrics are enabled
nicholas@886 604
nicholas@886 605 var commentShow = testXML.elementComments;
nicholas@886 606
nicholas@886 607 var metric = document.createElement('metric');
nicholas@886 608 if (audioEngineContext.metric.enableTestTimer)
nicholas@886 609 {
nicholas@886 610 var testTime = document.createElement('metricResult');
nicholas@886 611 testTime.id = 'testTime';
nicholas@886 612 testTime.textContent = audioEngineContext.timer.testDuration;
nicholas@886 613 metric.appendChild(testTime);
nicholas@886 614 }
nicholas@886 615 xmlDoc.appendChild(metric);
nicholas@886 616 var audioObjects = audioEngineContext.audioObjects;
nicholas@886 617 for (var i=0; i<audioObjects.length; i++)
nicholas@886 618 {
nicholas@886 619 var audioElement = audioEngineContext.audioObjects[i].exportXMLDOM();
nicholas@886 620 xmlDoc.appendChild(audioElement);
nicholas@886 621 }
nicholas@886 622
nicholas@886 623 $(interfaceContext.commentQuestions).each(function(index,element){
nicholas@886 624 var node = element.exportXMLDOM();
nicholas@886 625 xmlDoc.appendChild(node);
nicholas@886 626 });
nicholas@886 627 store = xmlDoc;
nicholas@886 628 }