annotate interfaces/discrete.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 c0022a09c4f6
rev   line source
nickjillings@1316 1 // Once this is loaded and parsed, begin execution
nickjillings@1316 2 loadInterface();
nickjillings@1316 3
nickjillings@1316 4 function loadInterface() {
nickjillings@1316 5 // Use this to do any one-time page / element construction. For instance, placing any stationary text objects,
nickjillings@1316 6 // holding div's, or setting up any nodes which are present for the entire test sequence
nickjillings@1316 7
nickjillings@1316 8 // The injection point into the HTML page
nickjillings@1316 9 interfaceContext.insertPoint = document.getElementById("topLevelBody");
nickjillings@1316 10 var testContent = document.createElement('div');
nickjillings@1316 11 testContent.id = 'testContent';
nickjillings@1316 12
nickjillings@1316 13 // Create the top div for the Title element
nickjillings@1316 14 var titleAttr = specification.title;
nickjillings@1316 15 var title = document.createElement('div');
nickjillings@1316 16 title.className = "title";
nickjillings@1316 17 title.align = "center";
nickjillings@1316 18 var titleSpan = document.createElement('span');
nickjillings@1316 19
nickjillings@1316 20 // Set title to that defined in XML, else set to default
nickjillings@1316 21 if (titleAttr != undefined) {
nickjillings@1316 22 titleSpan.textContent = titleAttr;
nickjillings@1316 23 } else {
nickjillings@1316 24 titleSpan.textContent = 'Listening test';
nickjillings@1316 25 }
nickjillings@1316 26 // Insert the titleSpan element into the title div element.
nickjillings@1316 27 title.appendChild(titleSpan);
nickjillings@1316 28
nickjillings@1316 29 var pagetitle = document.createElement('div');
nickjillings@1316 30 pagetitle.className = "pageTitle";
nickjillings@1316 31 pagetitle.align = "center";
nickjillings@1316 32 var titleSpan = document.createElement('span');
nickjillings@1316 33 titleSpan.id = "pageTitle";
nickjillings@1316 34 pagetitle.appendChild(titleSpan);
nickjillings@1316 35
nickjillings@1316 36 // Create Interface buttons!
nickjillings@1316 37 var interfaceButtons = document.createElement('div');
nickjillings@1316 38 interfaceButtons.id = 'interface-buttons';
nickjillings@1316 39 interfaceButtons.style.height = '25px';
nickjillings@1316 40
nickjillings@1316 41 // Create playback start/stop points
nickjillings@1316 42 var playback = document.createElement("button");
nickjillings@1316 43 playback.innerHTML = 'Stop';
nickjillings@1316 44 playback.id = 'playback-button';
nickjillings@1316 45 playback.style.float = 'left';
nickjillings@1316 46 // onclick function. Check if it is playing or not, call the correct function in the
nickjillings@1316 47 // audioEngine, change the button text to reflect the next state.
nickjillings@1316 48 playback.onclick = function() {
nickjillings@1316 49 if (audioEngineContext.status == 1) {
nickjillings@1316 50 audioEngineContext.stop();
nickjillings@1316 51 this.innerHTML = 'Stop';
nickjillings@1316 52 var time = audioEngineContext.timer.getTestTime();
nickjillings@1316 53 console.log('Stopped at ' + time); // DEBUG/SAFETY
nickjillings@1316 54 }
nickjillings@1316 55 };
nickjillings@1316 56 // Create Submit (save) button
nickjillings@1316 57 var submit = document.createElement("button");
nickjillings@1316 58 submit.innerHTML = 'Submit';
nickjillings@1316 59 submit.onclick = buttonSubmitClick;
nickjillings@1316 60 submit.id = 'submit-button';
nickjillings@1316 61 submit.style.float = 'left';
nickjillings@1316 62 // Append the interface buttons into the interfaceButtons object.
nickjillings@1316 63 interfaceButtons.appendChild(playback);
nickjillings@1316 64 interfaceButtons.appendChild(submit);
nickjillings@1316 65
nickjillings@1316 66 // Create a slider box
nickjillings@1316 67 var sliderBox = document.createElement('div');
nickjillings@1316 68 sliderBox.style.width = "100%";
nickjillings@1316 69 sliderBox.style.height = window.innerHeight - 200+12 + 'px';
nickjillings@1316 70 sliderBox.style.marginBottom = '10px';
nickjillings@1316 71 sliderBox.id = 'slider';
nickjillings@1316 72 var scaleHolder = document.createElement('div');
nickjillings@1316 73 scaleHolder.id = "scale-holder";
nickjillings@1316 74 scaleHolder.style.marginLeft = "107px";
nickjillings@1316 75 sliderBox.appendChild(scaleHolder);
nickjillings@1316 76 var scaleText = document.createElement('div');
nickjillings@1316 77 scaleText.id = "scale-text-holder";
nickjillings@1316 78 scaleText.style.height = "25px";
nickjillings@1316 79 scaleText.style.width = "100%";
nickjillings@1316 80 scaleHolder.appendChild(scaleText);
nickjillings@1316 81 var scaleCanvas = document.createElement('canvas');
nickjillings@1316 82 scaleCanvas.id = "scale-canvas";
nickjillings@1316 83 scaleCanvas.style.marginLeft = "150px";
nickjillings@1316 84 scaleHolder.appendChild(scaleCanvas);
nickjillings@1316 85 var sliderObjectHolder = document.createElement('div');
nickjillings@1316 86 sliderObjectHolder.id = 'slider-holder';
nickjillings@1316 87 sliderObjectHolder.align = "center";
nickjillings@1316 88 sliderBox.appendChild(sliderObjectHolder);
nickjillings@1316 89
nickjillings@1316 90 // Global parent for the comment boxes on the page
nickjillings@1316 91 var feedbackHolder = document.createElement('div');
nickjillings@1316 92 feedbackHolder.id = 'feedbackHolder';
nickjillings@1316 93
nickjillings@1316 94 testContent.style.zIndex = 1;
nickjillings@1316 95 interfaceContext.insertPoint.innerHTML = null; // Clear the current schema
nickjillings@1316 96
nickjillings@1316 97 // Inject into HTML
nickjillings@1316 98 testContent.appendChild(title); // Insert the title
nickjillings@1316 99 testContent.appendChild(pagetitle);
nickjillings@1316 100 testContent.appendChild(interfaceButtons);
nickjillings@1316 101 testContent.appendChild(sliderBox);
nickjillings@1316 102 testContent.appendChild(feedbackHolder);
nickjillings@1316 103 interfaceContext.insertPoint.appendChild(testContent);
nickjillings@1316 104
nickjillings@1316 105 // Load the full interface
nickjillings@1316 106 testState.initialise();
nickjillings@1316 107 testState.advanceState();
nickjillings@1316 108 };
nickjillings@1316 109
nickjillings@1316 110 function loadTest(page)
nickjillings@1316 111 {
nickjillings@1316 112 // Called each time a new test page is to be build. The page specification node is the only item passed in
nickjillings@1316 113 var id = page.id;
nickjillings@1316 114
nickjillings@1316 115 var feedbackHolder = document.getElementById('feedbackHolder');
nickjillings@1316 116 feedbackHolder.innerHTML = null;
nickjillings@1316 117 var interfaceObj = page.interfaces;
nickjillings@1316 118 if (interfaceObj.length > 1)
nickjillings@1316 119 {
nickjillings@1316 120 console.log("WARNING - This interface only supports one <interface> node per page. Using first interface node");
nickjillings@1316 121 }
nickjillings@1316 122 interfaceObj = interfaceObj[0];
nickjillings@1316 123 if(interfaceObj.title != null)
nickjillings@1316 124 {
nickjillings@1316 125 document.getElementById("pageTitle").textContent = interfaceObj.title;
nickjillings@1316 126 }
nickjillings@1316 127
nickjillings@1316 128 var interfaceOptions = specification.interfaces.options.concat(interfaceObj.options);
nickjillings@1316 129 for (var option of interfaceOptions)
nickjillings@1316 130 {
nickjillings@1316 131 if (option.type == "show")
nickjillings@1316 132 {
nickjillings@1316 133 switch(option.name) {
nickjillings@1316 134 case "playhead":
nickjillings@1316 135 var playbackHolder = document.getElementById('playback-holder');
nickjillings@1316 136 if (playbackHolder == null)
nickjillings@1316 137 {
nickjillings@1316 138 playbackHolder = document.createElement('div');
nickjillings@1316 139 playbackHolder.style.width = "100%";
nickjillings@1316 140 playbackHolder.align = 'center';
nickjillings@1316 141 playbackHolder.appendChild(interfaceContext.playhead.object);
nickjillings@1316 142 feedbackHolder.appendChild(playbackHolder);
nickjillings@1316 143 }
nickjillings@1316 144 break;
nickjillings@1316 145 case "page-count":
nickjillings@1316 146 var pagecountHolder = document.getElementById('page-count');
nickjillings@1316 147 if (pagecountHolder == null)
nickjillings@1316 148 {
nickjillings@1316 149 pagecountHolder = document.createElement('div');
nickjillings@1316 150 pagecountHolder.id = 'page-count';
nickjillings@1316 151 }
nickjillings@1316 152 pagecountHolder.innerHTML = '<span>Page '+(page.presentedId+1)+' of '+specification.pages.length+'</span>';
nickjillings@1316 153 var inject = document.getElementById('interface-buttons');
nickjillings@1316 154 inject.appendChild(pagecountHolder);
nickjillings@1316 155 break;
nickjillings@1316 156 case "volume":
nickjillings@1316 157 if (document.getElementById('master-volume-holder') == null)
nickjillings@1316 158 {
nickjillings@1316 159 feedbackHolder.appendChild(interfaceContext.volume.object);
nickjillings@1316 160 }
nickjillings@1316 161 break;
nickjillings@1316 162 }
nickjillings@1316 163 }
nickjillings@1316 164 }
nickjillings@1316 165
nickjillings@1316 166 // Delete outside reference
nickjillings@1316 167 var outsideReferenceHolder = document.getElementById('outside-reference');
nickjillings@1316 168 if (outsideReferenceHolder != null) {
nickjillings@1316 169 document.getElementById('interface-buttons').removeChild(outsideReferenceHolder);
nickjillings@1316 170 }
nickjillings@1316 171
nickjillings@1316 172 var sliderBox = document.getElementById('slider-holder');
nickjillings@1316 173 sliderBox.innerHTML = null;
nickjillings@1316 174
nickjillings@1316 175 var commentBoxPrefix = "Comment on track";
nickjillings@1316 176 if (interfaceObj.commentBoxPrefix != undefined) {
nickjillings@1316 177 commentBoxPrefix = interfaceObj.commentBoxPrefix;
nickjillings@1316 178 }
nickjillings@1316 179 var loopPlayback = page.loop;
nickjillings@1316 180
nickjillings@1316 181 $(page.commentQuestions).each(function(index,element) {
nickjillings@1316 182 var node = interfaceContext.createCommentQuestion(element);
nickjillings@1316 183 feedbackHolder.appendChild(node.holder);
nickjillings@1316 184 });
nickjillings@1316 185
nickjillings@1316 186 // Find all the audioElements from the audioHolder
nickjillings@1316 187 var label = 0;
nickjillings@1316 188 var interfaceScales = testState.currentStateMap.interfaces[0].scales;
nickjillings@1316 189 $(page.audioElements).each(function(index,element){
nickjillings@1316 190 // Find URL of track
nickjillings@1316 191 // In this jQuery loop, variable 'this' holds the current audioElement.
nickjillings@1316 192
nickjillings@1316 193 var audioObject = audioEngineContext.newTrack(element);
nickjillings@1316 194 if (element.type == 'outside-reference')
nickjillings@1316 195 {
nickjillings@1316 196 // Construct outside reference;
nickjillings@1316 197 var orNode = new outsideReferenceDOM(audioObject,index,document.getElementById('interface-buttons'));
nickjillings@1316 198 audioObject.bindInterface(orNode);
nickjillings@1316 199 } else {
nickjillings@1316 200 // Create a slider per track
nickjillings@1316 201 var sliderObj = new discreteObject(audioObject,label,interfaceScales);
nickjillings@1316 202 sliderBox.appendChild(sliderObj.holder);
nickjillings@1316 203 audioObject.bindInterface(sliderObj);
nickjillings@1316 204 interfaceContext.createCommentBox(audioObject);
nickjillings@1316 205 label += 1;
nickjillings@1316 206 }
nickjillings@1316 207
nickjillings@1316 208 });
nickjillings@1316 209
nickjillings@1316 210 if (page.showElementComments)
nickjillings@1316 211 {
nickjillings@1316 212 interfaceContext.showCommentBoxes(feedbackHolder,true);
nickjillings@1316 213 }
nickjillings@1316 214
nickjillings@1316 215 // Auto-align
nickjillings@1316 216 resizeWindow(null);
nickjillings@1316 217 }
nickjillings@1316 218
nickjillings@1316 219 function discreteObject(audioObject,label,interfaceScales)
nickjillings@1316 220 {
nickjillings@1316 221 // An example node, you can make this however you want for each audioElement.
nickjillings@1316 222 // However, every audioObject (audioEngineContext.audioObject) MUST have an interface object with the following
nickjillings@1316 223 // You attach them by calling audioObject.bindInterface( )
nickjillings@1316 224 if (interfaceScales == null || interfaceScales.length == 0)
nickjillings@1316 225 {
nickjillings@1316 226 console.log("WARNING: The discrete radio's are built depending on the number of scale points specified! Ensure you have some specified. Defaulting to 5 for now!");
nickjillings@1316 227 numOptions = 5;
nickjillings@1316 228 }
nickjillings@1316 229 this.parent = audioObject;
nickjillings@1316 230
nickjillings@1316 231 this.holder = document.createElement('div');
nickjillings@1316 232 this.title = document.createElement('div');
nickjillings@1316 233 this.discreteHolder = document.createElement('div');
nickjillings@1316 234 this.discretes = [];
nickjillings@1316 235 this.play = document.createElement('button');
nickjillings@1316 236
nickjillings@1316 237 this.holder.className = 'track-slider';
nickjillings@1316 238 this.holder.style.width = window.innerWidth-200 + 'px';
nickjillings@1316 239 this.holder.appendChild(this.title);
nickjillings@1316 240 this.holder.appendChild(this.discreteHolder);
nickjillings@1316 241 this.holder.appendChild(this.play);
nickjillings@1316 242 this.holder.setAttribute('trackIndex',audioObject.id);
nickjillings@1316 243 this.title.textContent = label;
nickjillings@1316 244 this.title.className = 'track-slider-title';
nickjillings@1316 245
nickjillings@1316 246 this.discreteHolder.className = "track-slider-range";
nickjillings@1316 247 this.discreteHolder.style.width = window.innerWidth-500 + 'px';
nickjillings@1316 248 for (var i=0; i<interfaceScales.length; i++)
nickjillings@1316 249 {
nickjillings@1316 250 var node = document.createElement('input');
nickjillings@1316 251 node.setAttribute('type','radio');
nickjillings@1316 252 node.className = 'track-radio';
nickjillings@1316 253 node.disabled = true;
nickjillings@1316 254 node.setAttribute('position',interfaceScales[i].position);
nickjillings@1316 255 node.setAttribute('name',audioObject.specification.id);
nickjillings@1316 256 node.setAttribute('id',audioObject.specification.id+'-'+String(i));
nickjillings@1316 257 this.discretes.push(node);
nickjillings@1316 258 this.discreteHolder.appendChild(node);
nickjillings@1316 259 node.onclick = function(event)
nickjillings@1316 260 {
nickjillings@1316 261 if (audioEngineContext.status == 0)
nickjillings@1316 262 {
nickjillings@1316 263 event.currentTarget.checked = false;
nickjillings@1316 264 return;
nickjillings@1316 265 }
nickjillings@1316 266 var time = audioEngineContext.timer.getTestTime();
nickjillings@1316 267 var id = Number(event.currentTarget.parentNode.parentNode.getAttribute('trackIndex'));
nickjillings@1316 268 var value = event.currentTarget.getAttribute('position') / 100.0;
nickjillings@1316 269 audioEngineContext.audioObjects[id].metric.moved(time,value);
nickjillings@1316 270 console.log('slider '+id+' moved to '+value+' ('+time+')');
nickjillings@1316 271 };
nickjillings@1316 272 }
nickjillings@1316 273
nickjillings@1316 274 this.play.className = 'track-slider-button';
nickjillings@1316 275 this.play.textContent = "Loading...";
nickjillings@1316 276 this.play.value = audioObject.id;
nickjillings@1316 277 this.play.disabled = true;
nickjillings@1316 278 this.play.onclick = function(event)
nickjillings@1316 279 {
nickjillings@1316 280 var id = Number(event.currentTarget.value);
nickjillings@1316 281 //audioEngineContext.metric.sliderPlayed(id);
nickjillings@1316 282 audioEngineContext.play(id);
nickjillings@1316 283 };
nickjillings@1316 284 this.resize = function(event)
nickjillings@1316 285 {
nickjillings@1316 286 this.holder.style.width = window.innerWidth-200 + 'px';
nickjillings@1316 287 this.discreteHolder.style.width = window.innerWidth-500 + 'px';
nickjillings@1316 288 //text.style.left = (posPix+150-($(text).width()/2)) +'px';
nickjillings@1316 289 for (var i=0; i<this.discretes.length; i++)
nickjillings@1316 290 {
nickjillings@1316 291 var width = $(this.discreteHolder).width() - 20;
nickjillings@1316 292 var node = this.discretes[i];
nickjillings@1316 293 var nodeW = $(node).width();
nickjillings@1316 294 var position = node.getAttribute('position');
nickjillings@1316 295 var posPix = Math.round(width * (position / 100.0));
nickjillings@1316 296 node.style.left = (posPix+10 - (nodeW/2)) + 'px';
nickjillings@1316 297 }
nickjillings@1316 298 };
nickjillings@1316 299 this.enable = function()
nickjillings@1316 300 {
nickjillings@1316 301 // This is used to tell the interface object that playback of this node is ready
nickjillings@1316 302 this.play.disabled = false;
nickjillings@1316 303 this.play.textContent = "Play";
nickjillings@1316 304 $(this.slider).removeClass('track-slider-disabled');
nickjillings@1316 305 for (var radio of this.discretes)
nickjillings@1316 306 {
nickjillings@1316 307 radio.disabled = false;
nickjillings@1316 308 }
nickjillings@1316 309 };
nickjillings@1316 310 this.updateLoading = function(progress)
nickjillings@1316 311 {
nickjillings@1316 312 // progress is a value from 0 to 100 indicating the current download state of media files
nickjillings@1316 313 if (progress != 100)
nickjillings@1316 314 {
nickjillings@1316 315 progress = String(progress);
nickjillings@1316 316 progress = progress.split('.')[0];
nickjillings@1316 317 this.play.textContent = progress+'%';
nickjillings@1316 318 } else {
nickjillings@1316 319 this.play.textContent = "Play";
nickjillings@1316 320 }
nickjillings@1316 321 };
nickjillings@1316 322
nickjillings@1316 323 this.startPlayback = function()
nickjillings@1316 324 {
nickjillings@1316 325 // Called by audioObject when playback begins
nickjillings@1316 326 $(".track-slider").removeClass('track-slider-playing');
nickjillings@1316 327 $(this.holder).addClass('track-slider-playing');
nickjillings@1316 328 var outsideReference = document.getElementById('outside-reference');
nickjillings@1316 329 this.play.textContent = "Listening";
nickjillings@1316 330 if (outsideReference != null) {
nickjillings@1316 331 $(outsideReference).removeClass('track-slider-playing');
nickjillings@1316 332 }
nickjillings@1316 333 }
nickjillings@1316 334 this.stopPlayback = function()
nickjillings@1316 335 {
nickjillings@1316 336 // Called by audioObject when playback stops
nickjillings@1316 337 $(this.holder).removeClass('track-slider-playing');
nickjillings@1316 338 this.play.textContent = "Play";
nickjillings@1316 339 }
nickjillings@1316 340
nickjillings@1316 341 this.getValue = function()
nickjillings@1316 342 {
nickjillings@1316 343 // Return the current value of the object. If there is no value, return -1
nickjillings@1316 344 var value = -1;
nickjillings@1316 345 for (var i=0; i<this.discretes.length; i++)
nickjillings@1316 346 {
nickjillings@1316 347 if (this.discretes[i].checked == true)
nickjillings@1316 348 {
nickjillings@1316 349 value = this.discretes[i].getAttribute('position') / 100.0;
nickjillings@1316 350 break;
nickjillings@1316 351 }
nickjillings@1316 352 }
nickjillings@1316 353 return value;
nickjillings@1316 354 };
nickjillings@1316 355 this.getPresentedId = function()
nickjillings@1316 356 {
nickjillings@1316 357 // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale
nickjillings@1316 358 return this.title.textContent;
nickjillings@1316 359 };
nickjillings@1316 360 this.canMove = function()
nickjillings@1316 361 {
nickjillings@1316 362 // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale.
nickjillings@1316 363 // These are checked primarily if the interface check option 'fragmentMoved' is enabled.
nickjillings@1316 364 return true;
nickjillings@1316 365 };
nickjillings@1316 366 this.exportXMLDOM = function(audioObject) {
nickjillings@1316 367 // Called by the audioObject holding this element to export the interface <value> node.
nickjillings@1316 368 // If there is no value node (such as outside reference), return null
nickjillings@1316 369 // If there are multiple value nodes (such as multiple scale / 2D scales), return an array of nodes with each value node having an 'interfaceName' attribute
nickjillings@1316 370 // Use storage.document.createElement('value'); to generate the XML node.
nickjillings@1316 371 var node = storage.document.createElement('value');
nickjillings@1316 372 node.textContent = this.getValue();
nickjillings@1316 373 return node;
nickjillings@1316 374 };
nickjillings@1316 375 };
nickjillings@1316 376
nickjillings@1316 377 function resizeWindow(event)
nickjillings@1316 378 {
nickjillings@1316 379 // Called on every window resize event, use this to scale your page properly
nickjillings@1316 380 var numObj = document.getElementsByClassName('track-slider').length;
nickjillings@1316 381 var totalHeight = (numObj * 66)-30;
nickjillings@1316 382 document.getElementById('scale-holder').style.width = window.innerWidth-220 + 'px';
nickjillings@1316 383 var canvas = document.getElementById('scale-canvas');
nickjillings@1316 384 canvas.width = window.innerWidth-520;
nickjillings@1316 385 canvas.height = totalHeight;
nickjillings@1316 386 for (var i in audioEngineContext.audioObjects)
nickjillings@1316 387 {
nickjillings@1316 388 if (audioEngineContext.audioObjects[i].specification.type != 'outside-reference'){
nickjillings@1316 389 audioEngineContext.audioObjects[i].interfaceDOM.resize(event);
nickjillings@1316 390 }
nickjillings@1316 391 }
nickjillings@1316 392 document.getElementById('slider-holder').style.height = totalHeight + 'px';
nickjillings@1316 393 document.getElementById('slider').style.height = totalHeight + 70 + 'px';
nickjillings@1316 394 drawScale();
nickjillings@1316 395 }
nickjillings@1316 396
nickjillings@1316 397 function drawScale()
nickjillings@1316 398 {
nickjillings@1316 399 var interfaceObj = testState.currentStateMap.interfaces[0];
nickjillings@1316 400 var scales = testState.currentStateMap.interfaces[0].scales;
nickjillings@1316 401 scales = scales.sort(function(a,b) {
nickjillings@1316 402 return a.position - b.position;
nickjillings@1316 403 });
nickjillings@1316 404 var canvas = document.getElementById('scale-canvas');
nickjillings@1316 405 var ctx = canvas.getContext("2d");
nickjillings@1316 406 var height = canvas.height;
nickjillings@1316 407 var width = canvas.width;
nickjillings@1316 408 var textHolder = document.getElementById('scale-text-holder');
nickjillings@1316 409 textHolder.innerHTML = null;
nickjillings@1316 410 ctx.fillStyle = "#000000";
nickjillings@1316 411 ctx.setLineDash([1,4]);
nickjillings@1316 412 for (var scale of scales)
nickjillings@1316 413 {
nickjillings@1316 414 var posPercent = scale.position / 100.0;
nickjillings@1316 415 var posPix = Math.round(width * posPercent);
nickjillings@1316 416 if(posPix<=0){posPix=1;}
nickjillings@1316 417 if(posPix>=width){posPix=width-1;}
nickjillings@1316 418 ctx.moveTo(posPix,0);
nickjillings@1316 419 ctx.lineTo(posPix,height);
nickjillings@1316 420 ctx.stroke();
nickjillings@1316 421
nickjillings@1316 422 var text = document.createElement('div');
nickjillings@1316 423 text.align = "center";
nickjillings@1316 424 var textC = document.createElement('span');
nickjillings@1316 425 textC.textContent = scale.text;
nickjillings@1316 426 text.appendChild(textC);
nickjillings@1316 427 text.className = "scale-text";
nickjillings@1316 428 textHolder.appendChild(text);
nickjillings@1316 429 text.style.width = $(text.children[0]).width()+'px';
nickjillings@1316 430 text.style.left = (posPix+150-($(text).width()/2)) +'px';
nickjillings@1316 431 }
nickjillings@1316 432 }
nickjillings@1316 433
nickjillings@1316 434 function buttonSubmitClick() // TODO: Only when all songs have been played!
nickjillings@1316 435 {
nickjillings@1316 436 var checks = [];
nickjillings@1316 437 checks = checks.concat(testState.currentStateMap.interfaces[0].options);
nickjillings@1316 438 checks = checks.concat(specification.interfaces.options);
nickjillings@1316 439 var canContinue = true;
nickjillings@1316 440
nickjillings@1316 441 // Check that the anchor and reference objects are correctly placed
nickjillings@1316 442 if (interfaceContext.checkHiddenAnchor() == false) {return;}
nickjillings@1316 443 if (interfaceContext.checkHiddenReference() == false) {return;}
nickjillings@1316 444
nickjillings@1316 445 for (var i=0; i<checks.length; i++) {
nickjillings@1316 446 if (checks[i].type == 'check')
nickjillings@1316 447 {
nickjillings@1316 448 switch(checks[i].name) {
nickjillings@1316 449 case 'fragmentPlayed':
nickjillings@1316 450 // Check if all fragments have been played
nickjillings@1316 451 var checkState = interfaceContext.checkAllPlayed();
nickjillings@1316 452 if (checkState == false) {canContinue = false;}
nickjillings@1316 453 break;
nickjillings@1316 454 case 'fragmentFullPlayback':
nickjillings@1316 455 // Check all fragments have been played to their full length
nickjillings@1316 456 var checkState = interfaceContext.checkAllPlayed();
nickjillings@1316 457 if (checkState == false) {canContinue = false;}
nickjillings@1316 458 console.log('NOTE: fragmentFullPlayback not currently implemented, performing check fragmentPlayed instead');
nickjillings@1316 459 break;
nickjillings@1316 460 case 'fragmentMoved':
nickjillings@1316 461 // Check all fragment sliders have been moved.
nickjillings@1316 462 var checkState = interfaceContext.checkAllMoved();
nickjillings@1316 463 if (checkState == false) {canContinue = false;}
nickjillings@1316 464 break;
nickjillings@1316 465 case 'fragmentComments':
nickjillings@1316 466 // Check all fragment sliders have been moved.
nickjillings@1316 467 var checkState = interfaceContext.checkAllCommented();
nickjillings@1316 468 if (checkState == false) {canContinue = false;}
nickjillings@1316 469 break;
nickjillings@1316 470 //case 'scalerange':
nickjillings@1316 471 // Check the scale is used to its full width outlined by the node
nickjillings@1316 472 //var checkState = interfaceContext.checkScaleRange();
nickjillings@1316 473 //if (checkState == false) {canContinue = false;}
nickjillings@1316 474 // break;
nickjillings@1316 475 default:
nickjillings@1316 476 console.log("WARNING - Check option "+checks[i].check+" is not supported on this interface");
nickjillings@1316 477 break;
nickjillings@1316 478 }
nickjillings@1316 479
nickjillings@1316 480 }
nickjillings@1316 481 if (!canContinue) {break;}
nickjillings@1316 482 }
nickjillings@1316 483
nickjillings@1316 484 if (canContinue) {
nickjillings@1316 485 if (audioEngineContext.status == 1) {
nickjillings@1316 486 var playback = document.getElementById('playback-button');
nickjillings@1316 487 playback.click();
nickjillings@1316 488 // 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 489 } else
nickjillings@1316 490 {
nickjillings@1316 491 if (audioEngineContext.timer.testStarted == false)
nickjillings@1316 492 {
nickjillings@1316 493 alert('You have not started the test! Please press start to begin the test!');
nickjillings@1316 494 return;
nickjillings@1316 495 }
nickjillings@1316 496 }
nickjillings@1316 497 testState.advanceState();
nickjillings@1316 498 }
nickjillings@1316 499 }
nickjillings@1316 500
nickjillings@1316 501 function pageXMLSave(store, pageSpecification)
nickjillings@1316 502 {
nickjillings@1316 503 // MANDATORY
nickjillings@1316 504 // Saves a specific test page
nickjillings@1316 505 // You can use this space to add any extra nodes to your XML <audioHolder> saves
nickjillings@1316 506 // Get the current <page> information in store (remember to appendChild your data to it)
nickjillings@1316 507 // pageSpecification is the current page node configuration
nickjillings@1316 508 // To create new XML nodes, use storage.document.createElement();
nickjillings@1316 509 }