annotate ape.js @ 119:3df87d0e4dbc

Removed commented chunk in ape.js
author Nicholas Jillings <nicholas.jillings@eecs.qmul.ac.uk>
date Tue, 26 May 2015 14:19:03 +0100
parents 43c0e9dbc367
children 1ea9a9eeeae5
rev   line source
nicholas@2 1 /**
nicholas@2 2 * ape.js
nicholas@2 3 * Create the APE interface
nicholas@2 4 */
nicholas@2 5
n@38 6 // preTest - In preTest state
n@38 7 // testRun-ID - In test running, test Id number at the end 'testRun-2'
n@38 8 // testRunPost-ID - Post test of test ID
n@38 9 // testRunPre-ID - Pre-test of test ID
n@38 10 // postTest - End of test, final submission!
n@38 11
n@32 12
nicholas@2 13 // Once this is loaded and parsed, begin execution
nicholas@2 14 loadInterface(projectXML);
nicholas@2 15
nicholas@2 16 function loadInterface(xmlDoc) {
nicholas@2 17
n@16 18 // Get the dimensions of the screen available to the page
nicholas@2 19 var width = window.innerWidth;
nicholas@2 20 var height = window.innerHeight;
nicholas@2 21
nicholas@2 22 // The injection point into the HTML page
nicholas@2 23 var insertPoint = document.getElementById("topLevelBody");
n@22 24 var testContent = document.createElement('div');
n@22 25 testContent.id = 'testContent';
nicholas@2 26
nicholas@7 27
nicholas@2 28 // Decode parts of the xmlDoc that are needed
nicholas@2 29 // xmlDoc MUST already be parsed by jQuery!
nicholas@2 30 var xmlSetup = xmlDoc.find('setup');
nicholas@2 31 // Should put in an error function here incase of malprocessed or malformed XML
nicholas@2 32
n@34 33 // Extract the different test XML DOM trees
n@50 34 var audioHolders = xmlDoc.find('audioHolder');
n@50 35 audioHolders.each(function(index,element) {
n@50 36 var repeatN = element.attributes['repeatCount'].value;
n@50 37 for (var r=0; r<=repeatN; r++) {
n@50 38 testXMLSetups[testXMLSetups.length] = element;
n@50 39 }
n@50 40 });
n@44 41
n@50 42 // New check if we need to randomise the test order
n@50 43 var randomise = xmlSetup[0].attributes['randomiseOrder'];
n@50 44 if (randomise != undefined) {
nicholas@109 45 if (randomise.value === 'true'){
nicholas@109 46 randomise = true;
nicholas@109 47 } else {
nicholas@109 48 randomise = false;
nicholas@109 49 }
n@50 50 } else {
n@50 51 randomise = false;
n@50 52 }
nicholas@109 53
n@50 54 if (randomise)
n@50 55 {
n@54 56 testXMLSetups = randomiseOrder(testXMLSetups);
n@50 57 }
n@44 58
n@50 59 // Obtain the metrics enabled
n@50 60 var metricNode = xmlSetup.find('Metric');
n@50 61 var metricNode = metricNode.find('metricEnable');
n@50 62 metricNode.each(function(index,node){
n@50 63 var enabled = node.textContent;
n@50 64 switch(enabled)
n@50 65 {
n@50 66 case 'testTimer':
n@50 67 sessionMetrics.prototype.enableTestTimer = true;
n@50 68 break;
n@50 69 case 'elementTimer':
n@50 70 sessionMetrics.prototype.enableElementTimer = true;
n@50 71 break;
n@50 72 case 'elementTracker':
n@50 73 sessionMetrics.prototype.enableElementTracker = true;
n@50 74 break;
n@50 75 case 'elementInitalPosition':
n@50 76 sessionMetrics.prototype.enableElementInitialPosition = true;
n@50 77 break;
n@50 78 case 'elementFlagListenedTo':
n@50 79 sessionMetrics.prototype.enableFlagListenedTo = true;
n@50 80 break;
n@50 81 case 'elementFlagMoved':
n@50 82 sessionMetrics.prototype.enableFlagMoved = true;
n@50 83 break;
n@50 84 case 'elementFlagComments':
n@50 85 sessionMetrics.prototype.enableFlagComments = true;
n@50 86 break;
n@50 87 }
n@50 88 });
n@34 89
n@52 90 // Create APE specific metric functions
n@52 91 audioEngineContext.metric.initialiseTest = function()
n@52 92 {
n@52 93 var sliders = document.getElementsByClassName('track-slider');
n@52 94 for (var i=0; i<sliders.length; i++)
n@52 95 {
n@52 96 audioEngineContext.audioObjects[i].metric.initialised(convSliderPosToRate(i));
n@52 97 }
n@52 98 };
n@52 99
n@52 100 audioEngineContext.metric.sliderMoveStart = function(id)
n@52 101 {
n@52 102 if (this.data == -1)
n@52 103 {
n@52 104 this.data = id;
n@52 105 } else {
n@52 106 console.log('ERROR: Metric tracker detecting two moves!');
n@52 107 this.data = -1;
n@52 108 }
n@52 109 };
n@52 110 audioEngineContext.metric.sliderMoved = function()
n@52 111 {
n@52 112 var time = audioEngineContext.timer.getTestTime();
n@52 113 var id = this.data;
n@52 114 this.data = -1;
n@52 115 var position = convSliderPosToRate(id);
b@115 116 console.log('slider ' + id + ': '+ position + ' (' + time + ')'); // DEBUG/SAFETY: show position and slider id
n@52 117 if (audioEngineContext.timer.testStarted)
n@52 118 {
n@52 119 audioEngineContext.audioObjects[id].metric.moved(time,position);
n@52 120 }
n@52 121 };
n@52 122
n@52 123 audioEngineContext.metric.sliderPlayed = function(id)
n@52 124 {
n@52 125 var time = audioEngineContext.timer.getTestTime();
n@52 126 if (audioEngineContext.timer.testStarted)
n@52 127 {
n@52 128 if (this.lastClicked >= 0)
n@52 129 {
n@52 130 audioEngineContext.audioObjects[this.lastClicked].metric.listening(time);
n@52 131 }
n@52 132 this.lastClicked = id;
n@52 133 audioEngineContext.audioObjects[id].metric.listening(time);
n@52 134 }
b@115 135 console.log('slider ' + id + ' played (' + time + ')'); // DEBUG/SAFETY: show played slider id
n@52 136 };
n@52 137
nicholas@2 138 // Create the top div for the Title element
nicholas@2 139 var titleAttr = xmlSetup[0].attributes['title'];
nicholas@2 140 var title = document.createElement('div');
nicholas@2 141 title.className = "title";
nicholas@2 142 title.align = "center";
nicholas@2 143 var titleSpan = document.createElement('span');
nicholas@2 144
nicholas@2 145 // Set title to that defined in XML, else set to default
nicholas@2 146 if (titleAttr != undefined) {
n@25 147 titleSpan.innerHTML = titleAttr.value;
nicholas@2 148 } else {
b@75 149 titleSpan.innerHTML = 'Listening test';
nicholas@2 150 }
nicholas@2 151 // Insert the titleSpan element into the title div element.
nicholas@2 152 title.appendChild(titleSpan);
nicholas@2 153
n@47 154 var pagetitle = document.createElement('div');
n@47 155 pagetitle.className = "pageTitle";
n@47 156 pagetitle.align = "center";
n@47 157 var titleSpan = document.createElement('span');
n@47 158 titleSpan.id = "pageTitle";
n@47 159 pagetitle.appendChild(titleSpan);
n@47 160
nicholas@7 161 // Store the return URL path in global projectReturn
nicholas@7 162 projectReturn = xmlSetup[0].attributes['projectReturn'].value;
nicholas@7 163
nicholas@7 164 // Create Interface buttons!
nicholas@7 165 var interfaceButtons = document.createElement('div');
nicholas@7 166 interfaceButtons.id = 'interface-buttons';
nicholas@7 167
nicholas@7 168 // MANUAL DOWNLOAD POINT
nicholas@7 169 // If project return is null, this MUST be specified as the location to create the download link
nicholas@7 170 var downloadPoint = document.createElement('div');
nicholas@7 171 downloadPoint.id = 'download-point';
nicholas@7 172
nicholas@7 173 // Create playback start/stop points
nicholas@7 174 var playback = document.createElement("button");
b@101 175 playback.innerHTML = 'Stop';
n@49 176 playback.id = 'playback-button';
n@16 177 // onclick function. Check if it is playing or not, call the correct function in the
n@16 178 // audioEngine, change the button text to reflect the next state.
nicholas@7 179 playback.onclick = function() {
b@101 180 if (audioEngineContext.status == 1) {
b@101 181 audioEngineContext.stop();
n@25 182 this.innerHTML = 'Stop';
b@115 183 var time = audioEngineContext.timer.getTestTime();
b@115 184 console.log('Stopped at ' + time); // DEBUG/SAFETY
nicholas@7 185 }
n@16 186 };
nicholas@7 187 // Create Submit (save) button
nicholas@7 188 var submit = document.createElement("button");
n@25 189 submit.innerHTML = 'Submit';
n@43 190 submit.onclick = buttonSubmitClick;
n@49 191 submit.id = 'submit-button';
n@16 192 // Append the interface buttons into the interfaceButtons object.
nicholas@7 193 interfaceButtons.appendChild(playback);
nicholas@7 194 interfaceButtons.appendChild(submit);
nicholas@7 195 interfaceButtons.appendChild(downloadPoint);
nicholas@7 196
nicholas@2 197 // Now create the slider and HTML5 canvas boxes
nicholas@2 198
n@16 199 // Create the div box to center align
nicholas@2 200 var sliderBox = document.createElement('div');
nicholas@2 201 sliderBox.className = 'sliderCanvasDiv';
n@16 202 sliderBox.id = 'sliderCanvasHolder';
nicholas@2 203 sliderBox.align = 'center';
nicholas@2 204
n@16 205 // Create the slider box to hold the slider elements
nicholas@5 206 var canvas = document.createElement('div');
nicholas@2 207 canvas.id = 'slider';
n@16 208 // Must have a known EXACT width, as this is used later to determine the ratings
nicholas@5 209 canvas.style.width = width - 100 +"px";
nicholas@5 210 canvas.align = "left";
nicholas@2 211 sliderBox.appendChild(canvas);
n@16 212
n@47 213 // Create the div to hold any scale objects
n@47 214 var scale = document.createElement('div');
n@47 215 scale.className = 'sliderScale';
n@47 216 scale.id = 'sliderScaleHolder';
n@47 217 scale.align = 'left';
n@47 218 sliderBox.appendChild(scale);
n@47 219
n@16 220 // Global parent for the comment boxes on the page
nicholas@3 221 var feedbackHolder = document.createElement('div');
n@34 222 feedbackHolder.id = 'feedbackHolder';
nicholas@2 223
n@38 224 testContent.style.zIndex = 1;
n@38 225 insertPoint.innerHTML = null; // Clear the current schema
n@38 226
n@22 227 // Create pre and post test questions
n@22 228
n@36 229 var preTest = xmlSetup.find('PreTest');
n@36 230 var postTest = xmlSetup.find('PostTest');
n@22 231 preTest = preTest[0];
n@22 232 postTest = postTest[0];
n@38 233
n@38 234 currentState = 'preTest';
n@22 235
n@22 236 // Create Pre-Test Box
nicholas@105 237 if (preTest != undefined && preTest.childElementCount >= 1)
n@22 238 {
nicholas@116 239 //popup.showPopup();
nicholas@116 240 //preTestPopupStart(preTest);
nicholas@116 241 popup.initState(preTest);
n@22 242 }
n@38 243
n@38 244 // Inject into HTML
n@38 245 testContent.appendChild(title); // Insert the title
n@47 246 testContent.appendChild(pagetitle);
n@38 247 testContent.appendChild(interfaceButtons);
n@38 248 testContent.appendChild(sliderBox);
n@38 249 testContent.appendChild(feedbackHolder);
n@38 250 insertPoint.appendChild(testContent);
n@22 251
n@36 252 // Load the full interface
n@39 253
nicholas@2 254 }
nicholas@5 255
n@39 256 function loadTest(id)
n@34 257 {
nicholas@110 258
nicholas@110 259 // Reset audioEngineContext.Metric globals for new test
n@113 260 audioEngineContext.newTestPage();
nicholas@110 261
n@34 262 // Used to load a specific test page
n@39 263 var textXML = testXMLSetups[id];
n@34 264
n@34 265 var feedbackHolder = document.getElementById('feedbackHolder');
n@34 266 var canvas = document.getElementById('slider');
n@34 267 feedbackHolder.innerHTML = null;
n@34 268 canvas.innerHTML = null;
n@47 269
n@47 270 // Setup question title
n@47 271 var interfaceObj = $(textXML).find('interface');
n@47 272 var titleNode = interfaceObj.find('title');
n@47 273 if (titleNode[0] != undefined)
n@47 274 {
n@47 275 document.getElementById('pageTitle').textContent = titleNode[0].textContent;
n@47 276 }
n@47 277 var positionScale = canvas.style.width.substr(0,canvas.style.width.length-2);
n@47 278 var offset = 50-8; // Half the offset of the slider (window width -100) minus the body padding of 8
n@47 279 // TODO: AUTOMATE ABOVE!!
n@47 280 var scale = document.getElementById('sliderScaleHolder');
n@47 281 scale.innerHTML = null;
n@47 282 interfaceObj.find('scale').each(function(index,scaleObj){
n@47 283 var position = Number(scaleObj.attributes['position'].value)*0.01;
n@47 284 var pixelPosition = (position*positionScale)+offset;
n@47 285 var scaleDOM = document.createElement('span');
n@47 286 scaleDOM.textContent = scaleObj.textContent;
n@47 287 scale.appendChild(scaleDOM);
n@47 288 scaleDOM.style.left = Math.floor((pixelPosition-($(scaleDOM).width()/2)))+'px';
n@47 289 });
n@34 290
n@34 291 // Extract the hostURL attribute. If not set, create an empty string.
n@34 292 var hostURL = textXML.attributes['hostURL'];
n@34 293 if (hostURL == undefined) {
n@34 294 hostURL = "";
n@34 295 } else {
n@34 296 hostURL = hostURL.value;
n@34 297 }
n@34 298 // Extract the sampleRate. If set, convert the string to a Number.
n@34 299 var hostFs = textXML.attributes['sampleRate'];
n@34 300 if (hostFs != undefined) {
n@34 301 hostFs = Number(hostFs.value);
n@34 302 }
n@34 303
n@34 304 /// CHECK FOR SAMPLE RATE COMPATIBILITY
n@34 305 if (hostFs != undefined) {
n@34 306 if (Number(hostFs) != audioContext.sampleRate) {
n@34 307 var errStr = 'Sample rates do not match! Requested '+Number(hostFs)+', got '+audioContext.sampleRate+'. Please set the sample rate to match before completing this test.';
n@34 308 alert(errStr);
n@34 309 return;
n@34 310 }
n@34 311 }
n@45 312
nicholas@66 313 var commentShow = textXML.attributes['elementComments'];
nicholas@66 314 if (commentShow != undefined) {
nicholas@66 315 if (commentShow.value == 'false') {commentShow = false;}
nicholas@66 316 else {commentShow = true;}
nicholas@66 317 } else {commentShow = true;}
nicholas@66 318
n@57 319 var loopPlayback = textXML.attributes['loop'];
n@57 320 if (loopPlayback != undefined)
n@57 321 {
n@57 322 loopPlayback = loopPlayback.value;
n@57 323 if (loopPlayback == 'true') {
n@57 324 loopPlayback = true;
n@57 325 } else {
n@57 326 loopPlayback = false;
n@57 327 }
n@57 328 } else {
n@57 329 loopPlayback = false;
n@57 330 }
n@57 331 audioEngineContext.loopPlayback = loopPlayback;
nicholas@110 332 loopPlayback = false;
n@57 333 // Create AudioEngine bindings for playback
n@57 334 if (loopPlayback) {
n@57 335 audioEngineContext.selectedTrack = function(id) {
n@57 336 for (var i=0; i<this.audioObjects.length; i++)
n@57 337 {
n@57 338 if (id == i) {
n@57 339 this.audioObjects[i].outputGain.gain.value = 1.0;
n@57 340 } else {
n@57 341 this.audioObjects[i].outputGain.gain.value = 0.0;
n@57 342 }
n@57 343 }
n@57 344 };
n@57 345 } else {
n@57 346 audioEngineContext.selectedTrack = function(id) {
n@57 347 for (var i=0; i<this.audioObjects.length; i++)
n@57 348 {
n@97 349 this.audioObjects[i].outputGain.gain.value = 0.0;
n@97 350 this.audioObjects[i].stop();
n@57 351 }
n@99 352 if (this.status == 1) {
n@99 353 this.audioObjects[id].outputGain.gain.value = 1.0;
n@99 354 this.audioObjects[id].play(audioContext.currentTime+0.01);
n@99 355 }
n@57 356 };
n@57 357 }
n@57 358
n@46 359 currentTestHolder = document.createElement('audioHolder');
n@46 360 currentTestHolder.id = textXML.id;
n@46 361 currentTestHolder.repeatCount = textXML.attributes['repeatCount'].value;
n@46 362
n@45 363 var randomise = textXML.attributes['randomiseOrder'];
n@45 364 if (randomise != undefined) {randomise = randomise.value;}
n@45 365 else {randomise = false;}
n@45 366
n@34 367 var audioElements = $(textXML).find('audioElements');
nicholas@58 368 currentTrackOrder = [];
n@34 369 audioElements.each(function(index,element){
n@45 370 // Find any blind-repeats
b@100 371 // Not implemented yet, but just in case
n@45 372 currentTrackOrder[index] = element;
n@45 373 });
n@45 374 if (randomise) {
n@54 375 currentTrackOrder = randomiseOrder(currentTrackOrder);
n@45 376 }
n@45 377
nicholas@58 378 // Delete any previous audioObjects associated with the audioEngine
nicholas@58 379 audioEngineContext.audioObjects = [];
nicholas@58 380
n@45 381 // Find all the audioElements from the audioHolder
n@45 382 $(currentTrackOrder).each(function(index,element){
n@34 383 // Find URL of track
n@34 384 // In this jQuery loop, variable 'this' holds the current audioElement.
n@34 385
n@34 386 // Now load each audio sample. First create the new track by passing the full URL
n@34 387 var trackURL = hostURL + this.attributes['url'].value;
n@34 388 audioEngineContext.newTrack(trackURL);
nicholas@66 389
nicholas@66 390 if (commentShow) {
nicholas@66 391 // Create document objects to hold the comment boxes
nicholas@66 392 var trackComment = document.createElement('div');
nicholas@66 393 trackComment.className = 'comment-div';
nicholas@66 394 // Create a string next to each comment asking for a comment
nicholas@66 395 var trackString = document.createElement('span');
nicholas@66 396 trackString.innerHTML = 'Comment on track '+index;
nicholas@66 397 // Create the HTML5 comment box 'textarea'
nicholas@66 398 var trackCommentBox = document.createElement('textarea');
nicholas@66 399 trackCommentBox.rows = '4';
nicholas@66 400 trackCommentBox.cols = '100';
nicholas@66 401 trackCommentBox.name = 'trackComment'+index;
nicholas@66 402 trackCommentBox.className = 'trackComment';
nicholas@66 403 var br = document.createElement('br');
nicholas@66 404 // Add to the holder.
nicholas@66 405 trackComment.appendChild(trackString);
nicholas@66 406 trackComment.appendChild(br);
nicholas@66 407 trackComment.appendChild(trackCommentBox);
nicholas@66 408 feedbackHolder.appendChild(trackComment);
nicholas@66 409 }
n@34 410
n@34 411 // Create a slider per track
n@34 412
n@34 413 var trackSliderObj = document.createElement('div');
n@34 414 trackSliderObj.className = 'track-slider';
n@34 415 trackSliderObj.id = 'track-slider-'+index;
n@34 416 // Distribute it randomnly
n@34 417 var w = window.innerWidth - 100;
n@34 418 w = Math.random()*w;
n@34 419 trackSliderObj.style.left = Math.floor(w)+50+'px';
n@34 420 trackSliderObj.innerHTML = '<span>'+index+'</span>';
n@34 421 trackSliderObj.draggable = true;
n@34 422 trackSliderObj.ondragend = dragEnd;
n@49 423 trackSliderObj.ondragstart = function()
n@49 424 {
n@49 425 var id = Number(this.id.substr(13,2)); // Maximum theoretical tracks is 99!
n@49 426 audioEngineContext.metric.sliderMoveStart(id);
n@49 427 };
n@34 428
n@34 429 // Onclick, switch playback to that track
n@34 430 trackSliderObj.onclick = function() {
nicholas@108 431 // Start the test on first click, that way timings are more accurate.
nicholas@108 432 audioEngineContext.play();
n@34 433 // Get the track ID from the object ID
n@34 434 var id = Number(this.id.substr(13,2)); // Maximum theoretical tracks is 99!
nicholas@110 435 //audioEngineContext.metric.sliderPlayed(id);
n@34 436 audioEngineContext.selectedTrack(id);
b@100 437 // Currently playing track red, rest green
b@100 438 document.getElementById('track-slider-'+index).style.backgroundColor = "#FF0000";
b@100 439 for (var i = 0; i<$(currentTrackOrder).length; i++)
b@100 440 {
b@102 441 if (i!=index) // Make all other sliders green
b@100 442 {
b@100 443 document.getElementById('track-slider-'+i).style.backgroundColor = "rgb(100,200,100)";
b@100 444 }
b@100 445
b@100 446 }
n@34 447 };
n@34 448
n@34 449 canvas.appendChild(trackSliderObj);
b@102 450
n@34 451 });
n@39 452
nicholas@65 453 // Append any commentQuestion boxes
nicholas@65 454 var commentQuestions = $(textXML).find('CommentQuestion');
nicholas@65 455 $(commentQuestions).each(function(index,element) {
nicholas@65 456 // Create document objects to hold the comment boxes
nicholas@65 457 var trackComment = document.createElement('div');
nicholas@65 458 trackComment.className = 'comment-div commentQuestion';
nicholas@65 459 trackComment.id = element.attributes['id'].value;
nicholas@65 460 // Create a string next to each comment asking for a comment
nicholas@65 461 var trackString = document.createElement('span');
nicholas@65 462 trackString.innerHTML = element.textContent;
nicholas@65 463 // Create the HTML5 comment box 'textarea'
nicholas@65 464 var trackCommentBox = document.createElement('textarea');
nicholas@65 465 trackCommentBox.rows = '4';
nicholas@65 466 trackCommentBox.cols = '100';
nicholas@65 467 trackCommentBox.name = 'commentQuestion'+index;
nicholas@65 468 trackCommentBox.className = 'trackComment';
nicholas@65 469 var br = document.createElement('br');
nicholas@65 470 // Add to the holder.
nicholas@65 471 trackComment.appendChild(trackString);
nicholas@65 472 trackComment.appendChild(br);
nicholas@65 473 trackComment.appendChild(trackCommentBox);
nicholas@65 474 feedbackHolder.appendChild(trackComment);
nicholas@65 475 });
nicholas@65 476
n@39 477 // Now process any pre-test commands
n@39 478
n@44 479 var preTest = $(testXMLSetups[id]).find('PreTest')[0];
nicholas@105 480 if (preTest.childElementCount > 0)
n@39 481 {
n@39 482 currentState = 'testRunPre-'+id;
nicholas@116 483 //preTestPopupStart(preTest);
nicholas@116 484 popup.initState(preTest);
nicholas@116 485 //popup.showPopup();
n@39 486 } else {
n@39 487 currentState = 'testRun-'+id;
n@39 488 }
n@39 489 }
n@39 490
n@39 491 function preTestPopupStart(preTest)
n@39 492 {
n@39 493 var popupHolder = document.getElementById('popupHolder');
n@39 494 popupHolder.innerHTML = null;
n@39 495 // Parse the first box
n@39 496 var preTestOption = document.createElement('div');
n@39 497 preTestOption.id = 'preTest';
n@39 498 preTestOption.style.marginTop = '25px';
n@39 499 preTestOption.align = "center";
nicholas@105 500 var child = $(preTest).children()[0];
n@39 501 if (child.nodeName == 'statement')
n@39 502 {
nicholas@105 503 preTestOption.innerHTML = '<span>'+child.textContent+'</span>';
n@39 504 } else if (child.nodeName == 'question')
n@39 505 {
n@39 506 var textHold = document.createElement('span');
nicholas@105 507 textHold.innerHTML = child.textContent;
n@39 508 var textEnter = document.createElement('textarea');
n@112 509 textEnter.id = child.attributes['id'].value + 'response';
n@112 510 var br = document.createElement('br');
n@112 511 preTestOption.innerHTML = null;
n@39 512 preTestOption.appendChild(textHold);
n@112 513 preTestOption.appendChild(br);
n@39 514 preTestOption.appendChild(textEnter);
n@39 515 }
n@39 516 var nextButton = document.createElement('button');
n@39 517 nextButton.className = 'popupButton';
n@39 518 nextButton.value = '0';
n@39 519 nextButton.innerHTML = 'Next';
n@39 520 nextButton.onclick = popupButtonClick;
n@39 521
n@39 522 popupHolder.appendChild(preTestOption);
n@39 523 popupHolder.appendChild(nextButton);
n@34 524 }
n@34 525
n@38 526 function popupButtonClick()
n@38 527 {
n@38 528 // Global call from the 'Next' button click
n@38 529 if (currentState == 'preTest')
n@38 530 {
n@38 531 // At the start of the preTest routine!
n@39 532 var xmlTree = projectXML.find('setup');
n@39 533 var preTest = xmlTree.find('PreTest')[0];
n@39 534 this.value = preTestButtonClick(preTest,this.value);
n@39 535 } else if (currentState.substr(0,10) == 'testRunPre')
n@39 536 {
n@39 537 //Specific test pre-test
n@39 538 var testId = currentState.substr(11,currentState.length-10);
n@44 539 var preTest = $(testXMLSetups[testId]).find('PreTest')[0];
n@39 540 this.value = preTestButtonClick(preTest,this.value);
n@42 541 } else if (currentState.substr(0,11) == 'testRunPost')
n@42 542 {
n@42 543 // Specific test post-test
n@42 544 var testId = currentState.substr(12,currentState.length-11);
n@44 545 var preTest = $(testXMLSetups[testId]).find('PostTest')[0];
n@42 546 this.value = preTestButtonClick(preTest,this.value);
n@41 547 } else if (currentState == 'postTest')
n@41 548 {
n@41 549 // At the end of the test, running global post test
n@41 550 var xmlTree = projectXML.find('setup');
n@41 551 var PostTest = xmlTree.find('PostTest')[0];
n@41 552 this.value = preTestButtonClick(PostTest,this.value);
n@38 553 }
n@38 554 }
n@38 555
n@39 556 function preTestButtonClick(preTest,index)
n@34 557 {
n@34 558 // Called on click of pre-test button
n@36 559 // Need to find and parse preTest again!
n@36 560 var preTestOption = document.getElementById('preTest');
n@36 561 // Check if current state is a question!
nicholas@105 562 if ($(preTest).children()[index].nodeName == 'question') {
nicholas@105 563 var questionId = $(preTest).children()[index].attributes['id'].value;
n@36 564 var questionHold = document.createElement('comment');
n@36 565 var questionResponse = document.getElementById(questionId + 'response');
nicholas@105 566 var mandatory = $(preTest).children()[index].attributes['mandatory'];
nicholas@64 567 if (mandatory != undefined){
nicholas@64 568 if (mandatory.value == 'true') {mandatory = true;}
nicholas@64 569 else {mandatory = false;}
nicholas@64 570 } else {mandatory = false;}
nicholas@64 571 if (mandatory == true && questionResponse.value.length == 0) {
nicholas@64 572 return index;
nicholas@64 573 }
n@36 574 questionHold.id = questionId;
n@36 575 questionHold.innerHTML = questionResponse.value;
n@46 576 postPopupResponse(questionHold);
n@36 577 }
n@38 578 index++;
nicholas@105 579 if (index < preTest.childElementCount)
n@36 580 {
n@36 581 // More to process
nicholas@105 582 var child = $(preTest).children()[index];
n@36 583 if (child.nodeName == 'statement')
n@36 584 {
nicholas@105 585 preTestOption.innerHTML = '<span>'+child.textContent+'</span>';
n@36 586 } else if (child.nodeName == 'question')
n@36 587 {
n@36 588 var textHold = document.createElement('span');
nicholas@105 589 textHold.innerHTML = child.textContent;
n@36 590 var textEnter = document.createElement('textarea');
n@36 591 textEnter.id = child.attributes['id'].value + 'response';
n@36 592 var br = document.createElement('br');
n@36 593 preTestOption.innerHTML = null;
n@36 594 preTestOption.appendChild(textHold);
n@36 595 preTestOption.appendChild(br);
n@36 596 preTestOption.appendChild(textEnter);
n@36 597 }
n@36 598 } else {
n@36 599 // Time to clear
n@37 600 preTestOption.innerHTML = null;
n@43 601 if (currentState != 'postTest') {
nicholas@116 602 popup.hidePopup();
n@43 603 // Progress the state!
n@43 604 advanceState();
n@43 605 } else {
n@43 606 a = createProjectSave(projectReturn);
n@43 607 preTestOption.appendChild(a);
n@43 608 }
n@36 609 }
n@38 610 return index;
n@36 611 }
n@36 612
n@46 613 function postPopupResponse(response)
n@46 614 {
n@46 615 if (currentState == 'preTest') {
n@46 616 preTestQuestions.appendChild(response);
n@46 617 } else if (currentState == 'postTest') {
n@46 618 postTestQuestions.appendChild(response);
n@46 619 } else {
n@46 620 // Inside a specific test
n@46 621 if (currentState.substr(0,10) == 'testRunPre') {
n@46 622 // Pre Test
n@46 623 var store = $(currentTestHolder).find('preTest');
n@46 624 } else {
n@46 625 // Post Test
n@46 626 var store = $(currentTestHolder).find('postTest');
n@46 627 }
n@46 628 store[0].appendChild(response);
n@46 629 }
n@46 630 }
nicholas@119 631
nicholas@119 632
nicholas@5 633 function dragEnd(ev) {
nicholas@5 634 // Function call when a div has been dropped
n@33 635 var slider = document.getElementById('slider');
n@51 636 var w = slider.style.width;
n@51 637 w = Number(w.substr(0,w.length-2));
n@51 638 var x = ev.x;
n@51 639 if (x >= 42 && x < w+42) {
n@51 640 this.style.left = (x)+'px';
nicholas@5 641 } else {
n@51 642 if (x<42) {
n@51 643 this.style.left = '42px';
nicholas@5 644 } else {
n@51 645 this.style.left = (w+42) + 'px';
nicholas@5 646 }
nicholas@5 647 }
n@49 648 audioEngineContext.metric.sliderMoved();
nicholas@5 649 }
nicholas@7 650
b@101 651 function buttonSubmitClick() // TODO: Only when all songs have been played!
n@40 652 {
nicholas@107 653 hasBeenPlayed = audioEngineContext.checkAllPlayed();
nicholas@107 654 if (hasBeenPlayed.length == 0) {
nicholas@107 655 if (audioEngineContext.status == 1) {
nicholas@107 656 var playback = document.getElementById('playback-button');
nicholas@107 657 playback.click();
nicholas@107 658 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options
nicholas@107 659 } else
nicholas@107 660 {
nicholas@107 661 if (audioEngineContext.timer.testStarted == false)
nicholas@107 662 {
nicholas@107 663 alert('You have not started the test! Please press start to begin the test!');
nicholas@107 664 return;
nicholas@107 665 }
nicholas@107 666 }
nicholas@107 667 if (currentState.substr(0,7) == 'testRun')
nicholas@107 668 {
nicholas@107 669 hasBeenPlayed = []; // clear array to prepare for next test
nicholas@107 670 audioEngineContext.timer.stopTest();
nicholas@107 671 advanceState();
nicholas@107 672 }
b@102 673 } else // if a fragment has not been played yet
b@102 674 {
nicholas@107 675 str = "";
nicholas@107 676 if (hasBeenPlayed.length > 1) {
nicholas@107 677 for (var i=0; i<hasBeenPlayed.length; i++) {
nicholas@107 678 str = str + hasBeenPlayed[i];
nicholas@107 679 if (i < hasBeenPlayed.length-2){
nicholas@107 680 str += ", ";
nicholas@107 681 } else if (i == hasBeenPlayed.length-2) {
nicholas@107 682 str += " or ";
nicholas@107 683 }
nicholas@107 684 }
nicholas@107 685 alert('You have not played fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.');
nicholas@107 686 } else {
nicholas@107 687 alert('You have not played fragment ' + hasBeenPlayed[0] + ' yet. Please listen, rate and comment all samples before submitting.');
nicholas@107 688 }
b@102 689 return;
b@102 690 }
n@40 691 }
n@40 692
n@51 693 function convSliderPosToRate(id)
n@51 694 {
n@51 695 var w = document.getElementById('slider').style.width;
n@51 696 var maxPix = w.substr(0,w.length-2);
n@51 697 var slider = document.getElementsByClassName('track-slider')[id];
n@51 698 var pix = slider.style.left;
n@51 699 pix = pix.substr(0,pix.length-2);
n@51 700 var rate = (pix-42)/maxPix;
n@51 701 return rate;
n@51 702 }
n@51 703
n@44 704 function pageXMLSave(testId)
n@44 705 {
n@44 706 // Saves a specific test page
n@46 707 var xmlDoc = currentTestHolder;
n@50 708 // Check if any session wide metrics are enabled
nicholas@67 709
nicholas@67 710 var commentShow = testXMLSetups[testId].attributes['elementComments'];
nicholas@67 711 if (commentShow != undefined) {
nicholas@67 712 if (commentShow.value == 'false') {commentShow = false;}
nicholas@67 713 else {commentShow = true;}
nicholas@67 714 } else {commentShow = true;}
nicholas@67 715
n@50 716 var metric = document.createElement('metric');
n@50 717 if (audioEngineContext.metric.enableTestTimer)
n@50 718 {
n@50 719 var testTime = document.createElement('metricResult');
n@50 720 testTime.id = 'testTime';
n@50 721 testTime.textContent = audioEngineContext.timer.testDuration;
n@50 722 metric.appendChild(testTime);
n@50 723 }
n@50 724 xmlDoc.appendChild(metric);
n@45 725 var trackSliderObjects = document.getElementsByClassName('track-slider');
n@45 726 var commentObjects = document.getElementsByClassName('comment-div');
n@45 727 for (var i=0; i<trackSliderObjects.length; i++)
n@45 728 {
n@45 729 var audioElement = document.createElement('audioElement');
n@45 730 audioElement.id = currentTrackOrder[i].attributes['id'].value;
n@45 731 audioElement.url = currentTrackOrder[i].attributes['url'].value;
n@51 732 var value = document.createElement('value');
n@51 733 value.innerHTML = convSliderPosToRate(i);
nicholas@67 734 if (commentShow) {
nicholas@67 735 var comment = document.createElement("comment");
nicholas@67 736 var question = document.createElement("question");
nicholas@67 737 var response = document.createElement("response");
nicholas@67 738 question.textContent = commentObjects[i].children[0].textContent;
nicholas@67 739 response.textContent = commentObjects[i].children[2].value;
b@115 740 console.log('Comment ' + i + ': ' + commentObjects[i].children[2].value); // DEBUG/SAFETY
nicholas@67 741 comment.appendChild(question);
nicholas@67 742 comment.appendChild(response);
nicholas@67 743 audioElement.appendChild(comment);
nicholas@67 744 }
n@45 745 audioElement.appendChild(value);
n@50 746 // Check for any per element metrics
n@50 747 var metric = document.createElement('metric');
n@50 748 var elementMetric = audioEngineContext.audioObjects[i].metric;
n@50 749 if (audioEngineContext.metric.enableElementTimer) {
n@50 750 var elementTimer = document.createElement('metricResult');
n@50 751 elementTimer.id = 'elementTimer';
n@50 752 elementTimer.textContent = elementMetric.listenedTimer;
n@50 753 metric.appendChild(elementTimer);
n@50 754 }
n@50 755 if (audioEngineContext.metric.enableElementTracker) {
n@50 756 var elementTrackerFull = document.createElement('metricResult');
n@50 757 elementTrackerFull.id = 'elementTrackerFull';
n@50 758 var data = elementMetric.movementTracker;
n@50 759 for (var k=0; k<data.length; k++)
n@50 760 {
n@50 761 var timePos = document.createElement('timePos');
n@50 762 timePos.id = k;
n@50 763 var time = document.createElement('time');
n@50 764 time.textContent = data[k][0];
n@50 765 var position = document.createElement('position');
n@50 766 position.textContent = data[k][1];
n@50 767 timePos.appendChild(time);
n@50 768 timePos.appendChild(position);
n@50 769 elementTrackerFull.appendChild(timePos);
n@50 770 }
n@50 771 metric.appendChild(elementTrackerFull);
n@50 772 }
n@50 773 if (audioEngineContext.metric.enableElementInitialPosition) {
n@50 774 var elementInitial = document.createElement('metricResult');
n@50 775 elementInitial.id = 'elementInitialPosition';
n@50 776 elementInitial.textContent = elementMetric.initialPosition;
n@50 777 metric.appendChild(elementInitial);
n@50 778 }
n@50 779 if (audioEngineContext.metric.enableFlagListenedTo) {
n@50 780 var flagListenedTo = document.createElement('metricResult');
n@50 781 flagListenedTo.id = 'elementFlagListenedTo';
n@50 782 flagListenedTo.textContent = elementMetric.wasListenedTo;
n@50 783 metric.appendChild(flagListenedTo);
n@50 784 }
n@50 785 if (audioEngineContext.metric.enableFlagMoved) {
n@50 786 var flagMoved = document.createElement('metricResult');
n@50 787 flagMoved.id = 'elementFlagMoved';
n@50 788 flagMoved.textContent = elementMetric.wasMoved;
n@50 789 metric.appendChild(flagMoved);
n@50 790 }
n@50 791 if (audioEngineContext.metric.enableFlagComments) {
n@50 792 var flagComments = document.createElement('metricResult');
n@50 793 flagComments.id = 'elementFlagComments';
n@50 794 if (response.textContent.length == 0) {flag.textContent = 'false';}
n@50 795 else {flag.textContet = 'true';}
n@50 796 metric.appendChild(flagComments);
n@50 797 }
n@50 798 audioElement.appendChild(metric);
n@45 799 xmlDoc.appendChild(audioElement);
n@45 800 }
nicholas@65 801 var commentQuestion = document.getElementsByClassName('commentQuestion');
nicholas@65 802 for (var i=0; i<commentQuestion.length; i++)
nicholas@65 803 {
nicholas@65 804 var cqHolder = document.createElement('CommentQuestion');
nicholas@65 805 var comment = document.createElement('comment');
nicholas@65 806 var question = document.createElement('question');
nicholas@65 807 cqHolder.id = commentQuestion[i].id;
nicholas@65 808 comment.textContent = commentQuestion[i].children[2].value;
nicholas@65 809 question.textContent = commentQuestion[i].children[0].textContent;
b@115 810 console.log('Question ' + i + ': ' + commentObjects[i].children[2].value); // DEBUG/SAFETY
nicholas@65 811 cqHolder.appendChild(question);
nicholas@65 812 cqHolder.appendChild(comment);
nicholas@65 813 xmlDoc.appendChild(cqHolder);
nicholas@65 814 }
n@45 815 testResultsHolders[testId] = xmlDoc;
n@44 816 }
n@44 817
nicholas@7 818 // Only other global function which must be defined in the interface class. Determines how to create the XML document.
nicholas@7 819 function interfaceXMLSave(){
nicholas@7 820 // Create the XML string to be exported with results
nicholas@7 821 var xmlDoc = document.createElement("BrowserEvaluationResult");
n@45 822 for (var i=0; i<testResultsHolders.length; i++)
nicholas@7 823 {
n@45 824 xmlDoc.appendChild(testResultsHolders[i]);
nicholas@7 825 }
n@23 826 // Append Pre/Post Questions
n@23 827 xmlDoc.appendChild(preTestQuestions);
n@23 828 xmlDoc.appendChild(postTestQuestions);
n@23 829
nicholas@7 830 return xmlDoc;
nicholas@67 831 }