annotate ape.js @ 815:3b0770e1e616

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