annotate ape.js @ 753:66d732c2bc14

Index page now links to example APE project, example MUSHRA project, test creator, analysis page, citing info, GNU license, and instructions. Instructions and example project contain info on checkboxes.
author Brecht De Man <BrechtDeMan@users.noreply.github.com>
date Fri, 18 Dec 2015 18:26:46 +0000
parents
children 8540d153caec
rev   line source
BrechtDeMan@753 1 /**
BrechtDeMan@753 2 * ape.js
BrechtDeMan@753 3 * Create the APE interface
BrechtDeMan@753 4 */
BrechtDeMan@753 5
BrechtDeMan@753 6
BrechtDeMan@753 7 // Once this is loaded and parsed, begin execution
BrechtDeMan@753 8 loadInterface();
BrechtDeMan@753 9
BrechtDeMan@753 10 function loadInterface() {
BrechtDeMan@753 11
BrechtDeMan@753 12 // Get the dimensions of the screen available to the page
BrechtDeMan@753 13 var width = window.innerWidth;
BrechtDeMan@753 14 var height = window.innerHeight;
BrechtDeMan@753 15
BrechtDeMan@753 16 // The injection point into the HTML page
BrechtDeMan@753 17 interfaceContext.insertPoint = document.getElementById("topLevelBody");
BrechtDeMan@753 18 var testContent = document.createElement('div');
BrechtDeMan@753 19
BrechtDeMan@753 20 testContent.id = 'testContent';
BrechtDeMan@753 21
BrechtDeMan@753 22 // Bindings for interfaceContext
BrechtDeMan@753 23 interfaceContext.checkAllPlayed = function()
BrechtDeMan@753 24 {
BrechtDeMan@753 25 hasBeenPlayed = audioEngineContext.checkAllPlayed();
BrechtDeMan@753 26 if (hasBeenPlayed.length > 0) // if a fragment has not been played yet
BrechtDeMan@753 27 {
BrechtDeMan@753 28 str = "";
BrechtDeMan@753 29 if (hasBeenPlayed.length > 1) {
BrechtDeMan@753 30 for (var i=0; i<hasBeenPlayed.length; i++) {
BrechtDeMan@753 31 str = str + hasBeenPlayed[i];
BrechtDeMan@753 32 if (i < hasBeenPlayed.length-2){
BrechtDeMan@753 33 str += ", ";
BrechtDeMan@753 34 } else if (i == hasBeenPlayed.length-2) {
BrechtDeMan@753 35 str += " or ";
BrechtDeMan@753 36 }
BrechtDeMan@753 37 }
BrechtDeMan@753 38 alert('You have not played fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.');
BrechtDeMan@753 39 } else {
BrechtDeMan@753 40 alert('You have not played fragment ' + hasBeenPlayed[0] + ' yet. Please listen, rate and comment all samples before submitting.');
BrechtDeMan@753 41 }
BrechtDeMan@753 42 return false;
BrechtDeMan@753 43 }
BrechtDeMan@753 44 return true;
BrechtDeMan@753 45 };
BrechtDeMan@753 46
BrechtDeMan@753 47 interfaceContext.checkAllMoved = function() {
BrechtDeMan@753 48 var state = true;
BrechtDeMan@753 49 var str = 'You have not moved the following sliders. ';
BrechtDeMan@753 50 for (var i=0; i<this.interfaceSliders.length; i++)
BrechtDeMan@753 51 {
BrechtDeMan@753 52 var interfaceTID = [];
BrechtDeMan@753 53 for (var j=0; j<this.interfaceSliders[i].metrics.length; j++)
BrechtDeMan@753 54 {
BrechtDeMan@753 55 if (this.interfaceSliders[i].metrics[j].wasMoved == false)
BrechtDeMan@753 56 {
BrechtDeMan@753 57 state = false;
BrechtDeMan@753 58 interfaceTID.push(j);
BrechtDeMan@753 59 }
BrechtDeMan@753 60 }
BrechtDeMan@753 61 if (interfaceTID.length != 0)
BrechtDeMan@753 62 {
BrechtDeMan@753 63 var interfaceName = this.interfaceSliders[i].interfaceObject.title;
BrechtDeMan@753 64 if (interfaceName == undefined) {
BrechtDeMan@753 65 str += 'On axis '+String(i+1)+' you must move ';
BrechtDeMan@753 66 } else {
BrechtDeMan@753 67 str += 'On axis "'+interfaceName+'" you must move ';
BrechtDeMan@753 68 }
BrechtDeMan@753 69 if (interfaceTID.length == 1)
BrechtDeMan@753 70 {
BrechtDeMan@753 71 str += 'slider '+interfaceTID[0]+'. ';
BrechtDeMan@753 72 }
BrechtDeMan@753 73 else {
BrechtDeMan@753 74 str += 'sliders ';
BrechtDeMan@753 75 for (var k=0; k<interfaceTID.length-1; k++)
BrechtDeMan@753 76 {
BrechtDeMan@753 77 str += interfaceTID[k]+', ';
BrechtDeMan@753 78 }
BrechtDeMan@753 79 str += interfaceTID[interfaceTID.length-1] +'. ';
BrechtDeMan@753 80 }
BrechtDeMan@753 81 }
BrechtDeMan@753 82 }
BrechtDeMan@753 83 if (state != true)
BrechtDeMan@753 84 {
BrechtDeMan@753 85 alert(str);
BrechtDeMan@753 86 console.log(str);
BrechtDeMan@753 87 }
BrechtDeMan@753 88 return state;
BrechtDeMan@753 89 };
BrechtDeMan@753 90
BrechtDeMan@753 91 Interface.prototype.checkAllCommented = function() {
BrechtDeMan@753 92 var audioObjs = audioEngineContext.audioObjects;
BrechtDeMan@753 93 var audioHolder = testState.stateMap[testState.stateIndex];
BrechtDeMan@753 94 var state = true;
BrechtDeMan@753 95 if (audioHolder.elementComments) {
BrechtDeMan@753 96 var strNums = [];
BrechtDeMan@753 97 for (var i=0; i<audioObjs.length; i++)
BrechtDeMan@753 98 {
BrechtDeMan@753 99 if (audioObjs[i].commentDOM.trackCommentBox.value.length == 0) {
BrechtDeMan@753 100 state = false;
BrechtDeMan@753 101 strNums.push(i);
BrechtDeMan@753 102 }
BrechtDeMan@753 103 }
BrechtDeMan@753 104 if (state == false) {
BrechtDeMan@753 105 if (strNums.length > 1) {
BrechtDeMan@753 106 var str = "";
BrechtDeMan@753 107 for (var i=0; i<strNums.length; i++) {
BrechtDeMan@753 108 str = str + strNums[i];
BrechtDeMan@753 109 if (i < strNums.length-2){
BrechtDeMan@753 110 str += ", ";
BrechtDeMan@753 111 } else if (i == strNums.length-2) {
BrechtDeMan@753 112 str += " or ";
BrechtDeMan@753 113 }
BrechtDeMan@753 114 }
BrechtDeMan@753 115 alert('You have not commented on fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.');
BrechtDeMan@753 116 } else {
BrechtDeMan@753 117 alert('You have not commented on fragment ' + strNums[0] + ' yet. Please listen, rate and comment all samples before submitting.');
BrechtDeMan@753 118 }
BrechtDeMan@753 119 }
BrechtDeMan@753 120 }
BrechtDeMan@753 121 return state;
BrechtDeMan@753 122 };
BrechtDeMan@753 123
BrechtDeMan@753 124 Interface.prototype.checkScaleRange = function()
BrechtDeMan@753 125 {
BrechtDeMan@753 126 var audioObjs = audioEngineContext.audioObjects;
BrechtDeMan@753 127 var audioHolder = testState.stateMap[testState.stateIndex];
BrechtDeMan@753 128 var state = true;
BrechtDeMan@753 129 var str = '';
BrechtDeMan@753 130 for (var i=0; i<this.interfaceSliders.length; i++)
BrechtDeMan@753 131 {
BrechtDeMan@753 132 var minScale;
BrechtDeMan@753 133 var maxScale;
BrechtDeMan@753 134 var interfaceObject = interfaceContext.interfaceSliders[0].interfaceObject;
BrechtDeMan@753 135 for (var j=0; j<interfaceObject.options.length; j++)
BrechtDeMan@753 136 {
BrechtDeMan@753 137 if (interfaceObject.options[j].check == "scalerange") {
BrechtDeMan@753 138 minScale = interfaceObject.options[j].min;
BrechtDeMan@753 139 maxScale = interfaceObject.options[j].max;
BrechtDeMan@753 140 break;
BrechtDeMan@753 141 }
BrechtDeMan@753 142 }
BrechtDeMan@753 143 var minRanking = convSliderPosToRate(this.interfaceSliders[i].sliders[0]);
BrechtDeMan@753 144 var maxRanking = minRanking;
BrechtDeMan@753 145 for (var j=1; j<this.interfaceSliders[i].sliders.length; j++)
BrechtDeMan@753 146 {
BrechtDeMan@753 147 var ranking = convSliderPosToRate(this.interfaceSliders[i].sliders[j]);
BrechtDeMan@753 148 if (ranking < minRanking)
BrechtDeMan@753 149 {
BrechtDeMan@753 150 minRanking = ranking;
BrechtDeMan@753 151 } else if (ranking > maxRanking)
BrechtDeMan@753 152 {
BrechtDeMan@753 153 maxRanking = ranking;
BrechtDeMan@753 154 }
BrechtDeMan@753 155 }
BrechtDeMan@753 156 if (minRanking > minScale || maxRanking < maxScale)
BrechtDeMan@753 157 {
BrechtDeMan@753 158 state = false;
BrechtDeMan@753 159 str += 'On axis "'+this.interfaceSliders[i].interfaceObject.title+'" you have not used the full width of the scale. ';
BrechtDeMan@753 160 }
BrechtDeMan@753 161 }
BrechtDeMan@753 162 if (state != true)
BrechtDeMan@753 163 {
BrechtDeMan@753 164 alert(str);
BrechtDeMan@753 165 console.log(str);
BrechtDeMan@753 166 }
BrechtDeMan@753 167 return state;
BrechtDeMan@753 168 };
BrechtDeMan@753 169
BrechtDeMan@753 170 Interface.prototype.objectSelected = null;
BrechtDeMan@753 171 Interface.prototype.objectMoved = false;
BrechtDeMan@753 172 Interface.prototype.selectObject = function(object)
BrechtDeMan@753 173 {
BrechtDeMan@753 174 if (this.objectSelected == null)
BrechtDeMan@753 175 {
BrechtDeMan@753 176 this.objectSelected = object;
BrechtDeMan@753 177 this.objectMoved = false;
BrechtDeMan@753 178 }
BrechtDeMan@753 179 };
BrechtDeMan@753 180 Interface.prototype.moveObject = function()
BrechtDeMan@753 181 {
BrechtDeMan@753 182 if (this.objectMoved == false)
BrechtDeMan@753 183 {
BrechtDeMan@753 184 this.objectMoved = true;
BrechtDeMan@753 185 }
BrechtDeMan@753 186 };
BrechtDeMan@753 187 Interface.prototype.releaseObject = function()
BrechtDeMan@753 188 {
BrechtDeMan@753 189 this.objectSelected = null;
BrechtDeMan@753 190 this.objectMoved = false;
BrechtDeMan@753 191 };
BrechtDeMan@753 192 Interface.prototype.getSelectedObject = function()
BrechtDeMan@753 193 {
BrechtDeMan@753 194 return this.objectSelected;
BrechtDeMan@753 195 };
BrechtDeMan@753 196 Interface.prototype.hasSelectedObjectMoved = function()
BrechtDeMan@753 197 {
BrechtDeMan@753 198 return this.objectMoved;
BrechtDeMan@753 199 };
BrechtDeMan@753 200
BrechtDeMan@753 201 // Bindings for slider interfaces
BrechtDeMan@753 202 Interface.prototype.interfaceSliders = [];
BrechtDeMan@753 203
BrechtDeMan@753 204 // Bindings for audioObjects
BrechtDeMan@753 205
BrechtDeMan@753 206 // Create the top div for the Title element
BrechtDeMan@753 207 var titleAttr = specification.title;
BrechtDeMan@753 208 var title = document.createElement('div');
BrechtDeMan@753 209 title.className = "title";
BrechtDeMan@753 210 title.align = "center";
BrechtDeMan@753 211 var titleSpan = document.createElement('span');
BrechtDeMan@753 212
BrechtDeMan@753 213 // Set title to that defined in XML, else set to default
BrechtDeMan@753 214 if (titleAttr != undefined) {
BrechtDeMan@753 215 titleSpan.textContent = titleAttr;
BrechtDeMan@753 216 } else {
BrechtDeMan@753 217 titleSpan.textContent = 'Listening test';
BrechtDeMan@753 218 }
BrechtDeMan@753 219 // Insert the titleSpan element into the title div element.
BrechtDeMan@753 220 title.appendChild(titleSpan);
BrechtDeMan@753 221
BrechtDeMan@753 222 // Create Interface buttons!
BrechtDeMan@753 223 var interfaceButtons = document.createElement('div');
BrechtDeMan@753 224 interfaceButtons.id = 'interface-buttons';
BrechtDeMan@753 225
BrechtDeMan@753 226 // Create playback start/stop points
BrechtDeMan@753 227 var playback = document.createElement("button");
BrechtDeMan@753 228 playback.innerHTML = 'Stop';
BrechtDeMan@753 229 playback.id = 'playback-button';
BrechtDeMan@753 230 // onclick function. Check if it is playing or not, call the correct function in the
BrechtDeMan@753 231 // audioEngine, change the button text to reflect the next state.
BrechtDeMan@753 232 playback.onclick = function() {
BrechtDeMan@753 233 if (audioEngineContext.status == 1) {
BrechtDeMan@753 234 audioEngineContext.stop();
BrechtDeMan@753 235 this.innerHTML = 'Stop';
BrechtDeMan@753 236 var time = audioEngineContext.timer.getTestTime();
BrechtDeMan@753 237 console.log('Stopped at ' + time); // DEBUG/SAFETY
BrechtDeMan@753 238 }
BrechtDeMan@753 239 };
BrechtDeMan@753 240 // Create Submit (save) button
BrechtDeMan@753 241 var submit = document.createElement("button");
BrechtDeMan@753 242 submit.innerHTML = 'Submit';
BrechtDeMan@753 243 submit.onclick = buttonSubmitClick;
BrechtDeMan@753 244 submit.id = 'submit-button';
BrechtDeMan@753 245 // Append the interface buttons into the interfaceButtons object.
BrechtDeMan@753 246 interfaceButtons.appendChild(playback);
BrechtDeMan@753 247 interfaceButtons.appendChild(submit);
BrechtDeMan@753 248
BrechtDeMan@753 249 var sliderHolder = document.createElement("div");
BrechtDeMan@753 250 sliderHolder.id = "slider-holder";
BrechtDeMan@753 251
BrechtDeMan@753 252
BrechtDeMan@753 253 // Global parent for the comment boxes on the page
BrechtDeMan@753 254 var feedbackHolder = document.createElement('div');
BrechtDeMan@753 255 feedbackHolder.id = 'feedbackHolder';
BrechtDeMan@753 256
BrechtDeMan@753 257 testContent.style.zIndex = 1;
BrechtDeMan@753 258 interfaceContext.insertPoint.innerHTML = null; // Clear the current schema
BrechtDeMan@753 259
BrechtDeMan@753 260 // Inject into HTML
BrechtDeMan@753 261 testContent.appendChild(title); // Insert the title
BrechtDeMan@753 262 testContent.appendChild(interfaceButtons);
BrechtDeMan@753 263 testContent.appendChild(sliderHolder);
BrechtDeMan@753 264 testContent.appendChild(feedbackHolder);
BrechtDeMan@753 265 interfaceContext.insertPoint.appendChild(testContent);
BrechtDeMan@753 266
BrechtDeMan@753 267 // Load the full interface
BrechtDeMan@753 268 testState.initialise();
BrechtDeMan@753 269 testState.advanceState();
BrechtDeMan@753 270
BrechtDeMan@753 271 }
BrechtDeMan@753 272
BrechtDeMan@753 273 function loadTest(audioHolderObject)
BrechtDeMan@753 274 {
BrechtDeMan@753 275 var width = window.innerWidth;
BrechtDeMan@753 276 var height = window.innerHeight;
BrechtDeMan@753 277 var id = audioHolderObject.id;
BrechtDeMan@753 278
BrechtDeMan@753 279 interfaceContext.interfaceSliders = [];
BrechtDeMan@753 280
BrechtDeMan@753 281 var feedbackHolder = document.getElementById('feedbackHolder');
BrechtDeMan@753 282 var sliderHolder = document.getElementById('slider-holder');
BrechtDeMan@753 283 feedbackHolder.innerHTML = null;
BrechtDeMan@753 284 sliderHolder.innerHTML = null;
BrechtDeMan@753 285
BrechtDeMan@753 286 var interfaceObj = audioHolderObject.interfaces;
BrechtDeMan@753 287 for (var k=0; k<interfaceObj.length; k++) {
BrechtDeMan@753 288 // Create the div box to center align
BrechtDeMan@753 289 interfaceContext.interfaceSliders.push(new interfaceSliderHolder(interfaceObj[k]));
BrechtDeMan@753 290 for (var i=0; i<interfaceObj[k].options.length; i++)
BrechtDeMan@753 291 {
BrechtDeMan@753 292 if (interfaceObj[k].options[i].type == 'option' && interfaceObj[k].options[i].name == 'playhead')
BrechtDeMan@753 293 {
BrechtDeMan@753 294 var playbackHolder = document.getElementById('playback-holder');
BrechtDeMan@753 295 if (playbackHolder == null)
BrechtDeMan@753 296 {
BrechtDeMan@753 297 playbackHolder = document.createElement('div');
BrechtDeMan@753 298 playbackHolder.style.width = "100%";
BrechtDeMan@753 299 playbackHolder.align = 'center';
BrechtDeMan@753 300 playbackHolder.appendChild(interfaceContext.playhead.object);
BrechtDeMan@753 301 feedbackHolder.appendChild(playbackHolder);
BrechtDeMan@753 302 }
BrechtDeMan@753 303 } else if (interfaceObj[k].options[i].type == 'option' && interfaceObj[k].options[i].name == 'page-count')
BrechtDeMan@753 304 {
BrechtDeMan@753 305 var pagecountHolder = document.getElementById('page-count');
BrechtDeMan@753 306 if (pagecountHolder == null)
BrechtDeMan@753 307 {
BrechtDeMan@753 308 pagecountHolder = document.createElement('div');
BrechtDeMan@753 309 pagecountHolder.id = 'page-count';
BrechtDeMan@753 310 }
BrechtDeMan@753 311 pagecountHolder.innerHTML = '<span>Page '+(audioHolderObject.presentedId+1)+' of '+specification.audioHolders.length+'</span>';
BrechtDeMan@753 312 var inject = document.getElementById('interface-buttons');
BrechtDeMan@753 313 inject.appendChild(pagecountHolder);
BrechtDeMan@753 314 }
BrechtDeMan@753 315 }
BrechtDeMan@753 316 }
BrechtDeMan@753 317
BrechtDeMan@753 318 var commentBoxPrefix = "Comment on track";
BrechtDeMan@753 319
BrechtDeMan@753 320 var commentShow = audioHolderObject.elementComments;
BrechtDeMan@753 321
BrechtDeMan@753 322 var loopPlayback = audioHolderObject.loop;
BrechtDeMan@753 323
BrechtDeMan@753 324 currentTestHolder = document.createElement('audioHolder');
BrechtDeMan@753 325 currentTestHolder.id = audioHolderObject.id;
BrechtDeMan@753 326 currentTestHolder.repeatCount = audioHolderObject.repeatCount;
BrechtDeMan@753 327
BrechtDeMan@753 328 // Find all the audioElements from the audioHolder
BrechtDeMan@753 329 $(audioHolderObject.audioElements).each(function(index,element){
BrechtDeMan@753 330 // Find URL of track
BrechtDeMan@753 331 // In this jQuery loop, variable 'this' holds the current audioElement.
BrechtDeMan@753 332
BrechtDeMan@753 333 // Check if an outside reference
BrechtDeMan@753 334 if (index == audioHolderObject.outsideReference)
BrechtDeMan@753 335 {
BrechtDeMan@753 336 return;
BrechtDeMan@753 337 }
BrechtDeMan@753 338
BrechtDeMan@753 339 // Now load each audio sample. First create the new track by passing the full URL
BrechtDeMan@753 340 var trackURL = audioHolderObject.hostURL + element.url;
BrechtDeMan@753 341 var audioObject = audioEngineContext.newTrack(element);
BrechtDeMan@753 342
BrechtDeMan@753 343 var node = interfaceContext.createCommentBox(audioObject);
BrechtDeMan@753 344
BrechtDeMan@753 345 // Create a slider per track
BrechtDeMan@753 346 audioObject.interfaceDOM = new sliderObject(audioObject,interfaceObj);
BrechtDeMan@753 347 audioObject.metric.initialPosition = convSliderPosToRate(audioObject.interfaceDOM.trackSliderObjects[0]);
BrechtDeMan@753 348 if (audioObject.state == 1)
BrechtDeMan@753 349 {
BrechtDeMan@753 350 audioObject.interfaceDOM.enable();
BrechtDeMan@753 351 }
BrechtDeMan@753 352
BrechtDeMan@753 353 });
BrechtDeMan@753 354
BrechtDeMan@753 355 $('.track-slider').mousedown(function(event) {
BrechtDeMan@753 356 interfaceContext.selectObject($(this)[0]);
BrechtDeMan@753 357 });
BrechtDeMan@753 358
BrechtDeMan@753 359 $('.track-slider').mousemove(function(event) {
BrechtDeMan@753 360 event.preventDefault();
BrechtDeMan@753 361 });
BrechtDeMan@753 362
BrechtDeMan@753 363 $('.slider').mousemove(function(event) {
BrechtDeMan@753 364 event.preventDefault();
BrechtDeMan@753 365 var obj = interfaceContext.getSelectedObject();
BrechtDeMan@753 366 if (obj == null) {return;}
BrechtDeMan@753 367 $(obj).css("left",event.clientX + "px");
BrechtDeMan@753 368 interfaceContext.moveObject();
BrechtDeMan@753 369 });
BrechtDeMan@753 370
BrechtDeMan@753 371 $(document).mouseup(function(event){
BrechtDeMan@753 372 event.preventDefault();
BrechtDeMan@753 373 var obj = interfaceContext.getSelectedObject();
BrechtDeMan@753 374 if (obj == null) {return;}
BrechtDeMan@753 375 var interfaceID = obj.parentElement.getAttribute("interfaceid");
BrechtDeMan@753 376 var trackID = obj.getAttribute("trackindex");
BrechtDeMan@753 377 if (interfaceContext.hasSelectedObjectMoved() == true)
BrechtDeMan@753 378 {
BrechtDeMan@753 379 var l = $(obj).css("left");
BrechtDeMan@753 380 var id = obj.getAttribute('trackIndex');
BrechtDeMan@753 381 var time = audioEngineContext.timer.getTestTime();
BrechtDeMan@753 382 var rate = convSliderPosToRate(obj);
BrechtDeMan@753 383 audioEngineContext.audioObjects[id].metric.moved(time,rate);
BrechtDeMan@753 384 interfaceContext.interfaceSliders[interfaceID].metrics[trackID].moved(time,rate);
BrechtDeMan@753 385 console.log("slider "+id+" moved to "+rate+' ('+time+')');
BrechtDeMan@753 386 } else {
BrechtDeMan@753 387 var id = Number(obj.attributes['trackIndex'].value);
BrechtDeMan@753 388 //audioEngineContext.metric.sliderPlayed(id);
BrechtDeMan@753 389 audioEngineContext.play(id);
BrechtDeMan@753 390 // Currently playing track red, rest green
BrechtDeMan@753 391
BrechtDeMan@753 392 $('.track-slider').removeClass('track-slider-playing');
BrechtDeMan@753 393 var name = ".track-slider-"+obj.getAttribute("trackindex");
BrechtDeMan@753 394 $(name).addClass('track-slider-playing');
BrechtDeMan@753 395 $('.comment-div').removeClass('comment-box-playing');
BrechtDeMan@753 396 $('#comment-div-'+id).addClass('comment-box-playing');
BrechtDeMan@753 397 var outsideReference = document.getElementById('outside-reference');
BrechtDeMan@753 398 if (outsideReference != undefined)
BrechtDeMan@753 399 $(outsideReference).removeClass('track-slider-playing');
BrechtDeMan@753 400 }
BrechtDeMan@753 401 interfaceContext.releaseObject();
BrechtDeMan@753 402 });
BrechtDeMan@753 403
BrechtDeMan@753 404
BrechtDeMan@753 405 if (commentShow) {
BrechtDeMan@753 406 interfaceContext.showCommentBoxes(feedbackHolder,true);
BrechtDeMan@753 407 }
BrechtDeMan@753 408
BrechtDeMan@753 409 $(audioHolderObject.commentQuestions).each(function(index,element) {
BrechtDeMan@753 410 var node = interfaceContext.createCommentQuestion(element);
BrechtDeMan@753 411 feedbackHolder.appendChild(node.holder);
BrechtDeMan@753 412 });
BrechtDeMan@753 413
BrechtDeMan@753 414 // Construct outside reference;
BrechtDeMan@753 415 if (audioHolderObject.outsideReference != null) {
BrechtDeMan@753 416 var outsideReferenceHolder = document.createElement('div');
BrechtDeMan@753 417 outsideReferenceHolder.id = 'outside-reference';
BrechtDeMan@753 418 outsideReferenceHolder.className = 'outside-reference';
BrechtDeMan@753 419 outsideReferenceHolderspan = document.createElement('span');
BrechtDeMan@753 420 outsideReferenceHolderspan.textContent = 'Reference';
BrechtDeMan@753 421 outsideReferenceHolder.appendChild(outsideReferenceHolderspan);
BrechtDeMan@753 422
BrechtDeMan@753 423 var audioObject = audioEngineContext.newTrack(audioHolderObject.audioElements[audioHolderObject.outsideReference]);
BrechtDeMan@753 424
BrechtDeMan@753 425 outsideReferenceHolder.onclick = function(event)
BrechtDeMan@753 426 {
BrechtDeMan@753 427 audioEngineContext.play(audioEngineContext.audioObjects.length-1);
BrechtDeMan@753 428 $('.track-slider').removeClass('track-slider-playing');
BrechtDeMan@753 429 $('.comment-div').removeClass('comment-box-playing');
BrechtDeMan@753 430 if (event.currentTarget.nodeName == 'DIV') {
BrechtDeMan@753 431 $(event.currentTarget).addClass('track-slider-playing');
BrechtDeMan@753 432 } else {
BrechtDeMan@753 433 $(event.currentTarget.parentElement).addClass('track-slider-playing');
BrechtDeMan@753 434 }
BrechtDeMan@753 435 };
BrechtDeMan@753 436
BrechtDeMan@753 437 document.getElementById('interface-buttons').appendChild(outsideReferenceHolder);
BrechtDeMan@753 438 }
BrechtDeMan@753 439
BrechtDeMan@753 440
BrechtDeMan@753 441 //testWaitIndicator();
BrechtDeMan@753 442 }
BrechtDeMan@753 443
BrechtDeMan@753 444 function interfaceSliderHolder(interfaceObject)
BrechtDeMan@753 445 {
BrechtDeMan@753 446 this.sliders = [];
BrechtDeMan@753 447 this.metrics = [];
BrechtDeMan@753 448 this.id = document.getElementsByClassName("sliderCanvasDiv").length;
BrechtDeMan@753 449 this.name = interfaceObject.name;
BrechtDeMan@753 450 this.interfaceObject = interfaceObject;
BrechtDeMan@753 451 this.sliderDOM = document.createElement('div');
BrechtDeMan@753 452 this.sliderDOM.className = 'sliderCanvasDiv';
BrechtDeMan@753 453 this.sliderDOM.id = 'sliderCanvasHolder-'+this.id;
BrechtDeMan@753 454
BrechtDeMan@753 455 var pagetitle = document.createElement('div');
BrechtDeMan@753 456 pagetitle.className = "pageTitle";
BrechtDeMan@753 457 pagetitle.align = "center";
BrechtDeMan@753 458 var titleSpan = document.createElement('span');
BrechtDeMan@753 459 titleSpan.id = "pageTitle-"+this.id;
BrechtDeMan@753 460 if (interfaceObject.title != undefined && typeof interfaceObject.title == "string")
BrechtDeMan@753 461 {
BrechtDeMan@753 462 titleSpan.textContent = interfaceObject.title;
BrechtDeMan@753 463 } else {
BrechtDeMan@753 464 titleSpan.textContent = "Axis "+String(this.id+1);
BrechtDeMan@753 465 }
BrechtDeMan@753 466 pagetitle.appendChild(titleSpan);
BrechtDeMan@753 467 this.sliderDOM.appendChild(pagetitle);
BrechtDeMan@753 468
BrechtDeMan@753 469 // Create the slider box to hold the slider elements
BrechtDeMan@753 470 this.canvas = document.createElement('div');
BrechtDeMan@753 471 if (this.name != undefined)
BrechtDeMan@753 472 this.canvas.id = 'slider-'+this.name;
BrechtDeMan@753 473 else
BrechtDeMan@753 474 this.canvas.id = 'slider-'+this.id;
BrechtDeMan@753 475 this.canvas.setAttribute("interfaceid",this.id);
BrechtDeMan@753 476 this.canvas.className = 'slider';
BrechtDeMan@753 477 this.canvas.align = "left";
BrechtDeMan@753 478 this.canvas.addEventListener('dragover',function(event){
BrechtDeMan@753 479 event.preventDefault();
BrechtDeMan@753 480 event.dataTransfer.effectAllowed = 'none';
BrechtDeMan@753 481 event.dataTransfer.dropEffect = 'copy';
BrechtDeMan@753 482 return false;
BrechtDeMan@753 483 },false);
BrechtDeMan@753 484 var sliderMargin = document.createAttribute('marginsize');
BrechtDeMan@753 485 sliderMargin.nodeValue = 42; // Set default margins to 42px either side
BrechtDeMan@753 486 // Must have a known EXACT width, as this is used later to determine the ratings
BrechtDeMan@753 487 var w = (Number(sliderMargin.nodeValue)+8)*2;
BrechtDeMan@753 488 this.canvas.style.width = window.innerWidth - w +"px";
BrechtDeMan@753 489 this.canvas.style.marginLeft = sliderMargin.nodeValue +'px';
BrechtDeMan@753 490 this.canvas.setAttributeNode(sliderMargin);
BrechtDeMan@753 491 this.sliderDOM.appendChild(this.canvas);
BrechtDeMan@753 492
BrechtDeMan@753 493 // Create the div to hold any scale objects
BrechtDeMan@753 494 this.scale = document.createElement('div');
BrechtDeMan@753 495 this.scale.className = 'sliderScale';
BrechtDeMan@753 496 this.scale.id = 'sliderScaleHolder-'+this.id;
BrechtDeMan@753 497 this.scale.align = 'left';
BrechtDeMan@753 498 this.sliderDOM.appendChild(this.scale);
BrechtDeMan@753 499 var positionScale = this.canvas.style.width.substr(0,this.canvas.style.width.length-2);
BrechtDeMan@753 500 var offset = Number(this.canvas.attributes['marginsize'].value);
BrechtDeMan@753 501 for (var index=0; index<interfaceObject.scale.length; index++)
BrechtDeMan@753 502 {
BrechtDeMan@753 503 var scaleObj = interfaceObject.scale[index];
BrechtDeMan@753 504 var value = document.createAttribute('value');
BrechtDeMan@753 505 var position = Number(scaleObj[0])*0.01;
BrechtDeMan@753 506 value.nodeValue = position;
BrechtDeMan@753 507 var pixelPosition = (position*positionScale)+offset;
BrechtDeMan@753 508 var scaleDOM = document.createElement('span');
BrechtDeMan@753 509 scaleDOM.textContent = scaleObj[1];
BrechtDeMan@753 510 this.scale.appendChild(scaleDOM);
BrechtDeMan@753 511 scaleDOM.style.left = Math.floor((pixelPosition-($(scaleDOM).width()/2)))+'px';
BrechtDeMan@753 512 scaleDOM.setAttributeNode(value);
BrechtDeMan@753 513 }
BrechtDeMan@753 514
BrechtDeMan@753 515 var dest = document.getElementById("slider-holder");
BrechtDeMan@753 516 dest.appendChild(this.sliderDOM);
BrechtDeMan@753 517
BrechtDeMan@753 518 this.createSliderObject = function(audioObject)
BrechtDeMan@753 519 {
BrechtDeMan@753 520 var trackObj = document.createElement('div');
BrechtDeMan@753 521 trackObj.className = 'track-slider track-slider-disabled track-slider-'+audioObject.id;
BrechtDeMan@753 522 trackObj.id = 'track-slider-'+this.id+'-'+audioObject.id;
BrechtDeMan@753 523 trackObj.setAttribute('trackIndex',audioObject.id);
BrechtDeMan@753 524 trackObj.innerHTML = '<span>'+audioObject.id+'</span>';
BrechtDeMan@753 525 if (this.name != undefined) {
BrechtDeMan@753 526 trackObj.setAttribute('interface-name',this.name);
BrechtDeMan@753 527 } else {
BrechtDeMan@753 528 trackObj.setAttribute('interface-name',this.id);
BrechtDeMan@753 529 }
BrechtDeMan@753 530 var offset = Number(this.canvas.attributes['marginsize'].value);
BrechtDeMan@753 531 // Distribute it randomnly
BrechtDeMan@753 532 var w = window.innerWidth - (offset+8)*2;
BrechtDeMan@753 533 w = Math.random()*w;
BrechtDeMan@753 534 w = Math.floor(w+(offset+8));
BrechtDeMan@753 535 trackObj.style.left = w+'px';
BrechtDeMan@753 536 this.canvas.appendChild(trackObj);
BrechtDeMan@753 537 this.sliders.push(trackObj);
BrechtDeMan@753 538 this.metrics.push(new metricTracker(this));
BrechtDeMan@753 539 this.metrics[this.metrics.length-1].initialPosition = convSliderPosToRate(trackObj);
BrechtDeMan@753 540 return trackObj;
BrechtDeMan@753 541 };
BrechtDeMan@753 542
BrechtDeMan@753 543 this.resize = function(event)
BrechtDeMan@753 544 {
BrechtDeMan@753 545 var holdValues = [];
BrechtDeMan@753 546 for (var index = 0; index < this.sliders.length; index++)
BrechtDeMan@753 547 {
BrechtDeMan@753 548 holdValues.push(convSliderPosToRate(this.sliders[index]));
BrechtDeMan@753 549 }
BrechtDeMan@753 550 var width = event.target.innerWidth;
BrechtDeMan@753 551 var sliderDiv = this.canvas;
BrechtDeMan@753 552 var sliderScaleDiv = this.scale;
BrechtDeMan@753 553 var marginsize = Number(sliderDiv.attributes['marginsize'].value);
BrechtDeMan@753 554 var w = (marginsize+8)*2;
BrechtDeMan@753 555 sliderDiv.style.width = width - w + 'px';
BrechtDeMan@753 556 var width = width - w;
BrechtDeMan@753 557 // Move sliders into new position
BrechtDeMan@753 558 for (var index = 0; index < this.sliders.length; index++)
BrechtDeMan@753 559 {
BrechtDeMan@753 560 var pos = holdValues[index];
BrechtDeMan@753 561 var pix = pos * width;
BrechtDeMan@753 562 this.sliders[index].style.left = pix+marginsize+'px';
BrechtDeMan@753 563 }
BrechtDeMan@753 564
BrechtDeMan@753 565 // Move scale labels
BrechtDeMan@753 566 for (var index = 0; index < this.scale.children.length; index++)
BrechtDeMan@753 567 {
BrechtDeMan@753 568 var scaleObj = this.scale.children[index];
BrechtDeMan@753 569 var position = Number(scaleObj.attributes['value'].value);
BrechtDeMan@753 570 var pixelPosition = (position*width)+marginsize;
BrechtDeMan@753 571 scaleObj.style.left = Math.floor((pixelPosition-($(scaleObj).width()/2)))+'px';
BrechtDeMan@753 572 }
BrechtDeMan@753 573 };
BrechtDeMan@753 574 }
BrechtDeMan@753 575
BrechtDeMan@753 576 function sliderObject(audioObject,interfaceObjects) {
BrechtDeMan@753 577 // Create a new slider object;
BrechtDeMan@753 578 this.parent = audioObject;
BrechtDeMan@753 579 this.trackSliderObjects = [];
BrechtDeMan@753 580 for (var i=0; i<interfaceContext.interfaceSliders.length; i++)
BrechtDeMan@753 581 {
BrechtDeMan@753 582 var trackObj = interfaceContext.interfaceSliders[i].createSliderObject(audioObject);
BrechtDeMan@753 583 this.trackSliderObjects.push(trackObj);
BrechtDeMan@753 584 }
BrechtDeMan@753 585
BrechtDeMan@753 586 // Onclick, switch playback to that track
BrechtDeMan@753 587
BrechtDeMan@753 588 this.enable = function() {
BrechtDeMan@753 589 if (this.parent.state == 1)
BrechtDeMan@753 590 {
BrechtDeMan@753 591 $(this.trackSliderObjects).each(function(i,trackObj){
BrechtDeMan@753 592 $(trackObj).removeClass('track-slider-disabled');
BrechtDeMan@753 593 });
BrechtDeMan@753 594 }
BrechtDeMan@753 595 };
BrechtDeMan@753 596 this.updateLoading = function(progress)
BrechtDeMan@753 597 {
BrechtDeMan@753 598 if (progress != 100)
BrechtDeMan@753 599 {
BrechtDeMan@753 600 progress = String(progress);
BrechtDeMan@753 601 progress = progress.split('.')[0];
BrechtDeMan@753 602 this.trackSliderObjects[0].children[0].textContent = progress+'%';
BrechtDeMan@753 603 } else {
BrechtDeMan@753 604 this.trackSliderObjects[0].children[0].textContent = this.parent.id;
BrechtDeMan@753 605 }
BrechtDeMan@753 606 };
BrechtDeMan@753 607 this.exportXMLDOM = function(audioObject) {
BrechtDeMan@753 608 // Called by the audioObject holding this element. Must be present
BrechtDeMan@753 609 var obj = [];
BrechtDeMan@753 610 $(this.trackSliderObjects).each(function(i,trackObj){
BrechtDeMan@753 611 var node = document.createElement('value');
BrechtDeMan@753 612 node.setAttribute("inteerface-name",trackObj.getAttribute("interface-name"));
BrechtDeMan@753 613 node.textContent = convSliderPosToRate(trackObj);
BrechtDeMan@753 614 obj.push(node);
BrechtDeMan@753 615 });
BrechtDeMan@753 616
BrechtDeMan@753 617 return obj;
BrechtDeMan@753 618 };
BrechtDeMan@753 619 this.getValue = function() {
BrechtDeMan@753 620 return convSliderPosToRate(this.trackSliderObj);
BrechtDeMan@753 621 };
BrechtDeMan@753 622 }
BrechtDeMan@753 623
BrechtDeMan@753 624 function buttonSubmitClick()
BrechtDeMan@753 625 {
BrechtDeMan@753 626 var checks = testState.currentStateMap[testState.currentIndex].interfaces[0].options;
BrechtDeMan@753 627 var canContinue = true;
BrechtDeMan@753 628
BrechtDeMan@753 629 // Check that the anchor and reference objects are correctly placed
BrechtDeMan@753 630 if (interfaceContext.checkHiddenAnchor() == false) {return;}
BrechtDeMan@753 631 if (interfaceContext.checkHiddenReference() == false) {return;}
BrechtDeMan@753 632
BrechtDeMan@753 633 for (var i=0; i<checks.length; i++) {
BrechtDeMan@753 634 if (checks[i].type == 'check')
BrechtDeMan@753 635 {
BrechtDeMan@753 636 switch(checks[i].check) {
BrechtDeMan@753 637 case 'fragmentPlayed':
BrechtDeMan@753 638 // Check if all fragments have been played
BrechtDeMan@753 639 var checkState = interfaceContext.checkAllPlayed();
BrechtDeMan@753 640 if (checkState == false) {canContinue = false;}
BrechtDeMan@753 641 break;
BrechtDeMan@753 642 case 'fragmentFullPlayback':
BrechtDeMan@753 643 // Check all fragments have been played to their full length
BrechtDeMan@753 644 var checkState = interfaceContext.checkFragmentsFullyPlayed();
BrechtDeMan@753 645 if (checkState == false) {canContinue = false;}
BrechtDeMan@753 646 break;
BrechtDeMan@753 647 case 'fragmentMoved':
BrechtDeMan@753 648 // Check all fragment sliders have been moved.
BrechtDeMan@753 649 var checkState = interfaceContext.checkAllMoved();
BrechtDeMan@753 650 if (checkState == false) {canContinue = false;}
BrechtDeMan@753 651 break;
BrechtDeMan@753 652 case 'fragmentComments':
BrechtDeMan@753 653 // Check all fragment sliders have been moved.
BrechtDeMan@753 654 var checkState = interfaceContext.checkAllCommented();
BrechtDeMan@753 655 if (checkState == false) {canContinue = false;}
BrechtDeMan@753 656 break;
BrechtDeMan@753 657 case 'scalerange':
BrechtDeMan@753 658 // Check the scale is used to its full width outlined by the node
BrechtDeMan@753 659 var checkState = interfaceContext.checkScaleRange();
BrechtDeMan@753 660 if (checkState == false) {canContinue = false;}
BrechtDeMan@753 661 break;
BrechtDeMan@753 662 default:
BrechtDeMan@753 663 console.log("WARNING - Check option "+checks[i].check+" is not supported on this interface");
BrechtDeMan@753 664 break;
BrechtDeMan@753 665 }
BrechtDeMan@753 666
BrechtDeMan@753 667 }
BrechtDeMan@753 668 if (!canContinue) {break;}
BrechtDeMan@753 669 }
BrechtDeMan@753 670
BrechtDeMan@753 671 if (canContinue) {
BrechtDeMan@753 672 if (audioEngineContext.status == 1) {
BrechtDeMan@753 673 var playback = document.getElementById('playback-button');
BrechtDeMan@753 674 playback.click();
BrechtDeMan@753 675 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options
BrechtDeMan@753 676 } else
BrechtDeMan@753 677 {
BrechtDeMan@753 678 if (audioEngineContext.timer.testStarted == false)
BrechtDeMan@753 679 {
BrechtDeMan@753 680 alert('You have not started the test! Please click a fragment to begin the test!');
BrechtDeMan@753 681 return;
BrechtDeMan@753 682 }
BrechtDeMan@753 683 }
BrechtDeMan@753 684 testState.advanceState();
BrechtDeMan@753 685 }
BrechtDeMan@753 686 }
BrechtDeMan@753 687
BrechtDeMan@753 688 function convSliderPosToRate(trackSlider)
BrechtDeMan@753 689 {
BrechtDeMan@753 690 var slider = trackSlider.parentElement;
BrechtDeMan@753 691 var w = slider.style.width;
BrechtDeMan@753 692 var marginsize = Number(slider.attributes['marginsize'].value);
BrechtDeMan@753 693 var maxPix = w.substr(0,w.length-2);
BrechtDeMan@753 694 var pix = trackSlider.style.left;
BrechtDeMan@753 695 pix = pix.substr(0,pix.length-2);
BrechtDeMan@753 696 var rate = (pix-marginsize)/maxPix;
BrechtDeMan@753 697 return rate;
BrechtDeMan@753 698 }
BrechtDeMan@753 699
BrechtDeMan@753 700 function resizeWindow(event){
BrechtDeMan@753 701 // Function called when the window has been resized.
BrechtDeMan@753 702 // MANDATORY FUNCTION
BrechtDeMan@753 703
BrechtDeMan@753 704 // Resize the slider objects
BrechtDeMan@753 705 for (var i=0; i<interfaceContext.interfaceSliders.length; i++)
BrechtDeMan@753 706 {
BrechtDeMan@753 707 interfaceContext.interfaceSliders[i].resize(event);
BrechtDeMan@753 708 }
BrechtDeMan@753 709 }
BrechtDeMan@753 710
BrechtDeMan@753 711 function pageXMLSave(store, testXML)
BrechtDeMan@753 712 {
BrechtDeMan@753 713 // MANDATORY
BrechtDeMan@753 714 // Saves a specific test page
BrechtDeMan@753 715 // You can use this space to add any extra nodes to your XML <audioHolder> saves
BrechtDeMan@753 716 // Get the current <audioHolder> information in store (remember to appendChild your data to it)
BrechtDeMan@753 717 if (interfaceContext.interfaceSliders.length == 1)
BrechtDeMan@753 718 {
BrechtDeMan@753 719 // If there is only one axis, there only needs to be one metric return
BrechtDeMan@753 720 return;
BrechtDeMan@753 721 }
BrechtDeMan@753 722 var audioelements = store.getElementsByTagName("audioelement");
BrechtDeMan@753 723 for (var i=0; i<audioelements.length; i++)
BrechtDeMan@753 724 {
BrechtDeMan@753 725 // Have to append the metric specific nodes
BrechtDeMan@753 726 if (testXML.outsideReference == null || testXML.outsideReference.id != audioelements[i].id)
BrechtDeMan@753 727 {
BrechtDeMan@753 728 var inject = audioelements[i].getElementsByTagName("metric");
BrechtDeMan@753 729 if (inject.length == 0)
BrechtDeMan@753 730 {
BrechtDeMan@753 731 inject = document.createElement("metric");
BrechtDeMan@753 732 } else {
BrechtDeMan@753 733 inject = inject[0];
BrechtDeMan@753 734 }
BrechtDeMan@753 735 for (var k=0; k<interfaceContext.interfaceSliders.length; k++)
BrechtDeMan@753 736 {
BrechtDeMan@753 737 var node = interfaceContext.interfaceSliders[k].metrics[i].exportXMLDOM();
BrechtDeMan@753 738 var mrnodes = node.getElementsByTagName("metricresult");
BrechtDeMan@753 739 for (var j=0; j<mrnodes.length; j++)
BrechtDeMan@753 740 {
BrechtDeMan@753 741 var name = mrnodes[j].getAttribute("name");
BrechtDeMan@753 742 if (name == "elementTracker" || name == "elementTrackerFull" || name == "elementInitialPosition" || name == "elementFlagMoved")
BrechtDeMan@753 743 {
BrechtDeMan@753 744 mrnodes[j].setAttribute("interface-name",interfaceContext.interfaceSliders[k].name);
BrechtDeMan@753 745 mrnodes[j].setAttribute("interface-id",k);
BrechtDeMan@753 746 inject.appendChild(mrnodes[j]);
BrechtDeMan@753 747 }
BrechtDeMan@753 748 }
BrechtDeMan@753 749 }
BrechtDeMan@753 750 }
BrechtDeMan@753 751 }
BrechtDeMan@753 752 }