annotate interfaces/ape.js @ 1316:279930a008ca

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