Mercurial > hg > webaudioevaluationtool
comparison ape.js @ 872:ca4ae613f1dd
Bug Fix #1303 on main
author | Nicholas Jillings <nicholas.jillings@eecs.qmul.ac.uk> |
---|---|
date | Thu, 25 Jun 2015 16:40:11 +0100 |
parents | |
children | 8ab5f8969856 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 872:ca4ae613f1dd |
---|---|
1 /** | |
2 * ape.js | |
3 * Create the APE interface | |
4 */ | |
5 | |
6 // preTest - In preTest state | |
7 // testRun-ID - In test running, test Id number at the end 'testRun-2' | |
8 // testRunPost-ID - Post test of test ID | |
9 // testRunPre-ID - Pre-test of test ID | |
10 // postTest - End of test, final submission! | |
11 | |
12 | |
13 // Once this is loaded and parsed, begin execution | |
14 loadInterface(); | |
15 | |
16 function loadInterface() { | |
17 | |
18 // Get the dimensions of the screen available to the page | |
19 var width = window.innerWidth; | |
20 var height = window.innerHeight; | |
21 | |
22 // The injection point into the HTML page | |
23 interfaceContext.insertPoint = document.getElementById("topLevelBody"); | |
24 var testContent = document.createElement('div'); | |
25 | |
26 testContent.id = 'testContent'; | |
27 | |
28 | |
29 // Create APE specific metric functions | |
30 audioEngineContext.metric.initialiseTest = function() | |
31 { | |
32 }; | |
33 | |
34 audioEngineContext.metric.sliderMoved = function() | |
35 { | |
36 | |
37 var id = this.data; | |
38 this.data = -1; | |
39 var position = convSliderPosToRate(id); | |
40 console.log('slider ' + id + ': '+ position + ' (' + time + ')'); // DEBUG/SAFETY: show position and slider id | |
41 if (audioEngineContext.timer.testStarted) | |
42 { | |
43 audioEngineContext.audioObjects[id].metric.moved(time,position); | |
44 } | |
45 }; | |
46 | |
47 audioEngineContext.metric.sliderPlayed = function(id) | |
48 { | |
49 var time = audioEngineContext.timer.getTestTime(); | |
50 if (audioEngineContext.timer.testStarted) | |
51 { | |
52 if (this.lastClicked >= 0) | |
53 { | |
54 audioEngineContext.audioObjects[this.lastClicked].metric.listening(time); | |
55 } | |
56 this.lastClicked = id; | |
57 audioEngineContext.audioObjects[id].metric.listening(time); | |
58 } | |
59 console.log('slider ' + id + ' played (' + time + ')'); // DEBUG/SAFETY: show played slider id | |
60 }; | |
61 | |
62 // Bindings for interfaceContext | |
63 Interface.prototype.checkAllPlayed = function() | |
64 { | |
65 hasBeenPlayed = audioEngineContext.checkAllPlayed(); | |
66 if (hasBeenPlayed.length > 0) // if a fragment has not been played yet | |
67 { | |
68 str = ""; | |
69 if (hasBeenPlayed.length > 1) { | |
70 for (var i=0; i<hasBeenPlayed.length; i++) { | |
71 str = str + hasBeenPlayed[i]; | |
72 if (i < hasBeenPlayed.length-2){ | |
73 str += ", "; | |
74 } else if (i == hasBeenPlayed.length-2) { | |
75 str += " or "; | |
76 } | |
77 } | |
78 alert('You have not played fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.'); | |
79 } else { | |
80 alert('You have not played fragment ' + hasBeenPlayed[0] + ' yet. Please listen, rate and comment all samples before submitting.'); | |
81 } | |
82 return false; | |
83 } | |
84 return true; | |
85 }; | |
86 | |
87 Interface.prototype.checkAllMoved = function() { | |
88 var audioObjs = audioEngineContext.audioObjects; | |
89 var state = true; | |
90 var strNums = []; | |
91 for (var i=0; i<audioObjs.length; i++) | |
92 { | |
93 if (audioObjs[i].metric.wasMoved == false) { | |
94 state = false; | |
95 strNums.push(i); | |
96 } | |
97 } | |
98 if (state == false) { | |
99 if (strNums.length > 1) { | |
100 var str = ""; | |
101 for (var i=0; i<strNums.length; i++) { | |
102 str = str + strNums[i]; | |
103 if (i < strNums.length-2){ | |
104 str += ", "; | |
105 } else if (i == strNums.length-2) { | |
106 str += " or "; | |
107 } | |
108 } | |
109 alert('You have not moved fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.'); | |
110 } else { | |
111 alert('You have not moved fragment ' + strNums[0] + ' yet. Please listen, rate and comment all samples before submitting.'); | |
112 } | |
113 } | |
114 return state; | |
115 }; | |
116 | |
117 Interface.prototype.checkAllCommented = function() { | |
118 var audioObjs = audioEngineContext.audioObjects; | |
119 var audioHolder = testState.stateMap[testState.stateIndex]; | |
120 var state = true; | |
121 if (audioHolder.elementComments) { | |
122 var strNums = []; | |
123 for (var i=0; i<audioObjs.length; i++) | |
124 { | |
125 if (audioObjs[i].commentDOM.trackCommentBox.value.length == 0) { | |
126 state = false; | |
127 strNums.push(i); | |
128 } | |
129 } | |
130 if (state == false) { | |
131 if (strNums.length > 1) { | |
132 var str = ""; | |
133 for (var i=0; i<strNums.length; i++) { | |
134 str = str + strNums[i]; | |
135 if (i < strNums.length-2){ | |
136 str += ", "; | |
137 } else if (i == strNums.length-2) { | |
138 str += " or "; | |
139 } | |
140 } | |
141 alert('You have not commented on fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.'); | |
142 } else { | |
143 alert('You have not commented on fragment ' + strNums[0] + ' yet. Please listen, rate and comment all samples before submitting.'); | |
144 } | |
145 } | |
146 } | |
147 return state; | |
148 }; | |
149 | |
150 // Bindings for audioObjects | |
151 | |
152 // Create the top div for the Title element | |
153 var titleAttr = specification.title; | |
154 var title = document.createElement('div'); | |
155 title.className = "title"; | |
156 title.align = "center"; | |
157 var titleSpan = document.createElement('span'); | |
158 | |
159 // Set title to that defined in XML, else set to default | |
160 if (titleAttr != undefined) { | |
161 titleSpan.textContent = titleAttr; | |
162 } else { | |
163 titleSpan.textContent = 'Listening test'; | |
164 } | |
165 // Insert the titleSpan element into the title div element. | |
166 title.appendChild(titleSpan); | |
167 | |
168 var pagetitle = document.createElement('div'); | |
169 pagetitle.className = "pageTitle"; | |
170 pagetitle.align = "center"; | |
171 var titleSpan = document.createElement('span'); | |
172 titleSpan.id = "pageTitle"; | |
173 pagetitle.appendChild(titleSpan); | |
174 | |
175 // Create Interface buttons! | |
176 var interfaceButtons = document.createElement('div'); | |
177 interfaceButtons.id = 'interface-buttons'; | |
178 | |
179 // Create playback start/stop points | |
180 var playback = document.createElement("button"); | |
181 playback.innerHTML = 'Stop'; | |
182 playback.id = 'playback-button'; | |
183 // onclick function. Check if it is playing or not, call the correct function in the | |
184 // audioEngine, change the button text to reflect the next state. | |
185 playback.onclick = function() { | |
186 if (audioEngineContext.status == 1) { | |
187 audioEngineContext.stop(); | |
188 this.innerHTML = 'Stop'; | |
189 var time = audioEngineContext.timer.getTestTime(); | |
190 console.log('Stopped at ' + time); // DEBUG/SAFETY | |
191 } | |
192 }; | |
193 // Create Submit (save) button | |
194 var submit = document.createElement("button"); | |
195 submit.innerHTML = 'Submit'; | |
196 submit.onclick = buttonSubmitClick; | |
197 submit.id = 'submit-button'; | |
198 // Append the interface buttons into the interfaceButtons object. | |
199 interfaceButtons.appendChild(playback); | |
200 interfaceButtons.appendChild(submit); | |
201 | |
202 // Now create the slider and HTML5 canvas boxes | |
203 | |
204 // Create the div box to center align | |
205 var sliderBox = document.createElement('div'); | |
206 sliderBox.className = 'sliderCanvasDiv'; | |
207 sliderBox.id = 'sliderCanvasHolder'; | |
208 | |
209 // Create the slider box to hold the slider elements | |
210 var canvas = document.createElement('div'); | |
211 canvas.id = 'slider'; | |
212 canvas.align = "left"; | |
213 canvas.addEventListener('dragover',function(event){ | |
214 event.preventDefault(); | |
215 return false; | |
216 },false); | |
217 var sliderMargin = document.createAttribute('marginsize'); | |
218 sliderMargin.nodeValue = 42; // Set default margins to 42px either side | |
219 // Must have a known EXACT width, as this is used later to determine the ratings | |
220 var w = (Number(sliderMargin.nodeValue)+8)*2; | |
221 canvas.style.width = width - w +"px"; | |
222 canvas.style.marginLeft = sliderMargin.nodeValue +'px'; | |
223 canvas.setAttributeNode(sliderMargin); | |
224 sliderBox.appendChild(canvas); | |
225 | |
226 // Create the div to hold any scale objects | |
227 var scale = document.createElement('div'); | |
228 scale.className = 'sliderScale'; | |
229 scale.id = 'sliderScaleHolder'; | |
230 scale.align = 'left'; | |
231 sliderBox.appendChild(scale); | |
232 | |
233 // Global parent for the comment boxes on the page | |
234 var feedbackHolder = document.createElement('div'); | |
235 feedbackHolder.id = 'feedbackHolder'; | |
236 | |
237 testContent.style.zIndex = 1; | |
238 interfaceContext.insertPoint.innerHTML = null; // Clear the current schema | |
239 | |
240 // Inject into HTML | |
241 testContent.appendChild(title); // Insert the title | |
242 testContent.appendChild(pagetitle); | |
243 testContent.appendChild(interfaceButtons); | |
244 testContent.appendChild(sliderBox); | |
245 testContent.appendChild(feedbackHolder); | |
246 interfaceContext.insertPoint.appendChild(testContent); | |
247 | |
248 // Load the full interface | |
249 testState.initialise(); | |
250 testState.advanceState(); | |
251 | |
252 } | |
253 | |
254 function loadTest(audioHolderObject) | |
255 { | |
256 | |
257 // Reset audioEngineContext.Metric globals for new test | |
258 audioEngineContext.newTestPage(); | |
259 | |
260 var id = audioHolderObject.id; | |
261 | |
262 var feedbackHolder = document.getElementById('feedbackHolder'); | |
263 var canvas = document.getElementById('slider'); | |
264 feedbackHolder.innerHTML = null; | |
265 canvas.innerHTML = null; | |
266 | |
267 //var playbackHolder = document.createElement('div'); | |
268 //playbackHolder.style.width = "100%"; | |
269 //playbackHolder.align = 'center'; | |
270 //playbackHolder.appendChild(interfaceContext.playhead.object); | |
271 //feedbackHolder.appendChild(playbackHolder); | |
272 // Setup question title | |
273 var interfaceObj = audioHolderObject.interfaces; | |
274 var commentBoxPrefix = "Comment on track"; | |
275 if (interfaceObj.length != 0) { | |
276 interfaceObj = interfaceObj[0]; | |
277 var titleNode = interfaceObj.title; | |
278 if (titleNode != undefined) | |
279 { | |
280 document.getElementById('pageTitle').textContent = titleNode; | |
281 } | |
282 var positionScale = canvas.style.width.substr(0,canvas.style.width.length-2); | |
283 var offset = Number(document.getElementById('slider').attributes['marginsize'].value); | |
284 var scale = document.getElementById('sliderScaleHolder'); | |
285 scale.innerHTML = null; | |
286 $(interfaceObj.scale).each(function(index,scaleObj){ | |
287 var value = document.createAttribute('value'); | |
288 var position = Number(scaleObj[0])*0.01; | |
289 value.nodeValue = position; | |
290 var pixelPosition = (position*positionScale)+offset; | |
291 var scaleDOM = document.createElement('span'); | |
292 scaleDOM.textContent = scaleObj[1]; | |
293 scale.appendChild(scaleDOM); | |
294 scaleDOM.style.left = Math.floor((pixelPosition-($(scaleDOM).width()/2)))+'px'; | |
295 scaleDOM.setAttributeNode(value); | |
296 }); | |
297 | |
298 if (interfaceObj.commentBoxPrefix != undefined) { | |
299 commentBoxPrefix = interfaceObj.commentBoxPrefix; | |
300 } | |
301 } | |
302 | |
303 /// CHECK FOR SAMPLE RATE COMPATIBILITY | |
304 if (audioHolderObject.sampleRate != undefined) { | |
305 if (Number(audioHolderObject.sampleRate) != audioContext.sampleRate) { | |
306 var errStr = 'Sample rates do not match! Requested '+Number(audioHolderObject.sampleRate)+', got '+audioContext.sampleRate+'. Please set the sample rate to match before completing this test.'; | |
307 alert(errStr); | |
308 return; | |
309 } | |
310 } | |
311 | |
312 var commentShow = audioHolderObject.elementComments; | |
313 | |
314 var loopPlayback = audioHolderObject.loop; | |
315 | |
316 audioEngineContext.loopPlayback = loopPlayback; | |
317 // Create AudioEngine bindings for playback | |
318 audioEngineContext.selectedTrack = function(id) { | |
319 console.log('Deprecated'); | |
320 }; | |
321 | |
322 currentTestHolder = document.createElement('audioHolder'); | |
323 currentTestHolder.id = audioHolderObject.id; | |
324 currentTestHolder.repeatCount = audioHolderObject.repeatCount; | |
325 | |
326 var randomise = audioHolderObject.randomiseOrder; | |
327 | |
328 var audioElements = audioHolderObject.audioElements; | |
329 currentTrackOrder = []; | |
330 if (randomise) { | |
331 audioHolderObject.audioElements = randomiseOrder(audioHolderObject.audioElements); | |
332 } | |
333 | |
334 // Delete any previous audioObjects associated with the audioEngine | |
335 audioEngineContext.audioObjects = []; | |
336 interfaceContext.deleteCommentBoxes(); | |
337 interfaceContext.deleteCommentQuestions(); | |
338 | |
339 // Find all the audioElements from the audioHolder | |
340 $(audioHolderObject.audioElements).each(function(index,element){ | |
341 // Find URL of track | |
342 // In this jQuery loop, variable 'this' holds the current audioElement. | |
343 | |
344 // Now load each audio sample. First create the new track by passing the full URL | |
345 var trackURL = audioHolderObject.hostURL + element.url; | |
346 var audioObject = audioEngineContext.newTrack(element); | |
347 | |
348 var node = interfaceContext.createCommentBox(audioObject); | |
349 | |
350 // Create a slider per track | |
351 audioObject.interfaceDOM = new sliderObject(audioObject); | |
352 | |
353 // Distribute it randomnly | |
354 var w = window.innerWidth - (offset+8)*2; | |
355 w = Math.random()*w; | |
356 w = Math.floor(w+(offset+8)); | |
357 audioObject.interfaceDOM.trackSliderObj.style.left = w+'px'; | |
358 | |
359 canvas.appendChild(audioObject.interfaceDOM.trackSliderObj); | |
360 audioObject.metric.initialised(convSliderPosToRate(audioObject.interfaceDOM.trackSliderObj)); | |
361 | |
362 }); | |
363 if (commentShow) { | |
364 interfaceContext.showCommentBoxes(feedbackHolder,true); | |
365 } | |
366 | |
367 $(audioHolderObject.commentQuestions).each(function(index,element) { | |
368 var node = interfaceContext.createCommentQuestion(element); | |
369 feedbackHolder.appendChild(node.holder); | |
370 }); | |
371 | |
372 | |
373 testWaitIndicator(); | |
374 } | |
375 | |
376 function sliderObject(audioObject) { | |
377 // Create a new slider object; | |
378 this.parent = audioObject; | |
379 this.trackSliderObj = document.createElement('div'); | |
380 this.trackSliderObj.className = 'track-slider'; | |
381 this.trackSliderObj.id = 'track-slider-'+audioObject.id; | |
382 | |
383 this.trackSliderObj.setAttribute('trackIndex',audioObject.id); | |
384 this.trackSliderObj.innerHTML = '<span>'+audioObject.id+'</span>'; | |
385 this.trackSliderObj.draggable = true; | |
386 this.trackSliderObj.ondragend = dragEnd; | |
387 | |
388 // Onclick, switch playback to that track | |
389 this.trackSliderObj.onclick = function() { | |
390 // Start the test on first click, that way timings are more accurate. | |
391 audioEngineContext.play(); | |
392 if (audioEngineContext.audioObjectsReady) { | |
393 // Cannot continue to issue play command until audioObjects reported as ready! | |
394 // Get the track ID from the object ID | |
395 var element; | |
396 if (event.srcElement.nodeName == "SPAN") { | |
397 element = event.srcElement.parentNode; | |
398 } else { | |
399 element = event.srcElement; | |
400 } | |
401 var id = Number(element.attributes['trackIndex'].value); | |
402 //audioEngineContext.metric.sliderPlayed(id); | |
403 audioEngineContext.play(id); | |
404 // Currently playing track red, rest green | |
405 | |
406 //document.getElementById('track-slider-'+index).style.backgroundColor = "#FF0000"; | |
407 $('.track-slider').removeClass('track-slider-playing'); | |
408 $(element).addClass('track-slider-playing'); | |
409 $('.comment-div').removeClass('comment-box-playing'); | |
410 $('#comment-div-'+id).addClass('comment-box-playing'); | |
411 } | |
412 }; | |
413 | |
414 this.exportXMLDOM = function(audioObject) { | |
415 // Called by the audioObject holding this element. Must be present | |
416 var node = document.createElement('value'); | |
417 node.textContent = convSliderPosToRate(this.trackSliderObj); | |
418 return node; | |
419 }; | |
420 this.getValue = function() { | |
421 return convSliderPosToRate(this.trackSliderObj); | |
422 }; | |
423 } | |
424 | |
425 function dragEnd(ev) { | |
426 // Function call when a div has been dropped | |
427 var slider = document.getElementById('slider'); | |
428 var marginSize = Number(slider.attributes['marginsize'].value); | |
429 var w = slider.style.width; | |
430 w = Number(w.substr(0,w.length-2)); | |
431 var x = ev.x; | |
432 if (x >= marginSize && x < w+marginSize) { | |
433 this.style.left = (x)+'px'; | |
434 } else { | |
435 if (x<marginSize) { | |
436 this.style.left = marginSize+'px'; | |
437 } else { | |
438 this.style.left = (w+marginSize) + 'px'; | |
439 } | |
440 } | |
441 var time = audioEngineContext.timer.getTestTime(); | |
442 var id = Number(ev.srcElement.getAttribute('trackindex')); | |
443 audioEngineContext.audioObjects[id].metric.moved(time,convSliderPosToRate(ev.srcElement)); | |
444 } | |
445 | |
446 function buttonSubmitClick() // TODO: Only when all songs have been played! | |
447 { | |
448 var checks = specification.commonInterface.options; | |
449 var canContinue = true; | |
450 | |
451 // Check that the anchor and reference objects are correctly placed | |
452 var audioObjs = audioEngineContext.audioObjects; | |
453 var audioHolder = testState.stateMap[testState.stateIndex]; | |
454 var anchorId = null; | |
455 var referenceId = null; | |
456 for (var i=0; i<audioObjs.length; i++) { | |
457 if (audioObjs[i].specification.anchor == true && anchorId == null) {anchorId = i;} | |
458 if (audioObjs[i].specification.reference == true && referenceId == null) {referenceId = i;} | |
459 } | |
460 if (anchorId != null) { | |
461 if (audioObjs[anchorId].specification.marker != null) { | |
462 if (audioObjs[anchorId].interfaceDOM.getValue() > audioObjs[anchorId].specification.marker) | |
463 { | |
464 // Anchor is not set below | |
465 console.log('Anchor node not below marker value'); | |
466 alert('Please keep listening'); | |
467 return; | |
468 } | |
469 } else { | |
470 // No marker value given, ensure it is the minimum value | |
471 var anchorVal = audioObjs[anchorId].interfaceDOM.getValue(); | |
472 for (var i=0; i<audioObjs.length; i++) { | |
473 if (i != anchorId) { | |
474 if (anchorVal > audioObjs[i].interfaceDOM.getValue()) { | |
475 // Anchor not the minimum | |
476 console.log('No marker set, anchor node not the minimum'); | |
477 alert('Please keep listening'); | |
478 return; | |
479 } | |
480 } | |
481 } | |
482 } | |
483 } | |
484 if (referenceId != null) { | |
485 if (audioObjs[referenceId].specification.marker != null) { | |
486 if (audioObjs[referenceId].interfaceDOM.getValue() < audioObjs[referenceId].specification.marker) | |
487 { | |
488 // Anchor is not set below | |
489 console.log('Reference node not above marker value'); | |
490 alert('Please keep listening'); | |
491 return; | |
492 } | |
493 } else { | |
494 // No marker value given, ensure it is the minimum value | |
495 var referenceVal = audioObjs[referenceId].interfaceDOM.getValue(); | |
496 for (var i=0; i<audioObjs.length; i++) { | |
497 if (i != referenceId) { | |
498 if (referenceVal > audioObjs[i].interfaceDOM.getValue()) { | |
499 // Anchor not the minimum | |
500 console.log('No marker set, reference node not the maximum'); | |
501 alert('Please keep listening'); | |
502 return; | |
503 } | |
504 } | |
505 } | |
506 } | |
507 } | |
508 | |
509 for (var i=0; i<checks.length; i++) { | |
510 if (checks[i].type == 'check') | |
511 { | |
512 switch(checks[i].check) { | |
513 case 'fragmentPlayed': | |
514 // Check if all fragments have been played | |
515 var checkState = interfaceContext.checkAllPlayed(); | |
516 if (checkState == false) {canContinue = false;} | |
517 break; | |
518 case 'fragmentFullPlayback': | |
519 // Check all fragments have been played to their full length | |
520 var checkState = interfaceContext.checkAllPlayed(); | |
521 if (checkState == false) {canContinue = false;} | |
522 console.log('NOTE: fragmentFullPlayback not currently implemented, performing check fragmentPlayed instead'); | |
523 break; | |
524 case 'fragmentMoved': | |
525 // Check all fragment sliders have been moved. | |
526 var checkState = interfaceContext.checkAllMoved(); | |
527 if (checkState == false) {canContinue = false;} | |
528 break; | |
529 case 'fragmentComments': | |
530 // Check all fragment sliders have been moved. | |
531 var checkState = interfaceContext.checkAllCommented(); | |
532 if (checkState == false) {canContinue = false;} | |
533 break; | |
534 } | |
535 | |
536 } | |
537 } | |
538 | |
539 if (canContinue) { | |
540 if (audioEngineContext.status == 1) { | |
541 var playback = document.getElementById('playback-button'); | |
542 playback.click(); | |
543 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options | |
544 } else | |
545 { | |
546 if (audioEngineContext.timer.testStarted == false) | |
547 { | |
548 alert('You have not started the test! Please press start to begin the test!'); | |
549 return; | |
550 } | |
551 } | |
552 testState.advanceState(); | |
553 } | |
554 } | |
555 | |
556 function convSliderPosToRate(slider) | |
557 { | |
558 var w = document.getElementById('slider').style.width; | |
559 var marginsize = Number(document.getElementById('slider').attributes['marginsize'].value); | |
560 var maxPix = w.substr(0,w.length-2); | |
561 var pix = slider.style.left; | |
562 pix = pix.substr(0,pix.length-2); | |
563 var rate = (pix-marginsize)/maxPix; | |
564 return rate; | |
565 } | |
566 | |
567 function resizeWindow(event){ | |
568 // Function called when the window has been resized. | |
569 // MANDATORY FUNCTION | |
570 | |
571 // Store the slider marker values | |
572 var holdValues = []; | |
573 $(".track-slider").each(function(index,sliderObj){ | |
574 holdValues.push(convSliderPosToRate(index)); | |
575 }); | |
576 | |
577 var width = event.target.innerWidth; | |
578 var canvas = document.getElementById('sliderCanvasHolder'); | |
579 var sliderDiv = canvas.children[0]; | |
580 var sliderScaleDiv = canvas.children[1]; | |
581 var marginsize = Number(sliderDiv.attributes['marginsize'].value); | |
582 var w = (marginsize+8)*2; | |
583 sliderDiv.style.width = width - w + 'px'; | |
584 var width = width - w; | |
585 // Move sliders into new position | |
586 $(".track-slider").each(function(index,sliderObj){ | |
587 var pos = holdValues[index]; | |
588 var pix = pos * width; | |
589 sliderObj.style.left = pix+marginsize+'px'; | |
590 }); | |
591 | |
592 // Move scale labels | |
593 $(sliderScaleDiv.children).each(function(index,scaleObj){ | |
594 var position = Number(scaleObj.attributes['value'].value); | |
595 var pixelPosition = (position*width)+marginsize; | |
596 scaleObj.style.left = Math.floor((pixelPosition-($(scaleObj).width()/2)))+'px'; | |
597 }); | |
598 } | |
599 | |
600 function pageXMLSave(store, testXML) | |
601 { | |
602 // Saves a specific test page | |
603 var xmlDoc = store; | |
604 // Check if any session wide metrics are enabled | |
605 | |
606 var commentShow = testXML.elementComments; | |
607 | |
608 var metric = document.createElement('metric'); | |
609 if (audioEngineContext.metric.enableTestTimer) | |
610 { | |
611 var testTime = document.createElement('metricResult'); | |
612 testTime.id = 'testTime'; | |
613 testTime.textContent = audioEngineContext.timer.testDuration; | |
614 metric.appendChild(testTime); | |
615 } | |
616 xmlDoc.appendChild(metric); | |
617 var audioObjects = audioEngineContext.audioObjects; | |
618 for (var i=0; i<audioObjects.length; i++) | |
619 { | |
620 var audioElement = audioEngineContext.audioObjects[i].exportXMLDOM(); | |
621 xmlDoc.appendChild(audioElement); | |
622 } | |
623 | |
624 $(interfaceContext.commentQuestions).each(function(index,element){ | |
625 var node = element.exportXMLDOM(); | |
626 xmlDoc.appendChild(node); | |
627 }); | |
628 store = xmlDoc; | |
629 } |