Mercurial > hg > webaudioevaluationtool
comparison interfaces/ABX.js @ 2695:211364181d16
JSHint ABX (#180)
author | Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk> |
---|---|
date | Sat, 11 Mar 2017 18:38:12 +0000 |
parents | 22efb2d04bc9 |
children | 536cb44c7292 |
comparison
equal
deleted
inserted
replaced
2694:1ccc083552d5 | 2695:211364181d16 |
---|---|
2 * WAET Blank Template | 2 * WAET Blank Template |
3 * Use this to start building your custom interface | 3 * Use this to start building your custom interface |
4 */ | 4 */ |
5 | 5 |
6 // Once this is loaded and parsed, begin execution | 6 // Once this is loaded and parsed, begin execution |
7 /* globals interfaceContext, Interface, testState, audioEngineContext, console, document, window, feedbackHolder, $, specification, storage*/ | |
7 loadInterface(); | 8 loadInterface(); |
8 | 9 |
9 function loadInterface() { | 10 function loadInterface() { |
10 // Use this to do any one-time page / element construction. For instance, placing any stationary text objects, | 11 // Use this to do any one-time page / element construction. For instance, placing any stationary text objects, |
11 // holding div's, or setting up any nodes which are present for the entire test sequence | 12 // holding div's, or setting up any nodes which are present for the entire test sequence |
27 if (rank > maxRanking) { | 28 if (rank > maxRanking) { |
28 maxRanking = rank; | 29 maxRanking = rank; |
29 } | 30 } |
30 } | 31 } |
31 if (maxRanking * 100 < max) { | 32 if (maxRanking * 100 < max) { |
32 str += "At least one fragment must be selected." | 33 str += "At least one fragment must be selected."; |
33 state = false; | 34 state = false; |
34 } | 35 } |
35 if (!state) { | 36 if (!state) { |
36 console.log(str); | 37 console.log(str); |
37 this.storeErrorNode(str); | 38 this.storeErrorNode(str); |
38 interfaceContext.lightbox.post("Message", str); | 39 interfaceContext.lightbox.post("Message", str); |
39 } | 40 } |
40 return state; | 41 return state; |
41 } | 42 }; |
42 | 43 |
43 // Custom comparator Object | 44 // Custom comparator Object |
44 Interface.prototype.comparator = null; | 45 Interface.prototype.comparator = null; |
45 | 46 |
46 // The injection point into the HTML page | 47 // The injection point into the HTML page |
55 title.align = "center"; | 56 title.align = "center"; |
56 var titleSpan = document.createElement('span'); | 57 var titleSpan = document.createElement('span'); |
57 titleSpan.id = "test-title"; | 58 titleSpan.id = "test-title"; |
58 | 59 |
59 // Set title to that defined in XML, else set to default | 60 // Set title to that defined in XML, else set to default |
60 if (titleAttr != undefined) { | 61 if (titleAttr !== undefined) { |
61 titleSpan.textContent = titleAttr; | 62 titleSpan.textContent = titleAttr; |
62 } else { | 63 } else { |
63 titleSpan.textContent = 'Listening test'; | 64 titleSpan.textContent = 'Listening test'; |
64 } | 65 } |
65 // Insert the titleSpan element into the title div element. | 66 // Insert the titleSpan element into the title div element. |
66 title.appendChild(titleSpan); | 67 title.appendChild(titleSpan); |
67 | 68 |
68 var pagetitle = document.createElement('div'); | 69 var pagetitle = document.createElement('div'); |
69 pagetitle.className = "pageTitle"; | 70 pagetitle.className = "pageTitle"; |
70 pagetitle.align = "center"; | 71 pagetitle.align = "center"; |
71 var titleSpan = document.createElement('span'); | 72 |
73 titleSpan = document.createElement('span'); | |
72 titleSpan.id = "pageTitle"; | 74 titleSpan.id = "pageTitle"; |
73 pagetitle.appendChild(titleSpan); | 75 pagetitle.appendChild(titleSpan); |
74 | 76 |
75 // Create Interface buttons! | 77 // Create Interface buttons! |
76 var interfaceButtons = document.createElement('div'); | 78 var interfaceButtons = document.createElement('div'); |
129 interfaceContext.insertPoint.appendChild(testContent); | 131 interfaceContext.insertPoint.appendChild(testContent); |
130 | 132 |
131 // Load the full interface | 133 // Load the full interface |
132 testState.initialise(); | 134 testState.initialise(); |
133 testState.advanceState(); | 135 testState.advanceState(); |
134 }; | 136 } |
135 | 137 |
136 function loadTest(page) { | 138 function loadTest(page) { |
137 // Called each time a new test page is to be build. The page specification node is the only item passed in | 139 // Called each time a new test page is to be build. The page specification node is the only item passed in |
138 document.getElementById('box-holders').innerHTML = ""; | 140 document.getElementById('box-holders').innerHTML = ""; |
139 | 141 |
146 var commentHolder = document.getElementById("comment-box-holder"); | 148 var commentHolder = document.getElementById("comment-box-holder"); |
147 commentHolder.innerHTML = ""; | 149 commentHolder.innerHTML = ""; |
148 | 150 |
149 // Set the page title | 151 // Set the page title |
150 if (typeof page.title == "string" && page.title.length > 0) { | 152 if (typeof page.title == "string" && page.title.length > 0) { |
151 document.getElementById("test-title").textContent = page.title | 153 document.getElementById("test-title").textContent = page.title; |
152 } | 154 } |
153 | 155 |
154 if (interfaceObj.title != null) { | 156 if (interfaceObj.title !== null) { |
155 document.getElementById("pageTitle").textContent = interfaceObj.title; | 157 document.getElementById("pageTitle").textContent = interfaceObj.title; |
156 } | 158 } |
157 | 159 |
158 interfaceContext.comparator = new comparator(page); | 160 interfaceContext.comparator = new comparator(page); |
159 | 161 |
161 for (var option of interfaceOptions) { | 163 for (var option of interfaceOptions) { |
162 if (option.type == "show") { | 164 if (option.type == "show") { |
163 switch (option.name) { | 165 switch (option.name) { |
164 case "playhead": | 166 case "playhead": |
165 var playbackHolder = document.getElementById('playback-holder'); | 167 var playbackHolder = document.getElementById('playback-holder'); |
166 if (playbackHolder == null) { | 168 if (playbackHolder === null) { |
167 playbackHolder = document.createElement('div'); | 169 playbackHolder = document.createElement('div'); |
168 playbackHolder.style.width = "100%"; | 170 playbackHolder.style.width = "100%"; |
169 playbackHolder.style.float = "left"; | 171 playbackHolder.style.float = "left"; |
170 playbackHolder.align = 'center'; | 172 playbackHolder.align = 'center'; |
171 playbackHolder.appendChild(interfaceContext.playhead.object); | 173 playbackHolder.appendChild(interfaceContext.playhead.object); |
172 feedbackHolder.appendChild(playbackHolder); | 174 feedbackHolder.appendChild(playbackHolder); |
173 } | 175 } |
174 break; | 176 break; |
175 case "page-count": | 177 case "page-count": |
176 var pagecountHolder = document.getElementById('page-count'); | 178 var pagecountHolder = document.getElementById('page-count'); |
177 if (pagecountHolder == null) { | 179 if (pagecountHolder === null) { |
178 pagecountHolder = document.createElement('div'); | 180 pagecountHolder = document.createElement('div'); |
179 pagecountHolder.id = 'page-count'; | 181 pagecountHolder.id = 'page-count'; |
180 } | 182 } |
181 pagecountHolder.innerHTML = '<span>Page ' + (testState.stateIndex + 1) + ' of ' + testState.stateMap.length + '</span>'; | 183 pagecountHolder.innerHTML = '<span>Page ' + (testState.stateIndex + 1) + ' of ' + testState.stateMap.length + '</span>'; |
182 var inject = document.getElementById('interface-buttons'); | 184 var inject = document.getElementById('interface-buttons'); |
183 inject.appendChild(pagecountHolder); | 185 inject.appendChild(pagecountHolder); |
184 break; | 186 break; |
185 case "volume": | 187 case "volume": |
186 if (document.getElementById('master-volume-holder') == null) { | 188 if (document.getElementById('master-volume-holder') === null) { |
187 feedbackHolder.appendChild(interfaceContext.volume.object); | 189 feedbackHolder.appendChild(interfaceContext.volume.object); |
188 } | 190 } |
189 break; | 191 break; |
190 case "comments": | 192 case "comments": |
191 // Generate one comment box per presented page | 193 // Generate one comment box per presented page |
229 this.playback.className = 'comparator-button'; | 231 this.playback.className = 'comparator-button'; |
230 this.playback.disabled = true; | 232 this.playback.disabled = true; |
231 this.playback.textContent = "Listen"; | 233 this.playback.textContent = "Listen"; |
232 this.box.appendChild(this.selector); | 234 this.box.appendChild(this.selector); |
233 this.box.appendChild(this.playback); | 235 this.box.appendChild(this.playback); |
234 this.selector.onclick = function (event) { | 236 this.selectorClicked = function (event) { |
235 var label = event.currentTarget.children[0].textContent; | |
236 if (label == "X" || label == "x") { | 237 if (label == "X" || label == "x") { |
237 return; | 238 return; |
238 } | 239 } |
239 var time = audioEngineContext.timer.getTestTime(); | 240 var time = audioEngineContext.timer.getTestTime(); |
240 if ($(event.currentTarget).hasClass('disabled')) { | 241 if (this.disabled) { |
242 interfaceContext.lightbox.post("Message", "Please wait until sample has loaded"); | |
241 console.log("Please wait until sample has loaded"); | 243 console.log("Please wait until sample has loaded"); |
242 return; | 244 return; |
243 } | 245 } |
244 if (audioEngineContext.status == 0) { | 246 if (audioEngineContext.status === 0) { |
245 interfaceContext.lightbox.post("Message", "Please listen to the samples before making a selection"); | 247 interfaceContext.lightbox.post("Message", "Please listen to the samples before making a selection"); |
246 console.log("Please listen to the samples before making a selection"); | 248 console.log("Please listen to the samples before making a selection"); |
247 return; | 249 return; |
248 } | 250 } |
249 var id = event.currentTarget.parentElement.getAttribute('track-id'); | 251 interfaceContext.comparator.selected = this.id; |
250 interfaceContext.comparator.selected = id; | 252 $(".comparator-selector").removeClass('selected'); |
251 if ($(event.currentTarget).hasClass("selected")) { | 253 $(this.selector).addClass('selected'); |
252 $(".comparator-selector").removeClass('selected'); | 254 interfaceContext.comparator.pair.forEach(function (obj) { |
253 for (var i = 0; i < interfaceContext.comparator.pair.length; i++) { | 255 obj.value = 1.0 * obj === this; |
254 var obj = interfaceContext.comparator.pair[i]; | 256 obj.parent.metric.moved(time, obj.value); |
255 obj.parent.metric.moved(time, 0); | 257 }); |
256 obj.value = 0; | 258 console.log("Selected " + this.id + ' (' + time + ')'); |
257 } | |
258 } else { | |
259 $(".comparator-selector").removeClass('selected'); | |
260 $(event.currentTarget).addClass('selected'); | |
261 for (var i = 0; i < interfaceContext.comparator.pair.length; i++) { | |
262 var obj = interfaceContext.comparator.pair[i]; | |
263 if (i == id) { | |
264 obj.value = 1; | |
265 } else { | |
266 obj.value = 0; | |
267 } | |
268 obj.parent.metric.moved(time, obj.value); | |
269 } | |
270 console.log("Selected " + id + ' (' + time + ')'); | |
271 } | |
272 }; | 259 }; |
273 this.playback.setAttribute("playstate", "ready"); | 260 this.playback.setAttribute("playstate", "ready"); |
274 this.playback.onclick = function (event) { | 261 this.playbackClicked = function (event) { |
275 var id = event.currentTarget.parentElement.getAttribute('track-id'); | 262 if (this.playback.getAttribute("playstate") == "ready") { |
276 if (event.currentTarget.getAttribute("playstate") == "ready") { | 263 audioEngineContext.play(this.id); |
277 audioEngineContext.play(id); | |
278 } else if (event.currentTarget.getAttribute("playstate") == "playing") { | 264 } else if (event.currentTarget.getAttribute("playstate") == "playing") { |
279 audioEngineContext.stop(); | 265 audioEngineContext.stop(); |
280 } | 266 } |
281 | 267 |
282 }; | 268 }; |
269 this.handleEvent = function (event) { | |
270 if (event.currentTarget === this.playback) { | |
271 this.playbackClicked(event); | |
272 } else if (event.currentTarget === this.selector) { | |
273 this.selectorClicked(event); | |
274 } | |
275 }; | |
276 this.playback.addEventListener("click", this); | |
277 this.selector.addEventListener("click", this); | |
283 this.enable = function () { | 278 this.enable = function () { |
284 // This is used to tell the interface object that playback of this node is ready | 279 // This is used to tell the interface object that playback of this node is ready |
285 if (this.parent.state == 1) { | 280 if (this.parent.state == 1) { |
286 $(this.selector).removeClass('disabled'); | 281 $(this.selector).removeClass('disabled'); |
287 this.playback.disabled = false; | 282 this.playback.disabled = false; |
283 this.disabled = false; | |
288 } | 284 } |
289 }; | 285 }; |
290 this.updateLoading = function (progress) { | 286 this.updateLoading = function (progress) { |
291 // progress is a value from 0 to 100 indicating the current download state of media files | 287 // progress is a value from 0 to 100 indicating the current download state of media files |
292 if (progress != 100) { | 288 if (progress != 100) { |
343 return node; | 339 return node; |
344 | 340 |
345 }; | 341 }; |
346 this.error = function () { | 342 this.error = function () { |
347 // If there is an error with the audioObject, this will be called to indicate a failure | 343 // If there is an error with the audioObject, this will be called to indicate a failure |
348 } | 344 }; |
349 }; | 345 }; |
350 // Ensure there are only two comparisons per page | 346 // Ensure there are only two comparisons per page |
351 if (page.audioElements.length != 2) { | 347 if (page.audioElements.length != 2) { |
352 console.error('FATAL - There must be 2 <audioelement> nodes on each <page>: ' + page.id); | 348 console.error('FATAL - There must be 2 <audioelement> nodes on each <page>: ' + page.id); |
353 return; | 349 return; |
354 } | 350 } |
355 // Build the three audio elements | 351 // Build the three audio elements |
352 | |
353 function buildElement(index, audioObject) { | |
354 var label; | |
355 switch (index) { | |
356 case 0: | |
357 label = "A"; | |
358 break; | |
359 case 1: | |
360 label = "B"; | |
361 break; | |
362 default: | |
363 label = "X"; | |
364 break; | |
365 } | |
366 var node = new this.interfaceObject(audioObject, label); | |
367 audioObject.bindInterface(node); | |
368 return node; | |
369 } | |
370 | |
356 this.pair = []; | 371 this.pair = []; |
357 this.X = null; | 372 this.X = null; |
358 this.boxHolders = document.getElementById('box-holders'); | 373 this.boxHolders = document.getElementById('box-holders'); |
359 for (var index = 0; index < page.audioElements.length; index++) { | 374 var node; |
360 var element = page.audioElements[index]; | 375 page.audioElements.forEach(function (element, index) { |
361 if (element.type != 'normal') { | 376 if (element.type != 'normal') { |
362 console.log("WARNING - ABX can only have normal elements. Page " + page.id + ", Element " + element.id); | 377 console.log("WARNING - ABX can only have normal elements. Page " + page.id + ", Element " + element.id); |
363 element.type = "normal"; | 378 element.type = "normal"; |
364 } | 379 } |
365 var audioObject = audioEngineContext.newTrack(element); | 380 node = buildElement.call(this, index, audioEngineContext.newTrack(element)); |
366 var label; | |
367 if (index == 0) { | |
368 label = "A"; | |
369 } else { | |
370 label = "B"; | |
371 } | |
372 var node = new this.interfaceObject(audioObject, label); | |
373 audioObject.bindInterface(node); | |
374 this.pair.push(node); | 381 this.pair.push(node); |
375 this.boxHolders.appendChild(node.box); | 382 this.boxHolders.appendChild(node.box); |
376 } | 383 }, this); |
377 var elementId = Math.floor(Math.random() * 2); //Randomly pick A or B to be X | 384 var elementId = Math.floor(Math.random() * 2); //Randomly pick A or B to be X |
378 var element = new page.audioElementNode(specification); | 385 var element = new page.audioElementNode(specification); |
379 for (var atr in page.audioElements[elementId]) { | 386 for (var atr in page.audioElements[elementId]) { |
380 eval("element." + atr + " = page.audioElements[elementId]." + atr); | 387 element[atr] = page.audioElements[elementId][atr]; |
381 } | 388 } |
382 element.id += "-X"; | 389 element.id += "-X"; |
383 if (typeof element.name == "string") { | 390 if (typeof element.name == "string") { |
384 element.name += "-X"; | 391 element.name += "-X"; |
385 } | 392 } |
395 aeNode.setAttribute('url', element.url); | 402 aeNode.setAttribute('url', element.url); |
396 aeNode.setAttribute('gain', element.gain); | 403 aeNode.setAttribute('gain', element.gain); |
397 aeNode.appendChild(storage.document.createElement('metric')); | 404 aeNode.appendChild(storage.document.createElement('metric')); |
398 root.appendChild(aeNode); | 405 root.appendChild(aeNode); |
399 // Build the 'X' element | 406 // Build the 'X' element |
407 var label; | |
400 var audioObject = audioEngineContext.newTrack(element); | 408 var audioObject = audioEngineContext.newTrack(element); |
401 var label; | 409 node = buildElement.call(this, 3, audioObject); |
402 switch (audioObject.specification.parent.label) { | |
403 case "letter": | |
404 label = "x"; | |
405 break; | |
406 default: | |
407 label = "X"; | |
408 break; | |
409 } | |
410 var node = new this.interfaceObject(audioObject, label); | |
411 node.box.children[0].classList.add('inactive'); | 410 node.box.children[0].classList.add('inactive'); |
412 audioObject.bindInterface(node); | 411 audioObject.bindInterface(node); |
413 this.X = node; | 412 this.X = node; |
414 this.boxHolders.appendChild(node.box); | 413 this.boxHolders.appendChild(node.box); |
415 } | 414 } |
432 function buttonSubmitClick() { | 431 function buttonSubmitClick() { |
433 var checks = testState.currentStateMap.interfaces[0].options, | 432 var checks = testState.currentStateMap.interfaces[0].options, |
434 canContinue = true; | 433 canContinue = true; |
435 | 434 |
436 for (var i = 0; i < checks.length; i++) { | 435 for (var i = 0; i < checks.length; i++) { |
436 var checkState; | |
437 if (checks[i].type == 'check') { | 437 if (checks[i].type == 'check') { |
438 switch (checks[i].name) { | 438 switch (checks[i].name) { |
439 case 'fragmentPlayed': | 439 case 'fragmentPlayed': |
440 // Check if all fragments have been played | 440 // Check if all fragments have been played |
441 var checkState = interfaceContext.checkAllPlayed(); | 441 checkState = interfaceContext.checkAllPlayed(); |
442 if (checkState == false) { | 442 if (checkState === false) { |
443 canContinue = false; | 443 canContinue = false; |
444 } | 444 } |
445 break; | 445 break; |
446 case 'fragmentFullPlayback': | 446 case 'fragmentFullPlayback': |
447 // Check all fragments have been played to their full length | 447 // Check all fragments have been played to their full length |
448 var checkState = interfaceContext.checkFragmentsFullyPlayed(); | 448 checkState = interfaceContext.checkFragmentsFullyPlayed(); |
449 if (checkState == false) { | 449 if (checkState === false) { |
450 canContinue = false; | 450 canContinue = false; |
451 } | 451 } |
452 break; | 452 break; |
453 case 'fragmentMoved': | 453 case 'fragmentMoved': |
454 // Check all fragment sliders have been moved. | 454 // Check all fragment sliders have been moved. |
455 var checkState = interfaceContext.checkAllMoved(); | 455 checkState = interfaceContext.checkAllMoved(); |
456 if (checkState == false) { | 456 if (checkState === false) { |
457 canContinue = false; | 457 canContinue = false; |
458 } | 458 } |
459 break; | 459 break; |
460 case 'fragmentComments': | 460 case 'fragmentComments': |
461 // Check all fragment sliders have been moved. | 461 // Check all fragment sliders have been moved. |
462 var checkState = interfaceContext.checkAllCommented(); | 462 checkState = interfaceContext.checkAllCommented(); |
463 if (checkState == false) { | 463 if (checkState === false) { |
464 canContinue = false; | 464 canContinue = false; |
465 } | 465 } |
466 break; | 466 break; |
467 case 'scalerange': | 467 case 'scalerange': |
468 // Check the scale has been used effectively | 468 // Check the scale has been used effectively |
469 var checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max); | 469 checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max); |
470 if (checkState == false) { | 470 if (checkState === false) { |
471 canContinue = false; | 471 canContinue = false; |
472 } | 472 } |
473 break; | 473 break; |
474 default: | 474 default: |
475 console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); | 475 console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); |
485 if (audioEngineContext.status == 1) { | 485 if (audioEngineContext.status == 1) { |
486 var playback = document.getElementById('playback-button'); | 486 var playback = document.getElementById('playback-button'); |
487 playback.click(); | 487 playback.click(); |
488 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options | 488 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options |
489 } else { | 489 } else { |
490 if (audioEngineContext.timer.testStarted == false) { | 490 if (audioEngineContext.timer.testStarted === false) { |
491 interfaceContext.lightbox.post("Warning", 'You have not started the test! Please listen to a sample to begin the test!'); | 491 interfaceContext.lightbox.post("Warning", 'You have not started the test! Please listen to a sample to begin the test!'); |
492 return; | 492 return; |
493 } | 493 } |
494 } | 494 } |
495 testState.advanceState(); | 495 testState.advanceState(); |