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