comparison mushra.js @ 1453:04e8a9c07c7e

Updating test create using questions
author Nicholas Jillings <nickjillings@users.noreply.github.com>
date Wed, 23 Sep 2015 11:42:11 +0100
parents
children 81246d594793
comparison
equal deleted inserted replaced
-1:000000000000 1453:04e8a9c07c7e
1 /**
2 * mushra.js
3 * Create the MUSHRA interface
4 */
5
6 // Once this is loaded and parsed, begin execution
7 loadInterface();
8
9 function loadInterface() {
10 // Get the dimensions of the screen available to the page
11 var width = window.innerWidth;
12 var height = window.innerHeight;
13
14 // The injection point into the HTML page
15 interfaceContext.insertPoint = document.getElementById("topLevelBody");
16 var testContent = document.createElement('div');
17 testContent.id = 'testContent';
18
19 // Create the top div for the Title element
20 var titleAttr = specification.title;
21 var title = document.createElement('div');
22 title.className = "title";
23 title.align = "center";
24 var titleSpan = document.createElement('span');
25
26 // Set title to that defined in XML, else set to default
27 if (titleAttr != undefined) {
28 titleSpan.textContent = titleAttr;
29 } else {
30 titleSpan.textContent = 'Listening test';
31 }
32 // Insert the titleSpan element into the title div element.
33 title.appendChild(titleSpan);
34
35 var pagetitle = document.createElement('div');
36 pagetitle.className = "pageTitle";
37 pagetitle.align = "center";
38 var titleSpan = document.createElement('span');
39 titleSpan.id = "pageTitle";
40 pagetitle.appendChild(titleSpan);
41
42 // Create Interface buttons!
43 var interfaceButtons = document.createElement('div');
44 interfaceButtons.id = 'interface-buttons';
45
46 // Create playback start/stop points
47 var playback = document.createElement("button");
48 playback.innerHTML = 'Stop';
49 playback.id = 'playback-button';
50 // onclick function. Check if it is playing or not, call the correct function in the
51 // audioEngine, change the button text to reflect the next state.
52 playback.onclick = function() {
53 if (audioEngineContext.status == 1) {
54 audioEngineContext.stop();
55 this.innerHTML = 'Stop';
56 var time = audioEngineContext.timer.getTestTime();
57 console.log('Stopped at ' + time); // DEBUG/SAFETY
58 }
59 };
60 // Create Submit (save) button
61 var submit = document.createElement("button");
62 submit.innerHTML = 'Submit';
63 submit.onclick = buttonSubmitClick;
64 submit.id = 'submit-button';
65 // Append the interface buttons into the interfaceButtons object.
66 interfaceButtons.appendChild(playback);
67 interfaceButtons.appendChild(submit);
68
69 // Create a slider box
70 var sliderBox = document.createElement('div');
71 sliderBox.style.width = "100%";
72 sliderBox.style.height = window.innerHeight - 180 + 'px';
73 sliderBox.id = 'slider';
74 sliderBox.align = "center";
75
76 // Global parent for the comment boxes on the page
77 var feedbackHolder = document.createElement('div');
78 feedbackHolder.id = 'feedbackHolder';
79
80 testContent.style.zIndex = 1;
81 interfaceContext.insertPoint.innerHTML = null; // Clear the current schema
82
83 // Inject into HTML
84 testContent.appendChild(title); // Insert the title
85 testContent.appendChild(pagetitle);
86 testContent.appendChild(interfaceButtons);
87 testContent.appendChild(sliderBox);
88 testContent.appendChild(feedbackHolder);
89 interfaceContext.insertPoint.appendChild(testContent);
90
91 // Load the full interface
92 testState.initialise();
93 testState.advanceState();
94 }
95
96 function loadTest(audioHolderObject)
97 {
98 // Reset audioEngineContext.Metric globals for new test
99 audioEngineContext.newTestPage();
100
101 // Delete any previous audioObjects associated with the audioEngine
102 audioEngineContext.audioObjects = [];
103 interfaceContext.deleteCommentBoxes();
104 interfaceContext.deleteCommentQuestions();
105
106 var id = audioHolderObject.id;
107
108 var feedbackHolder = document.getElementById('feedbackHolder');
109 var interfaceObj = audioHolderObject.interfaces;
110
111 var sliderBox = document.getElementById('slider');
112 feedbackHolder.innerHTML = null;
113 sliderBox.innerHTML = null;
114
115 var commentBoxPrefix = "Comment on track";
116 if (interfaceObj.commentBoxPrefix != undefined) {
117 commentBoxPrefix = interfaceObj.commentBoxPrefix;
118 }
119
120 /// CHECK FOR SAMPLE RATE COMPATIBILITY
121 if (audioHolderObject.sampleRate != undefined) {
122 if (Number(audioHolderObject.sampleRate) != audioContext.sampleRate) {
123 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.';
124 alert(errStr);
125 return;
126 }
127 }
128
129 var loopPlayback = audioHolderObject.loop;
130
131 audioEngineContext.loopPlayback = loopPlayback;
132
133 currentTestHolder = document.createElement('audioHolder');
134 currentTestHolder.id = audioHolderObject.id;
135 currentTestHolder.repeatCount = audioHolderObject.repeatCount;
136
137 $(audioHolderObject.commentQuestions).each(function(index,element) {
138 var node = interfaceContext.createCommentQuestion(element);
139 feedbackHolder.appendChild(node.holder);
140 });
141
142 // Find all the audioElements from the audioHolder
143 $(audioHolderObject.audioElements).each(function(index,element){
144 // Find URL of track
145 // In this jQuery loop, variable 'this' holds the current audioElement.
146
147 // Now load each audio sample. First create the new track by passing the full URL
148 var trackURL = audioHolderObject.hostURL + element.url;
149 var audioObject = audioEngineContext.newTrack(element);
150
151 var node = interfaceContext.createCommentBox(audioObject);
152
153 // Create a slider per track
154 audioObject.interfaceDOM = new sliderObject(audioObject);
155
156 // Distribute it randomnly
157 audioObject.interfaceDOM.slider.value = Math.random();
158
159 sliderBox.appendChild(audioObject.interfaceDOM.holder);
160 audioObject.metric.initialised(audioObject.interfaceDOM.slider.value);
161
162 });
163
164 // Auto-align
165 var numObj = audioHolderObject.audioElements.length;
166 var totalWidth = (numObj-1)*150+100;
167 var diff = (window.innerWidth - totalWidth)/2;
168 audioEngineContext.audioObjects[0].interfaceDOM.holder.style.marginLeft = diff + 'px';
169 }
170
171 function sliderObject(audioObject)
172 {
173 // Constructs the slider object. We use the HTML5 slider object
174 this.parent = audioObject;
175 this.holder = document.createElement('div');
176 this.title = document.createElement('span');
177 this.slider = document.createElement('input');
178 this.play = document.createElement('button');
179
180 this.holder.className = 'track-slider';
181 this.holder.style.height = window.innerHeight-200 + 'px';
182 this.holder.appendChild(this.title);
183 this.holder.appendChild(this.slider);
184 this.holder.appendChild(this.play);
185 this.holder.align = "center";
186 this.holder.style.marginLeft = "50px";
187 this.holder.setAttribute('trackIndex',audioObject.id);
188
189 this.title.textContent = audioObject.id;
190 this.title.style.width = "100%";
191 this.title.style.float = "left";
192
193 this.slider.type = "range";
194 this.slider.min = "0";
195 this.slider.max = "1";
196 this.slider.step = "0.01";
197 this.slider.setAttribute('orient','vertical');
198 this.slider.style.float = "left";
199 this.slider.style.width = "100%";
200 this.slider.style.height = window.innerHeight-250 + 'px';
201 this.slider.onchange = function()
202 {
203 var time = audioEngineContext.timer.getTestTime();
204 var id = Number(this.parentNode.getAttribute('trackIndex'));
205 audioEngineContext.audioObjects[id].metric.moved(time,this.value);
206 console.log('slider '+id+' moved to '+this.value+' ('+time+')');
207 };
208
209 this.play.textContent = "Play";
210 this.play.value = audioObject.id;
211 this.play.style.float = "left";
212 this.play.style.width = "100%";
213 this.play.onclick = function()
214 {
215 audioEngineContext.play();
216 if (audioEngineContext.audioObjectsReady) {
217 var id = Number(event.srcElement.value);
218 //audioEngineContext.metric.sliderPlayed(id);
219 audioEngineContext.play(id);
220 }
221 };
222
223 this.enable = function() {
224 if (this.parent.state == 1)
225 {
226 $(this.slider).removeClass('track-slider-disabled');
227 }
228 };
229
230 this.exportXMLDOM = function(audioObject) {
231 // Called by the audioObject holding this element. Must be present
232 var node = document.createElement('value');
233 node.textContent = this.slider.value;
234 return node;
235 };
236 this.getValue = function() {
237 return this.slider.value;
238 };
239 }
240
241
242 function buttonSubmitClick() // TODO: Only when all songs have been played!
243 {
244 var checks = testState.currentStateMap[testState.currentIndex].interfaces[0].options;
245 var canContinue = true;
246
247 // Check that the anchor and reference objects are correctly placed
248 if (interfaceContext.checkHiddenAnchor() == false) {return;}
249 if (interfaceContext.checkHiddenReference() == false) {return;}
250 /*
251 for (var i=0; i<checks.length; i++) {
252 if (checks[i].type == 'check')
253 {
254 switch(checks[i].check) {
255 case 'fragmentPlayed':
256 // Check if all fragments have been played
257 var checkState = interfaceContext.checkAllPlayed();
258 if (checkState == false) {canContinue = false;}
259 break;
260 case 'fragmentFullPlayback':
261 // Check all fragments have been played to their full length
262 var checkState = interfaceContext.checkAllPlayed();
263 if (checkState == false) {canContinue = false;}
264 console.log('NOTE: fragmentFullPlayback not currently implemented, performing check fragmentPlayed instead');
265 break;
266 case 'fragmentMoved':
267 // Check all fragment sliders have been moved.
268 var checkState = interfaceContext.checkAllMoved();
269 if (checkState == false) {canContinue = false;}
270 break;
271 case 'fragmentComments':
272 // Check all fragment sliders have been moved.
273 var checkState = interfaceContext.checkAllCommented();
274 if (checkState == false) {canContinue = false;}
275 break;
276 case 'scalerange':
277 // Check the scale is used to its full width outlined by the node
278 var checkState = interfaceContext.checkScaleRange();
279 if (checkState == false) {canContinue = false;}
280 break;
281 }
282
283 }
284 if (!canContinue) {break;}
285 }
286 */
287 if (canContinue) {
288 if (audioEngineContext.status == 1) {
289 var playback = document.getElementById('playback-button');
290 playback.click();
291 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options
292 } else
293 {
294 if (audioEngineContext.timer.testStarted == false)
295 {
296 alert('You have not started the test! Please press start to begin the test!');
297 return;
298 }
299 }
300 testState.advanceState();
301 }
302 }
303
304 function pageXMLSave(store, testXML)
305 {
306 // Saves a specific test page
307 var xmlDoc = store;
308 // Check if any session wide metrics are enabled
309
310 var commentShow = testXML.elementComments;
311
312 var metric = document.createElement('metric');
313 if (audioEngineContext.metric.enableTestTimer)
314 {
315 var testTime = document.createElement('metricResult');
316 testTime.id = 'testTime';
317 testTime.textContent = audioEngineContext.timer.testDuration;
318 metric.appendChild(testTime);
319 }
320 xmlDoc.appendChild(metric);
321 var audioObjects = audioEngineContext.audioObjects;
322 for (var i=0; i<audioObjects.length; i++)
323 {
324 var audioElement = audioEngineContext.audioObjects[i].exportXMLDOM();
325 audioElement.setAttribute('presentedId',i);
326 xmlDoc.appendChild(audioElement);
327 }
328
329 $(interfaceContext.commentQuestions).each(function(index,element){
330 var node = element.exportXMLDOM();
331 xmlDoc.appendChild(node);
332 });
333 store = xmlDoc;
334 }