comparison interfaces/discrete.js @ 3045:f888168418ad

#126 Complete redesign of discrete interface
author Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk>
date Wed, 27 Sep 2017 13:17:11 +0100
parents 5b652438802c
children 20de79c56ad7
comparison
equal deleted inserted replaced
3044:2020be3c592c 3045:f888168418ad
1 /* globals interfaceContext, document, window, $, specification, audioEngineContext, console, window, testState, storage */ 1 /**
2 * WAET Blank Template
3 * Use this to start building your custom interface
4 */
5
2 // Once this is loaded and parsed, begin execution 6 // Once this is loaded and parsed, begin execution
3 loadInterface(); 7 loadInterface();
4 8
5 function loadInterface() { 9 function loadInterface() {
6 // Use this to do any one-time page / element construction. For instance, placing any stationary text objects, 10 // Use this to do any one-time page / element construction. For instance, placing any stationary text objects,
54 this.innerHTML = 'Stop'; 58 this.innerHTML = 'Stop';
55 var time = audioEngineContext.timer.getTestTime(); 59 var time = audioEngineContext.timer.getTestTime();
56 console.log('Stopped at ' + time); // DEBUG/SAFETY 60 console.log('Stopped at ' + time); // DEBUG/SAFETY
57 } 61 }
58 }; 62 };
59
60 // Create outside reference holder
61 var outsideRef = document.createElement("div");
62 outsideRef.id = "outside-reference-holder";
63
64 // Create Submit (save) button 63 // Create Submit (save) button
65 var submit = document.createElement("button"); 64 var submit = document.createElement("button");
66 submit.innerHTML = 'Next'; 65 submit.innerHTML = 'Next';
67 submit.onclick = buttonSubmitClick; 66 submit.onclick = buttonSubmitClick;
68 submit.id = 'submit-button'; 67 submit.id = 'submit-button';
79 // Append the interface buttons into the interfaceButtons object. 78 // Append the interface buttons into the interfaceButtons object.
80 interfaceButtons.appendChild(playback); 79 interfaceButtons.appendChild(playback);
81 interfaceButtons.appendChild(submit); 80 interfaceButtons.appendChild(submit);
82 interfaceButtons.appendChild(sort); 81 interfaceButtons.appendChild(sort);
83 82
84 // Create a slider box 83
85 var sliderBox = document.createElement('div'); 84 // Create outside reference holder
86 sliderBox.style.width = "100%"; 85 var outsideRef = document.createElement("div");
87 sliderBox.style.height = window.innerHeight - 200 + 12 + 'px'; 86 outsideRef.id = "outside-reference-holder";
88 sliderBox.style.marginBottom = '10px'; 87
89 sliderBox.id = 'slider'; 88 // Create a holder for the slider rows
90 var scaleHolder = document.createElement('div'); 89 var sliderBox = document.createElement("div");
91 scaleHolder.id = "scale-holder"; 90 sliderBox.id = 'slider-box';
92 scaleHolder.style.marginLeft = "107px"; 91 var sliderGrid = document.createElement("div");
93 sliderBox.appendChild(scaleHolder); 92 sliderGrid.id = "slider-grid";
93 sliderBox.appendChild(sliderGrid);
94 var scaleText = document.createElement('div'); 94 var scaleText = document.createElement('div');
95 scaleText.id = "scale-text-holder"; 95 scaleText.id = "scale-text-holder";
96 scaleText.style.height = "25px"; 96 sliderGrid.appendChild(scaleText);
97 scaleText.style.width = "100%"; 97
98 scaleHolder.appendChild(scaleText);
99 var scaleCanvas = document.createElement('canvas');
100 scaleCanvas.id = "scale-canvas";
101 scaleCanvas.style.marginLeft = "150px";
102 scaleHolder.appendChild(scaleCanvas);
103 var sliderObjectHolder = document.createElement('div');
104 sliderObjectHolder.id = 'slider-holder';
105 sliderObjectHolder.align = "center";
106 sliderBox.appendChild(sliderObjectHolder);
107 98
108 // Global parent for the comment boxes on the page 99 // Global parent for the comment boxes on the page
109 var feedbackHolder = document.createElement('div'); 100 var feedbackHolder = document.createElement('div');
110 feedbackHolder.id = 'feedbackHolder'; 101 feedbackHolder.id = 'feedbackHolder';
111 102
122 interfaceContext.insertPoint.appendChild(testContent); 113 interfaceContext.insertPoint.appendChild(testContent);
123 114
124 // Load the full interface 115 // Load the full interface
125 testState.initialise(); 116 testState.initialise();
126 testState.advanceState(); 117 testState.advanceState();
127 } 118 };
128 119
129 function loadTest(page) { 120 function loadTest(page) {
130 // Called each time a new test page is to be build. The page specification node is the only item passed in 121 // Called each time a new test page is to be build. The page specification node is the only item passed in
131 var id = page.id;
132 122
133 var feedbackHolder = document.getElementById('feedbackHolder'); 123 var feedbackHolder = document.getElementById('feedbackHolder');
124 var sliderBox = document.getElementById('slider-box');
125 var sliderGrid = document.getElementById("slider-grid");
126 var scaleTextHolder = document.getElementById("scale-text-holder");
127 var interfaceObj = interfaceContext.getCombinedInterfaces(page);
128 var commentBoxPrefix = "Comment on track";
129 var loopPlayback = page.loop;
134 feedbackHolder.innerHTML = ""; 130 feedbackHolder.innerHTML = "";
135 var interfaceObj = interfaceContext.getCombinedInterfaces(page); 131
136 if (interfaceObj.length > 1) { 132 if (interfaceObj.length > 1) {
137 console.log("WARNING - This interface only supports one <interface> node per page. Using first interface node"); 133 console.log("WARNING - This interface only supports one <interface> node per page. Using first interface node");
138 } 134 }
139 interfaceObj = interfaceObj[0]; 135 interfaceObj = interfaceObj[0];
140 136
141 // Set the page title 137 // Set the page title
142 if (typeof page.title == "string" && page.title.length > 0) { 138 if (typeof page.title == "string" && page.title.length > 0) {
143 document.getElementById("test-title").textContent = page.title; 139 document.getElementById("test-title").textContent = page.title;
144 } 140 }
145 141 // Set the axis title
146 if (interfaceObj.title !== null) { 142 if (interfaceObj.title !== null) {
147 document.getElementById("pageTitle").textContent = interfaceObj.title; 143 document.getElementById("pageTitle").textContent = interfaceObj.title;
148 } 144 }
149 145
150 if (interfaceObj.image !== undefined || page.audioElements.some(function (elem) { 146 if (interfaceObj.image !== undefined || page.audioElements.some(function (elem) {
155 } 151 }
156 152
157 // Delete outside reference 153 // Delete outside reference
158 document.getElementById("outside-reference-holder").innerHTML = ""; 154 document.getElementById("outside-reference-holder").innerHTML = "";
159 155
160 var sliderBox = document.getElementById('slider-holder'); 156 // Get the comment box prefix
161 sliderBox.innerHTML = "";
162
163 var commentBoxPrefix = "Comment on track";
164 if (interfaceObj.commentBoxPrefix !== undefined) { 157 if (interfaceObj.commentBoxPrefix !== undefined) {
165 commentBoxPrefix = interfaceObj.commentBoxPrefix; 158 commentBoxPrefix = interfaceObj.commentBoxPrefix;
166 } 159 }
167 var loopPlayback = page.loop; 160
168 161 // Populate the comment questions
162 $(page.commentQuestions).each(function (index, element) {
163 var node = interfaceContext.createCommentQuestion(element);
164 feedbackHolder.appendChild(node.holder);
165 });
166
167 // Configure the grid
168 var numRows = page.audioElements.filter(function (a) {
169 return (a.type !== "outside-reference");
170 }).length;
171 var numColumns = page.interfaces[0].scales.length;
172 sliderGrid.style.gridTemplateRows = "50px repeat(" + numRows + ", 72px)";
173 scaleTextHolder.style.gridTemplateColumns = "100px repeat(" + numColumns + ", 1fr) 100px";
174 page.interfaces[0].scales.sort(function (a, b) {
175 if (a.position > b.position) {
176 return 1;
177 } else if (a.position < b.position) {
178 return -1;
179 }
180 return 0;
181 }).forEach(function (a, i) {
182 var h = document.createElement("div");
183 var text = document.createElement("span");
184 h.className = "scale-text";
185 h.style.gridColumn = String(i + 2) + "/" + String(i + 3);
186 text.textContent = a.text;
187 h.appendChild(text);
188 scaleTextHolder.appendChild(h);
189 })
190
191 // Find all the audioElements from the audioHolder
192 var index = 0;
193 var labelType = page.label;
194 if (labelType == "default") {
195 labelType = "number";
196 }
197 $(page.audioElements).each(function (pageIndex, element) {
198 // Find URL of track
199 // In this jQuery loop, variable 'this' holds the current audioElement.
200
201 var audioObject = audioEngineContext.newTrack(element);
202 if (element.type == 'outside-reference') {
203 // Construct outside reference;
204 var orNode = new interfaceContext.outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder"));
205 audioObject.bindInterface(orNode);
206 } else {
207 // Create a slider per track
208 var label = interfaceContext.getLabel(labelType, index, page.labelStart);
209 var sliderObj = new discreteObject(audioObject, label);
210 sliderGrid.appendChild(sliderObj.DOMRoot);
211 audioObject.bindInterface(sliderObj);
212 interfaceContext.commentBoxes.createCommentBox(audioObject);
213 index += 1;
214 }
215
216 });
169 interfaceObj.options.forEach(function (option) { 217 interfaceObj.options.forEach(function (option) {
170 if (option.type == "show") { 218 if (option.type == "show") {
171 switch (option.name) { 219 switch (option.name) {
172 case "playhead": 220 case "playhead":
173 var playbackHolder = document.getElementById('playback-holder'); 221 var playbackHolder = document.getElementById('playback-holder');
202 button.style.visibility = "visible"; 250 button.style.visibility = "visible";
203 break; 251 break;
204 } 252 }
205 } 253 }
206 }); 254 });
207
208 // Find all the audioElements from the audioHolder
209 var index = 0;
210 var interfaceScales = page.interfaces[0].scales;
211 var labelType = page.label;
212 if (labelType == "default") {
213 labelType = "number";
214 }
215 $(page.audioElements).each(function (pageIndex, element) {
216 // Find URL of track
217 // In this jQuery loop, variable 'this' holds the current audioElement.
218
219 var audioObject = audioEngineContext.newTrack(element);
220 if (element.type == 'outside-reference') {
221 // Construct outside reference;
222 var orNode = new interfaceContext.outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder"));
223 audioObject.bindInterface(orNode);
224 } else {
225 // Create a slider per track
226 var label = interfaceContext.getLabel(labelType, index, page.labelStart);
227 var sliderObj = new discreteObject(audioObject, label, interfaceScales);
228 sliderBox.appendChild(sliderObj.holder);
229 audioObject.bindInterface(sliderObj);
230 interfaceContext.commentBoxes.createCommentBox(audioObject);
231 index += 1;
232 }
233
234 });
235
236 $(page.commentQuestions).each(function (index, element) {
237 var node = interfaceContext.createCommentQuestion(element);
238 feedbackHolder.appendChild(node.holder);
239 });
240
241 // Auto-align 255 // Auto-align
242 resizeWindow(null); 256 resizeWindow(null);
243 } 257 }
244 258
245 function discreteObject(audioObject, label, interfaceScales) { 259 function discreteObject(audioObject, label) {
246 // An example node, you can make this however you want for each audioElement. 260 // An example node, you can make this however you want for each audioElement.
247 // However, every audioObject (audioEngineContext.audioObject) MUST have an interface object with the following 261 // However, every audioObject (audioEngineContext.audioObject) MUST have an interface object with the following
248 // You attach them by calling audioObject.bindInterface( ) 262 // You attach them by calling audioObject.bindInterface( )
249 if (interfaceScales === null || interfaceScales.length === 0) { 263 var playing = false;
250 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!"); 264
251 var numOptions = 5; 265 function buttonClicked(event) {
252 } 266 if (!playing) {
253 this.parent = audioObject; 267 audioEngineContext.play(audioObject.id);
254 268 } else {
255 this.holder = document.createElement('div'); 269 audioEngineContext.stop();
256 this.title = document.createElement('div'); 270 }
257 this.discreteHolder = document.createElement('div'); 271 };
258 this.discretes = []; 272
259 this.play = document.createElement('button'); 273 function radioSelected(event) {
260
261 this.holder.className = 'track-slider';
262 this.holder.style.width = window.innerWidth - 200 + 'px';
263 this.holder.appendChild(this.title);
264 this.holder.appendChild(this.discreteHolder);
265 this.holder.appendChild(this.play);
266 this.holder.setAttribute('trackIndex', audioObject.id);
267 this.title.textContent = label;
268 this.title.className = 'track-slider-title';
269
270 this.discreteHolder.className = "track-slider-range";
271 this.discreteHolder.style.width = window.innerWidth - 500 + 'px';
272 this.radioClicked = function (event) {
273 var time = audioEngineContext.timer.getTestTime(); 274 var time = audioEngineContext.timer.getTestTime();
274 if (audioEngineContext.status === 0) { 275 audioObject.metric.moved(time, event.currentTarget.value);
275 event.currentTarget.checked = false; 276 console.log("slider " + audioObject.id + " moved to " + event.currentTarget.value + "(" + time + ")");
276 return; 277 };
277 } 278
278 var id = this.parent.id; 279 var root = document.createElement("div"),
279 var position = this.getValue(); 280 labelHolder = document.createElement("div"),
280 this.parent.metric.moved(time, position); 281 button = document.createElement("button");
281 console.log('slider ' + id + ' moved to ' + position + ' (' + time + ')'); 282 root.className = "discrete-row";
282 283 labelHolder.className = "discrete-label";
283 }; 284 button.className = "discrete-button";
285 root.appendChild(labelHolder);
286
287 var labelSpan = document.createElement("span");
288 labelHolder.appendChild(labelSpan);
289 labelSpan.textContent = label;
290 button.textContent = "Listen";
291 button.disabled = "true";
292 button.addEventListener("click", this);
293
294 var numScales = audioObject.specification.parent.interfaces[0].scales.length;
295 root.style.gridTemplateColumns = "100px repeat(" + numScales + ", 1fr) 100px";
296 for (var n = 0; n < numScales; n++) {
297 var input = document.createElement("input");
298 input.type = "radio";
299 input.disabled = "true";
300 input.value = n / (numScales - 1);
301 input.addEventListener("click", this);
302 input.name = audioObject.specification.id;
303 root.appendChild(input);
304 }
305 root.appendChild(button);
284 this.handleEvent = function (event) { 306 this.handleEvent = function (event) {
285 if (event.currentTarget.getAttribute("name") === this.parent.specification.id) { 307 if (event.currentTarget === button) {
286 this.radioClicked(event); 308 buttonClicked(event);
287 } 309 } else if (event.currentTarget.type === "radio") {
288 }; 310 radioSelected(event);
289 for (var i = 0; i < interfaceScales.length; i++) { 311 }
290 var node = document.createElement('input'); 312 }
291 node.setAttribute('type', 'radio');
292 node.className = 'track-radio';
293 node.disabled = true;
294 node.setAttribute('position', interfaceScales[i].position);
295 node.setAttribute('name', audioObject.specification.id);
296 node.setAttribute('id', audioObject.specification.id + '-' + String(i));
297 this.discretes.push(node);
298 this.discreteHolder.appendChild(node);
299 node.addEventListener("click", this);
300 }
301
302 this.play.className = 'track-slider-button';
303 this.play.textContent = "Loading...";
304 this.play.value = audioObject.id;
305 this.play.disabled = true;
306 this.play.setAttribute("playstate", "ready");
307 this.play.onclick = function (event) {
308 var id = Number(event.currentTarget.value);
309 //audioEngineContext.metric.sliderPlayed(id);
310 if (event.currentTarget.getAttribute("playstate") == "ready")
311 audioEngineContext.play(id);
312 else if (event.currentTarget.getAttribute("playstate") == "playing")
313 audioEngineContext.stop();
314 };
315 this.resize = function (event) {
316 this.holder.style.width = window.innerWidth - 200 + 'px';
317 this.discreteHolder.style.width = window.innerWidth - 500 + 'px';
318 //text.style.left = (posPix+150-($(text).width()/2)) +'px';
319 for (var i = 0; i < this.discretes.length; i++) {
320 var width = $(this.discreteHolder).width() - 20;
321 var node = this.discretes[i];
322 var nodeW = $(node).width();
323 var position = node.getAttribute('position');
324 var posPix = Math.round(width * (position / 100.0));
325 node.style.left = (posPix + 10 - (nodeW / 2)) + 'px';
326 }
327 };
328 this.enable = function () { 313 this.enable = function () {
329 // This is used to tell the interface object that playback of this node is ready 314 // This is used to tell the interface object that playback of this node is ready
330 this.play.disabled = false; 315 button.disabled = "";
331 this.play.textContent = "Play"; 316 var a = root.querySelectorAll("input[type=\"radio\"]");
332 $(this.slider).removeClass('track-slider-disabled'); 317 for (var n = 0; n < a.length; n++) {
333 this.discretes.forEach(function (elem) { 318 a[n].disabled = false;
334 elem.disabled = false; 319 }
335 }); 320 button.textContent = "Listen";
336 }; 321 };
337 this.updateLoading = function (progress) { 322 this.updateLoading = function (progress) {
338 // progress is a value from 0 to 100 indicating the current download state of media files 323 // progress is a value from 0 to 100 indicating the current download state of media files
339 if (progress != 100) { 324 button.textContent = progress + "%";
340 progress = String(progress); 325 };
341 progress = progress.split('.')[0];
342 this.play.textContent = progress + '%';
343 } else {
344 this.play.textContent = "Play";
345 }
346 };
347
348 this.startPlayback = function () { 326 this.startPlayback = function () {
349 // Called by audioObject when playback begins 327 // Called when playback has begun
350 this.play.setAttribute("playstate", "playing"); 328 playing = true;
351 $(".track-slider").removeClass('track-slider-playing'); 329 $(root).addClass("discrete-row-playing");
352 $(this.holder).addClass('track-slider-playing'); 330 button.textContent = "Stop";
353 var outsideReference = document.getElementById('outside-reference');
354 this.play.textContent = "Listening";
355 if (outsideReference !== null) {
356 $(outsideReference).removeClass('track-slider-playing');
357 }
358 if (this.parent.specification.parent.playOne || specification.playOne) {
359 $('.track-slider-button').text = "Wait";
360 $('.track-slider-button').attr("disabled", "true");
361 }
362 interfaceContext.commentBoxes.highlightById(audioObject.id);
363 if (audioObject.specification.image !== undefined) {
364 interfaceContext.imageHolder.setImage(audioObject.specification.image);
365 }
366 }; 331 };
367 this.stopPlayback = function () { 332 this.stopPlayback = function () {
368 // Called by audioObject when playback stops 333 // Called when playback has stopped. This gets called even if playback never started!
369 if (this.play.getAttribute("playstate") == "playing") { 334 playing = false;
370 this.play.setAttribute("playstate", "ready"); 335 $(root).removeClass("discrete-row-playing");
371 $(this.holder).removeClass('track-slider-playing'); 336 button.textContent = "Listen";
372 $('.track-slider-button').text = "Play"; 337 };
373 this.play.textContent = "Play"; 338 this.getValue = function () {
374 $('.track-slider-button').removeAttr("disabled"); 339 // Return the current value of the object. If there is no value, return 0
375 var box = interfaceContext.commentBoxes.boxes.find(function (a) { 340 var a = root.querySelectorAll("input[type=\"radio\"]");
376 return a.id === audioObject.id; 341 for (var n = 0; n < a.length; n++) {
377 }); 342 if (a[n].checked) {
378 if (box) { 343 return Number(a[n].value);
379 box.highlight(false);
380 } 344 }
381 if (audioObject.specification.parent.interfaces[0].image !== undefined) { 345 }
382 interfaceContext.imageHolder.setImage(audioObject.specification.parent.interfaces[0].image); 346 return -1;
383 } else {
384 interfaceContext.imageHolder.setImage("");
385 }
386 }
387 };
388
389 this.getValue = function () {
390 // Return the current value of the object. If there is no value, return -1
391 var checkedElement = this.discretes.find(function (elem) {
392 return elem.checked;
393 });
394 if (checkedElement === undefined) {
395 return -1;
396 }
397 return checkedElement.getAttribute("position") / 100.0;
398 }; 347 };
399 this.getPresentedId = function () { 348 this.getPresentedId = function () {
400 // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale 349 // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale
401 return this.title.textContent; 350 return label;
402 }; 351 };
403 this.canMove = function () { 352 this.canMove = function () {
404 // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale. 353 // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale.
405 // These are checked primarily if the interface check option 'fragmentMoved' is enabled. 354 // These are checked primarily if the interface check option 'fragmentMoved' is enabled.
406 return true; 355 return true;
411 // 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 360 // 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
412 // Use storage.document.createElement('value'); to generate the XML node. 361 // Use storage.document.createElement('value'); to generate the XML node.
413 var node = storage.document.createElement('value'); 362 var node = storage.document.createElement('value');
414 node.textContent = this.getValue(); 363 node.textContent = this.getValue();
415 return node; 364 return node;
365
416 }; 366 };
417 this.error = function () { 367 this.error = function () {
418 // audioObject has an error!! 368 // If there is an error with the audioObject, this will be called to indicate a failure
419 this.playback.textContent = "Error"; 369 };
420 $(this.playback).addClass("error-colour"); 370 Object.defineProperties(this, {
421 }; 371 "DOMRoot": {
422 } 372 "value": root
373 }
374 });
375 };
423 376
424 function resizeWindow(event) { 377 function resizeWindow(event) {
425 // Called on every window resize event, use this to scale your page properly 378 // Called on every window resize event, use this to scale your page properly
426 var numObj = document.getElementsByClassName('track-slider').length;
427 var totalHeight = (numObj * 66) - 30;
428 document.getElementById('scale-holder').style.width = window.innerWidth - 220 + 'px';
429 // Cheers edge for making me delete a canvas every resize.
430 var canvas = document.getElementById('scale-canvas');
431 var new_canvas = document.createElement("canvas");
432 new_canvas.id = 'scale-canvas';
433 new_canvas.style.marginLeft = "150px";
434 canvas.parentElement.appendChild(new_canvas);
435 canvas.parentElement.removeChild(canvas);
436 new_canvas.width = window.innerWidth - 520;
437 new_canvas.height = totalHeight;
438 for (var i in audioEngineContext.audioObjects) {
439 if (audioEngineContext.audioObjects[i].specification.type != 'outside-reference') {
440 audioEngineContext.audioObjects[i].interfaceDOM.resize(event);
441 }
442 }
443 document.getElementById('slider-holder').style.height = totalHeight + 'px';
444 document.getElementById('slider').style.height = totalHeight + 70 + 'px';
445 drawScale();
446 } 379 }
447 380
448 function drawScale() { 381 function buttonSortFragmentClick() {
449 var interfaceObj = testState.currentStateMap.interfaces[0]; 382 var sortIndex = interfaceContext.sortFragmentsByScore();
450 var scales = testState.currentStateMap.interfaces[0].scales; 383 var sliderBox = document.getElementById("slider-holder");
451 var ticks = specification.interfaces.options.concat(interfaceObj.options).find(function (a) { 384 var nodes = audioEngineContext.audioObjects.filter(function (ao) {
452 return (a.type == "show" && a.name == "ticks"); 385 return ao.specification.type !== "outside-reference";
453 }); 386 });
454 if (ticks !== undefined) { 387 var i;
455 ticks = true; 388 nodes.forEach(function (ao) {
456 } else { 389 sliderBox.removeChild(ao.interfaceDOM.holder);
457 ticks = false; 390 });
458 } 391 for (i = 0; i < nodes.length; i++) {
459 scales = scales.sort(function (a, b) { 392 var j = sortIndex[i];
460 return a.position - b.position; 393 sliderBox.appendChild(nodes[j].interfaceDOM.holder);
461 }); 394 }
462 var canvas = document.getElementById('scale-canvas');
463 var ctx = canvas.getContext("2d");
464 var height = canvas.height;
465 var width = canvas.width;
466 var textHolder = document.getElementById('scale-text-holder');
467 textHolder.innerHTML = "";
468 ctx.fillStyle = "#000000";
469 ctx.setLineDash([1, 4]);
470 scales.forEach(function (scale) {
471 var posPercent = scale.position / 100.0;
472 var posPix = Math.round(width * posPercent);
473 if (posPix <= 0) {
474 posPix = 1;
475 }
476 if (posPix >= width) {
477 posPix = width - 1;
478 }
479 if (ticks) {
480 ctx.moveTo(posPix, 0);
481 ctx.lineTo(posPix, height);
482 ctx.stroke();
483 }
484
485 var text = document.createElement('div');
486 text.align = "center";
487 var textC = document.createElement('span');
488 textC.textContent = scale.text;
489 text.appendChild(textC);
490 text.className = "scale-text";
491 textHolder.appendChild(text);
492 text.style.width = $(text.children[0]).width() + 'px';
493 text.style.left = (posPix + 150 - ($(text).width() / 2)) + 'px';
494 });
495 } 395 }
496 396
497 function buttonSubmitClick() // TODO: Only when all songs have been played! 397 function buttonSubmitClick() // TODO: Only when all songs have been played!
498 { 398 {
499 var checks = testState.currentStateMap.interfaces[0].options, 399 var checks = testState.currentStateMap.interfaces[0].options,
512 if (interfaceContext.checkCommentQuestions() === false) { 412 if (interfaceContext.checkCommentQuestions() === false) {
513 return; 413 return;
514 } 414 }
515 415
516 for (var i = 0; i < checks.length; i++) { 416 for (var i = 0; i < checks.length; i++) {
517 var checkState; 417 var checkState = true;
518 if (checks[i].type == 'check') { 418 if (checks[i].type == 'check') {
519 switch (checks[i].name) { 419 switch (checks[i].name) {
520 case 'fragmentPlayed': 420 case 'fragmentPlayed':
521 // Check if all fragments have been played 421 // Check if all fragments have been played
522 checkState = interfaceContext.checkAllPlayed(checks[i].errorMessage); 422 checkState = interfaceContext.checkAllPlayed(checks[i].errorMessage);
535 checkState = interfaceContext.checkAllCommented(checks[i].errorMessage); 435 checkState = interfaceContext.checkAllCommented(checks[i].errorMessage);
536 break; 436 break;
537 case 'scalerange': 437 case 'scalerange':
538 // Check the scale has been used effectively 438 // Check the scale has been used effectively
539 checkState = interfaceContext.checkScaleRange(checks[i].errorMessage); 439 checkState = interfaceContext.checkScaleRange(checks[i].errorMessage);
440
540 break; 441 break;
541 default: 442 default:
542 console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); 443 console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface");
543 break; 444 break;
544 } 445 }
545 if (checkState === false) { 446 }
546 canContinue = false; 447 if (checkState === false) {
547 } 448 canContinue = false;
548 }
549 if (!canContinue) {
550 break; 449 break;
551 } 450 }
552 } 451 }
553 452
554 if (canContinue) { 453 if (canContinue) {
564 } 463 }
565 testState.advanceState(); 464 testState.advanceState();
566 } 465 }
567 } 466 }
568 467
569 function buttonSortFragmentClick() {
570 var sortIndex = interfaceContext.sortFragmentsByScore();
571 var sliderBox = document.getElementById("slider-holder");
572 var nodes = audioEngineContext.audioObjects.filter(function (ao) {
573 return ao.specification.type !== "outside-reference";
574 });
575 var i;
576 nodes.forEach(function (ao) {
577 sliderBox.removeChild(ao.interfaceDOM.holder);
578 });
579 for (i = 0; i < nodes.length; i++) {
580 var j = sortIndex[i];
581 sliderBox.appendChild(nodes[j].interfaceDOM.holder);
582 }
583 }
584
585 function pageXMLSave(store, pageSpecification) { 468 function pageXMLSave(store, pageSpecification) {
586 // MANDATORY 469 // MANDATORY
587 // Saves a specific test page 470 // Saves a specific test page
588 // You can use this space to add any extra nodes to your XML <audioHolder> saves 471 // You can use this space to add any extra nodes to your XML <audioHolder> saves
589 // Get the current <page> information in store (remember to appendChild your data to it) 472 // Get the current <page> information in store (remember to appendChild your data to it)