Mercurial > hg > webaudioevaluationtool
comparison ape.js @ 1575:9eae8c728460
Merge from the default branch
author | Nicholas Jillings <nickjillings@users.noreply.github.com> |
---|---|
date | Thu, 04 Jun 2015 10:36:05 +0100 |
parents | |
children | 6d37dd0f1dc7 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 1575:9eae8c728460 |
---|---|
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(projectXML); | |
15 | |
16 function loadInterface(xmlDoc) { | |
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 var insertPoint = document.getElementById("topLevelBody"); | |
24 var testContent = document.createElement('div'); | |
25 | |
26 testContent.id = 'testContent'; | |
27 | |
28 | |
29 // Decode parts of the xmlDoc that are needed | |
30 // xmlDoc MUST already be parsed by jQuery! | |
31 var xmlSetup = xmlDoc.find('setup'); | |
32 // Should put in an error function here incase of malprocessed or malformed XML | |
33 | |
34 // Create pre and post test questions | |
35 | |
36 var preTest = xmlSetup.find('PreTest'); | |
37 var postTest = xmlSetup.find('PostTest'); | |
38 preTest = preTest[0]; | |
39 postTest = postTest[0]; | |
40 | |
41 if (preTest == undefined) {preTest = document.createElement("preTest");} | |
42 if (postTest == undefined){postTest= document.createElement("postTest");} | |
43 | |
44 testState.stateMap.push(preTest); | |
45 | |
46 // Extract the different test XML DOM trees | |
47 var audioHolders = xmlDoc.find('audioHolder'); | |
48 var testXMLSetups = []; | |
49 audioHolders.each(function(index,element) { | |
50 var repeatN = element.attributes['repeatCount'].value; | |
51 for (var r=0; r<=repeatN; r++) { | |
52 testXMLSetups.push(element); | |
53 } | |
54 }); | |
55 | |
56 // New check if we need to randomise the test order | |
57 var randomise = xmlSetup[0].attributes['randomiseOrder']; | |
58 if (randomise != undefined) { | |
59 if (randomise.value === 'true'){ | |
60 randomise = true; | |
61 } else { | |
62 randomise = false; | |
63 } | |
64 } else { | |
65 randomise = false; | |
66 } | |
67 | |
68 if (randomise) | |
69 { | |
70 testXMLSetups = randomiseOrder(testXMLSetups); | |
71 } | |
72 | |
73 $(testXMLSetups).each(function(index,elem){ | |
74 testState.stateMap.push(elem); | |
75 }) | |
76 | |
77 testState.stateMap.push(postTest); | |
78 | |
79 // Obtain the metrics enabled | |
80 var metricNode = xmlSetup.find('Metric'); | |
81 var metricNode = metricNode.find('metricEnable'); | |
82 metricNode.each(function(index,node){ | |
83 var enabled = node.textContent; | |
84 switch(enabled) | |
85 { | |
86 case 'testTimer': | |
87 sessionMetrics.prototype.enableTestTimer = true; | |
88 break; | |
89 case 'elementTimer': | |
90 sessionMetrics.prototype.enableElementTimer = true; | |
91 break; | |
92 case 'elementTracker': | |
93 sessionMetrics.prototype.enableElementTracker = true; | |
94 break; | |
95 case 'elementListenTracker': | |
96 sessionMetrics.prototype.enableElementListenTracker = true; | |
97 break; | |
98 case 'elementInitialPosition': | |
99 sessionMetrics.prototype.enableElementInitialPosition = true; | |
100 break; | |
101 case 'elementFlagListenedTo': | |
102 sessionMetrics.prototype.enableFlagListenedTo = true; | |
103 break; | |
104 case 'elementFlagMoved': | |
105 sessionMetrics.prototype.enableFlagMoved = true; | |
106 break; | |
107 case 'elementFlagComments': | |
108 sessionMetrics.prototype.enableFlagComments = true; | |
109 break; | |
110 } | |
111 }); | |
112 | |
113 // Create APE specific metric functions | |
114 audioEngineContext.metric.initialiseTest = function() | |
115 { | |
116 }; | |
117 | |
118 audioEngineContext.metric.sliderMoveStart = function(id) | |
119 { | |
120 if (this.data == -1) | |
121 { | |
122 this.data = id; | |
123 } else { | |
124 console.log('ERROR: Metric tracker detecting two moves!'); | |
125 this.data = -1; | |
126 } | |
127 }; | |
128 audioEngineContext.metric.sliderMoved = function() | |
129 { | |
130 var time = audioEngineContext.timer.getTestTime(); | |
131 var id = this.data; | |
132 this.data = -1; | |
133 var position = convSliderPosToRate(id); | |
134 console.log('slider ' + id + ': '+ position + ' (' + time + ')'); // DEBUG/SAFETY: show position and slider id | |
135 if (audioEngineContext.timer.testStarted) | |
136 { | |
137 audioEngineContext.audioObjects[id].metric.moved(time,position); | |
138 } | |
139 }; | |
140 | |
141 audioEngineContext.metric.sliderPlayed = function(id) | |
142 { | |
143 var time = audioEngineContext.timer.getTestTime(); | |
144 if (audioEngineContext.timer.testStarted) | |
145 { | |
146 if (this.lastClicked >= 0) | |
147 { | |
148 audioEngineContext.audioObjects[this.lastClicked].metric.listening(time); | |
149 } | |
150 this.lastClicked = id; | |
151 audioEngineContext.audioObjects[id].metric.listening(time); | |
152 } | |
153 console.log('slider ' + id + ' played (' + time + ')'); // DEBUG/SAFETY: show played slider id | |
154 }; | |
155 | |
156 // Create the top div for the Title element | |
157 var titleAttr = xmlSetup[0].attributes['title']; | |
158 var title = document.createElement('div'); | |
159 title.className = "title"; | |
160 title.align = "center"; | |
161 var titleSpan = document.createElement('span'); | |
162 | |
163 // Set title to that defined in XML, else set to default | |
164 if (titleAttr != undefined) { | |
165 titleSpan.innerHTML = titleAttr.value; | |
166 } else { | |
167 titleSpan.innerHTML = 'Listening test'; | |
168 } | |
169 // Insert the titleSpan element into the title div element. | |
170 title.appendChild(titleSpan); | |
171 | |
172 var pagetitle = document.createElement('div'); | |
173 pagetitle.className = "pageTitle"; | |
174 pagetitle.align = "center"; | |
175 var titleSpan = document.createElement('span'); | |
176 titleSpan.id = "pageTitle"; | |
177 pagetitle.appendChild(titleSpan); | |
178 | |
179 // Store the return URL path in global projectReturn | |
180 projectReturn = xmlSetup[0].attributes['projectReturn']; | |
181 if (projectReturn == undefined) { | |
182 console.log("WARNING - projectReturn not specified! Will assume null."); | |
183 projectReturn = "null"; | |
184 } else { | |
185 projectReturn = projectReturn.value; | |
186 } | |
187 | |
188 // Create Interface buttons! | |
189 var interfaceButtons = document.createElement('div'); | |
190 interfaceButtons.id = 'interface-buttons'; | |
191 | |
192 // MANUAL DOWNLOAD POINT | |
193 // If project return is null, this MUST be specified as the location to create the download link | |
194 var downloadPoint = document.createElement('div'); | |
195 downloadPoint.id = 'download-point'; | |
196 | |
197 // Create playback start/stop points | |
198 var playback = document.createElement("button"); | |
199 playback.innerHTML = 'Stop'; | |
200 playback.id = 'playback-button'; | |
201 // onclick function. Check if it is playing or not, call the correct function in the | |
202 // audioEngine, change the button text to reflect the next state. | |
203 playback.onclick = function() { | |
204 if (audioEngineContext.status == 1) { | |
205 audioEngineContext.stop(); | |
206 this.innerHTML = 'Stop'; | |
207 var time = audioEngineContext.timer.getTestTime(); | |
208 console.log('Stopped at ' + time); // DEBUG/SAFETY | |
209 } | |
210 }; | |
211 // Create Submit (save) button | |
212 var submit = document.createElement("button"); | |
213 submit.innerHTML = 'Submit'; | |
214 submit.onclick = buttonSubmitClick; | |
215 submit.id = 'submit-button'; | |
216 // Append the interface buttons into the interfaceButtons object. | |
217 interfaceButtons.appendChild(playback); | |
218 interfaceButtons.appendChild(submit); | |
219 interfaceButtons.appendChild(downloadPoint); | |
220 | |
221 // Now create the slider and HTML5 canvas boxes | |
222 | |
223 // Create the div box to center align | |
224 var sliderBox = document.createElement('div'); | |
225 sliderBox.className = 'sliderCanvasDiv'; | |
226 sliderBox.id = 'sliderCanvasHolder'; | |
227 | |
228 // Create the slider box to hold the slider elements | |
229 var canvas = document.createElement('div'); | |
230 canvas.id = 'slider'; | |
231 canvas.align = "left"; | |
232 canvas.addEventListener('dragover',function(event){ | |
233 event.preventDefault(); | |
234 return false; | |
235 },false); | |
236 var sliderMargin = document.createAttribute('marginsize'); | |
237 sliderMargin.nodeValue = 42; // Set default margins to 42px either side | |
238 // Must have a known EXACT width, as this is used later to determine the ratings | |
239 var w = (Number(sliderMargin.nodeValue)+8)*2; | |
240 canvas.style.width = width - w +"px"; | |
241 canvas.style.marginLeft = sliderMargin.nodeValue +'px'; | |
242 canvas.setAttributeNode(sliderMargin); | |
243 sliderBox.appendChild(canvas); | |
244 | |
245 // Create the div to hold any scale objects | |
246 var scale = document.createElement('div'); | |
247 scale.className = 'sliderScale'; | |
248 scale.id = 'sliderScaleHolder'; | |
249 scale.align = 'left'; | |
250 sliderBox.appendChild(scale); | |
251 | |
252 // Global parent for the comment boxes on the page | |
253 var feedbackHolder = document.createElement('div'); | |
254 feedbackHolder.id = 'feedbackHolder'; | |
255 | |
256 testContent.style.zIndex = 1; | |
257 insertPoint.innerHTML = null; // Clear the current schema | |
258 | |
259 currentState = 'preTest'; | |
260 | |
261 // Inject into HTML | |
262 testContent.appendChild(title); // Insert the title | |
263 testContent.appendChild(pagetitle); | |
264 testContent.appendChild(interfaceButtons); | |
265 testContent.appendChild(sliderBox); | |
266 testContent.appendChild(feedbackHolder); | |
267 insertPoint.appendChild(testContent); | |
268 | |
269 // Load the full interface | |
270 testState.initialise(); | |
271 testState.advanceState(); | |
272 | |
273 } | |
274 | |
275 function loadTest(textXML) | |
276 { | |
277 | |
278 // Reset audioEngineContext.Metric globals for new test | |
279 audioEngineContext.newTestPage(); | |
280 | |
281 var id = textXML.id; | |
282 | |
283 var feedbackHolder = document.getElementById('feedbackHolder'); | |
284 var canvas = document.getElementById('slider'); | |
285 feedbackHolder.innerHTML = null; | |
286 canvas.innerHTML = null; | |
287 | |
288 // Setup question title | |
289 var interfaceObj = $(textXML).find('interface'); | |
290 var titleNode = interfaceObj.find('title'); | |
291 if (titleNode[0] != undefined) | |
292 { | |
293 document.getElementById('pageTitle').textContent = titleNode[0].textContent; | |
294 } | |
295 var positionScale = canvas.style.width.substr(0,canvas.style.width.length-2); | |
296 var offset = Number(document.getElementById('slider').attributes['marginsize'].value); | |
297 var scale = document.getElementById('sliderScaleHolder'); | |
298 scale.innerHTML = null; | |
299 interfaceObj.find('scale').each(function(index,scaleObj){ | |
300 var value = document.createAttribute('value'); | |
301 var position = Number(scaleObj.attributes['position'].value)*0.01; | |
302 value.nodeValue = position; | |
303 var pixelPosition = (position*positionScale)+offset; | |
304 var scaleDOM = document.createElement('span'); | |
305 scaleDOM.textContent = scaleObj.textContent; | |
306 scale.appendChild(scaleDOM); | |
307 scaleDOM.style.left = Math.floor((pixelPosition-($(scaleDOM).width()/2)))+'px'; | |
308 scaleDOM.setAttributeNode(value); | |
309 }); | |
310 | |
311 var commentBoxPrefix = interfaceObj.find('commentBoxPrefix'); | |
312 if (commentBoxPrefix.length != 0) { | |
313 commentBoxPrefix = commentBoxPrefix[0].textContent; | |
314 } else { | |
315 commentBoxPrefix = "Comment on track"; | |
316 } | |
317 | |
318 // Extract the hostURL attribute. If not set, create an empty string. | |
319 var hostURL = textXML.attributes['hostURL']; | |
320 if (hostURL == undefined) { | |
321 hostURL = ""; | |
322 } else { | |
323 hostURL = hostURL.value; | |
324 } | |
325 // Extract the sampleRate. If set, convert the string to a Number. | |
326 var hostFs = textXML.attributes['sampleRate']; | |
327 if (hostFs != undefined) { | |
328 hostFs = Number(hostFs.value); | |
329 } | |
330 | |
331 /// CHECK FOR SAMPLE RATE COMPATIBILITY | |
332 if (hostFs != undefined) { | |
333 if (Number(hostFs) != audioContext.sampleRate) { | |
334 var errStr = 'Sample rates do not match! Requested '+Number(hostFs)+', got '+audioContext.sampleRate+'. Please set the sample rate to match before completing this test.'; | |
335 alert(errStr); | |
336 return; | |
337 } | |
338 } | |
339 | |
340 var commentShow = textXML.attributes['elementComments']; | |
341 if (commentShow != undefined) { | |
342 if (commentShow.value == 'false') {commentShow = false;} | |
343 else {commentShow = true;} | |
344 } else {commentShow = true;} | |
345 | |
346 var loopPlayback = textXML.attributes['loop']; | |
347 if (loopPlayback != undefined) | |
348 { | |
349 loopPlayback = loopPlayback.value; | |
350 if (loopPlayback == 'true') { | |
351 loopPlayback = true; | |
352 } else { | |
353 loopPlayback = false; | |
354 } | |
355 } else { | |
356 loopPlayback = false; | |
357 } | |
358 audioEngineContext.loopPlayback = loopPlayback; | |
359 // Create AudioEngine bindings for playback | |
360 if (loopPlayback) { | |
361 audioEngineContext.selectedTrack = function(id) { | |
362 for (var i=0; i<this.audioObjects.length; i++) | |
363 { | |
364 if (id == i) { | |
365 this.audioObjects[i].loopStart(); | |
366 } else { | |
367 this.audioObjects[i].loopStop(); | |
368 } | |
369 } | |
370 }; | |
371 } else { | |
372 audioEngineContext.selectedTrack = function(id) { | |
373 for (var i=0; i<this.audioObjects.length; i++) | |
374 { | |
375 this.audioObjects[i].outputGain.gain.value = 0.0; | |
376 this.audioObjects[i].stop(); | |
377 } | |
378 if (this.status == 1) { | |
379 this.audioObjects[id].outputGain.gain.value = 1.0; | |
380 this.audioObjects[id].play(audioContext.currentTime+0.01); | |
381 } | |
382 }; | |
383 } | |
384 | |
385 currentTestHolder = document.createElement('audioHolder'); | |
386 currentTestHolder.id = textXML.id; | |
387 currentTestHolder.repeatCount = textXML.attributes['repeatCount'].value; | |
388 | |
389 var randomise = textXML.attributes['randomiseOrder']; | |
390 if (randomise != undefined) {randomise = randomise.value;} | |
391 else {randomise = false;} | |
392 | |
393 var audioElements = $(textXML).find('audioElements'); | |
394 currentTrackOrder = []; | |
395 audioElements.each(function(index,element){ | |
396 // Find any blind-repeats | |
397 // Not implemented yet, but just in case | |
398 currentTrackOrder[index] = element; | |
399 }); | |
400 if (randomise) { | |
401 currentTrackOrder = randomiseOrder(currentTrackOrder); | |
402 } | |
403 | |
404 // Delete any previous audioObjects associated with the audioEngine | |
405 audioEngineContext.audioObjects = []; | |
406 | |
407 // Find all the audioElements from the audioHolder | |
408 $(currentTrackOrder).each(function(index,element){ | |
409 // Find URL of track | |
410 // In this jQuery loop, variable 'this' holds the current audioElement. | |
411 | |
412 // Now load each audio sample. First create the new track by passing the full URL | |
413 var trackURL = hostURL + this.attributes['url'].value; | |
414 audioEngineContext.newTrack(trackURL); | |
415 | |
416 if (commentShow) { | |
417 // Create document objects to hold the comment boxes | |
418 var trackComment = document.createElement('div'); | |
419 trackComment.className = 'comment-div'; | |
420 trackComment.id = 'comment-div-'+index; | |
421 // Create a string next to each comment asking for a comment | |
422 var trackString = document.createElement('span'); | |
423 trackString.innerHTML = commentBoxPrefix+' '+index; | |
424 // Create the HTML5 comment box 'textarea' | |
425 var trackCommentBox = document.createElement('textarea'); | |
426 trackCommentBox.rows = '4'; | |
427 trackCommentBox.cols = '100'; | |
428 trackCommentBox.name = 'trackComment'+index; | |
429 trackCommentBox.className = 'trackComment'; | |
430 var br = document.createElement('br'); | |
431 // Add to the holder. | |
432 trackComment.appendChild(trackString); | |
433 trackComment.appendChild(br); | |
434 trackComment.appendChild(trackCommentBox); | |
435 feedbackHolder.appendChild(trackComment); | |
436 } | |
437 | |
438 // Create a slider per track | |
439 | |
440 var trackSliderObj = document.createElement('div'); | |
441 trackSliderObj.className = 'track-slider'; | |
442 trackSliderObj.id = 'track-slider-'+index; | |
443 | |
444 var trackSliderAOIndex = document.createAttribute('trackIndex'); | |
445 trackSliderAOIndex.nodeValue = index; | |
446 trackSliderObj.setAttributeNode(trackSliderAOIndex); | |
447 | |
448 // Distribute it randomnly | |
449 var w = window.innerWidth - (offset+8)*2; | |
450 w = Math.random()*w; | |
451 w = Math.floor(w+(offset+8)); | |
452 trackSliderObj.style.left = w+'px'; | |
453 trackSliderObj.innerHTML = '<span>'+index+'</span>'; | |
454 trackSliderObj.draggable = true; | |
455 trackSliderObj.ondragend = dragEnd; | |
456 trackSliderObj.ondragstart = function() | |
457 { | |
458 var id = Number(event.srcElement.attributes['trackIndex'].value); | |
459 audioEngineContext.metric.sliderMoveStart(id); | |
460 }; | |
461 | |
462 // Onclick, switch playback to that track | |
463 trackSliderObj.onclick = function() { | |
464 // Start the test on first click, that way timings are more accurate. | |
465 audioEngineContext.play(); | |
466 if (audioEngineContext.audioObjectsReady) { | |
467 // Cannot continue to issue play command until audioObjects reported as ready! | |
468 // Get the track ID from the object ID | |
469 var id = Number(event.srcElement.attributes['trackIndex'].value); | |
470 //audioEngineContext.metric.sliderPlayed(id); | |
471 audioEngineContext.selectedTrack(id); | |
472 // Currently playing track red, rest green | |
473 | |
474 //document.getElementById('track-slider-'+index).style.backgroundColor = "#FF0000"; | |
475 $('.track-slider').removeClass('track-slider-playing'); | |
476 $(event.srcElement).addClass('track-slider-playing'); | |
477 $('.comment-div').removeClass('comment-box-playing'); | |
478 $('#comment-div-'+id).addClass('comment-box-playing'); | |
479 } | |
480 }; | |
481 | |
482 canvas.appendChild(trackSliderObj); | |
483 audioEngineContext.audioObjects[index].metric.initialised(convSliderPosToRate(index)); | |
484 | |
485 }); | |
486 | |
487 // Append any commentQuestion boxes | |
488 var commentQuestions = $(textXML).find('CommentQuestion'); | |
489 $(commentQuestions).each(function(index,element) { | |
490 // Create document objects to hold the comment boxes | |
491 var trackComment = document.createElement('div'); | |
492 trackComment.className = 'comment-div commentQuestion'; | |
493 trackComment.id = element.attributes['id'].value; | |
494 // Create a string next to each comment asking for a comment | |
495 var trackString = document.createElement('span'); | |
496 trackString.innerHTML = element.textContent; | |
497 // Create the HTML5 comment box 'textarea' | |
498 var trackCommentBox = document.createElement('textarea'); | |
499 trackCommentBox.rows = '4'; | |
500 trackCommentBox.cols = '100'; | |
501 trackCommentBox.name = 'commentQuestion'+index; | |
502 trackCommentBox.className = 'trackComment'; | |
503 var br = document.createElement('br'); | |
504 // Add to the holder. | |
505 trackComment.appendChild(trackString); | |
506 trackComment.appendChild(br); | |
507 trackComment.appendChild(trackCommentBox); | |
508 feedbackHolder.appendChild(trackComment); | |
509 }); | |
510 | |
511 | |
512 testWaitIndicator(); | |
513 } | |
514 | |
515 | |
516 function dragEnd(ev) { | |
517 // Function call when a div has been dropped | |
518 var slider = document.getElementById('slider'); | |
519 var marginSize = Number(slider.attributes['marginsize'].value); | |
520 var w = slider.style.width; | |
521 w = Number(w.substr(0,w.length-2)); | |
522 var x = ev.x; | |
523 if (x >= marginSize && x < w+marginSize) { | |
524 this.style.left = (x)+'px'; | |
525 } else { | |
526 if (x<marginSize) { | |
527 this.style.left = marginSize+'px'; | |
528 } else { | |
529 this.style.left = (w+marginSize) + 'px'; | |
530 } | |
531 } | |
532 audioEngineContext.metric.sliderMoved(); | |
533 } | |
534 | |
535 function buttonSubmitClick() // TODO: Only when all songs have been played! | |
536 { | |
537 hasBeenPlayed = audioEngineContext.checkAllPlayed(); | |
538 if (hasBeenPlayed.length == 0) { | |
539 if (audioEngineContext.status == 1) { | |
540 var playback = document.getElementById('playback-button'); | |
541 playback.click(); | |
542 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options | |
543 } else | |
544 { | |
545 if (audioEngineContext.timer.testStarted == false) | |
546 { | |
547 alert('You have not started the test! Please press start to begin the test!'); | |
548 return; | |
549 } | |
550 } | |
551 testState.advanceState(); | |
552 } else // if a fragment has not been played yet | |
553 { | |
554 str = ""; | |
555 if (hasBeenPlayed.length > 1) { | |
556 for (var i=0; i<hasBeenPlayed.length; i++) { | |
557 str = str + hasBeenPlayed[i]; | |
558 if (i < hasBeenPlayed.length-2){ | |
559 str += ", "; | |
560 } else if (i == hasBeenPlayed.length-2) { | |
561 str += " or "; | |
562 } | |
563 } | |
564 alert('You have not played fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.'); | |
565 } else { | |
566 alert('You have not played fragment ' + hasBeenPlayed[0] + ' yet. Please listen, rate and comment all samples before submitting.'); | |
567 } | |
568 return; | |
569 } | |
570 } | |
571 | |
572 function convSliderPosToRate(id) | |
573 { | |
574 var w = document.getElementById('slider').style.width; | |
575 var marginsize = Number(document.getElementById('slider').attributes['marginsize'].value); | |
576 var maxPix = w.substr(0,w.length-2); | |
577 var slider = document.getElementsByClassName('track-slider')[id]; | |
578 var pix = slider.style.left; | |
579 pix = pix.substr(0,pix.length-2); | |
580 var rate = (pix-marginsize)/maxPix; | |
581 return rate; | |
582 } | |
583 | |
584 function resizeWindow(event){ | |
585 // Function called when the window has been resized. | |
586 // MANDATORY FUNCTION | |
587 | |
588 // Store the slider marker values | |
589 var holdValues = []; | |
590 $(".track-slider").each(function(index,sliderObj){ | |
591 holdValues.push(convSliderPosToRate(index)); | |
592 }); | |
593 | |
594 var width = event.target.innerWidth; | |
595 var canvas = document.getElementById('sliderCanvasHolder'); | |
596 var sliderDiv = canvas.children[0]; | |
597 var sliderScaleDiv = canvas.children[1]; | |
598 var marginsize = Number(sliderDiv.attributes['marginsize'].value); | |
599 var w = (marginsize+8)*2; | |
600 sliderDiv.style.width = width - w + 'px'; | |
601 var width = width - w; | |
602 // Move sliders into new position | |
603 $(".track-slider").each(function(index,sliderObj){ | |
604 var pos = holdValues[index]; | |
605 var pix = pos * width; | |
606 sliderObj.style.left = pix+marginsize+'px'; | |
607 }); | |
608 | |
609 // Move scale labels | |
610 $(sliderScaleDiv.children).each(function(index,scaleObj){ | |
611 var position = Number(scaleObj.attributes['value'].value); | |
612 var pixelPosition = (position*width)+marginsize; | |
613 scaleObj.style.left = Math.floor((pixelPosition-($(scaleObj).width()/2)))+'px'; | |
614 }); | |
615 } | |
616 | |
617 function pageXMLSave(store, testXML, testId) | |
618 { | |
619 // Saves a specific test page | |
620 var xmlDoc = store; | |
621 // Check if any session wide metrics are enabled | |
622 | |
623 var commentShow = testXML.attributes['elementComments']; | |
624 if (commentShow != undefined) { | |
625 if (commentShow.value == 'false') {commentShow = false;} | |
626 else {commentShow = true;} | |
627 } else {commentShow = true;} | |
628 | |
629 var metric = document.createElement('metric'); | |
630 if (audioEngineContext.metric.enableTestTimer) | |
631 { | |
632 var testTime = document.createElement('metricResult'); | |
633 testTime.id = 'testTime'; | |
634 testTime.textContent = audioEngineContext.timer.testDuration; | |
635 metric.appendChild(testTime); | |
636 } | |
637 xmlDoc.appendChild(metric); | |
638 var trackSliderObjects = document.getElementsByClassName('track-slider'); | |
639 var commentObjects = document.getElementsByClassName('comment-div'); | |
640 for (var i=0; i<trackSliderObjects.length; i++) | |
641 { | |
642 var audioElement = document.createElement('audioElement'); | |
643 audioElement.id = currentTrackOrder[i].attributes['id'].value; | |
644 audioElement.url = currentTrackOrder[i].attributes['url'].value; | |
645 var value = document.createElement('value'); | |
646 value.innerHTML = convSliderPosToRate(i); | |
647 if (commentShow) { | |
648 var comment = document.createElement("comment"); | |
649 var question = document.createElement("question"); | |
650 var response = document.createElement("response"); | |
651 question.textContent = commentObjects[i].children[0].textContent; | |
652 response.textContent = commentObjects[i].children[2].value; | |
653 console.log('Comment ' + i + ': ' + commentObjects[i].children[2].value); // DEBUG/SAFETY | |
654 comment.appendChild(question); | |
655 comment.appendChild(response); | |
656 audioElement.appendChild(comment); | |
657 } | |
658 audioElement.appendChild(value); | |
659 // Check for any per element metrics | |
660 var metric = document.createElement('metric'); | |
661 var elementMetric = audioEngineContext.audioObjects[i].metric; | |
662 if (audioEngineContext.metric.enableElementTimer) { | |
663 var elementTimer = document.createElement('metricResult'); | |
664 elementTimer.id = 'elementTimer'; | |
665 elementTimer.textContent = elementMetric.listenedTimer; | |
666 metric.appendChild(elementTimer); | |
667 } | |
668 if (audioEngineContext.metric.enableElementTracker) { | |
669 var elementTrackerFull = document.createElement('metricResult'); | |
670 elementTrackerFull.id = 'elementTrackerFull'; | |
671 var data = elementMetric.movementTracker; | |
672 for (var k=0; k<data.length; k++) | |
673 { | |
674 var timePos = document.createElement('timePos'); | |
675 timePos.id = k; | |
676 var time = document.createElement('time'); | |
677 time.textContent = data[k][0]; | |
678 var position = document.createElement('position'); | |
679 position.textContent = data[k][1]; | |
680 timePos.appendChild(time); | |
681 timePos.appendChild(position); | |
682 elementTrackerFull.appendChild(timePos); | |
683 } | |
684 metric.appendChild(elementTrackerFull); | |
685 } | |
686 if (audioEngineContext.metric.enableElementListenTracker) { | |
687 var elementListenTracker = document.createElement('metricResult'); | |
688 elementListenTracker.id = 'elementListenTracker'; | |
689 var obj = elementMetric.listenTracker; | |
690 for (var k=0; k<obj.length; k++) { | |
691 elementListenTracker.appendChild(obj[k]); | |
692 } | |
693 metric.appendChild(elementListenTracker); | |
694 } | |
695 if (audioEngineContext.metric.enableElementInitialPosition) { | |
696 var elementInitial = document.createElement('metricResult'); | |
697 elementInitial.id = 'elementInitialPosition'; | |
698 elementInitial.textContent = elementMetric.initialPosition; | |
699 metric.appendChild(elementInitial); | |
700 } | |
701 if (audioEngineContext.metric.enableFlagListenedTo) { | |
702 var flagListenedTo = document.createElement('metricResult'); | |
703 flagListenedTo.id = 'elementFlagListenedTo'; | |
704 flagListenedTo.textContent = elementMetric.wasListenedTo; | |
705 metric.appendChild(flagListenedTo); | |
706 } | |
707 if (audioEngineContext.metric.enableFlagMoved) { | |
708 var flagMoved = document.createElement('metricResult'); | |
709 flagMoved.id = 'elementFlagMoved'; | |
710 flagMoved.textContent = elementMetric.wasMoved; | |
711 metric.appendChild(flagMoved); | |
712 } | |
713 if (audioEngineContext.metric.enableFlagComments) { | |
714 var flagComments = document.createElement('metricResult'); | |
715 flagComments.id = 'elementFlagComments'; | |
716 if (response.textContent.length == 0) {flag.textContent = 'false';} | |
717 else {flag.textContet = 'true';} | |
718 metric.appendChild(flagComments); | |
719 } | |
720 audioElement.appendChild(metric); | |
721 xmlDoc.appendChild(audioElement); | |
722 } | |
723 var commentQuestion = document.getElementsByClassName('commentQuestion'); | |
724 for (var i=0; i<commentQuestion.length; i++) | |
725 { | |
726 var cqHolder = document.createElement('CommentQuestion'); | |
727 var comment = document.createElement('comment'); | |
728 var question = document.createElement('question'); | |
729 cqHolder.id = commentQuestion[i].id; | |
730 comment.textContent = commentQuestion[i].children[2].value; | |
731 question.textContent = commentQuestion[i].children[0].textContent; | |
732 console.log('Question ' + i + ': ' + commentQuestion[i].children[2].value); // DEBUG/SAFETY | |
733 cqHolder.appendChild(question); | |
734 cqHolder.appendChild(comment); | |
735 xmlDoc.appendChild(cqHolder); | |
736 } | |
737 store = xmlDoc; | |
738 } |