Mercurial > hg > webaudioevaluationtool
comparison interfaces/AB.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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 1316:279930a008ca |
---|---|
1 // Once this is loaded and parsed, begin execution | |
2 loadInterface(); | |
3 | |
4 function loadInterface() { | |
5 // Get the dimensions of the screen available to the page | |
6 var width = window.innerWidth; | |
7 var height = window.innerHeight; | |
8 interfaceContext.insertPoint.innerHTML = null; // Clear the current schema | |
9 | |
10 // Custom Comparitor Object | |
11 Interface.prototype.comparitor = null; | |
12 | |
13 // The injection point into the HTML page | |
14 interfaceContext.insertPoint = document.getElementById("topLevelBody"); | |
15 var testContent = document.createElement('div'); | |
16 testContent.id = 'testContent'; | |
17 | |
18 // Create the top div for the Title element | |
19 var titleAttr = specification.title; | |
20 var title = document.createElement('div'); | |
21 title.className = "title"; | |
22 title.align = "center"; | |
23 var titleSpan = document.createElement('span'); | |
24 | |
25 // Set title to that defined in XML, else set to default | |
26 if (titleAttr != undefined) { | |
27 titleSpan.textContent = titleAttr; | |
28 } else { | |
29 titleSpan.textContent = 'Listening test'; | |
30 } | |
31 // Insert the titleSpan element into the title div element. | |
32 title.appendChild(titleSpan); | |
33 | |
34 var pagetitle = document.createElement('div'); | |
35 pagetitle.className = "pageTitle"; | |
36 pagetitle.align = "center"; | |
37 var titleSpan = document.createElement('span'); | |
38 titleSpan.id = "pageTitle"; | |
39 pagetitle.appendChild(titleSpan); | |
40 | |
41 // Create Interface buttons! | |
42 var interfaceButtons = document.createElement('div'); | |
43 interfaceButtons.id = 'interface-buttons'; | |
44 interfaceButtons.style.height = '25px'; | |
45 | |
46 // Create playback start/stop points | |
47 var playback = document.createElement("button"); | |
48 playback.innerHTML = 'Stop'; | |
49 playback.id = 'playback-button'; | |
50 playback.style.float = 'left'; | |
51 // onclick function. Check if it is playing or not, call the correct function in the | |
52 // audioEngine, change the button text to reflect the next state. | |
53 playback.onclick = function() { | |
54 if (audioEngineContext.status == 1) { | |
55 audioEngineContext.stop(); | |
56 this.innerHTML = 'Stop'; | |
57 var time = audioEngineContext.timer.getTestTime(); | |
58 console.log('Stopped at ' + time); // DEBUG/SAFETY | |
59 } | |
60 }; | |
61 // Append the interface buttons into the interfaceButtons object. | |
62 interfaceButtons.appendChild(playback); | |
63 | |
64 // Global parent for the comment boxes on the page | |
65 var feedbackHolder = document.createElement('div'); | |
66 feedbackHolder.id = 'feedbackHolder'; | |
67 | |
68 // Construct the AB Boxes | |
69 var boxes = document.createElement('div'); | |
70 boxes.align = "center"; | |
71 boxes.id = "box-holders"; | |
72 boxes.style.float = "left"; | |
73 | |
74 var submit = document.createElement('button'); | |
75 submit.id = "submit"; | |
76 submit.onclick = buttonSubmitClick; | |
77 submit.className = "big-button"; | |
78 submit.textContent = "submit"; | |
79 submit.style.position = "relative"; | |
80 submit.style.left = (window.innerWidth-250)/2 + 'px'; | |
81 | |
82 feedbackHolder.appendChild(boxes); | |
83 | |
84 // Inject into HTML | |
85 testContent.appendChild(title); // Insert the title | |
86 testContent.appendChild(pagetitle); | |
87 testContent.appendChild(interfaceButtons); | |
88 testContent.appendChild(feedbackHolder); | |
89 testContent.appendChild(submit); | |
90 interfaceContext.insertPoint.appendChild(testContent); | |
91 | |
92 // Load the full interface | |
93 testState.initialise(); | |
94 testState.advanceState(); | |
95 } | |
96 | |
97 function loadTest(audioHolderObject) | |
98 { | |
99 var feedbackHolder = document.getElementById('feedbackHolder'); | |
100 var interfaceObj = audioHolderObject.interfaces; | |
101 if (interfaceObj.length > 1) | |
102 { | |
103 console.log("WARNING - This interface only supports one <interface> node per page. Using first interface node"); | |
104 } | |
105 interfaceObj = interfaceObj[0]; | |
106 | |
107 if(interfaceObj.title != null) | |
108 { | |
109 document.getElementById("pageTitle").textContent = interfaceObj.title; | |
110 } | |
111 | |
112 var interfaceOptions = specification.interfaces.options.concat(interfaceObj.options); | |
113 for (var option of interfaceOptions) | |
114 { | |
115 if (option.type == "show") | |
116 { | |
117 switch(option.name) { | |
118 case "playhead": | |
119 var playbackHolder = document.getElementById('playback-holder'); | |
120 if (playbackHolder == null) | |
121 { | |
122 playbackHolder = document.createElement('div'); | |
123 playbackHolder.style.width = "100%"; | |
124 playbackHolder.style.float = "left"; | |
125 playbackHolder.align = 'center'; | |
126 playbackHolder.appendChild(interfaceContext.playhead.object); | |
127 feedbackHolder.appendChild(playbackHolder); | |
128 } | |
129 break; | |
130 case "page-count": | |
131 var pagecountHolder = document.getElementById('page-count'); | |
132 if (pagecountHolder == null) | |
133 { | |
134 pagecountHolder = document.createElement('div'); | |
135 pagecountHolder.id = 'page-count'; | |
136 } | |
137 pagecountHolder.innerHTML = '<span>Page '+(audioHolderObject.presentedId+1)+' of '+specification.pages.length+'</span>'; | |
138 var inject = document.getElementById('interface-buttons'); | |
139 inject.appendChild(pagecountHolder); | |
140 break; | |
141 case "volume": | |
142 if (document.getElementById('master-volume-holder') == null) | |
143 { | |
144 feedbackHolder.appendChild(interfaceContext.volume.object); | |
145 } | |
146 break; | |
147 } | |
148 } | |
149 } | |
150 | |
151 // Populate the comparitor object | |
152 interfaceContext.comparitor = new Comparitor(audioHolderObject); | |
153 if (audioHolderObject.showElementComments) | |
154 { | |
155 var commentHolder = document.createElement('div'); | |
156 commentHolder.id = 'commentHolder'; | |
157 document.getElementById('testContent').appendChild(commentHolder); | |
158 // Generate one comment box per presented page | |
159 for (var element of audioEngineContext.audioObjects) | |
160 { | |
161 interfaceContext.createCommentBox(element); | |
162 } | |
163 interfaceContext.showCommentBoxes(commentHolder,true); | |
164 } | |
165 resizeWindow(null); | |
166 } | |
167 | |
168 function Comparitor(audioHolderObject) | |
169 { | |
170 this.comparitorBox = function(audioElement,id,text) | |
171 { | |
172 this.parent = audioElement; | |
173 this.id = id; | |
174 this.value = 0; | |
175 this.disabled = true; | |
176 this.box = document.createElement('div'); | |
177 this.box.className = 'comparitor-holder'; | |
178 this.box.setAttribute('track-id',audioElement.id); | |
179 this.box.id = 'comparitor-'+text; | |
180 this.selector = document.createElement('div'); | |
181 this.selector.className = 'comparitor-selector disabled'; | |
182 var selectorText = document.createElement('span'); | |
183 selectorText.textContent = text; | |
184 this.selector.appendChild(selectorText); | |
185 this.playback = document.createElement('button'); | |
186 this.playback.className = 'comparitor-button'; | |
187 this.playback.disabled = true; | |
188 this.playback.textContent = "Listen"; | |
189 this.box.appendChild(this.selector); | |
190 this.box.appendChild(this.playback); | |
191 this.selector.onclick = function(event) | |
192 { | |
193 var time = audioEngineContext.timer.getTestTime(); | |
194 if ($(event.currentTarget).hasClass('disabled')) | |
195 { | |
196 console.log("Please wait until sample has loaded"); | |
197 return; | |
198 } | |
199 if (audioEngineContext.status == 0) | |
200 { | |
201 alert("Please listen to the samples before making a selection"); | |
202 console.log("Please listen to the samples before making a selection"); | |
203 return; | |
204 } | |
205 $(".comparitor-selector").removeClass('selected'); | |
206 var id = event.currentTarget.parentElement.getAttribute('track-id'); | |
207 interfaceContext.comparitor.selected = id; | |
208 $(event.currentTarget).addClass('selected'); | |
209 for (var i=0; i<interfaceContext.comparitor.comparitors.length; i++) | |
210 { | |
211 var obj = interfaceContext.comparitor.comparitors[i]; | |
212 if (i == id) { | |
213 obj.value = 1; | |
214 } else { | |
215 obj.value = 0; | |
216 } | |
217 obj.parent.metric.moved(time,obj.value); | |
218 } | |
219 console.log("Selected "+id+' ('+time+')'); | |
220 }; | |
221 this.playback.onclick = function(event) | |
222 { | |
223 var id = event.currentTarget.parentElement.getAttribute('track-id'); | |
224 audioEngineContext.play(id); | |
225 }; | |
226 | |
227 this.enable = function() | |
228 { | |
229 if (this.parent.state == 1) | |
230 { | |
231 $(this.selector).removeClass('disabled'); | |
232 this.playback.disabled = false; | |
233 } | |
234 }; | |
235 this.updateLoading = function(progress) | |
236 { | |
237 if (progress != 100) | |
238 { | |
239 progress = String(progress); | |
240 progress = progress.split('.')[0]; | |
241 this.playback.textContent = progress+'%'; | |
242 } else { | |
243 this.playback.textContent = "Listen"; | |
244 } | |
245 }; | |
246 this.startPlayback = function() | |
247 { | |
248 $('.comparitor-button').text('Listen'); | |
249 $(this.playback).text('Playing'); | |
250 }; | |
251 this.stopPlayback = function() | |
252 { | |
253 $(this.playback).text('Listen'); | |
254 }; | |
255 this.exportXMLDOM = function(audioObject) | |
256 { | |
257 var node = storage.document.createElement('value'); | |
258 node.textContent = this.value; | |
259 return node; | |
260 }; | |
261 this.getValue = function() { | |
262 return this.value; | |
263 }; | |
264 this.getPresentedId = function() | |
265 { | |
266 return this.selector.children[0].textContent; | |
267 }; | |
268 this.canMove = function() | |
269 { | |
270 return false; | |
271 }; | |
272 }; | |
273 | |
274 this.boxHolders = document.getElementById('box-holders'); | |
275 this.boxHolders.innerHTML = null; | |
276 this.comparitors = []; | |
277 this.selected = null; | |
278 | |
279 // First generate the Audio Objects for the Audio Engine | |
280 for (var index=0; index<audioHolderObject.audioElements.length; index++) | |
281 { | |
282 var element = audioHolderObject.audioElements[index]; | |
283 if (index == audioHolderObject.outsideReference || element.type == 'outside-reference') | |
284 { | |
285 console.log("WARNING - AB cannot have fixed reference"); | |
286 } | |
287 var audioObject = audioEngineContext.newTrack(element); | |
288 var node = new this.comparitorBox(audioObject,index,String.fromCharCode(65 + index)); | |
289 audioObject.bindInterface(node); | |
290 this.comparitors.push(node); | |
291 this.boxHolders.appendChild(node.box); | |
292 } | |
293 return this; | |
294 } | |
295 | |
296 function resizeWindow(event) | |
297 { | |
298 document.getElementById('submit').style.left = (window.innerWidth-250)/2 + 'px'; | |
299 var numObj = interfaceContext.comparitor.comparitors.length; | |
300 var boxW = numObj*312; | |
301 var diff = window.innerWidth - boxW; | |
302 while (diff < 0) | |
303 { | |
304 numObj = Math.ceil(numObj/2); | |
305 boxW = numObj*312; | |
306 diff = window.innerWidth - boxW; | |
307 } | |
308 document.getElementById('box-holders').style.marginLeft = diff/2 + 'px'; | |
309 document.getElementById('box-holders').style.marginRight = diff/2 + 'px'; | |
310 document.getElementById('box-holders').style.width = boxW + 'px'; | |
311 } | |
312 | |
313 function buttonSubmitClick() | |
314 { | |
315 var checks = []; | |
316 checks = checks.concat(testState.currentStateMap.interfaces[0].options); | |
317 checks = checks.concat(specification.interfaces.options); | |
318 var canContinue = true; | |
319 | |
320 for (var i=0; i<checks.length; i++) { | |
321 if (checks[i].type == 'check') | |
322 { | |
323 switch(checks[i].name) { | |
324 case 'fragmentPlayed': | |
325 // Check if all fragments have been played | |
326 var checkState = interfaceContext.checkAllPlayed(); | |
327 if (checkState == false) {canContinue = false;} | |
328 break; | |
329 case 'fragmentFullPlayback': | |
330 // Check all fragments have been played to their full length | |
331 var checkState = interfaceContext.checkFragmentsFullyPlayed(); | |
332 if (checkState == false) {canContinue = false;} | |
333 break; | |
334 case 'fragmentMoved': | |
335 // Check all fragment sliders have been moved. | |
336 var checkState = interfaceContext.checkAllMoved(); | |
337 if (checkState == false) {canContinue = false;} | |
338 break; | |
339 case 'fragmentComments': | |
340 // Check all fragment sliders have been moved. | |
341 var checkState = interfaceContext.checkAllCommented(); | |
342 if (checkState == false) {canContinue = false;} | |
343 break; | |
344 default: | |
345 console.log("WARNING - Check option "+checks[i].check+" is not supported on this interface"); | |
346 break; | |
347 } | |
348 | |
349 } | |
350 if (!canContinue) {break;} | |
351 } | |
352 if (canContinue) | |
353 { | |
354 if (audioEngineContext.status == 1) { | |
355 var playback = document.getElementById('playback-button'); | |
356 playback.click(); | |
357 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options | |
358 } else | |
359 { | |
360 if (audioEngineContext.timer.testStarted == false) | |
361 { | |
362 alert('You have not started the test! Please press start to begin the test!'); | |
363 return; | |
364 } | |
365 } | |
366 testState.advanceState(); | |
367 } | |
368 } | |
369 | |
370 function pageXMLSave(store, pageSpecification) | |
371 { | |
372 // MANDATORY | |
373 // Saves a specific test page | |
374 // You can use this space to add any extra nodes to your XML <audioHolder> saves | |
375 // Get the current <page> information in store (remember to appendChild your data to it) | |
376 // pageSpecification is the current page node configuration | |
377 // To create new XML nodes, use storage.document.createElement(); | |
378 } |