annotate ape.js @ 1505:a667f80c417e

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