annotate ape.js @ 178:510dbc57e97e Dev_main

ape.js pageSaveXML uses view from audioObjects.
author Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk>
date Thu, 04 Jun 2015 11:18:21 +0100
parents 25c296b254f8
children 8655b05c874f
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');
nicholas@135 25
n@22 26 testContent.id = 'testContent';
nicholas@2 27
nicholas@7 28
nicholas@2 29 // Decode parts of the xmlDoc that are needed
nicholas@2 30 // xmlDoc MUST already be parsed by jQuery!
nicholas@2 31 var xmlSetup = xmlDoc.find('setup');
nicholas@2 32 // Should put in an error function here incase of malprocessed or malformed XML
n@176 33
n@34 34
n@52 35 // Create APE specific metric functions
n@52 36 audioEngineContext.metric.initialiseTest = function()
n@52 37 {
n@52 38 };
n@52 39
n@52 40 audioEngineContext.metric.sliderMoveStart = function(id)
n@52 41 {
n@52 42 if (this.data == -1)
n@52 43 {
n@52 44 this.data = id;
n@52 45 } else {
n@52 46 console.log('ERROR: Metric tracker detecting two moves!');
n@52 47 this.data = -1;
n@52 48 }
n@52 49 };
n@52 50 audioEngineContext.metric.sliderMoved = function()
n@52 51 {
n@52 52 var time = audioEngineContext.timer.getTestTime();
n@52 53 var id = this.data;
n@52 54 this.data = -1;
n@52 55 var position = convSliderPosToRate(id);
b@115 56 console.log('slider ' + id + ': '+ position + ' (' + time + ')'); // DEBUG/SAFETY: show position and slider id
n@52 57 if (audioEngineContext.timer.testStarted)
n@52 58 {
n@52 59 audioEngineContext.audioObjects[id].metric.moved(time,position);
n@52 60 }
n@52 61 };
n@52 62
n@52 63 audioEngineContext.metric.sliderPlayed = function(id)
n@52 64 {
n@52 65 var time = audioEngineContext.timer.getTestTime();
n@52 66 if (audioEngineContext.timer.testStarted)
n@52 67 {
n@52 68 if (this.lastClicked >= 0)
n@52 69 {
n@52 70 audioEngineContext.audioObjects[this.lastClicked].metric.listening(time);
n@52 71 }
n@52 72 this.lastClicked = id;
n@52 73 audioEngineContext.audioObjects[id].metric.listening(time);
n@52 74 }
b@115 75 console.log('slider ' + id + ' played (' + time + ')'); // DEBUG/SAFETY: show played slider id
n@52 76 };
n@52 77
n@177 78 // Bindings for audioObjects
n@177 79
nicholas@2 80 // Create the top div for the Title element
nicholas@2 81 var titleAttr = xmlSetup[0].attributes['title'];
nicholas@2 82 var title = document.createElement('div');
nicholas@2 83 title.className = "title";
nicholas@2 84 title.align = "center";
nicholas@2 85 var titleSpan = document.createElement('span');
nicholas@2 86
nicholas@2 87 // Set title to that defined in XML, else set to default
nicholas@2 88 if (titleAttr != undefined) {
n@25 89 titleSpan.innerHTML = titleAttr.value;
nicholas@2 90 } else {
b@75 91 titleSpan.innerHTML = 'Listening test';
nicholas@2 92 }
nicholas@2 93 // Insert the titleSpan element into the title div element.
nicholas@2 94 title.appendChild(titleSpan);
nicholas@2 95
n@47 96 var pagetitle = document.createElement('div');
n@47 97 pagetitle.className = "pageTitle";
n@47 98 pagetitle.align = "center";
n@47 99 var titleSpan = document.createElement('span');
n@47 100 titleSpan.id = "pageTitle";
n@47 101 pagetitle.appendChild(titleSpan);
n@47 102
nicholas@7 103 // Store the return URL path in global projectReturn
n@140 104 projectReturn = xmlSetup[0].attributes['projectReturn'];
n@140 105 if (projectReturn == undefined) {
n@140 106 console.log("WARNING - projectReturn not specified! Will assume null.");
n@140 107 projectReturn = "null";
n@140 108 } else {
n@140 109 projectReturn = projectReturn.value;
n@140 110 }
nicholas@7 111
nicholas@7 112 // Create Interface buttons!
nicholas@7 113 var interfaceButtons = document.createElement('div');
nicholas@7 114 interfaceButtons.id = 'interface-buttons';
nicholas@7 115
nicholas@7 116 // MANUAL DOWNLOAD POINT
nicholas@7 117 // If project return is null, this MUST be specified as the location to create the download link
nicholas@7 118 var downloadPoint = document.createElement('div');
nicholas@7 119 downloadPoint.id = 'download-point';
nicholas@7 120
nicholas@7 121 // Create playback start/stop points
nicholas@7 122 var playback = document.createElement("button");
b@101 123 playback.innerHTML = 'Stop';
n@49 124 playback.id = 'playback-button';
n@16 125 // onclick function. Check if it is playing or not, call the correct function in the
n@16 126 // audioEngine, change the button text to reflect the next state.
nicholas@7 127 playback.onclick = function() {
b@101 128 if (audioEngineContext.status == 1) {
b@101 129 audioEngineContext.stop();
n@25 130 this.innerHTML = 'Stop';
b@115 131 var time = audioEngineContext.timer.getTestTime();
b@115 132 console.log('Stopped at ' + time); // DEBUG/SAFETY
nicholas@7 133 }
n@16 134 };
nicholas@7 135 // Create Submit (save) button
nicholas@7 136 var submit = document.createElement("button");
n@25 137 submit.innerHTML = 'Submit';
n@43 138 submit.onclick = buttonSubmitClick;
n@49 139 submit.id = 'submit-button';
n@16 140 // Append the interface buttons into the interfaceButtons object.
nicholas@7 141 interfaceButtons.appendChild(playback);
nicholas@7 142 interfaceButtons.appendChild(submit);
nicholas@7 143 interfaceButtons.appendChild(downloadPoint);
nicholas@7 144
nicholas@2 145 // Now create the slider and HTML5 canvas boxes
nicholas@2 146
n@16 147 // Create the div box to center align
nicholas@2 148 var sliderBox = document.createElement('div');
nicholas@2 149 sliderBox.className = 'sliderCanvasDiv';
n@16 150 sliderBox.id = 'sliderCanvasHolder';
nicholas@2 151
n@16 152 // Create the slider box to hold the slider elements
nicholas@5 153 var canvas = document.createElement('div');
nicholas@2 154 canvas.id = 'slider';
n@127 155 canvas.align = "left";
n@127 156 canvas.addEventListener('dragover',function(event){
n@127 157 event.preventDefault();
n@127 158 return false;
n@127 159 },false);
n@127 160 var sliderMargin = document.createAttribute('marginsize');
n@127 161 sliderMargin.nodeValue = 42; // Set default margins to 42px either side
n@16 162 // Must have a known EXACT width, as this is used later to determine the ratings
n@127 163 var w = (Number(sliderMargin.nodeValue)+8)*2;
n@127 164 canvas.style.width = width - w +"px";
n@127 165 canvas.style.marginLeft = sliderMargin.nodeValue +'px';
n@127 166 canvas.setAttributeNode(sliderMargin);
nicholas@2 167 sliderBox.appendChild(canvas);
n@16 168
n@47 169 // Create the div to hold any scale objects
n@47 170 var scale = document.createElement('div');
n@47 171 scale.className = 'sliderScale';
n@47 172 scale.id = 'sliderScaleHolder';
n@47 173 scale.align = 'left';
n@47 174 sliderBox.appendChild(scale);
n@47 175
n@16 176 // Global parent for the comment boxes on the page
nicholas@3 177 var feedbackHolder = document.createElement('div');
n@34 178 feedbackHolder.id = 'feedbackHolder';
nicholas@2 179
n@38 180 testContent.style.zIndex = 1;
n@38 181 insertPoint.innerHTML = null; // Clear the current schema
n@38 182
n@38 183 // Inject into HTML
n@38 184 testContent.appendChild(title); // Insert the title
n@47 185 testContent.appendChild(pagetitle);
n@38 186 testContent.appendChild(interfaceButtons);
n@38 187 testContent.appendChild(sliderBox);
n@38 188 testContent.appendChild(feedbackHolder);
n@38 189 insertPoint.appendChild(testContent);
n@22 190
n@36 191 // Load the full interface
nicholas@129 192 testState.initialise();
nicholas@129 193 testState.advanceState();
nicholas@135 194
nicholas@2 195 }
nicholas@5 196
nicholas@129 197 function loadTest(textXML)
n@34 198 {
nicholas@110 199
nicholas@110 200 // Reset audioEngineContext.Metric globals for new test
n@113 201 audioEngineContext.newTestPage();
nicholas@110 202
nicholas@129 203 var id = textXML.id;
n@34 204
n@34 205 var feedbackHolder = document.getElementById('feedbackHolder');
n@34 206 var canvas = document.getElementById('slider');
n@34 207 feedbackHolder.innerHTML = null;
n@34 208 canvas.innerHTML = null;
n@47 209
n@47 210 // Setup question title
n@47 211 var interfaceObj = $(textXML).find('interface');
n@47 212 var titleNode = interfaceObj.find('title');
n@47 213 if (titleNode[0] != undefined)
n@47 214 {
n@47 215 document.getElementById('pageTitle').textContent = titleNode[0].textContent;
n@47 216 }
n@47 217 var positionScale = canvas.style.width.substr(0,canvas.style.width.length-2);
n@127 218 var offset = Number(document.getElementById('slider').attributes['marginsize'].value);
n@47 219 var scale = document.getElementById('sliderScaleHolder');
n@47 220 scale.innerHTML = null;
n@47 221 interfaceObj.find('scale').each(function(index,scaleObj){
n@127 222 var value = document.createAttribute('value');
n@47 223 var position = Number(scaleObj.attributes['position'].value)*0.01;
n@127 224 value.nodeValue = position;
n@47 225 var pixelPosition = (position*positionScale)+offset;
n@47 226 var scaleDOM = document.createElement('span');
n@47 227 scaleDOM.textContent = scaleObj.textContent;
n@47 228 scale.appendChild(scaleDOM);
n@47 229 scaleDOM.style.left = Math.floor((pixelPosition-($(scaleDOM).width()/2)))+'px';
n@127 230 scaleDOM.setAttributeNode(value);
n@47 231 });
n@174 232
n@174 233 var commentBoxPrefix = interfaceObj.find('commentBoxPrefix');
n@174 234 if (commentBoxPrefix.length != 0) {
n@174 235 commentBoxPrefix = commentBoxPrefix[0].textContent;
n@174 236 } else {
n@174 237 commentBoxPrefix = "Comment on track";
n@174 238 }
n@34 239
n@34 240 // Extract the hostURL attribute. If not set, create an empty string.
n@34 241 var hostURL = textXML.attributes['hostURL'];
n@34 242 if (hostURL == undefined) {
n@34 243 hostURL = "";
n@34 244 } else {
n@34 245 hostURL = hostURL.value;
n@34 246 }
n@34 247 // Extract the sampleRate. If set, convert the string to a Number.
n@34 248 var hostFs = textXML.attributes['sampleRate'];
n@34 249 if (hostFs != undefined) {
n@34 250 hostFs = Number(hostFs.value);
n@34 251 }
n@34 252
n@34 253 /// CHECK FOR SAMPLE RATE COMPATIBILITY
n@34 254 if (hostFs != undefined) {
n@34 255 if (Number(hostFs) != audioContext.sampleRate) {
n@34 256 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 257 alert(errStr);
n@34 258 return;
n@34 259 }
n@34 260 }
n@45 261
nicholas@66 262 var commentShow = textXML.attributes['elementComments'];
nicholas@66 263 if (commentShow != undefined) {
nicholas@66 264 if (commentShow.value == 'false') {commentShow = false;}
nicholas@66 265 else {commentShow = true;}
nicholas@66 266 } else {commentShow = true;}
nicholas@66 267
n@57 268 var loopPlayback = textXML.attributes['loop'];
n@57 269 if (loopPlayback != undefined)
n@57 270 {
n@57 271 loopPlayback = loopPlayback.value;
n@57 272 if (loopPlayback == 'true') {
n@57 273 loopPlayback = true;
n@57 274 } else {
n@57 275 loopPlayback = false;
n@57 276 }
n@57 277 } else {
n@57 278 loopPlayback = false;
n@57 279 }
n@57 280 audioEngineContext.loopPlayback = loopPlayback;
n@57 281 // Create AudioEngine bindings for playback
n@57 282 if (loopPlayback) {
n@57 283 audioEngineContext.selectedTrack = function(id) {
n@57 284 for (var i=0; i<this.audioObjects.length; i++)
n@57 285 {
n@57 286 if (id == i) {
nicholas@132 287 this.audioObjects[i].loopStart();
n@57 288 } else {
nicholas@132 289 this.audioObjects[i].loopStop();
n@57 290 }
n@57 291 }
n@57 292 };
n@57 293 } else {
n@57 294 audioEngineContext.selectedTrack = function(id) {
n@57 295 for (var i=0; i<this.audioObjects.length; i++)
n@57 296 {
n@97 297 this.audioObjects[i].outputGain.gain.value = 0.0;
n@97 298 this.audioObjects[i].stop();
n@57 299 }
n@99 300 if (this.status == 1) {
n@99 301 this.audioObjects[id].outputGain.gain.value = 1.0;
n@99 302 this.audioObjects[id].play(audioContext.currentTime+0.01);
n@99 303 }
n@57 304 };
n@57 305 }
n@57 306
n@46 307 currentTestHolder = document.createElement('audioHolder');
n@46 308 currentTestHolder.id = textXML.id;
n@46 309 currentTestHolder.repeatCount = textXML.attributes['repeatCount'].value;
n@46 310
n@45 311 var randomise = textXML.attributes['randomiseOrder'];
n@45 312 if (randomise != undefined) {randomise = randomise.value;}
n@45 313 else {randomise = false;}
n@45 314
n@34 315 var audioElements = $(textXML).find('audioElements');
nicholas@58 316 currentTrackOrder = [];
n@34 317 audioElements.each(function(index,element){
n@45 318 // Find any blind-repeats
b@100 319 // Not implemented yet, but just in case
n@45 320 currentTrackOrder[index] = element;
n@45 321 });
n@45 322 if (randomise) {
n@54 323 currentTrackOrder = randomiseOrder(currentTrackOrder);
n@45 324 }
n@45 325
nicholas@58 326 // Delete any previous audioObjects associated with the audioEngine
nicholas@58 327 audioEngineContext.audioObjects = [];
nicholas@58 328
n@45 329 // Find all the audioElements from the audioHolder
n@45 330 $(currentTrackOrder).each(function(index,element){
n@34 331 // Find URL of track
n@34 332 // In this jQuery loop, variable 'this' holds the current audioElement.
n@34 333
n@34 334 // Now load each audio sample. First create the new track by passing the full URL
n@34 335 var trackURL = hostURL + this.attributes['url'].value;
n@34 336 audioEngineContext.newTrack(trackURL);
n@178 337 audioEngineContext.audioObjects[index].id = this.attributes['id'].value;
nicholas@66 338
nicholas@66 339 if (commentShow) {
nicholas@66 340 // Create document objects to hold the comment boxes
nicholas@66 341 var trackComment = document.createElement('div');
nicholas@66 342 trackComment.className = 'comment-div';
n@154 343 trackComment.id = 'comment-div-'+index;
nicholas@66 344 // Create a string next to each comment asking for a comment
nicholas@66 345 var trackString = document.createElement('span');
n@174 346 trackString.innerHTML = commentBoxPrefix+' '+index;
nicholas@66 347 // Create the HTML5 comment box 'textarea'
nicholas@66 348 var trackCommentBox = document.createElement('textarea');
nicholas@66 349 trackCommentBox.rows = '4';
nicholas@66 350 trackCommentBox.cols = '100';
nicholas@66 351 trackCommentBox.name = 'trackComment'+index;
nicholas@66 352 trackCommentBox.className = 'trackComment';
nicholas@66 353 var br = document.createElement('br');
nicholas@66 354 // Add to the holder.
nicholas@66 355 trackComment.appendChild(trackString);
nicholas@66 356 trackComment.appendChild(br);
nicholas@66 357 trackComment.appendChild(trackCommentBox);
nicholas@66 358 feedbackHolder.appendChild(trackComment);
n@178 359 audioEngineContext.audioObjects[index].commentDOM = trackComment;
nicholas@66 360 }
n@34 361
n@34 362 // Create a slider per track
n@34 363
n@34 364 var trackSliderObj = document.createElement('div');
n@34 365 trackSliderObj.className = 'track-slider';
n@34 366 trackSliderObj.id = 'track-slider-'+index;
n@154 367
n@154 368 var trackSliderAOIndex = document.createAttribute('trackIndex');
n@154 369 trackSliderAOIndex.nodeValue = index;
n@154 370 trackSliderObj.setAttributeNode(trackSliderAOIndex);
n@154 371
n@34 372 // Distribute it randomnly
n@138 373 var w = window.innerWidth - (offset+8)*2;
n@34 374 w = Math.random()*w;
n@138 375 w = Math.floor(w+(offset+8));
n@138 376 trackSliderObj.style.left = w+'px';
n@34 377 trackSliderObj.innerHTML = '<span>'+index+'</span>';
n@34 378 trackSliderObj.draggable = true;
n@34 379 trackSliderObj.ondragend = dragEnd;
n@49 380 trackSliderObj.ondragstart = function()
n@49 381 {
n@154 382 var id = Number(event.srcElement.attributes['trackIndex'].value);
n@49 383 audioEngineContext.metric.sliderMoveStart(id);
n@49 384 };
n@34 385
n@34 386 // Onclick, switch playback to that track
n@34 387 trackSliderObj.onclick = function() {
nicholas@108 388 // Start the test on first click, that way timings are more accurate.
nicholas@108 389 audioEngineContext.play();
nicholas@135 390 if (audioEngineContext.audioObjectsReady) {
nicholas@135 391 // Cannot continue to issue play command until audioObjects reported as ready!
nicholas@135 392 // Get the track ID from the object ID
n@154 393 var id = Number(event.srcElement.attributes['trackIndex'].value);
nicholas@135 394 //audioEngineContext.metric.sliderPlayed(id);
nicholas@135 395 audioEngineContext.selectedTrack(id);
nicholas@135 396 // Currently playing track red, rest green
n@154 397
n@154 398 //document.getElementById('track-slider-'+index).style.backgroundColor = "#FF0000";
n@154 399 $('.track-slider').removeClass('track-slider-playing');
n@154 400 $(event.srcElement).addClass('track-slider-playing');
n@154 401 $('.comment-div').removeClass('comment-box-playing');
n@154 402 $('#comment-div-'+id).addClass('comment-box-playing');
nicholas@135 403 }
n@34 404 };
n@34 405
n@177 406 // Attach binding
n@177 407 audioEngineContext.audioObjects[index].sliderDOM = trackSliderObj;
n@177 408
n@34 409 canvas.appendChild(trackSliderObj);
n@138 410 audioEngineContext.audioObjects[index].metric.initialised(convSliderPosToRate(index));
b@102 411
n@34 412 });
n@39 413
nicholas@65 414 // Append any commentQuestion boxes
nicholas@65 415 var commentQuestions = $(textXML).find('CommentQuestion');
nicholas@65 416 $(commentQuestions).each(function(index,element) {
nicholas@65 417 // Create document objects to hold the comment boxes
nicholas@65 418 var trackComment = document.createElement('div');
nicholas@65 419 trackComment.className = 'comment-div commentQuestion';
nicholas@65 420 trackComment.id = element.attributes['id'].value;
nicholas@65 421 // Create a string next to each comment asking for a comment
nicholas@65 422 var trackString = document.createElement('span');
nicholas@65 423 trackString.innerHTML = element.textContent;
nicholas@65 424 // Create the HTML5 comment box 'textarea'
nicholas@65 425 var trackCommentBox = document.createElement('textarea');
nicholas@65 426 trackCommentBox.rows = '4';
nicholas@65 427 trackCommentBox.cols = '100';
nicholas@65 428 trackCommentBox.name = 'commentQuestion'+index;
nicholas@65 429 trackCommentBox.className = 'trackComment';
nicholas@65 430 var br = document.createElement('br');
nicholas@65 431 // Add to the holder.
nicholas@65 432 trackComment.appendChild(trackString);
nicholas@65 433 trackComment.appendChild(br);
nicholas@65 434 trackComment.appendChild(trackCommentBox);
nicholas@65 435 feedbackHolder.appendChild(trackComment);
nicholas@65 436 });
n@153 437
n@153 438
n@153 439 testWaitIndicator();
n@39 440 }
n@39 441
nicholas@119 442
nicholas@5 443 function dragEnd(ev) {
nicholas@5 444 // Function call when a div has been dropped
n@33 445 var slider = document.getElementById('slider');
n@127 446 var marginSize = Number(slider.attributes['marginsize'].value);
n@51 447 var w = slider.style.width;
n@51 448 w = Number(w.substr(0,w.length-2));
nicholas@133 449 var x = ev.x;
n@127 450 if (x >= marginSize && x < w+marginSize) {
n@51 451 this.style.left = (x)+'px';
nicholas@5 452 } else {
n@127 453 if (x<marginSize) {
n@127 454 this.style.left = marginSize+'px';
nicholas@5 455 } else {
n@127 456 this.style.left = (w+marginSize) + 'px';
nicholas@5 457 }
nicholas@5 458 }
n@49 459 audioEngineContext.metric.sliderMoved();
nicholas@5 460 }
nicholas@7 461
b@101 462 function buttonSubmitClick() // TODO: Only when all songs have been played!
n@40 463 {
nicholas@107 464 hasBeenPlayed = audioEngineContext.checkAllPlayed();
nicholas@107 465 if (hasBeenPlayed.length == 0) {
nicholas@107 466 if (audioEngineContext.status == 1) {
nicholas@107 467 var playback = document.getElementById('playback-button');
nicholas@107 468 playback.click();
nicholas@107 469 // 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 470 } else
nicholas@107 471 {
nicholas@107 472 if (audioEngineContext.timer.testStarted == false)
nicholas@107 473 {
nicholas@107 474 alert('You have not started the test! Please press start to begin the test!');
nicholas@107 475 return;
nicholas@107 476 }
nicholas@107 477 }
nicholas@129 478 testState.advanceState();
b@102 479 } else // if a fragment has not been played yet
b@102 480 {
nicholas@107 481 str = "";
nicholas@107 482 if (hasBeenPlayed.length > 1) {
nicholas@107 483 for (var i=0; i<hasBeenPlayed.length; i++) {
nicholas@107 484 str = str + hasBeenPlayed[i];
nicholas@107 485 if (i < hasBeenPlayed.length-2){
nicholas@107 486 str += ", ";
nicholas@107 487 } else if (i == hasBeenPlayed.length-2) {
nicholas@107 488 str += " or ";
nicholas@107 489 }
nicholas@107 490 }
nicholas@107 491 alert('You have not played fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.');
nicholas@107 492 } else {
nicholas@107 493 alert('You have not played fragment ' + hasBeenPlayed[0] + ' yet. Please listen, rate and comment all samples before submitting.');
nicholas@107 494 }
b@102 495 return;
b@102 496 }
n@40 497 }
n@40 498
n@51 499 function convSliderPosToRate(id)
n@51 500 {
n@51 501 var w = document.getElementById('slider').style.width;
n@127 502 var marginsize = Number(document.getElementById('slider').attributes['marginsize'].value);
n@51 503 var maxPix = w.substr(0,w.length-2);
n@51 504 var slider = document.getElementsByClassName('track-slider')[id];
n@51 505 var pix = slider.style.left;
n@51 506 pix = pix.substr(0,pix.length-2);
n@127 507 var rate = (pix-marginsize)/maxPix;
n@51 508 return rate;
n@51 509 }
n@51 510
n@127 511 function resizeWindow(event){
n@127 512 // Function called when the window has been resized.
n@127 513 // MANDATORY FUNCTION
n@127 514
n@127 515 // Store the slider marker values
n@127 516 var holdValues = [];
n@127 517 $(".track-slider").each(function(index,sliderObj){
n@127 518 holdValues.push(convSliderPosToRate(index));
n@127 519 });
n@127 520
n@127 521 var width = event.target.innerWidth;
n@127 522 var canvas = document.getElementById('sliderCanvasHolder');
n@127 523 var sliderDiv = canvas.children[0];
n@127 524 var sliderScaleDiv = canvas.children[1];
n@127 525 var marginsize = Number(sliderDiv.attributes['marginsize'].value);
n@127 526 var w = (marginsize+8)*2;
n@127 527 sliderDiv.style.width = width - w + 'px';
n@127 528 var width = width - w;
n@127 529 // Move sliders into new position
n@127 530 $(".track-slider").each(function(index,sliderObj){
n@127 531 var pos = holdValues[index];
n@127 532 var pix = pos * width;
n@127 533 sliderObj.style.left = pix+marginsize+'px';
n@127 534 });
n@127 535
n@127 536 // Move scale labels
n@127 537 $(sliderScaleDiv.children).each(function(index,scaleObj){
n@127 538 var position = Number(scaleObj.attributes['value'].value);
n@127 539 var pixelPosition = (position*width)+marginsize;
n@127 540 scaleObj.style.left = Math.floor((pixelPosition-($(scaleObj).width()/2)))+'px';
n@127 541 });
n@127 542 }
n@127 543
nicholas@129 544 function pageXMLSave(store, testXML, testId)
n@44 545 {
n@44 546 // Saves a specific test page
nicholas@129 547 var xmlDoc = store;
n@50 548 // Check if any session wide metrics are enabled
nicholas@67 549
nicholas@129 550 var commentShow = testXML.attributes['elementComments'];
nicholas@67 551 if (commentShow != undefined) {
nicholas@67 552 if (commentShow.value == 'false') {commentShow = false;}
nicholas@67 553 else {commentShow = true;}
nicholas@67 554 } else {commentShow = true;}
nicholas@67 555
n@50 556 var metric = document.createElement('metric');
n@50 557 if (audioEngineContext.metric.enableTestTimer)
n@50 558 {
n@50 559 var testTime = document.createElement('metricResult');
n@50 560 testTime.id = 'testTime';
n@50 561 testTime.textContent = audioEngineContext.timer.testDuration;
n@50 562 metric.appendChild(testTime);
n@50 563 }
n@50 564 xmlDoc.appendChild(metric);
n@178 565 var audioObjects = audioEngineContext.audioObjects;
n@178 566 for (var i=0; i<audioObjects.length; i++)
n@45 567 {
n@45 568 var audioElement = document.createElement('audioElement');
n@178 569 audioElement.id = audioObjects[i].id;
n@178 570 audioElement.setAttribute('url',audioObjects[i].url);
n@51 571 var value = document.createElement('value');
n@51 572 value.innerHTML = convSliderPosToRate(i);
nicholas@67 573 if (commentShow) {
nicholas@67 574 var comment = document.createElement("comment");
nicholas@67 575 var question = document.createElement("question");
nicholas@67 576 var response = document.createElement("response");
n@178 577 question.textContent = audioObjects[i].commentDOM.children[0].textContent;
n@178 578 response.textContent = audioObjects[i].commentDOM.children[2].value;
n@178 579 console.log('Comment ' + i + ': ' + response.textContent); // DEBUG/SAFETY
nicholas@67 580 comment.appendChild(question);
nicholas@67 581 comment.appendChild(response);
nicholas@67 582 audioElement.appendChild(comment);
nicholas@67 583 }
n@45 584 audioElement.appendChild(value);
n@50 585 // Check for any per element metrics
n@177 586
n@178 587 audioElement.appendChild(audioObjects[i].metric.exportXMLDOM());
n@45 588 xmlDoc.appendChild(audioElement);
n@45 589 }
nicholas@65 590 var commentQuestion = document.getElementsByClassName('commentQuestion');
nicholas@65 591 for (var i=0; i<commentQuestion.length; i++)
nicholas@65 592 {
nicholas@65 593 var cqHolder = document.createElement('CommentQuestion');
nicholas@65 594 var comment = document.createElement('comment');
nicholas@65 595 var question = document.createElement('question');
nicholas@65 596 cqHolder.id = commentQuestion[i].id;
nicholas@65 597 comment.textContent = commentQuestion[i].children[2].value;
nicholas@65 598 question.textContent = commentQuestion[i].children[0].textContent;
n@124 599 console.log('Question ' + i + ': ' + commentQuestion[i].children[2].value); // DEBUG/SAFETY
nicholas@65 600 cqHolder.appendChild(question);
nicholas@65 601 cqHolder.appendChild(comment);
nicholas@65 602 xmlDoc.appendChild(cqHolder);
nicholas@65 603 }
nicholas@129 604 store = xmlDoc;
nicholas@67 605 }