nickjillings@1682
|
1 /**
|
nickjillings@1682
|
2 * core.js
|
nickjillings@1682
|
3 *
|
nickjillings@1682
|
4 * Main script to run, calls all other core functions and manages loading/store to backend.
|
nickjillings@1682
|
5 * Also contains all global variables.
|
nickjillings@1682
|
6 */
|
nickjillings@1682
|
7
|
nickjillings@1682
|
8 /* create the web audio API context and store in audioContext*/
|
nickjillings@1643
|
9 var audioContext; // Hold the browser web audio API
|
nickjillings@1643
|
10 var projectXML; // Hold the parsed setup XML
|
nickjillings@1324
|
11 var schemaXSD; // Hold the parsed schema XSD
|
nickjillings@1581
|
12 var specification;
|
nickjillings@1582
|
13 var interfaceContext;
|
nickjillings@1324
|
14 var storage;
|
nickjillings@1622
|
15 var popup; // Hold the interfacePopup object
|
nickjillings@1634
|
16 var testState;
|
nickjillings@1655
|
17 var currentTrackOrder = []; // Hold the current XML tracks in their (randomised) order
|
nickjillings@1643
|
18 var audioEngineContext; // The custome AudioEngine object
|
nickjillings@1643
|
19 var projectReturn; // Hold the URL for the return
|
nickjillings@2013
|
20
|
nickjillings@1318
|
21
|
nickjillings@1318
|
22 // Add a prototype to the bufferSourceNode to reference to the audioObject holding it
|
nickjillings@1318
|
23 AudioBufferSourceNode.prototype.owner = undefined;
|
nickjillings@2101
|
24 // Add a prototype to the bufferSourceNode to hold when the object was given a play command
|
nickjillings@2101
|
25 AudioBufferSourceNode.prototype.playbackStartTime = undefined;
|
nickjillings@1318
|
26 // Add a prototype to the bufferNode to hold the desired LINEAR gain
|
nickjillings@1320
|
27 AudioBuffer.prototype.playbackGain = undefined;
|
nickjillings@1318
|
28 // Add a prototype to the bufferNode to hold the computed LUFS loudness
|
nickjillings@1318
|
29 AudioBuffer.prototype.lufs = undefined;
|
nickjillings@1318
|
30
|
nickjillings@1348
|
31 // Firefox does not have an XMLDocument.prototype.getElementsByName
|
nickjillings@1348
|
32 // and there is no searchAll style command, this custom function will
|
nickjillings@1348
|
33 // search all children recusrively for the name. Used for XSD where all
|
nickjillings@1348
|
34 // element nodes must have a name and therefore can pull the schema node
|
nickjillings@1348
|
35 XMLDocument.prototype.getAllElementsByName = function(name)
|
nickjillings@1348
|
36 {
|
nickjillings@1348
|
37 name = String(name);
|
nickjillings@1348
|
38 var selected = this.documentElement.getAllElementsByName(name);
|
nickjillings@1348
|
39 return selected;
|
nickjillings@1348
|
40 }
|
nickjillings@1348
|
41
|
nickjillings@1348
|
42 Element.prototype.getAllElementsByName = function(name)
|
nickjillings@1348
|
43 {
|
nickjillings@1348
|
44 name = String(name);
|
nickjillings@1348
|
45 var selected = [];
|
nickjillings@1348
|
46 var node = this.firstElementChild;
|
nickjillings@1348
|
47 while(node != null)
|
nickjillings@1348
|
48 {
|
nickjillings@1348
|
49 if (node.getAttribute('name') == name)
|
nickjillings@1348
|
50 {
|
nickjillings@1348
|
51 selected.push(node);
|
nickjillings@1348
|
52 }
|
nickjillings@1348
|
53 if (node.childElementCount > 0)
|
nickjillings@1348
|
54 {
|
nickjillings@1348
|
55 selected = selected.concat(node.getAllElementsByName(name));
|
nickjillings@1348
|
56 }
|
nickjillings@1348
|
57 node = node.nextElementSibling;
|
nickjillings@1348
|
58 }
|
nickjillings@1348
|
59 return selected;
|
nickjillings@1348
|
60 }
|
nickjillings@1348
|
61
|
nickjillings@1348
|
62 XMLDocument.prototype.getAllElementsByTagName = function(name)
|
nickjillings@1348
|
63 {
|
nickjillings@1348
|
64 name = String(name);
|
nickjillings@1348
|
65 var selected = this.documentElement.getAllElementsByTagName(name);
|
nickjillings@1348
|
66 return selected;
|
nickjillings@1348
|
67 }
|
nickjillings@1348
|
68
|
nickjillings@1348
|
69 Element.prototype.getAllElementsByTagName = function(name)
|
nickjillings@1348
|
70 {
|
nickjillings@1348
|
71 name = String(name);
|
nickjillings@1348
|
72 var selected = [];
|
nickjillings@1348
|
73 var node = this.firstElementChild;
|
nickjillings@1348
|
74 while(node != null)
|
nickjillings@1348
|
75 {
|
nickjillings@1348
|
76 if (node.nodeName == name)
|
nickjillings@1348
|
77 {
|
nickjillings@1348
|
78 selected.push(node);
|
nickjillings@1348
|
79 }
|
nickjillings@1348
|
80 if (node.childElementCount > 0)
|
nickjillings@1348
|
81 {
|
nickjillings@1348
|
82 selected = selected.concat(node.getAllElementsByTagName(name));
|
nickjillings@1348
|
83 }
|
nickjillings@1348
|
84 node = node.nextElementSibling;
|
nickjillings@1348
|
85 }
|
nickjillings@1348
|
86 return selected;
|
nickjillings@1348
|
87 }
|
nickjillings@1348
|
88
|
nickjillings@1348
|
89 // Firefox does not have an XMLDocument.prototype.getElementsByName
|
nickjillings@1348
|
90 if (typeof XMLDocument.prototype.getElementsByName != "function") {
|
nickjillings@1348
|
91 XMLDocument.prototype.getElementsByName = function(name)
|
nickjillings@1348
|
92 {
|
nickjillings@1348
|
93 name = String(name);
|
nickjillings@1348
|
94 var node = this.documentElement.firstElementChild;
|
nickjillings@1348
|
95 var selected = [];
|
nickjillings@1348
|
96 while(node != null)
|
nickjillings@1348
|
97 {
|
nickjillings@1348
|
98 if (node.getAttribute('name') == name)
|
nickjillings@1348
|
99 {
|
nickjillings@1348
|
100 selected.push(node);
|
nickjillings@1348
|
101 }
|
nickjillings@1348
|
102 node = node.nextElementSibling;
|
nickjillings@1348
|
103 }
|
nickjillings@1348
|
104 return selected;
|
nickjillings@1348
|
105 }
|
nickjillings@1348
|
106 }
|
nickjillings@1348
|
107
|
nickjillings@1682
|
108 window.onload = function() {
|
nickjillings@1682
|
109 // Function called once the browser has loaded all files.
|
nickjillings@1682
|
110 // This should perform any initial commands such as structure / loading documents
|
nickjillings@1682
|
111
|
nickjillings@1682
|
112 // Create a web audio API context
|
nickjillings@1701
|
113 // Fixed for cross-browser support
|
nickjillings@1701
|
114 var AudioContext = window.AudioContext || window.webkitAudioContext;
|
nickjillings@1688
|
115 audioContext = new AudioContext;
|
nickjillings@1682
|
116
|
nickjillings@1634
|
117 // Create test state
|
nickjillings@1634
|
118 testState = new stateMachine();
|
nickjillings@1634
|
119
|
nickjillings@1622
|
120 // Create the popup interface object
|
nickjillings@1622
|
121 popup = new interfacePopup();
|
nickjillings@1370
|
122
|
nickjillings@1370
|
123 // Create the specification object
|
nickjillings@1581
|
124 specification = new Specification();
|
nickjillings@1582
|
125
|
nickjillings@1582
|
126 // Create the interface object
|
nickjillings@1582
|
127 interfaceContext = new Interface(specification);
|
nickjillings@1324
|
128
|
nickjillings@1324
|
129 // Create the storage object
|
nickjillings@1324
|
130 storage = new Storage();
|
nickjillings@1410
|
131 // Define window callbacks for interface
|
nickjillings@1410
|
132 window.onresize = function(event){interfaceContext.resizeWindow(event);};
|
nickjillings@1697
|
133 };
|
nickjillings@1682
|
134
|
nickjillings@1408
|
135 function loadProjectSpec(url) {
|
nickjillings@1408
|
136 // Load the project document from the given URL, decode the XML and instruct audioEngine to get audio data
|
nickjillings@1408
|
137 // If url is null, request client to upload project XML document
|
nickjillings@1324
|
138 var xmlhttp = new XMLHttpRequest();
|
nickjillings@1324
|
139 xmlhttp.open("GET",'test-schema.xsd',true);
|
nickjillings@1324
|
140 xmlhttp.onload = function()
|
nickjillings@1324
|
141 {
|
nickjillings@1324
|
142 schemaXSD = xmlhttp.response;
|
nickjillings@1324
|
143 var parse = new DOMParser();
|
nickjillings@1324
|
144 specification.schema = parse.parseFromString(xmlhttp.response,'text/xml');
|
nickjillings@1324
|
145 var r = new XMLHttpRequest();
|
nickjillings@1324
|
146 r.open('GET',url,true);
|
nickjillings@1324
|
147 r.onload = function() {
|
nickjillings@1324
|
148 loadProjectSpecCallback(r.response);
|
nickjillings@1324
|
149 };
|
nickjillings@2110
|
150 r.onerror = function() {
|
nickjillings@2110
|
151 document.getElementsByTagName('body')[0].innerHTML = null;
|
nickjillings@2110
|
152 var msg = document.createElement("h3");
|
nickjillings@2110
|
153 msg.textContent = "FATAL ERROR";
|
nickjillings@2110
|
154 var span = document.createElement("p");
|
nickjillings@2110
|
155 span.textContent = "There was an error when loading your XML file. Please check your path in the URL. After the path to this page, there should be '?url=path/to/your/file.xml'. Check the spelling of your filename as well. If you are still having issues, check the log of the python server or your webserver distribution for 404 codes for your file.";
|
nickjillings@2110
|
156 document.getElementsByTagName('body')[0].appendChild(msg);
|
nickjillings@2110
|
157 document.getElementsByTagName('body')[0].appendChild(span);
|
nickjillings@2110
|
158 }
|
nickjillings@1324
|
159 r.send();
|
nickjillings@1408
|
160 };
|
nickjillings@1324
|
161 xmlhttp.send();
|
nickjillings@1408
|
162 };
|
nickjillings@1408
|
163
|
nickjillings@1408
|
164 function loadProjectSpecCallback(response) {
|
nickjillings@1408
|
165 // Function called after asynchronous download of XML project specification
|
nickjillings@1408
|
166 //var decode = $.parseXML(response);
|
nickjillings@1408
|
167 //projectXML = $(decode);
|
nickjillings@1408
|
168
|
nickjillings@2147
|
169 // Check if XML is new or a resumption
|
nickjillings@2147
|
170 var parse = new DOMParser();
|
nickjillings@2147
|
171 var responseDocument = parse.parseFromString(response,'text/xml');
|
nickjillings@2147
|
172 var errorNode = responseDocument.getElementsByTagName('parsererror');
|
nickjillings@1443
|
173 if (errorNode.length >= 1)
|
nickjillings@1443
|
174 {
|
nickjillings@1443
|
175 var msg = document.createElement("h3");
|
nickjillings@1443
|
176 msg.textContent = "FATAL ERROR";
|
nickjillings@1443
|
177 var span = document.createElement("span");
|
nickjillings@1443
|
178 span.textContent = "The XML parser returned the following errors when decoding your XML file";
|
nickjillings@1445
|
179 document.getElementsByTagName('body')[0].innerHTML = null;
|
nickjillings@1443
|
180 document.getElementsByTagName('body')[0].appendChild(msg);
|
nickjillings@1443
|
181 document.getElementsByTagName('body')[0].appendChild(span);
|
nickjillings@1443
|
182 document.getElementsByTagName('body')[0].appendChild(errorNode[0]);
|
nickjillings@1443
|
183 return;
|
nickjillings@1443
|
184 }
|
nickjillings@2147
|
185 if (responseDocument.children[0].nodeName == "waet") {
|
nickjillings@2147
|
186 // document is a specification
|
nickjillings@2147
|
187
|
nickjillings@2147
|
188 // Perform XML schema validation
|
nickjillings@2147
|
189 var Module = {
|
nickjillings@2147
|
190 xml: response,
|
nickjillings@2147
|
191 schema: schemaXSD,
|
nickjillings@2147
|
192 arguments:["--noout", "--schema", 'test-schema.xsd','document.xml']
|
nickjillings@2147
|
193 };
|
nickjillings@2147
|
194 projectXML = responseDocument;
|
nickjillings@2147
|
195 var xmllint = validateXML(Module);
|
nickjillings@2147
|
196 console.log(xmllint);
|
nickjillings@2147
|
197 if(xmllint != 'document.xml validates\n')
|
nickjillings@2147
|
198 {
|
nickjillings@2147
|
199 document.getElementsByTagName('body')[0].innerHTML = null;
|
nickjillings@2147
|
200 var msg = document.createElement("h3");
|
nickjillings@2147
|
201 msg.textContent = "FATAL ERROR";
|
nickjillings@2147
|
202 var span = document.createElement("h4");
|
nickjillings@2147
|
203 span.textContent = "The XML validator returned the following errors when decoding your XML file";
|
nickjillings@2147
|
204 document.getElementsByTagName('body')[0].appendChild(msg);
|
nickjillings@2147
|
205 document.getElementsByTagName('body')[0].appendChild(span);
|
nickjillings@2147
|
206 xmllint = xmllint.split('\n');
|
nickjillings@2147
|
207 for (var i in xmllint)
|
nickjillings@2147
|
208 {
|
nickjillings@2147
|
209 document.getElementsByTagName('body')[0].appendChild(document.createElement('br'));
|
nickjillings@2147
|
210 var span = document.createElement("span");
|
nickjillings@2147
|
211 span.textContent = xmllint[i];
|
nickjillings@2147
|
212 document.getElementsByTagName('body')[0].appendChild(span);
|
nickjillings@2147
|
213 }
|
nickjillings@2147
|
214 return;
|
nickjillings@2147
|
215 }
|
nickjillings@2149
|
216 // Build the specification
|
nickjillings@2149
|
217 specification.decode(projectXML);
|
nickjillings@2147
|
218 // Generate the session-key
|
nickjillings@2147
|
219 storage.initialise();
|
nickjillings@2147
|
220
|
nickjillings@2147
|
221 } else if (responseDocument.children[0].nodeName == "waetresult") {
|
nickjillings@2147
|
222 // document is a result
|
nickjillings@2147
|
223 projectXML = responseDocument.getElementsByTagName('waet')[0];
|
nickjillings@2149
|
224 // Build the specification
|
nickjillings@2149
|
225 specification.decode(projectXML);
|
nickjillings@2147
|
226 // Use the session-key
|
nickjillings@2147
|
227 var sessionKey = responseDocument.children[0].getAttribute(key);
|
nickjillings@2147
|
228 storage.initialise(sessionKey);
|
nickjillings@2147
|
229 }
|
nickjillings@1339
|
230 /// CHECK FOR SAMPLE RATE COMPATIBILITY
|
nickjillings@1339
|
231 if (specification.sampleRate != undefined) {
|
nickjillings@1339
|
232 if (Number(specification.sampleRate) != audioContext.sampleRate) {
|
nickjillings@1339
|
233 var errStr = 'Sample rates do not match! Requested '+Number(specification.sampleRate)+', got '+audioContext.sampleRate+'. Please set the sample rate to match before completing this test.';
|
nickjillings@1339
|
234 alert(errStr);
|
nickjillings@1339
|
235 return;
|
nickjillings@1339
|
236 }
|
nickjillings@1339
|
237 }
|
nickjillings@1408
|
238
|
nickjillings@1408
|
239 // Detect the interface to use and load the relevant javascripts.
|
nickjillings@1408
|
240 var interfaceJS = document.createElement('script');
|
nickjillings@1408
|
241 interfaceJS.setAttribute("type","text/javascript");
|
nickjillings@1329
|
242 switch(specification.interface)
|
nickjillings@1329
|
243 {
|
nickjillings@1329
|
244 case "APE":
|
nickjillings@1341
|
245 interfaceJS.setAttribute("src","interfaces/ape.js");
|
nickjillings@1408
|
246
|
nickjillings@1408
|
247 // APE comes with a css file
|
nickjillings@1408
|
248 var css = document.createElement('link');
|
nickjillings@1408
|
249 css.rel = 'stylesheet';
|
nickjillings@1408
|
250 css.type = 'text/css';
|
nickjillings@1341
|
251 css.href = 'interfaces/ape.css';
|
nickjillings@1408
|
252
|
nickjillings@1408
|
253 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@1329
|
254 break;
|
nickjillings@1329
|
255
|
nickjillings@1329
|
256 case "MUSHRA":
|
nickjillings@1341
|
257 interfaceJS.setAttribute("src","interfaces/mushra.js");
|
nickjillings@1408
|
258
|
nickjillings@1408
|
259 // MUSHRA comes with a css file
|
nickjillings@1408
|
260 var css = document.createElement('link');
|
nickjillings@1408
|
261 css.rel = 'stylesheet';
|
nickjillings@1408
|
262 css.type = 'text/css';
|
nickjillings@1341
|
263 css.href = 'interfaces/mushra.css';
|
nickjillings@1408
|
264
|
nickjillings@1408
|
265 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@1329
|
266 break;
|
nickjillings@1329
|
267
|
nickjillings@1329
|
268 case "AB":
|
nickjillings@1341
|
269 interfaceJS.setAttribute("src","interfaces/AB.js");
|
nickjillings@1329
|
270
|
nickjillings@1329
|
271 // AB comes with a css file
|
nickjillings@1329
|
272 var css = document.createElement('link');
|
nickjillings@1329
|
273 css.rel = 'stylesheet';
|
nickjillings@1329
|
274 css.type = 'text/css';
|
nickjillings@1341
|
275 css.href = 'interfaces/AB.css';
|
nickjillings@1329
|
276
|
nickjillings@1329
|
277 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@1345
|
278 break;
|
nickjillings@1345
|
279 case "Bipolar":
|
nickjillings@1345
|
280 case "ACR":
|
nickjillings@1345
|
281 case "DCR":
|
nickjillings@1345
|
282 case "CCR":
|
nickjillings@1343
|
283 case "ABC":
|
nickjillings@1343
|
284 // Above enumerate to horizontal sliders
|
nickjillings@1343
|
285 interfaceJS.setAttribute("src","interfaces/horizontal-sliders.js");
|
nickjillings@1343
|
286
|
nickjillings@1343
|
287 // horizontal-sliders comes with a css file
|
nickjillings@1343
|
288 var css = document.createElement('link');
|
nickjillings@1343
|
289 css.rel = 'stylesheet';
|
nickjillings@1343
|
290 css.type = 'text/css';
|
nickjillings@1343
|
291 css.href = 'interfaces/horizontal-sliders.css';
|
nickjillings@1343
|
292
|
nickjillings@1343
|
293 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@1345
|
294 break;
|
nickjillings@1345
|
295 case "discrete":
|
nickjillings@1345
|
296 case "likert":
|
nickjillings@1345
|
297 // Above enumerate to horizontal discrete radios
|
nickjillings@1345
|
298 interfaceJS.setAttribute("src","interfaces/discrete.js");
|
nickjillings@1345
|
299
|
nickjillings@1345
|
300 // horizontal-sliders comes with a css file
|
nickjillings@1345
|
301 var css = document.createElement('link');
|
nickjillings@1345
|
302 css.rel = 'stylesheet';
|
nickjillings@1345
|
303 css.type = 'text/css';
|
nickjillings@1345
|
304 css.href = 'interfaces/discrete.css';
|
nickjillings@1345
|
305
|
nickjillings@1345
|
306 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@1345
|
307 break;
|
nickjillings@1408
|
308 }
|
nickjillings@1408
|
309 document.getElementsByTagName("head")[0].appendChild(interfaceJS);
|
nickjillings@1408
|
310
|
nickjillings@1410
|
311 // Create the audio engine object
|
nickjillings@1410
|
312 audioEngineContext = new AudioEngine(specification);
|
nickjillings@1410
|
313
|
nickjillings@1324
|
314 $(specification.pages).each(function(index,elem){
|
nickjillings@1410
|
315 $(elem.audioElements).each(function(i,audioElem){
|
nickjillings@1324
|
316 var URL = elem.hostURL + audioElem.url;
|
nickjillings@1410
|
317 var buffer = null;
|
nickjillings@1410
|
318 for (var i=0; i<audioEngineContext.buffers.length; i++)
|
nickjillings@1410
|
319 {
|
nickjillings@1410
|
320 if (URL == audioEngineContext.buffers[i].url)
|
nickjillings@1410
|
321 {
|
nickjillings@1410
|
322 buffer = audioEngineContext.buffers[i];
|
nickjillings@1410
|
323 break;
|
nickjillings@1410
|
324 }
|
nickjillings@1410
|
325 }
|
nickjillings@1410
|
326 if (buffer == null)
|
nickjillings@1410
|
327 {
|
nickjillings@1430
|
328 buffer = new audioEngineContext.bufferObj();
|
nickjillings@1430
|
329 buffer.getMedia(URL);
|
nickjillings@1410
|
330 audioEngineContext.buffers.push(buffer);
|
nickjillings@1410
|
331 }
|
nickjillings@1410
|
332 });
|
nickjillings@1410
|
333 });
|
nickjillings@1408
|
334 }
|
nickjillings@1408
|
335
|
nickjillings@1408
|
336 function createProjectSave(destURL) {
|
nickjillings@1408
|
337 // Save the data from interface into XML and send to destURL
|
nickjillings@1408
|
338 // If destURL is null then download XML in client
|
nickjillings@1408
|
339 // Now time to render file locally
|
nickjillings@1408
|
340 var xmlDoc = interfaceXMLSave();
|
nickjillings@1408
|
341 var parent = document.createElement("div");
|
nickjillings@1408
|
342 parent.appendChild(xmlDoc);
|
nickjillings@1408
|
343 var file = [parent.innerHTML];
|
nickjillings@1408
|
344 if (destURL == "null" || destURL == undefined) {
|
nickjillings@1408
|
345 var bb = new Blob(file,{type : 'application/xml'});
|
nickjillings@1408
|
346 var dnlk = window.URL.createObjectURL(bb);
|
nickjillings@1408
|
347 var a = document.createElement("a");
|
nickjillings@1408
|
348 a.hidden = '';
|
nickjillings@1408
|
349 a.href = dnlk;
|
nickjillings@1408
|
350 a.download = "save.xml";
|
nickjillings@1408
|
351 a.textContent = "Save File";
|
nickjillings@1408
|
352
|
nickjillings@1408
|
353 popup.showPopup();
|
nickjillings@1332
|
354 popup.popupContent.innerHTML = "</span>Please save the file below to give to your test supervisor</span><br>";
|
nickjillings@1408
|
355 popup.popupContent.appendChild(a);
|
nickjillings@1408
|
356 } else {
|
nickjillings@1408
|
357 var xmlhttp = new XMLHttpRequest;
|
nickjillings@1408
|
358 xmlhttp.open("POST",destURL,true);
|
nickjillings@1408
|
359 xmlhttp.setRequestHeader('Content-Type', 'text/xml');
|
nickjillings@1408
|
360 xmlhttp.onerror = function(){
|
nickjillings@1408
|
361 console.log('Error saving file to server! Presenting download locally');
|
nickjillings@1408
|
362 createProjectSave(null);
|
nickjillings@1408
|
363 };
|
nickjillings@1408
|
364 xmlhttp.onreadystatechange = function() {
|
nickjillings@1408
|
365 console.log(xmlhttp.status);
|
nickjillings@1408
|
366 if (xmlhttp.status != 200 && xmlhttp.readyState == 4) {
|
nickjillings@1408
|
367 createProjectSave(null);
|
nickjillings@1408
|
368 } else {
|
giuliomoro@1304
|
369 var parser = new DOMParser();
|
giuliomoro@1304
|
370 var xmlDoc = parser.parseFromString(xmlhttp.responseText, "application/xml");
|
giuliomoro@1304
|
371 if (xmlDoc == null)
|
nickjillings@1408
|
372 {
|
nickjillings@1324
|
373 createProjectSave('null');
|
nickjillings@1408
|
374 }
|
giuliomoro@1304
|
375 var response = xmlDoc.childNodes[0];
|
nickjillings@1408
|
376 if (response.getAttribute('state') == "OK")
|
nickjillings@1408
|
377 {
|
nickjillings@1408
|
378 var file = response.getElementsByTagName('file')[0];
|
nickjillings@1408
|
379 console.log('Save OK: Filename '+file.textContent+','+file.getAttribute('bytes')+'B');
|
nickjillings@1408
|
380 popup.showPopup();
|
nickjillings@1408
|
381 popup.popupContent.innerHTML = null;
|
nickjillings@1408
|
382 popup.popupContent.textContent = "Thank you!";
|
giuliomoro@2145
|
383 window.onbeforeunload=null;
|
nickjillings@1408
|
384 } else {
|
nickjillings@1408
|
385 var message = response.getElementsByTagName('message')[0];
|
nickjillings@1408
|
386 errorSessionDump(message.textContent);
|
nickjillings@1408
|
387 }
|
nickjillings@1408
|
388 }
|
nickjillings@1408
|
389 };
|
nickjillings@1408
|
390 xmlhttp.send(file);
|
nickjillings@1332
|
391 popup.showPopup();
|
nickjillings@1332
|
392 popup.popupContent.innerHTML = null;
|
nickjillings@1332
|
393 popup.popupContent.textContent = "Submitting. Please Wait";
|
nickjillings@2106
|
394 popup.hideNextButton();
|
nickjillings@2106
|
395 popup.hidePreviousButton();
|
nickjillings@1408
|
396 }
|
nickjillings@1408
|
397 }
|
nickjillings@1408
|
398
|
nickjillings@1408
|
399 function errorSessionDump(msg){
|
nickjillings@1408
|
400 // Create the partial interface XML save
|
nickjillings@1408
|
401 // Include error node with message on why the dump occured
|
nickjillings@1443
|
402 popup.showPopup();
|
nickjillings@1443
|
403 popup.popupContent.innerHTML = null;
|
nickjillings@1443
|
404 var err = document.createElement('error');
|
nickjillings@1443
|
405 var parent = document.createElement("div");
|
nickjillings@1443
|
406 if (typeof msg === "object")
|
nickjillings@1443
|
407 {
|
nickjillings@1443
|
408 err.appendChild(msg);
|
nickjillings@1443
|
409 popup.popupContent.appendChild(msg);
|
nickjillings@1443
|
410
|
nickjillings@1443
|
411 } else {
|
nickjillings@1443
|
412 err.textContent = msg;
|
nickjillings@1443
|
413 popup.popupContent.innerHTML = "ERROR : "+msg;
|
nickjillings@1443
|
414 }
|
nickjillings@1408
|
415 var xmlDoc = interfaceXMLSave();
|
nickjillings@1408
|
416 xmlDoc.appendChild(err);
|
nickjillings@1408
|
417 parent.appendChild(xmlDoc);
|
nickjillings@1408
|
418 var file = [parent.innerHTML];
|
nickjillings@1408
|
419 var bb = new Blob(file,{type : 'application/xml'});
|
nickjillings@1408
|
420 var dnlk = window.URL.createObjectURL(bb);
|
nickjillings@1408
|
421 var a = document.createElement("a");
|
nickjillings@1408
|
422 a.hidden = '';
|
nickjillings@1408
|
423 a.href = dnlk;
|
nickjillings@1408
|
424 a.download = "save.xml";
|
nickjillings@1408
|
425 a.textContent = "Save File";
|
nickjillings@1408
|
426
|
nickjillings@1443
|
427
|
nickjillings@1443
|
428
|
nickjillings@1408
|
429 popup.popupContent.appendChild(a);
|
nickjillings@1408
|
430 }
|
nickjillings@1408
|
431
|
nickjillings@1408
|
432 // Only other global function which must be defined in the interface class. Determines how to create the XML document.
|
nickjillings@1408
|
433 function interfaceXMLSave(){
|
nickjillings@1408
|
434 // Create the XML string to be exported with results
|
nickjillings@1324
|
435 return storage.finish();
|
nickjillings@1408
|
436 }
|
nickjillings@1408
|
437
|
nickjillings@1426
|
438 function linearToDecibel(gain)
|
nickjillings@1426
|
439 {
|
nickjillings@1426
|
440 return 20.0*Math.log10(gain);
|
nickjillings@1426
|
441 }
|
nickjillings@1426
|
442
|
nickjillings@1426
|
443 function decibelToLinear(gain)
|
nickjillings@1426
|
444 {
|
nickjillings@1426
|
445 return Math.pow(10,gain/20.0);
|
nickjillings@1426
|
446 }
|
nickjillings@1426
|
447
|
nickjillings@2147
|
448 function randomString(length) {
|
nickjillings@2147
|
449 return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1);
|
nickjillings@2147
|
450 }
|
nickjillings@2147
|
451
|
nickjillings@1622
|
452 function interfacePopup() {
|
nickjillings@1622
|
453 // Creates an object to manage the popup
|
nickjillings@1622
|
454 this.popup = null;
|
nickjillings@1622
|
455 this.popupContent = null;
|
nickjillings@1526
|
456 this.popupTitle = null;
|
nickjillings@1526
|
457 this.popupResponse = null;
|
nickjillings@1574
|
458 this.buttonProceed = null;
|
nickjillings@2034
|
459 this.buttonPrevious = null;
|
nickjillings@1622
|
460 this.popupOptions = null;
|
nickjillings@1622
|
461 this.currentIndex = null;
|
nickjillings@1324
|
462 this.node = null;
|
nickjillings@1324
|
463 this.store = null;
|
nickjillings@1422
|
464 $(window).keypress(function(e){
|
nickjillings@1422
|
465 if (e.keyCode == 13 && popup.popup.style.visibility == 'visible')
|
nickjillings@1422
|
466 {
|
nickjillings@1422
|
467 console.log(e);
|
nickjillings@1422
|
468 popup.buttonProceed.onclick();
|
nickjillings@1424
|
469 e.preventDefault();
|
nickjillings@1422
|
470 }
|
nickjillings@1422
|
471 });
|
nickjillings@1581
|
472
|
nickjillings@1622
|
473 this.createPopup = function(){
|
nickjillings@1622
|
474 // Create popup window interface
|
nickjillings@1622
|
475 var insertPoint = document.getElementById("topLevelBody");
|
nickjillings@1622
|
476
|
nickjillings@1379
|
477 this.popup = document.getElementById('popupHolder');
|
nickjillings@1622
|
478 this.popup.style.left = (window.innerWidth/2)-250 + 'px';
|
nickjillings@1622
|
479 this.popup.style.top = (window.innerHeight/2)-125 + 'px';
|
nickjillings@1622
|
480
|
nickjillings@1379
|
481 this.popupContent = document.getElementById('popupContent');
|
nickjillings@1622
|
482
|
nickjillings@1379
|
483 this.popupTitle = document.getElementById('popupTitle');
|
nickjillings@1526
|
484
|
nickjillings@1379
|
485 this.popupResponse = document.getElementById('popupResponse');
|
nickjillings@1526
|
486
|
nickjillings@1379
|
487 this.buttonProceed = document.getElementById('popup-proceed');
|
nickjillings@1574
|
488 this.buttonProceed.onclick = function(){popup.proceedClicked();};
|
nickjillings@2034
|
489
|
nickjillings@1379
|
490 this.buttonPrevious = document.getElementById('popup-previous');
|
nickjillings@2034
|
491 this.buttonPrevious.onclick = function(){popup.previousClick();};
|
nickjillings@2034
|
492
|
nickjillings@1379
|
493 this.hidePopup();
|
nickjillings@1379
|
494
|
nickjillings@1581
|
495 this.popup.style.zIndex = -1;
|
nickjillings@1581
|
496 this.popup.style.visibility = 'hidden';
|
nickjillings@1622
|
497 };
|
nickjillings@1621
|
498
|
nickjillings@1622
|
499 this.showPopup = function(){
|
nickjillings@1581
|
500 if (this.popup == null) {
|
nickjillings@1622
|
501 this.createPopup();
|
nickjillings@1622
|
502 }
|
nickjillings@1622
|
503 this.popup.style.zIndex = 3;
|
nickjillings@1622
|
504 this.popup.style.visibility = 'visible';
|
nickjillings@1622
|
505 var blank = document.getElementsByClassName('testHalt')[0];
|
nickjillings@1622
|
506 blank.style.zIndex = 2;
|
nickjillings@1622
|
507 blank.style.visibility = 'visible';
|
nickjillings@1622
|
508 };
|
nickjillings@1622
|
509
|
nickjillings@1622
|
510 this.hidePopup = function(){
|
nickjillings@1622
|
511 this.popup.style.zIndex = -1;
|
nickjillings@1622
|
512 this.popup.style.visibility = 'hidden';
|
nickjillings@1622
|
513 var blank = document.getElementsByClassName('testHalt')[0];
|
nickjillings@1622
|
514 blank.style.zIndex = -2;
|
nickjillings@1622
|
515 blank.style.visibility = 'hidden';
|
nickjillings@1526
|
516 this.buttonPrevious.style.visibility = 'inherit';
|
nickjillings@1622
|
517 };
|
nickjillings@1622
|
518
|
nickjillings@1622
|
519 this.postNode = function() {
|
nickjillings@1622
|
520 // This will take the node from the popupOptions and display it
|
nickjillings@1622
|
521 var node = this.popupOptions[this.currentIndex];
|
nickjillings@1526
|
522 this.popupResponse.innerHTML = null;
|
nickjillings@1324
|
523 this.popupTitle.textContent = node.specification.statement;
|
nickjillings@1324
|
524 if (node.specification.type == 'question') {
|
nickjillings@1622
|
525 var textArea = document.createElement('textarea');
|
nickjillings@1324
|
526 switch (node.specification.boxsize) {
|
nickjillings@2030
|
527 case 'small':
|
nickjillings@2030
|
528 textArea.cols = "20";
|
nickjillings@2030
|
529 textArea.rows = "1";
|
nickjillings@2030
|
530 break;
|
nickjillings@2030
|
531 case 'normal':
|
nickjillings@2030
|
532 textArea.cols = "30";
|
nickjillings@2030
|
533 textArea.rows = "2";
|
nickjillings@2030
|
534 break;
|
nickjillings@2030
|
535 case 'large':
|
nickjillings@2030
|
536 textArea.cols = "40";
|
nickjillings@2030
|
537 textArea.rows = "5";
|
nickjillings@2030
|
538 break;
|
nickjillings@2030
|
539 case 'huge':
|
nickjillings@2030
|
540 textArea.cols = "50";
|
nickjillings@2030
|
541 textArea.rows = "10";
|
nickjillings@2030
|
542 break;
|
nickjillings@2030
|
543 }
|
nickjillings@1361
|
544 if (node.response == undefined) {
|
nickjillings@1361
|
545 node.response = "";
|
nickjillings@1361
|
546 } else {
|
nickjillings@1361
|
547 textArea.value = node.response;
|
nickjillings@1361
|
548 }
|
nickjillings@1526
|
549 this.popupResponse.appendChild(textArea);
|
nickjillings@1526
|
550 textArea.focus();
|
nickjillings@1382
|
551 this.popupResponse.style.textAlign="center";
|
nickjillings@1382
|
552 this.popupResponse.style.left="0%";
|
nickjillings@1324
|
553 } else if (node.specification.type == 'checkbox') {
|
nickjillings@1361
|
554 if (node.response == undefined) {
|
nickjillings@1361
|
555 node.response = Array(node.specification.options.length);
|
nickjillings@1361
|
556 }
|
nickjillings@1361
|
557 var index = 0;
|
nickjillings@1382
|
558 var max_w = 0;
|
nickjillings@1324
|
559 for (var option of node.specification.options) {
|
nickjillings@1588
|
560 var input = document.createElement('input');
|
nickjillings@2093
|
561 input.id = option.name;
|
nickjillings@1588
|
562 input.type = 'checkbox';
|
nickjillings@1588
|
563 var span = document.createElement('span');
|
nickjillings@1588
|
564 span.textContent = option.text;
|
nickjillings@1588
|
565 var hold = document.createElement('div');
|
nickjillings@1588
|
566 hold.setAttribute('name','option');
|
nickjillings@1588
|
567 hold.style.padding = '4px';
|
nickjillings@1588
|
568 hold.appendChild(input);
|
nickjillings@1588
|
569 hold.appendChild(span);
|
nickjillings@1324
|
570 this.popupResponse.appendChild(hold);
|
nickjillings@1361
|
571 if (node.response[index] != undefined){
|
nickjillings@1361
|
572 if (node.response[index].checked == true) {
|
nickjillings@1361
|
573 input.checked = "true";
|
nickjillings@1361
|
574 }
|
nickjillings@1361
|
575 }
|
nickjillings@1382
|
576 var w = $(span).width();
|
nickjillings@1382
|
577 if (w > max_w)
|
nickjillings@1382
|
578 max_w = w;
|
nickjillings@1361
|
579 index++;
|
nickjillings@1588
|
580 }
|
nickjillings@1382
|
581 max_w += 12;
|
nickjillings@1382
|
582 this.popupResponse.style.textAlign="";
|
nickjillings@1382
|
583 var leftP = ((max_w/500)/2)*100;
|
nickjillings@1382
|
584 this.popupResponse.style.left=leftP+"%";
|
nickjillings@1324
|
585 } else if (node.specification.type == 'radio') {
|
nickjillings@1361
|
586 if (node.response == undefined) {
|
nickjillings@1361
|
587 node.response = {name: "", text: ""};
|
nickjillings@1361
|
588 }
|
nickjillings@1361
|
589 var index = 0;
|
nickjillings@1382
|
590 var max_w = 0;
|
nickjillings@1324
|
591 for (var option of node.specification.options) {
|
nickjillings@1589
|
592 var input = document.createElement('input');
|
nickjillings@1589
|
593 input.id = option.name;
|
nickjillings@1589
|
594 input.type = 'radio';
|
nickjillings@1324
|
595 input.name = node.specification.id;
|
nickjillings@1589
|
596 var span = document.createElement('span');
|
nickjillings@1589
|
597 span.textContent = option.text;
|
nickjillings@1589
|
598 var hold = document.createElement('div');
|
nickjillings@1589
|
599 hold.setAttribute('name','option');
|
nickjillings@1589
|
600 hold.style.padding = '4px';
|
nickjillings@1589
|
601 hold.appendChild(input);
|
nickjillings@1589
|
602 hold.appendChild(span);
|
nickjillings@1324
|
603 this.popupResponse.appendChild(hold);
|
nickjillings@1361
|
604 if (input.id == node.response.name) {
|
nickjillings@1361
|
605 input.checked = "true";
|
nickjillings@1361
|
606 }
|
nickjillings@1382
|
607 var w = $(span).width();
|
nickjillings@1382
|
608 if (w > max_w)
|
nickjillings@1382
|
609 max_w = w;
|
nickjillings@1589
|
610 }
|
nickjillings@1382
|
611 max_w += 12;
|
nickjillings@1382
|
612 this.popupResponse.style.textAlign="";
|
nickjillings@1382
|
613 var leftP = ((max_w/500)/2)*100;
|
nickjillings@1382
|
614 this.popupResponse.style.left=leftP+"%";
|
nickjillings@1324
|
615 } else if (node.specification.type == 'number') {
|
nickjillings@1573
|
616 var input = document.createElement('input');
|
nickjillings@2044
|
617 input.type = 'textarea';
|
nickjillings@1324
|
618 if (node.min != null) {input.min = node.specification.min;}
|
nickjillings@1324
|
619 if (node.max != null) {input.max = node.specification.max;}
|
nickjillings@1324
|
620 if (node.step != null) {input.step = node.specification.step;}
|
nickjillings@1361
|
621 if (node.response != undefined) {
|
nickjillings@1361
|
622 input.value = node.response;
|
nickjillings@1361
|
623 }
|
nickjillings@1526
|
624 this.popupResponse.appendChild(input);
|
nickjillings@1382
|
625 this.popupResponse.style.textAlign="center";
|
nickjillings@1382
|
626 this.popupResponse.style.left="0%";
|
nickjillings@1622
|
627 }
|
nickjillings@2034
|
628 if(this.currentIndex+1 == this.popupOptions.length) {
|
nickjillings@1324
|
629 if (this.node.location == "pre") {
|
nickjillings@1531
|
630 this.buttonProceed.textContent = 'Start';
|
nickjillings@1531
|
631 } else {
|
nickjillings@1531
|
632 this.buttonProceed.textContent = 'Submit';
|
nickjillings@1531
|
633 }
|
nickjillings@2034
|
634 } else {
|
nickjillings@2034
|
635 this.buttonProceed.textContent = 'Next';
|
nickjillings@2034
|
636 }
|
nickjillings@2034
|
637 if(this.currentIndex > 0)
|
nickjillings@1526
|
638 this.buttonPrevious.style.visibility = 'visible';
|
nickjillings@1526
|
639 else
|
nickjillings@1526
|
640 this.buttonPrevious.style.visibility = 'hidden';
|
nickjillings@2015
|
641 };
|
nickjillings@1622
|
642
|
nickjillings@1324
|
643 this.initState = function(node,store) {
|
nickjillings@1622
|
644 //Call this with your preTest and postTest nodes when needed to
|
nickjillings@1622
|
645 // initialise the popup procedure.
|
nickjillings@1324
|
646 if (node.options.length > 0) {
|
nickjillings@1324
|
647 this.popupOptions = [];
|
nickjillings@1324
|
648 this.node = node;
|
nickjillings@1324
|
649 this.store = store;
|
nickjillings@1324
|
650 for (var opt of node.options)
|
nickjillings@1324
|
651 {
|
nickjillings@1324
|
652 this.popupOptions.push({
|
nickjillings@1324
|
653 specification: opt,
|
nickjillings@1324
|
654 response: null
|
nickjillings@1324
|
655 });
|
nickjillings@1324
|
656 }
|
nickjillings@1622
|
657 this.currentIndex = 0;
|
nickjillings@1622
|
658 this.showPopup();
|
nickjillings@1622
|
659 this.postNode();
|
nickjillings@1581
|
660 } else {
|
nickjillings@1581
|
661 advanceState();
|
nickjillings@1622
|
662 }
|
nickjillings@2015
|
663 };
|
nickjillings@1622
|
664
|
nickjillings@1574
|
665 this.proceedClicked = function() {
|
nickjillings@1622
|
666 // Each time the popup button is clicked!
|
nickjillings@1622
|
667 var node = this.popupOptions[this.currentIndex];
|
nickjillings@1324
|
668 if (node.specification.type == 'question') {
|
nickjillings@1622
|
669 // Must extract the question data
|
nickjillings@1622
|
670 var textArea = $(popup.popupContent).find('textarea')[0];
|
nickjillings@1324
|
671 if (node.specification.mandatory == true && textArea.value.length == 0) {
|
nickjillings@1622
|
672 alert('This question is mandatory');
|
nickjillings@1622
|
673 return;
|
nickjillings@1622
|
674 } else {
|
nickjillings@1622
|
675 // Save the text content
|
nickjillings@1324
|
676 console.log("Question: "+ node.specification.statement);
|
nickjillings@1623
|
677 console.log("Question Response: "+ textArea.value);
|
nickjillings@1324
|
678 node.response = textArea.value;
|
nickjillings@1622
|
679 }
|
nickjillings@1324
|
680 } else if (node.specification.type == 'checkbox') {
|
nickjillings@1588
|
681 // Must extract checkbox data
|
nickjillings@1326
|
682 console.log("Checkbox: "+ node.specification.statement);
|
nickjillings@1324
|
683 var inputs = this.popupResponse.getElementsByTagName('input');
|
nickjillings@1324
|
684 node.response = [];
|
nickjillings@1324
|
685 for (var i=0; i<node.specification.options.length; i++) {
|
nickjillings@1324
|
686 node.response.push({
|
nickjillings@1324
|
687 name: node.specification.options[i].name,
|
nickjillings@1324
|
688 text: node.specification.options[i].text,
|
nickjillings@1324
|
689 checked: inputs[i].checked
|
nickjillings@1324
|
690 });
|
nickjillings@1326
|
691 console.log(node.specification.options[i].name+": "+ inputs[i].checked);
|
nickjillings@1324
|
692 }
|
nickjillings@1324
|
693 } else if (node.specification.type == "radio") {
|
nickjillings@1526
|
694 var optHold = this.popupResponse;
|
nickjillings@1324
|
695 console.log("Radio: "+ node.specification.statement);
|
nickjillings@1324
|
696 node.response = null;
|
nickjillings@1589
|
697 var i=0;
|
nickjillings@1324
|
698 var inputs = optHold.getElementsByTagName('input');
|
nickjillings@1324
|
699 while(node.response == null) {
|
nickjillings@1324
|
700 if (i == inputs.length)
|
nickjillings@1324
|
701 {
|
nickjillings@1324
|
702 if (node.specification.mandatory == true)
|
nickjillings@1324
|
703 {
|
nickjillings@1324
|
704 alert("This radio is mandatory");
|
nickjillings@1324
|
705 } else {
|
nickjillings@1324
|
706 node.response = -1;
|
nickjillings@1324
|
707 }
|
nickjillings@1324
|
708 return;
|
nickjillings@1324
|
709 }
|
nickjillings@1324
|
710 if (inputs[i].checked == true) {
|
nickjillings@1324
|
711 node.response = node.specification.options[i];
|
nickjillings@1324
|
712 console.log("Selected: "+ node.specification.options[i].name);
|
nickjillings@1589
|
713 }
|
nickjillings@1589
|
714 i++;
|
nickjillings@1589
|
715 }
|
nickjillings@1324
|
716 } else if (node.specification.type == "number") {
|
nickjillings@1573
|
717 var input = this.popupContent.getElementsByTagName('input')[0];
|
nickjillings@1573
|
718 if (node.mandatory == true && input.value.length == 0) {
|
nickjillings@1574
|
719 alert('This question is mandatory. Please enter a number');
|
nickjillings@1574
|
720 return;
|
nickjillings@1574
|
721 }
|
nickjillings@1574
|
722 var enteredNumber = Number(input.value);
|
nickjillings@2044
|
723 if (isNaN(enteredNumber)) {
|
nickjillings@1574
|
724 alert('Please enter a valid number');
|
nickjillings@1574
|
725 return;
|
nickjillings@1574
|
726 }
|
nickjillings@1574
|
727 if (enteredNumber < node.min && node.min != null) {
|
nickjillings@1574
|
728 alert('Number is below the minimum value of '+node.min);
|
nickjillings@1574
|
729 return;
|
nickjillings@1574
|
730 }
|
nickjillings@1574
|
731 if (enteredNumber > node.max && node.max != null) {
|
nickjillings@1574
|
732 alert('Number is above the maximum value of '+node.max);
|
nickjillings@1573
|
733 return;
|
nickjillings@1573
|
734 }
|
nickjillings@1324
|
735 node.response = input.value;
|
nickjillings@1622
|
736 }
|
nickjillings@1622
|
737 this.currentIndex++;
|
nickjillings@1622
|
738 if (this.currentIndex < this.popupOptions.length) {
|
nickjillings@1622
|
739 this.postNode();
|
nickjillings@1622
|
740 } else {
|
nickjillings@1622
|
741 // Reached the end of the popupOptions
|
nickjillings@1622
|
742 this.hidePopup();
|
nickjillings@1324
|
743 for (var node of this.popupOptions)
|
nickjillings@1324
|
744 {
|
nickjillings@1324
|
745 this.store.postResult(node);
|
nickjillings@1634
|
746 }
|
nickjillings@2149
|
747 this.store.finish();
|
nickjillings@1622
|
748 advanceState();
|
nickjillings@1622
|
749 }
|
nickjillings@2015
|
750 };
|
nickjillings@2034
|
751
|
nickjillings@2034
|
752 this.previousClick = function() {
|
nickjillings@2034
|
753 // Triggered when the 'Back' button is clicked in the survey
|
nickjillings@2034
|
754 if (this.currentIndex > 0) {
|
nickjillings@2034
|
755 this.currentIndex--;
|
nickjillings@2034
|
756 this.postNode();
|
nickjillings@2034
|
757 }
|
nickjillings@2034
|
758 };
|
nickjillings@1421
|
759
|
nickjillings@1421
|
760 this.resize = function(event)
|
nickjillings@1421
|
761 {
|
nickjillings@1421
|
762 // Called on window resize;
|
nickjillings@1344
|
763 if (this.popup != null) {
|
nickjillings@1344
|
764 this.popup.style.left = (window.innerWidth/2)-250 + 'px';
|
nickjillings@1344
|
765 this.popup.style.top = (window.innerHeight/2)-125 + 'px';
|
nickjillings@1344
|
766 var blank = document.getElementsByClassName('testHalt')[0];
|
nickjillings@1344
|
767 blank.style.width = window.innerWidth;
|
nickjillings@1344
|
768 blank.style.height = window.innerHeight;
|
nickjillings@1344
|
769 }
|
nickjillings@1421
|
770 };
|
nickjillings@2106
|
771 this.hideNextButton = function() {
|
nickjillings@2106
|
772 this.buttonProceed.style.visibility = "hidden";
|
nickjillings@2106
|
773 }
|
nickjillings@2106
|
774 this.hidePreviousButton = function() {
|
nickjillings@2106
|
775 this.buttonPrevious.style.visibility = "hidden";
|
nickjillings@2106
|
776 }
|
nickjillings@2106
|
777 this.showNextButton = function() {
|
nickjillings@2106
|
778 this.buttonProceed.style.visibility = "visible";
|
nickjillings@2106
|
779 }
|
nickjillings@2106
|
780 this.showPreviousButton = function() {
|
nickjillings@2106
|
781 this.buttonPrevious.style.visibility = "visible";
|
nickjillings@2106
|
782 }
|
nickjillings@1621
|
783 }
|
nickjillings@1621
|
784
|
nickjillings@1622
|
785 function advanceState()
|
nickjillings@1621
|
786 {
|
nickjillings@1634
|
787 // Just for complete clarity
|
nickjillings@1634
|
788 testState.advanceState();
|
nickjillings@1634
|
789 }
|
nickjillings@1634
|
790
|
nickjillings@1634
|
791 function stateMachine()
|
nickjillings@1634
|
792 {
|
nickjillings@1634
|
793 // Object prototype for tracking and managing the test state
|
nickjillings@1634
|
794 this.stateMap = [];
|
nickjillings@1324
|
795 this.preTestSurvey = null;
|
nickjillings@1324
|
796 this.postTestSurvey = null;
|
nickjillings@1634
|
797 this.stateIndex = null;
|
nickjillings@1324
|
798 this.currentStateMap = null;
|
nickjillings@1324
|
799 this.currentStatePosition = null;
|
nickjillings@1354
|
800 this.currentStore = null;
|
nickjillings@1634
|
801 this.initialise = function(){
|
nickjillings@1324
|
802
|
nickjillings@1324
|
803 // Get the data from Specification
|
nickjillings@1324
|
804 var pageHolder = [];
|
nickjillings@1324
|
805 for (var page of specification.pages)
|
nickjillings@1324
|
806 {
|
nickjillings@1380
|
807 var repeat = page.repeatCount;
|
nickjillings@1380
|
808 while(repeat >= 0)
|
nickjillings@1380
|
809 {
|
nickjillings@1380
|
810 pageHolder.push(page);
|
nickjillings@1380
|
811 repeat--;
|
nickjillings@1380
|
812 }
|
nickjillings@1324
|
813 }
|
nickjillings@1324
|
814 if (specification.randomiseOrder)
|
nickjillings@1324
|
815 {
|
nickjillings@1324
|
816 pageHolder = randomiseOrder(pageHolder);
|
nickjillings@1324
|
817 }
|
nickjillings@1324
|
818 for (var i=0; i<pageHolder.length; i++)
|
nickjillings@1324
|
819 {
|
nickjillings@1324
|
820 pageHolder[i].presentedId = i;
|
nickjillings@1324
|
821 }
|
nickjillings@1324
|
822 for (var i=0; i<specification.pages.length; i++)
|
nickjillings@1324
|
823 {
|
nickjillings@2124
|
824 if (specification.testPages <= i && specification.testPages != 0) {break;}
|
nickjillings@1324
|
825 this.stateMap.push(pageHolder[i]);
|
nickjillings@2149
|
826 storage.createTestPageStore(pageHolder[i]);
|
nickjillings@1324
|
827 }
|
nickjillings@2124
|
828
|
nickjillings@1324
|
829 if (specification.preTest != null) {this.preTestSurvey = specification.preTest;}
|
nickjillings@1324
|
830 if (specification.postTest != null) {this.postTestSurvey = specification.postTest;}
|
nickjillings@1324
|
831
|
nickjillings@1634
|
832 if (this.stateMap.length > 0) {
|
nickjillings@1634
|
833 if(this.stateIndex != null) {
|
nickjillings@1634
|
834 console.log('NOTE - State already initialise');
|
nickjillings@1634
|
835 }
|
nickjillings@1634
|
836 this.stateIndex = -1;
|
nickjillings@1634
|
837 } else {
|
b@2059
|
838 console.log('FATAL - StateMap not correctly constructed. EMPTY_STATE_MAP');
|
nickjillings@1622
|
839 }
|
nickjillings@1634
|
840 };
|
nickjillings@1634
|
841 this.advanceState = function(){
|
nickjillings@1634
|
842 if (this.stateIndex == null) {
|
nickjillings@1634
|
843 this.initialise();
|
nickjillings@1634
|
844 }
|
nickjillings@1634
|
845 if (this.stateIndex == -1) {
|
nickjillings@1342
|
846 this.stateIndex++;
|
nickjillings@1634
|
847 console.log('Starting test...');
|
nickjillings@1324
|
848 if (this.preTestSurvey != null)
|
nickjillings@1324
|
849 {
|
nickjillings@1324
|
850 popup.initState(this.preTestSurvey,storage.globalPreTest);
|
nickjillings@1342
|
851 } else {
|
nickjillings@1342
|
852 this.advanceState();
|
nickjillings@1318
|
853 }
|
nickjillings@1324
|
854 } else if (this.stateIndex == this.stateMap.length)
|
nickjillings@1324
|
855 {
|
nickjillings@1324
|
856 // All test pages complete, post test
|
nickjillings@1324
|
857 console.log('Ending test ...');
|
nickjillings@1324
|
858 this.stateIndex++;
|
nickjillings@1324
|
859 if (this.postTestSurvey == null) {
|
nickjillings@1324
|
860 this.advanceState();
|
nickjillings@1318
|
861 } else {
|
nickjillings@1324
|
862 popup.initState(this.postTestSurvey,storage.globalPostTest);
|
nickjillings@1324
|
863 }
|
nickjillings@1324
|
864 } else if (this.stateIndex > this.stateMap.length)
|
nickjillings@1324
|
865 {
|
nickjillings@1324
|
866 createProjectSave(specification.projectReturn);
|
nickjillings@1634
|
867 }
|
nickjillings@1324
|
868 else
|
nickjillings@1324
|
869 {
|
nickjillings@1324
|
870 if (this.currentStateMap == null)
|
nickjillings@1324
|
871 {
|
nickjillings@1318
|
872 this.currentStateMap = this.stateMap[this.stateIndex];
|
nickjillings@1334
|
873 if (this.currentStateMap.randomiseOrder)
|
nickjillings@1334
|
874 {
|
nickjillings@1334
|
875 this.currentStateMap.audioElements = randomiseOrder(this.currentStateMap.audioElements);
|
nickjillings@1334
|
876 }
|
nickjillings@2149
|
877 this.currentStore = storage.testPages[this.stateIndex];
|
nickjillings@1324
|
878 if (this.currentStateMap.preTest != null)
|
nickjillings@1324
|
879 {
|
nickjillings@1324
|
880 this.currentStatePosition = 'pre';
|
nickjillings@1324
|
881 popup.initState(this.currentStateMap.preTest,storage.testPages[this.stateIndex].preTest);
|
nickjillings@1318
|
882 } else {
|
nickjillings@1324
|
883 this.currentStatePosition = 'test';
|
nickjillings@1324
|
884 }
|
nickjillings@1324
|
885 interfaceContext.newPage(this.currentStateMap,storage.testPages[this.stateIndex]);
|
nickjillings@1324
|
886 return;
|
nickjillings@1634
|
887 }
|
nickjillings@1324
|
888 switch(this.currentStatePosition)
|
nickjillings@1324
|
889 {
|
nickjillings@1324
|
890 case 'pre':
|
nickjillings@1324
|
891 this.currentStatePosition = 'test';
|
nickjillings@1324
|
892 break;
|
nickjillings@1324
|
893 case 'test':
|
nickjillings@1324
|
894 this.currentStatePosition = 'post';
|
nickjillings@1324
|
895 // Save the data
|
nickjillings@1324
|
896 this.testPageCompleted();
|
nickjillings@1324
|
897 if (this.currentStateMap.postTest == null)
|
nickjillings@1324
|
898 {
|
nickjillings@1318
|
899 this.advanceState();
|
nickjillings@1324
|
900 return;
|
nickjillings@1634
|
901 } else {
|
nickjillings@1324
|
902 popup.initState(this.currentStateMap.postTest,storage.testPages[this.stateIndex].postTest);
|
nickjillings@1634
|
903 }
|
nickjillings@1324
|
904 break;
|
nickjillings@1324
|
905 case 'post':
|
nickjillings@1324
|
906 this.stateIndex++;
|
nickjillings@1324
|
907 this.currentStateMap = null;
|
nickjillings@2149
|
908 this.currentStore.finish();
|
nickjillings@1324
|
909 this.advanceState();
|
nickjillings@1324
|
910 break;
|
nickjillings@1324
|
911 };
|
nickjillings@1634
|
912 }
|
nickjillings@1634
|
913 };
|
nickjillings@1634
|
914
|
nickjillings@1324
|
915 this.testPageCompleted = function() {
|
nickjillings@1634
|
916 // Function called each time a test page has been completed
|
nickjillings@1324
|
917 var storePoint = storage.testPages[this.stateIndex];
|
nickjillings@1324
|
918 // First get the test metric
|
nickjillings@1324
|
919
|
nickjillings@1324
|
920 var metric = storePoint.XMLDOM.getElementsByTagName('metric')[0];
|
nickjillings@1412
|
921 if (audioEngineContext.metric.enableTestTimer)
|
nickjillings@1412
|
922 {
|
nickjillings@1324
|
923 var testTime = storePoint.parent.document.createElement('metricresult');
|
nickjillings@1412
|
924 testTime.id = 'testTime';
|
nickjillings@1412
|
925 testTime.textContent = audioEngineContext.timer.testDuration;
|
nickjillings@1412
|
926 metric.appendChild(testTime);
|
nickjillings@1412
|
927 }
|
nickjillings@1324
|
928
|
nickjillings@1412
|
929 var audioObjects = audioEngineContext.audioObjects;
|
nickjillings@1324
|
930 for (var ao of audioEngineContext.audioObjects)
|
nickjillings@1412
|
931 {
|
nickjillings@1324
|
932 ao.exportXMLDOM();
|
nickjillings@1412
|
933 }
|
nickjillings@1324
|
934 for (var element of interfaceContext.commentQuestions)
|
nickjillings@1324
|
935 {
|
nickjillings@1324
|
936 element.exportXMLDOM(storePoint);
|
nickjillings@1324
|
937 }
|
nickjillings@1324
|
938 pageXMLSave(storePoint.XMLDOM, this.currentStateMap);
|
nickjillings@1576
|
939 };
|
nickjillings@1621
|
940 }
|
nickjillings@1621
|
941
|
nickjillings@1408
|
942 function AudioEngine(specification) {
|
nickjillings@1682
|
943
|
nickjillings@1682
|
944 // Create two output paths, the main outputGain and fooGain.
|
nickjillings@1682
|
945 // Output gain is default to 1 and any items for playback route here
|
nickjillings@1682
|
946 // Foo gain is used for analysis to ensure paths get processed, but are not heard
|
nickjillings@1682
|
947 // because web audio will optimise and any route which does not go to the destination gets ignored.
|
nickjillings@1682
|
948 this.outputGain = audioContext.createGain();
|
nickjillings@1682
|
949 this.fooGain = audioContext.createGain();
|
nickjillings@1682
|
950 this.fooGain.gain = 0;
|
nickjillings@1682
|
951
|
nickjillings@1688
|
952 // Use this to detect playback state: 0 - stopped, 1 - playing
|
nickjillings@1688
|
953 this.status = 0;
|
nickjillings@1688
|
954
|
nickjillings@1682
|
955 // Connect both gains to output
|
nickjillings@1682
|
956 this.outputGain.connect(audioContext.destination);
|
nickjillings@1682
|
957 this.fooGain.connect(audioContext.destination);
|
nickjillings@1682
|
958
|
nickjillings@1659
|
959 // Create the timer Object
|
nickjillings@1659
|
960 this.timer = new timer();
|
nickjillings@1659
|
961 // Create session metrics
|
nickjillings@1408
|
962 this.metric = new sessionMetrics(this,specification);
|
nickjillings@1659
|
963
|
nickjillings@1667
|
964 this.loopPlayback = false;
|
nickjillings@1667
|
965
|
nickjillings@1324
|
966 this.pageStore = null;
|
nickjillings@1324
|
967
|
nickjillings@1682
|
968 // Create store for new audioObjects
|
nickjillings@1682
|
969 this.audioObjects = [];
|
nickjillings@1682
|
970
|
nickjillings@1410
|
971 this.buffers = [];
|
nickjillings@1430
|
972 this.bufferObj = function()
|
nickjillings@1410
|
973 {
|
nickjillings@1430
|
974 this.url = null;
|
nickjillings@1410
|
975 this.buffer = null;
|
nickjillings@1410
|
976 this.xmlRequest = new XMLHttpRequest();
|
nickjillings@1396
|
977 this.xmlRequest.parent = this;
|
nickjillings@1410
|
978 this.users = [];
|
nickjillings@1316
|
979 this.progress = 0;
|
nickjillings@1316
|
980 this.status = 0;
|
nickjillings@1342
|
981 this.ready = function()
|
nickjillings@1342
|
982 {
|
nickjillings@1316
|
983 if (this.status >= 2)
|
nickjillings@1316
|
984 {
|
nickjillings@1316
|
985 this.status = 3;
|
nickjillings@1316
|
986 }
|
nickjillings@1342
|
987 for (var i=0; i<this.users.length; i++)
|
nickjillings@1342
|
988 {
|
nickjillings@1342
|
989 this.users[i].state = 1;
|
nickjillings@1342
|
990 if (this.users[i].interfaceDOM != null)
|
nickjillings@1342
|
991 {
|
nickjillings@1342
|
992 this.users[i].bufferLoaded(this);
|
nickjillings@1342
|
993 }
|
nickjillings@1342
|
994 }
|
nickjillings@1342
|
995 };
|
nickjillings@1430
|
996 this.getMedia = function(url) {
|
nickjillings@1430
|
997 this.url = url;
|
nickjillings@1430
|
998 this.xmlRequest.open('GET',this.url,true);
|
nickjillings@1430
|
999 this.xmlRequest.responseType = 'arraybuffer';
|
nickjillings@1430
|
1000
|
nickjillings@1430
|
1001 var bufferObj = this;
|
nickjillings@1430
|
1002
|
nickjillings@1430
|
1003 // Create callback to decode the data asynchronously
|
nickjillings@1430
|
1004 this.xmlRequest.onloadend = function() {
|
nickjillings@1353
|
1005 // Use inbuilt WAVE decoder first
|
nickjillings@2113
|
1006 if (this.status == -1) {return;}
|
nickjillings@1353
|
1007 var waveObj = new WAVE();
|
nickjillings@1353
|
1008 if (waveObj.open(bufferObj.xmlRequest.response) == 0)
|
nickjillings@1353
|
1009 {
|
nickjillings@1353
|
1010 bufferObj.buffer = audioContext.createBuffer(waveObj.num_channels,waveObj.num_samples,waveObj.sample_rate);
|
nickjillings@1353
|
1011 for (var c=0; c<waveObj.num_channels; c++)
|
nickjillings@1353
|
1012 {
|
nickjillings@1353
|
1013 var buffer_ptr = bufferObj.buffer.getChannelData(c);
|
nickjillings@1353
|
1014 for (var n=0; n<waveObj.num_samples; n++)
|
nickjillings@1353
|
1015 {
|
nickjillings@1353
|
1016 buffer_ptr[n] = waveObj.decoded_data[c][n];
|
nickjillings@1353
|
1017 }
|
nickjillings@1353
|
1018 }
|
nickjillings@1316
|
1019
|
nickjillings@1353
|
1020 delete waveObj;
|
nickjillings@1353
|
1021 } else {
|
nickjillings@1353
|
1022 audioContext.decodeAudioData(bufferObj.xmlRequest.response, function(decodedData) {
|
nickjillings@1353
|
1023 bufferObj.buffer = decodedData;
|
nickjillings@1353
|
1024 }, function(e){
|
nickjillings@1353
|
1025 // Should only be called if there was an error, but sometimes gets called continuously
|
nickjillings@1353
|
1026 // Check here if the error is genuine
|
nickjillings@1353
|
1027 if (bufferObj.xmlRequest.response == undefined) {
|
nickjillings@1353
|
1028 // Genuine error
|
nickjillings@1353
|
1029 console.log('FATAL - Error loading buffer on '+audioObj.id);
|
nickjillings@1353
|
1030 if (request.status == 404)
|
nickjillings@1353
|
1031 {
|
nickjillings@1353
|
1032 console.log('FATAL - Fragment '+audioObj.id+' 404 error');
|
nickjillings@1353
|
1033 console.log('URL: '+audioObj.url);
|
nickjillings@1353
|
1034 errorSessionDump('Fragment '+audioObj.id+' 404 error');
|
nickjillings@1353
|
1035 }
|
nickjillings@2113
|
1036 this.parent.status = -1;
|
nickjillings@1353
|
1037 }
|
nickjillings@1353
|
1038 });
|
nickjillings@1353
|
1039 }
|
nickjillings@1353
|
1040 if (bufferObj.buffer != undefined)
|
nickjillings@1353
|
1041 {
|
nickjillings@1316
|
1042 bufferObj.status = 2;
|
nickjillings@1353
|
1043 calculateLoudness(bufferObj,"I");
|
nickjillings@1353
|
1044 }
|
nickjillings@1430
|
1045 };
|
nickjillings@2113
|
1046
|
nickjillings@2113
|
1047 // Create callback for any error in loading
|
nickjillings@2113
|
1048 this.xmlRequest.onerror = function() {
|
nickjillings@2113
|
1049 this.parent.status = -1;
|
nickjillings@2113
|
1050 for (var i=0; i<this.parent.users.length; i++)
|
nickjillings@2113
|
1051 {
|
nickjillings@2113
|
1052 this.parent.users[i].state = -1;
|
nickjillings@2113
|
1053 if (this.parent.users[i].interfaceDOM != null)
|
nickjillings@2113
|
1054 {
|
nickjillings@2113
|
1055 this.parent.users[i].bufferLoaded(this);
|
nickjillings@2113
|
1056 }
|
nickjillings@2113
|
1057 }
|
nickjillings@2113
|
1058 }
|
nickjillings@2113
|
1059
|
nickjillings@1433
|
1060 this.progress = 0;
|
nickjillings@1433
|
1061 this.progressCallback = function(event){
|
nickjillings@1433
|
1062 if (event.lengthComputable)
|
nickjillings@1433
|
1063 {
|
nickjillings@1396
|
1064 this.parent.progress = event.loaded / event.total;
|
nickjillings@1396
|
1065 for (var i=0; i<this.parent.users.length; i++)
|
nickjillings@1396
|
1066 {
|
nickjillings@1396
|
1067 if(this.parent.users[i].interfaceDOM != null)
|
nickjillings@1396
|
1068 {
|
nickjillings@1396
|
1069 if (typeof this.parent.users[i].interfaceDOM.updateLoading === "function")
|
nickjillings@1396
|
1070 {
|
nickjillings@1396
|
1071 this.parent.users[i].interfaceDOM.updateLoading(this.parent.progress*100);
|
nickjillings@1396
|
1072 }
|
nickjillings@1396
|
1073 }
|
nickjillings@1396
|
1074 }
|
nickjillings@1433
|
1075 }
|
nickjillings@1433
|
1076 };
|
nickjillings@1433
|
1077 this.xmlRequest.addEventListener("progress", this.progressCallback);
|
nickjillings@1316
|
1078 this.status = 1;
|
nickjillings@1430
|
1079 this.xmlRequest.send();
|
nickjillings@1410
|
1080 };
|
nickjillings@1316
|
1081
|
nickjillings@1316
|
1082 this.registerAudioObject = function(audioObject)
|
nickjillings@1316
|
1083 {
|
nickjillings@1316
|
1084 // Called by an audioObject to register to the buffer for use
|
nickjillings@1316
|
1085 // First check if already in the register pool
|
nickjillings@1316
|
1086 for (var objects of this.users)
|
nickjillings@1316
|
1087 {
|
nickjillings@1316
|
1088 if (audioObject.id == objects.id){return 0;}
|
nickjillings@1316
|
1089 }
|
nickjillings@1316
|
1090 this.users.push(audioObject);
|
nickjillings@2113
|
1091 if (this.status == 3 || this.status == -1)
|
nickjillings@1316
|
1092 {
|
nickjillings@1316
|
1093 // The buffer is already ready, trigger bufferLoaded
|
nickjillings@1316
|
1094 audioObject.bufferLoaded(this);
|
nickjillings@1316
|
1095 }
|
nickjillings@1316
|
1096 }
|
nickjillings@1410
|
1097 };
|
nickjillings@1410
|
1098
|
nickjillings@1565
|
1099 this.play = function(id) {
|
nickjillings@1620
|
1100 // Start the timer and set the audioEngine state to playing (1)
|
nickjillings@1523
|
1101 if (this.status == 0 && this.loopPlayback) {
|
nickjillings@1620
|
1102 // Check if all audioObjects are ready
|
nickjillings@1523
|
1103 if(this.checkAllReady())
|
nickjillings@1523
|
1104 {
|
nickjillings@1565
|
1105 this.status = 1;
|
nickjillings@1523
|
1106 this.setSynchronousLoop();
|
nickjillings@1565
|
1107 }
|
nickjillings@1565
|
1108 }
|
nickjillings@1523
|
1109 else
|
nickjillings@1523
|
1110 {
|
nickjillings@1523
|
1111 this.status = 1;
|
nickjillings@1523
|
1112 }
|
nickjillings@1565
|
1113 if (this.status== 1) {
|
nickjillings@1523
|
1114 this.timer.startTest();
|
nickjillings@1567
|
1115 if (id == undefined) {
|
nickjillings@1567
|
1116 id = -1;
|
nickjillings@1523
|
1117 console.log('FATAL - Passed id was undefined - AudioEngineContext.play(id)');
|
nickjillings@1523
|
1118 return;
|
nickjillings@1567
|
1119 } else {
|
nickjillings@1567
|
1120 interfaceContext.playhead.setTimePerPixel(this.audioObjects[id]);
|
nickjillings@1567
|
1121 }
|
nickjillings@1565
|
1122 if (this.loopPlayback) {
|
nickjillings@2099
|
1123 var setTime = audioContext.currentTime;
|
nickjillings@1565
|
1124 for (var i=0; i<this.audioObjects.length; i++)
|
nickjillings@1565
|
1125 {
|
nickjillings@2099
|
1126 this.audioObjects[i].play(setTime);
|
nickjillings@1565
|
1127 if (id == i) {
|
nickjillings@1360
|
1128 this.audioObjects[i].loopStart(setTime);
|
nickjillings@1565
|
1129 } else {
|
nickjillings@1360
|
1130 this.audioObjects[i].loopStop(setTime);
|
nickjillings@1636
|
1131 }
|
nickjillings@1636
|
1132 }
|
nickjillings@1565
|
1133 } else {
|
nickjillings@1360
|
1134 var setTime = audioContext.currentTime+0.1;
|
nickjillings@1565
|
1135 for (var i=0; i<this.audioObjects.length; i++)
|
nickjillings@1565
|
1136 {
|
nickjillings@1565
|
1137 if (i != id) {
|
nickjillings@1360
|
1138 this.audioObjects[i].stop(setTime);
|
nickjillings@1565
|
1139 } else if (i == id) {
|
nickjillings@1360
|
1140 this.audioObjects[id].play(setTime);
|
nickjillings@1565
|
1141 }
|
nickjillings@1565
|
1142 }
|
nickjillings@1620
|
1143 }
|
nickjillings@1567
|
1144 interfaceContext.playhead.start();
|
nickjillings@1620
|
1145 }
|
nickjillings@1620
|
1146 };
|
nickjillings@1682
|
1147
|
nickjillings@1620
|
1148 this.stop = function() {
|
nickjillings@1378
|
1149 // Send stop and reset command to all playback buffers
|
nickjillings@1620
|
1150 if (this.status == 1) {
|
nickjillings@1360
|
1151 var setTime = audioContext.currentTime+0.1;
|
nickjillings@1620
|
1152 for (var i=0; i<this.audioObjects.length; i++)
|
nickjillings@1620
|
1153 {
|
nickjillings@1360
|
1154 this.audioObjects[i].stop(setTime);
|
nickjillings@1620
|
1155 }
|
nickjillings@1567
|
1156 interfaceContext.playhead.stop();
|
nickjillings@1620
|
1157 }
|
nickjillings@1620
|
1158 };
|
nickjillings@1689
|
1159
|
nickjillings@1582
|
1160 this.newTrack = function(element) {
|
nickjillings@1682
|
1161 // Pull data from given URL into new audio buffer
|
nickjillings@1682
|
1162 // URLs must either be from the same source OR be setup to 'Access-Control-Allow-Origin'
|
nickjillings@1688
|
1163
|
nickjillings@1682
|
1164 // Create the audioObject with ID of the new track length;
|
nickjillings@1659
|
1165 audioObjectId = this.audioObjects.length;
|
nickjillings@1682
|
1166 this.audioObjects[audioObjectId] = new audioObject(audioObjectId);
|
nickjillings@1688
|
1167
|
nickjillings@1410
|
1168 // Check if audioObject buffer is currently stored by full URL
|
nickjillings@1324
|
1169 var URL = testState.currentStateMap.hostURL + element.url;
|
nickjillings@1410
|
1170 var buffer = null;
|
nickjillings@1410
|
1171 for (var i=0; i<this.buffers.length; i++)
|
nickjillings@1410
|
1172 {
|
nickjillings@1410
|
1173 if (URL == this.buffers[i].url)
|
nickjillings@1410
|
1174 {
|
nickjillings@1410
|
1175 buffer = this.buffers[i];
|
nickjillings@1410
|
1176 break;
|
nickjillings@1410
|
1177 }
|
nickjillings@1410
|
1178 }
|
nickjillings@1410
|
1179 if (buffer == null)
|
nickjillings@1410
|
1180 {
|
nickjillings@1426
|
1181 console.log("[WARN]: Buffer was not loaded in pre-test! "+URL);
|
nickjillings@1430
|
1182 buffer = new this.bufferObj();
|
nickjillings@1316
|
1183 this.buffers.push(buffer);
|
nickjillings@1430
|
1184 buffer.getMedia(URL);
|
nickjillings@1410
|
1185 }
|
nickjillings@1582
|
1186 this.audioObjects[audioObjectId].specification = element;
|
nickjillings@1426
|
1187 this.audioObjects[audioObjectId].url = URL;
|
nickjillings@1324
|
1188 // Obtain store node
|
nickjillings@1324
|
1189 var aeNodes = this.pageStore.XMLDOM.getElementsByTagName('audioelement');
|
nickjillings@1324
|
1190 for (var i=0; i<aeNodes.length; i++)
|
nickjillings@1410
|
1191 {
|
nickjillings@1324
|
1192 if(aeNodes[i].id == element.id)
|
nickjillings@1324
|
1193 {
|
nickjillings@1324
|
1194 this.audioObjects[audioObjectId].storeDOM = aeNodes[i];
|
nickjillings@1324
|
1195 break;
|
nickjillings@1324
|
1196 }
|
nickjillings@1410
|
1197 }
|
nickjillings@1316
|
1198 buffer.registerAudioObject(this.audioObjects[audioObjectId]);
|
nickjillings@1579
|
1199 return this.audioObjects[audioObjectId];
|
nickjillings@1697
|
1200 };
|
nickjillings@1682
|
1201
|
nickjillings@1369
|
1202 this.newTestPage = function(audioHolderObject,store) {
|
nickjillings@1324
|
1203 this.pageStore = store;
|
nickjillings@2127
|
1204 this.status = 0;
|
nickjillings@1620
|
1205 this.audioObjectsReady = false;
|
nickjillings@1620
|
1206 this.metric.reset();
|
nickjillings@1410
|
1207 for (var i=0; i < this.buffers.length; i++)
|
nickjillings@1410
|
1208 {
|
nickjillings@1410
|
1209 this.buffers[i].users = [];
|
nickjillings@1410
|
1210 }
|
nickjillings@1620
|
1211 this.audioObjects = [];
|
nickjillings@1369
|
1212 this.timer = new timer();
|
nickjillings@1369
|
1213 this.loopPlayback = audioHolderObject.loop;
|
nickjillings@1620
|
1214 };
|
nickjillings@1620
|
1215
|
nickjillings@1614
|
1216 this.checkAllPlayed = function() {
|
nickjillings@1614
|
1217 arr = [];
|
nickjillings@1614
|
1218 for (var id=0; id<this.audioObjects.length; id++) {
|
nickjillings@2008
|
1219 if (this.audioObjects[id].metric.wasListenedTo == false) {
|
nickjillings@1614
|
1220 arr.push(this.audioObjects[id].id);
|
nickjillings@1614
|
1221 }
|
nickjillings@1614
|
1222 }
|
nickjillings@1614
|
1223 return arr;
|
nickjillings@1614
|
1224 };
|
nickjillings@1614
|
1225
|
nickjillings@1620
|
1226 this.checkAllReady = function() {
|
nickjillings@1620
|
1227 var ready = true;
|
nickjillings@1620
|
1228 for (var i=0; i<this.audioObjects.length; i++) {
|
nickjillings@1620
|
1229 if (this.audioObjects[i].state == 0) {
|
nickjillings@1620
|
1230 // Track not ready
|
nickjillings@1620
|
1231 console.log('WAIT -- audioObject '+i+' not ready yet!');
|
nickjillings@1620
|
1232 ready = false;
|
nickjillings@1620
|
1233 };
|
nickjillings@1620
|
1234 }
|
nickjillings@1620
|
1235 return ready;
|
nickjillings@1620
|
1236 };
|
nickjillings@1620
|
1237
|
nickjillings@1535
|
1238 this.setSynchronousLoop = function() {
|
nickjillings@1535
|
1239 // Pads the signals so they are all exactly the same length
|
nickjillings@1523
|
1240 var length = 0;
|
nickjillings@1523
|
1241 var maxId;
|
nickjillings@1523
|
1242 for (var i=0; i<this.audioObjects.length; i++)
|
nickjillings@1535
|
1243 {
|
nickjillings@1413
|
1244 if (length < this.audioObjects[i].buffer.buffer.length)
|
nickjillings@1535
|
1245 {
|
nickjillings@1413
|
1246 length = this.audioObjects[i].buffer.buffer.length;
|
nickjillings@1523
|
1247 maxId = i;
|
nickjillings@1535
|
1248 }
|
nickjillings@1523
|
1249 }
|
nickjillings@1404
|
1250 // Extract the audio and zero-pad
|
nickjillings@1430
|
1251 for (var i=0; i<this.audioObjects.length; i++)
|
nickjillings@1523
|
1252 {
|
nickjillings@1413
|
1253 var orig = this.audioObjects[i].buffer.buffer;
|
nickjillings@1523
|
1254 var hold = audioContext.createBuffer(orig.numberOfChannels,length,orig.sampleRate);
|
nickjillings@1523
|
1255 for (var c=0; c<orig.numberOfChannels; c++)
|
nickjillings@1535
|
1256 {
|
nickjillings@1523
|
1257 var inData = hold.getChannelData(c);
|
nickjillings@1523
|
1258 var outData = orig.getChannelData(c);
|
nickjillings@1523
|
1259 for (var n=0; n<orig.length; n++)
|
nickjillings@1523
|
1260 {inData[n] = outData[n];}
|
nickjillings@1535
|
1261 }
|
nickjillings@1320
|
1262 hold.playbackGain = orig.playbackGain;
|
nickjillings@1430
|
1263 hold.lufs = orig.lufs;
|
nickjillings@1413
|
1264 this.audioObjects[i].buffer.buffer = hold;
|
nickjillings@1535
|
1265 }
|
nickjillings@1535
|
1266 };
|
nickjillings@1370
|
1267
|
nickjillings@1370
|
1268 this.exportXML = function()
|
nickjillings@1370
|
1269 {
|
nickjillings@1370
|
1270
|
nickjillings@1370
|
1271 };
|
nickjillings@1535
|
1272
|
nickjillings@1682
|
1273 }
|
nickjillings@1682
|
1274
|
nickjillings@1682
|
1275 function audioObject(id) {
|
nickjillings@1682
|
1276 // The main buffer object with common control nodes to the AudioEngine
|
nickjillings@1682
|
1277
|
nickjillings@1582
|
1278 this.specification;
|
nickjillings@1682
|
1279 this.id = id;
|
nickjillings@1682
|
1280 this.state = 0; // 0 - no data, 1 - ready
|
nickjillings@1704
|
1281 this.url = null; // Hold the URL given for the output back to the results.
|
nickjillings@1602
|
1282 this.metric = new metricTracker(this);
|
nickjillings@1324
|
1283 this.storeDOM = null;
|
nickjillings@1682
|
1284
|
nickjillings@1577
|
1285 // Bindings for GUI
|
nickjillings@1583
|
1286 this.interfaceDOM = null;
|
nickjillings@1577
|
1287 this.commentDOM = null;
|
nickjillings@1577
|
1288
|
nickjillings@1682
|
1289 // Create a buffer and external gain control to allow internal patching of effects and volume leveling.
|
nickjillings@1667
|
1290 this.bufferNode = undefined;
|
nickjillings@1682
|
1291 this.outputGain = audioContext.createGain();
|
nickjillings@1682
|
1292
|
nickjillings@1324
|
1293 this.onplayGain = 1.0;
|
nickjillings@1689
|
1294
|
nickjillings@1682
|
1295 // Connect buffer to the audio graph
|
nickjillings@1682
|
1296 this.outputGain.connect(audioEngineContext.outputGain);
|
nickjillings@1682
|
1297
|
nickjillings@1682
|
1298 // the audiobuffer is not designed for multi-start playback
|
nickjillings@1682
|
1299 // When stopeed, the buffer node is deleted and recreated with the stored buffer.
|
nickjillings@1682
|
1300 this.buffer;
|
nickjillings@1434
|
1301
|
nickjillings@1434
|
1302 this.bufferLoaded = function(callee)
|
nickjillings@1434
|
1303 {
|
nickjillings@1434
|
1304 // Called by the associated buffer when it has finished loading, will then 'bind' the buffer to the
|
nickjillings@1434
|
1305 // audioObject and trigger the interfaceDOM.enable() function for user feedback
|
nickjillings@2113
|
1306 if (callee.status == -1) {
|
nickjillings@2113
|
1307 // ERROR
|
nickjillings@2113
|
1308 this.state = -1;
|
nickjillings@2113
|
1309 if (this.interfaceDOM != null) {this.interfaceDOM.error();}
|
nickjillings@2113
|
1310 this.buffer = callee;
|
nickjillings@2113
|
1311 return;
|
nickjillings@2113
|
1312 }
|
nickjillings@1434
|
1313 if (audioEngineContext.loopPlayback){
|
nickjillings@1434
|
1314 // First copy the buffer into this.buffer
|
nickjillings@1434
|
1315 this.buffer = new audioEngineContext.bufferObj();
|
nickjillings@1434
|
1316 this.buffer.url = callee.url;
|
nickjillings@1434
|
1317 this.buffer.buffer = audioContext.createBuffer(callee.buffer.numberOfChannels, callee.buffer.length, callee.buffer.sampleRate);
|
nickjillings@1434
|
1318 for (var c=0; c<callee.buffer.numberOfChannels; c++)
|
nickjillings@1434
|
1319 {
|
nickjillings@1434
|
1320 var src = callee.buffer.getChannelData(c);
|
nickjillings@1434
|
1321 var dst = this.buffer.buffer.getChannelData(c);
|
nickjillings@1434
|
1322 for (var n=0; n<src.length; n++)
|
nickjillings@1434
|
1323 {
|
nickjillings@1434
|
1324 dst[n] = src[n];
|
nickjillings@1434
|
1325 }
|
nickjillings@1434
|
1326 }
|
nickjillings@1434
|
1327 } else {
|
nickjillings@1434
|
1328 this.buffer = callee;
|
nickjillings@1434
|
1329 }
|
nickjillings@1434
|
1330 this.state = 1;
|
nickjillings@1320
|
1331 this.buffer.buffer.playbackGain = callee.buffer.playbackGain;
|
nickjillings@1434
|
1332 this.buffer.buffer.lufs = callee.buffer.lufs;
|
nickjillings@1348
|
1333 var targetLUFS = this.specification.parent.loudness || specification.loudness;
|
nickjillings@1434
|
1334 if (typeof targetLUFS === "number")
|
nickjillings@1434
|
1335 {
|
nickjillings@1320
|
1336 this.buffer.buffer.playbackGain = decibelToLinear(targetLUFS - this.buffer.buffer.lufs);
|
nickjillings@1434
|
1337 } else {
|
nickjillings@1320
|
1338 this.buffer.buffer.playbackGain = 1.0;
|
nickjillings@1434
|
1339 }
|
nickjillings@1434
|
1340 if (this.interfaceDOM != null) {
|
nickjillings@1434
|
1341 this.interfaceDOM.enable();
|
nickjillings@1434
|
1342 }
|
nickjillings@1324
|
1343 this.onplayGain = decibelToLinear(this.specification.gain)*this.buffer.buffer.playbackGain;
|
nickjillings@1324
|
1344 this.storeDOM.setAttribute('playGain',linearToDecibel(this.onplayGain));
|
nickjillings@1318
|
1345 };
|
nickjillings@1325
|
1346
|
nickjillings@1325
|
1347 this.bindInterface = function(interfaceObject)
|
nickjillings@1325
|
1348 {
|
nickjillings@1325
|
1349 this.interfaceDOM = interfaceObject;
|
nickjillings@1325
|
1350 this.metric.initialise(interfaceObject.getValue());
|
nickjillings@1325
|
1351 if (this.state == 1)
|
nickjillings@1325
|
1352 {
|
nickjillings@1325
|
1353 this.interfaceDOM.enable();
|
nickjillings@2113
|
1354 } else if (this.state == -1) {
|
nickjillings@2113
|
1355 // ERROR
|
nickjillings@2113
|
1356 this.interfaceDOM.error();
|
nickjillings@2113
|
1357 return;
|
nickjillings@2113
|
1358 }
|
nickjillings@1338
|
1359 this.storeDOM.setAttribute('presentedId',interfaceObject.getPresentedId());
|
nickjillings@1434
|
1360 };
|
b@1639
|
1361
|
nickjillings@1360
|
1362 this.loopStart = function(setTime) {
|
nickjillings@1360
|
1363 this.outputGain.gain.linearRampToValueAtTime(this.onplayGain,setTime);
|
nickjillings@1637
|
1364 this.metric.startListening(audioEngineContext.timer.getTestTime());
|
nickjillings@1360
|
1365 this.interfaceDOM.startPlayback();
|
nickjillings@1577
|
1366 };
|
nickjillings@1637
|
1367
|
nickjillings@1360
|
1368 this.loopStop = function(setTime) {
|
nickjillings@1637
|
1369 if (this.outputGain.gain.value != 0.0) {
|
nickjillings@1360
|
1370 this.outputGain.gain.linearRampToValueAtTime(0.0,setTime);
|
nickjillings@1637
|
1371 this.metric.stopListening(audioEngineContext.timer.getTestTime());
|
nickjillings@1637
|
1372 }
|
nickjillings@1360
|
1373 this.interfaceDOM.stopPlayback();
|
nickjillings@1577
|
1374 };
|
nickjillings@1637
|
1375
|
nickjillings@1682
|
1376 this.play = function(startTime) {
|
nickjillings@1410
|
1377 if (this.bufferNode == undefined && this.buffer.buffer != undefined) {
|
nickjillings@1565
|
1378 this.bufferNode = audioContext.createBufferSource();
|
nickjillings@1565
|
1379 this.bufferNode.owner = this;
|
nickjillings@1565
|
1380 this.bufferNode.connect(this.outputGain);
|
nickjillings@1410
|
1381 this.bufferNode.buffer = this.buffer.buffer;
|
nickjillings@1565
|
1382 this.bufferNode.loop = audioEngineContext.loopPlayback;
|
nickjillings@1522
|
1383 this.bufferNode.onended = function(event) {
|
nickjillings@1565
|
1384 // Safari does not like using 'this' to reference the calling object!
|
nickjillings@1458
|
1385 //event.currentTarget.owner.metric.stopListening(audioEngineContext.timer.getTestTime(),event.currentTarget.owner.getCurrentPosition());
|
nickjillings@2120
|
1386 if (event.currentTarget != null) {
|
nickjillings@2120
|
1387 event.currentTarget.owner.stop(audioContext.currentTime+1);
|
nickjillings@2120
|
1388 }
|
nickjillings@1565
|
1389 };
|
nickjillings@1565
|
1390 if (this.bufferNode.loop == false) {
|
nickjillings@1565
|
1391 this.metric.startListening(audioEngineContext.timer.getTestTime());
|
nickjillings@1360
|
1392 this.outputGain.gain.setValueAtTime(this.onplayGain,startTime);
|
nickjillings@1360
|
1393 this.interfaceDOM.startPlayback();
|
nickjillings@1360
|
1394 } else {
|
nickjillings@1360
|
1395 this.outputGain.gain.setValueAtTime(0.0,startTime);
|
nickjillings@1360
|
1396 }
|
nickjillings@1565
|
1397 this.bufferNode.start(startTime);
|
nickjillings@2126
|
1398 this.bufferNode.playbackStartTime = audioEngineContext.timer.getTestTime();
|
nickjillings@1617
|
1399 }
|
nickjillings@1697
|
1400 };
|
nickjillings@1682
|
1401
|
nickjillings@1360
|
1402 this.stop = function(stopTime) {
|
nickjillings@1360
|
1403 this.outputGain.gain.cancelScheduledValues(audioContext.currentTime);
|
nickjillings@2002
|
1404 if (this.bufferNode != undefined)
|
nickjillings@2002
|
1405 {
|
nickjillings@1566
|
1406 this.metric.stopListening(audioEngineContext.timer.getTestTime(),this.getCurrentPosition());
|
nickjillings@1360
|
1407 this.bufferNode.stop(stopTime);
|
nickjillings@2002
|
1408 this.bufferNode = undefined;
|
nickjillings@2002
|
1409 }
|
nickjillings@1360
|
1410 this.outputGain.gain.value = 0.0;
|
nickjillings@1360
|
1411 this.interfaceDOM.stopPlayback();
|
nickjillings@1697
|
1412 };
|
nickjillings@2019
|
1413
|
nickjillings@2019
|
1414 this.getCurrentPosition = function() {
|
nickjillings@2019
|
1415 var time = audioEngineContext.timer.getTestTime();
|
nickjillings@2019
|
1416 if (this.bufferNode != undefined) {
|
nickjillings@2138
|
1417 var position = (time - this.bufferNode.playbackStartTime)%this.buffer.buffer.duration;
|
nickjillings@2138
|
1418 if (isNaN(position)){return 0;}
|
nickjillings@2138
|
1419 return position;
|
nickjillings@2019
|
1420 } else {
|
nickjillings@2019
|
1421 return 0;
|
nickjillings@2019
|
1422 }
|
nickjillings@2019
|
1423 };
|
nickjillings@1688
|
1424
|
nickjillings@1583
|
1425 this.exportXMLDOM = function() {
|
nickjillings@1324
|
1426 var file = storage.document.createElement('file');
|
nickjillings@1416
|
1427 file.setAttribute('sampleRate',this.buffer.buffer.sampleRate);
|
nickjillings@1416
|
1428 file.setAttribute('channels',this.buffer.buffer.numberOfChannels);
|
nickjillings@1416
|
1429 file.setAttribute('sampleCount',this.buffer.buffer.length);
|
nickjillings@1416
|
1430 file.setAttribute('duration',this.buffer.buffer.duration);
|
nickjillings@1324
|
1431 this.storeDOM.appendChild(file);
|
nickjillings@1324
|
1432 if (this.specification.type != 'outside-reference') {
|
nickjillings@1413
|
1433 var interfaceXML = this.interfaceDOM.exportXMLDOM(this);
|
nickjillings@1340
|
1434 if (interfaceXML != null)
|
nickjillings@1340
|
1435 {
|
nickjillings@1340
|
1436 if (interfaceXML.length == undefined) {
|
nickjillings@1340
|
1437 this.storeDOM.appendChild(interfaceXML);
|
nickjillings@1340
|
1438 } else {
|
nickjillings@1340
|
1439 for (var i=0; i<interfaceXML.length; i++)
|
nickjillings@1340
|
1440 {
|
nickjillings@1340
|
1441 this.storeDOM.appendChild(interfaceXML[i]);
|
nickjillings@1340
|
1442 }
|
nickjillings@1413
|
1443 }
|
nickjillings@1413
|
1444 }
|
nickjillings@1330
|
1445 if (this.commentDOM != null) {
|
nickjillings@1330
|
1446 this.storeDOM.appendChild(this.commentDOM.exportXMLDOM(this));
|
nickjillings@1529
|
1447 }
|
nickjillings@2050
|
1448 }
|
nickjillings@1324
|
1449 var nodes = this.metric.exportXMLDOM();
|
nickjillings@1324
|
1450 var mroot = this.storeDOM.getElementsByTagName('metric')[0];
|
nickjillings@1324
|
1451 for (var i=0; i<nodes.length; i++)
|
nickjillings@1324
|
1452 {
|
nickjillings@1324
|
1453 mroot.appendChild(nodes[i]);
|
nickjillings@1324
|
1454 }
|
nickjillings@1583
|
1455 };
|
nickjillings@1659
|
1456 }
|
nickjillings@1659
|
1457
|
nickjillings@1659
|
1458 function timer()
|
nickjillings@1659
|
1459 {
|
nickjillings@1659
|
1460 /* Timer object used in audioEngine to keep track of session timings
|
nickjillings@1659
|
1461 * Uses the timer of the web audio API, so sample resolution
|
nickjillings@1659
|
1462 */
|
nickjillings@1659
|
1463 this.testStarted = false;
|
nickjillings@1659
|
1464 this.testStartTime = 0;
|
nickjillings@1659
|
1465 this.testDuration = 0;
|
nickjillings@1659
|
1466 this.minimumTestTime = 0; // No minimum test time
|
nickjillings@1659
|
1467 this.startTest = function()
|
nickjillings@1659
|
1468 {
|
nickjillings@1659
|
1469 if (this.testStarted == false)
|
nickjillings@1659
|
1470 {
|
nickjillings@1659
|
1471 this.testStartTime = audioContext.currentTime;
|
nickjillings@1659
|
1472 this.testStarted = true;
|
nickjillings@1659
|
1473 this.updateTestTime();
|
nickjillings@1662
|
1474 audioEngineContext.metric.initialiseTest();
|
nickjillings@1659
|
1475 }
|
nickjillings@1659
|
1476 };
|
nickjillings@1659
|
1477 this.stopTest = function()
|
nickjillings@1659
|
1478 {
|
nickjillings@1659
|
1479 if (this.testStarted)
|
nickjillings@1659
|
1480 {
|
nickjillings@1659
|
1481 this.testDuration = this.getTestTime();
|
nickjillings@1659
|
1482 this.testStarted = false;
|
nickjillings@1659
|
1483 } else {
|
nickjillings@1659
|
1484 console.log('ERR: Test tried to end before beginning');
|
nickjillings@1659
|
1485 }
|
nickjillings@1659
|
1486 };
|
nickjillings@1659
|
1487 this.updateTestTime = function()
|
nickjillings@1659
|
1488 {
|
nickjillings@1659
|
1489 if (this.testStarted)
|
nickjillings@1659
|
1490 {
|
nickjillings@1659
|
1491 this.testDuration = audioContext.currentTime - this.testStartTime;
|
nickjillings@1659
|
1492 }
|
nickjillings@1659
|
1493 };
|
nickjillings@1659
|
1494 this.getTestTime = function()
|
nickjillings@1659
|
1495 {
|
nickjillings@1659
|
1496 this.updateTestTime();
|
nickjillings@1659
|
1497 return this.testDuration;
|
nickjillings@1659
|
1498 };
|
nickjillings@1659
|
1499 }
|
nickjillings@1659
|
1500
|
nickjillings@1408
|
1501 function sessionMetrics(engine,specification)
|
nickjillings@1659
|
1502 {
|
nickjillings@1659
|
1503 /* Used by audioEngine to link to audioObjects to minimise the timer call timers;
|
nickjillings@1659
|
1504 */
|
nickjillings@1659
|
1505 this.engine = engine;
|
nickjillings@1659
|
1506 this.lastClicked = -1;
|
nickjillings@1659
|
1507 this.data = -1;
|
nickjillings@1620
|
1508 this.reset = function() {
|
nickjillings@1620
|
1509 this.lastClicked = -1;
|
nickjillings@1620
|
1510 this.data = -1;
|
nickjillings@1620
|
1511 };
|
nickjillings@1408
|
1512
|
nickjillings@1408
|
1513 this.enableElementInitialPosition = false;
|
nickjillings@1408
|
1514 this.enableElementListenTracker = false;
|
nickjillings@1408
|
1515 this.enableElementTimer = false;
|
nickjillings@1408
|
1516 this.enableElementTracker = false;
|
nickjillings@1408
|
1517 this.enableFlagListenedTo = false;
|
nickjillings@1408
|
1518 this.enableFlagMoved = false;
|
nickjillings@1408
|
1519 this.enableTestTimer = false;
|
nickjillings@1408
|
1520 // Obtain the metrics enabled
|
nickjillings@1324
|
1521 for (var i=0; i<specification.metrics.enabled.length; i++)
|
nickjillings@1408
|
1522 {
|
nickjillings@1324
|
1523 var node = specification.metrics.enabled[i];
|
nickjillings@1324
|
1524 switch(node)
|
nickjillings@1408
|
1525 {
|
nickjillings@1408
|
1526 case 'testTimer':
|
nickjillings@1408
|
1527 this.enableTestTimer = true;
|
nickjillings@1408
|
1528 break;
|
nickjillings@1408
|
1529 case 'elementTimer':
|
nickjillings@1408
|
1530 this.enableElementTimer = true;
|
nickjillings@1408
|
1531 break;
|
nickjillings@1408
|
1532 case 'elementTracker':
|
nickjillings@1408
|
1533 this.enableElementTracker = true;
|
nickjillings@1408
|
1534 break;
|
nickjillings@1408
|
1535 case 'elementListenTracker':
|
nickjillings@1408
|
1536 this.enableElementListenTracker = true;
|
nickjillings@1408
|
1537 break;
|
nickjillings@1408
|
1538 case 'elementInitialPosition':
|
nickjillings@1408
|
1539 this.enableElementInitialPosition = true;
|
nickjillings@1408
|
1540 break;
|
nickjillings@1408
|
1541 case 'elementFlagListenedTo':
|
nickjillings@1408
|
1542 this.enableFlagListenedTo = true;
|
nickjillings@1408
|
1543 break;
|
nickjillings@1408
|
1544 case 'elementFlagMoved':
|
nickjillings@1408
|
1545 this.enableFlagMoved = true;
|
nickjillings@1408
|
1546 break;
|
nickjillings@1408
|
1547 case 'elementFlagComments':
|
nickjillings@1408
|
1548 this.enableFlagComments = true;
|
nickjillings@1408
|
1549 break;
|
nickjillings@1408
|
1550 }
|
nickjillings@1408
|
1551 }
|
nickjillings@1662
|
1552 this.initialiseTest = function(){};
|
nickjillings@1659
|
1553 }
|
nickjillings@1659
|
1554
|
nickjillings@1602
|
1555 function metricTracker(caller)
|
nickjillings@1659
|
1556 {
|
nickjillings@1659
|
1557 /* Custom object to track and collect metric data
|
nickjillings@1659
|
1558 * Used only inside the audioObjects object.
|
nickjillings@1659
|
1559 */
|
nickjillings@1659
|
1560
|
nickjillings@1659
|
1561 this.listenedTimer = 0;
|
nickjillings@1659
|
1562 this.listenStart = 0;
|
nickjillings@1617
|
1563 this.listenHold = false;
|
nickjillings@1661
|
1564 this.initialPosition = -1;
|
nickjillings@1659
|
1565 this.movementTracker = [];
|
nickjillings@2019
|
1566 this.listenTracker =[];
|
nickjillings@1659
|
1567 this.wasListenedTo = false;
|
nickjillings@1659
|
1568 this.wasMoved = false;
|
nickjillings@1659
|
1569 this.hasComments = false;
|
nickjillings@1602
|
1570 this.parent = caller;
|
nickjillings@1659
|
1571
|
nickjillings@1324
|
1572 this.initialise = function(position)
|
nickjillings@1659
|
1573 {
|
nickjillings@1661
|
1574 if (this.initialPosition == -1) {
|
nickjillings@1661
|
1575 this.initialPosition = position;
|
nickjillings@1325
|
1576 this.moved(0,position);
|
nickjillings@1661
|
1577 }
|
nickjillings@1659
|
1578 };
|
nickjillings@1659
|
1579
|
nickjillings@1659
|
1580 this.moved = function(time,position)
|
nickjillings@1659
|
1581 {
|
nickjillings@1325
|
1582 if (time > 0) {this.wasMoved = true;}
|
nickjillings@1659
|
1583 this.movementTracker[this.movementTracker.length] = [time, position];
|
nickjillings@1659
|
1584 };
|
nickjillings@1659
|
1585
|
nickjillings@1637
|
1586 this.startListening = function(time)
|
nickjillings@1659
|
1587 {
|
nickjillings@1617
|
1588 if (this.listenHold == false)
|
nickjillings@1659
|
1589 {
|
nickjillings@1659
|
1590 this.wasListenedTo = true;
|
nickjillings@1659
|
1591 this.listenStart = time;
|
nickjillings@1617
|
1592 this.listenHold = true;
|
nickjillings@2019
|
1593
|
nickjillings@2019
|
1594 var evnt = document.createElement('event');
|
nickjillings@2019
|
1595 var testTime = document.createElement('testTime');
|
nickjillings@2019
|
1596 testTime.setAttribute('start',time);
|
nickjillings@2019
|
1597 var bufferTime = document.createElement('bufferTime');
|
nickjillings@2019
|
1598 bufferTime.setAttribute('start',this.parent.getCurrentPosition());
|
nickjillings@2019
|
1599 evnt.appendChild(testTime);
|
nickjillings@2019
|
1600 evnt.appendChild(bufferTime);
|
nickjillings@2019
|
1601 this.listenTracker.push(evnt);
|
nickjillings@2019
|
1602
|
nickjillings@1602
|
1603 console.log('slider ' + this.parent.id + ' played (' + time + ')'); // DEBUG/SAFETY: show played slider id
|
nickjillings@1602
|
1604 }
|
nickjillings@1602
|
1605 };
|
nickjillings@1637
|
1606
|
nickjillings@1566
|
1607 this.stopListening = function(time,bufferStopTime)
|
nickjillings@1637
|
1608 {
|
nickjillings@1637
|
1609 if (this.listenHold == true)
|
nickjillings@1637
|
1610 {
|
nickjillings@2019
|
1611 var diff = time - this.listenStart;
|
nickjillings@2019
|
1612 this.listenedTimer += (diff);
|
nickjillings@1659
|
1613 this.listenStart = 0;
|
nickjillings@1617
|
1614 this.listenHold = false;
|
nickjillings@2019
|
1615
|
nickjillings@2019
|
1616 var evnt = this.listenTracker[this.listenTracker.length-1];
|
nickjillings@2019
|
1617 var testTime = evnt.getElementsByTagName('testTime')[0];
|
nickjillings@2019
|
1618 var bufferTime = evnt.getElementsByTagName('bufferTime')[0];
|
nickjillings@2019
|
1619 testTime.setAttribute('stop',time);
|
nickjillings@1566
|
1620 if (bufferStopTime == undefined) {
|
nickjillings@1566
|
1621 bufferTime.setAttribute('stop',this.parent.getCurrentPosition());
|
nickjillings@1566
|
1622 } else {
|
nickjillings@1566
|
1623 bufferTime.setAttribute('stop',bufferStopTime);
|
nickjillings@1566
|
1624 }
|
nickjillings@2019
|
1625 console.log('slider ' + this.parent.id + ' played for (' + diff + ')'); // DEBUG/SAFETY: show played slider id
|
nickjillings@1659
|
1626 }
|
nickjillings@1659
|
1627 };
|
nickjillings@1577
|
1628
|
nickjillings@1577
|
1629 this.exportXMLDOM = function() {
|
nickjillings@1324
|
1630 var storeDOM = [];
|
nickjillings@1577
|
1631 if (audioEngineContext.metric.enableElementTimer) {
|
nickjillings@1324
|
1632 var mElementTimer = storage.document.createElement('metricresult');
|
nickjillings@1577
|
1633 mElementTimer.setAttribute('name','enableElementTimer');
|
nickjillings@1577
|
1634 mElementTimer.textContent = this.listenedTimer;
|
nickjillings@1324
|
1635 storeDOM.push(mElementTimer);
|
nickjillings@1577
|
1636 }
|
nickjillings@1577
|
1637 if (audioEngineContext.metric.enableElementTracker) {
|
nickjillings@1324
|
1638 var elementTrackerFull = storage.document.createElement('metricResult');
|
nickjillings@1577
|
1639 elementTrackerFull.setAttribute('name','elementTrackerFull');
|
nickjillings@1577
|
1640 for (var k=0; k<this.movementTracker.length; k++)
|
nickjillings@1577
|
1641 {
|
nickjillings@2138
|
1642 var timePos = storage.document.createElement('movement');
|
nickjillings@2138
|
1643 timePos.setAttribute("time",this.movementTracker[k][0]);
|
nickjillings@2138
|
1644 timePos.setAttribute("value",this.movementTracker[k][1]);
|
nickjillings@1577
|
1645 elementTrackerFull.appendChild(timePos);
|
nickjillings@1577
|
1646 }
|
nickjillings@1324
|
1647 storeDOM.push(elementTrackerFull);
|
nickjillings@1577
|
1648 }
|
nickjillings@1577
|
1649 if (audioEngineContext.metric.enableElementListenTracker) {
|
nickjillings@1324
|
1650 var elementListenTracker = storage.document.createElement('metricResult');
|
nickjillings@1577
|
1651 elementListenTracker.setAttribute('name','elementListenTracker');
|
nickjillings@1577
|
1652 for (var k=0; k<this.listenTracker.length; k++) {
|
nickjillings@1577
|
1653 elementListenTracker.appendChild(this.listenTracker[k]);
|
nickjillings@1577
|
1654 }
|
nickjillings@1324
|
1655 storeDOM.push(elementListenTracker);
|
nickjillings@1577
|
1656 }
|
nickjillings@1577
|
1657 if (audioEngineContext.metric.enableElementInitialPosition) {
|
nickjillings@1324
|
1658 var elementInitial = storage.document.createElement('metricResult');
|
nickjillings@1577
|
1659 elementInitial.setAttribute('name','elementInitialPosition');
|
nickjillings@1577
|
1660 elementInitial.textContent = this.initialPosition;
|
nickjillings@1324
|
1661 storeDOM.push(elementInitial);
|
nickjillings@1577
|
1662 }
|
nickjillings@1577
|
1663 if (audioEngineContext.metric.enableFlagListenedTo) {
|
nickjillings@1324
|
1664 var flagListenedTo = storage.document.createElement('metricResult');
|
nickjillings@1577
|
1665 flagListenedTo.setAttribute('name','elementFlagListenedTo');
|
nickjillings@1577
|
1666 flagListenedTo.textContent = this.wasListenedTo;
|
nickjillings@1324
|
1667 storeDOM.push(flagListenedTo);
|
nickjillings@1577
|
1668 }
|
nickjillings@1577
|
1669 if (audioEngineContext.metric.enableFlagMoved) {
|
nickjillings@1324
|
1670 var flagMoved = storage.document.createElement('metricResult');
|
nickjillings@1577
|
1671 flagMoved.setAttribute('name','elementFlagMoved');
|
nickjillings@1577
|
1672 flagMoved.textContent = this.wasMoved;
|
nickjillings@1324
|
1673 storeDOM.push(flagMoved);
|
nickjillings@1577
|
1674 }
|
nickjillings@1577
|
1675 if (audioEngineContext.metric.enableFlagComments) {
|
nickjillings@1324
|
1676 var flagComments = storage.document.createElement('metricResult');
|
nickjillings@1577
|
1677 flagComments.setAttribute('name','elementFlagComments');
|
nickjillings@1577
|
1678 if (this.parent.commentDOM == null)
|
nickjillings@1577
|
1679 {flag.textContent = 'false';}
|
nickjillings@1577
|
1680 else if (this.parent.commentDOM.textContent.length == 0)
|
nickjillings@1577
|
1681 {flag.textContent = 'false';}
|
nickjillings@1577
|
1682 else
|
nickjillings@1577
|
1683 {flag.textContet = 'true';}
|
nickjillings@1324
|
1684 storeDOM.push(flagComments);
|
nickjillings@1577
|
1685 }
|
nickjillings@1324
|
1686 return storeDOM;
|
nickjillings@1577
|
1687 };
|
nickjillings@1664
|
1688 }
|
nickjillings@1664
|
1689
|
nickjillings@1664
|
1690 function randomiseOrder(input)
|
nickjillings@1664
|
1691 {
|
nickjillings@1664
|
1692 // This takes an array of information and randomises the order
|
nickjillings@1664
|
1693 var N = input.length;
|
b@2037
|
1694
|
b@2037
|
1695 var inputSequence = []; // For safety purposes: keep track of randomisation
|
b@2037
|
1696 for (var counter = 0; counter < N; ++counter)
|
b@2037
|
1697 inputSequence.push(counter) // Fill array
|
b@2037
|
1698 var inputSequenceClone = inputSequence.slice(0);
|
b@2037
|
1699
|
nickjillings@1664
|
1700 var holdArr = [];
|
b@2037
|
1701 var outputSequence = [];
|
nickjillings@1664
|
1702 for (var n=0; n<N; n++)
|
nickjillings@1664
|
1703 {
|
nickjillings@1664
|
1704 // First pick a random number
|
nickjillings@1664
|
1705 var r = Math.random();
|
nickjillings@1664
|
1706 // Multiply and floor by the number of elements left
|
nickjillings@1664
|
1707 r = Math.floor(r*input.length);
|
nickjillings@1664
|
1708 // Pick out that element and delete from the array
|
nickjillings@1664
|
1709 holdArr.push(input.splice(r,1)[0]);
|
b@2037
|
1710 // Do the same with sequence
|
b@2037
|
1711 outputSequence.push(inputSequence.splice(r,1)[0]);
|
nickjillings@1664
|
1712 }
|
b@2037
|
1713 console.log(inputSequenceClone.toString()); // print original array to console
|
b@2037
|
1714 console.log(outputSequence.toString()); // print randomised array to console
|
nickjillings@1664
|
1715 return holdArr;
|
nickjillings@1631
|
1716 }
|
nickjillings@1631
|
1717
|
nickjillings@1631
|
1718 function returnDateNode()
|
nickjillings@1631
|
1719 {
|
nickjillings@1631
|
1720 // Create an XML Node for the Date and Time a test was conducted
|
nickjillings@1631
|
1721 // Structure is
|
nickjillings@1631
|
1722 // <datetime>
|
nickjillings@1631
|
1723 // <date year="##" month="##" day="##">DD/MM/YY</date>
|
nickjillings@1631
|
1724 // <time hour="##" minute="##" sec="##">HH:MM:SS</time>
|
nickjillings@1631
|
1725 // </datetime>
|
nickjillings@1631
|
1726 var dateTime = new Date();
|
nickjillings@1631
|
1727 var year = document.createAttribute('year');
|
nickjillings@1631
|
1728 var month = document.createAttribute('month');
|
nickjillings@1631
|
1729 var day = document.createAttribute('day');
|
nickjillings@1631
|
1730 var hour = document.createAttribute('hour');
|
nickjillings@1631
|
1731 var minute = document.createAttribute('minute');
|
nickjillings@1631
|
1732 var secs = document.createAttribute('secs');
|
nickjillings@1631
|
1733
|
nickjillings@1631
|
1734 year.nodeValue = dateTime.getFullYear();
|
nickjillings@1631
|
1735 month.nodeValue = dateTime.getMonth()+1;
|
nickjillings@1631
|
1736 day.nodeValue = dateTime.getDate();
|
nickjillings@1631
|
1737 hour.nodeValue = dateTime.getHours();
|
nickjillings@1631
|
1738 minute.nodeValue = dateTime.getMinutes();
|
nickjillings@1631
|
1739 secs.nodeValue = dateTime.getSeconds();
|
nickjillings@1631
|
1740
|
nickjillings@1631
|
1741 var hold = document.createElement("datetime");
|
nickjillings@1631
|
1742 var date = document.createElement("date");
|
nickjillings@1631
|
1743 date.textContent = year.nodeValue+'/'+month.nodeValue+'/'+day.nodeValue;
|
nickjillings@1631
|
1744 var time = document.createElement("time");
|
nickjillings@1631
|
1745 time.textContent = hour.nodeValue+':'+minute.nodeValue+':'+secs.nodeValue;
|
nickjillings@1631
|
1746
|
nickjillings@1631
|
1747 date.setAttributeNode(year);
|
nickjillings@1631
|
1748 date.setAttributeNode(month);
|
nickjillings@1631
|
1749 date.setAttributeNode(day);
|
nickjillings@1631
|
1750 time.setAttributeNode(hour);
|
nickjillings@1631
|
1751 time.setAttributeNode(minute);
|
nickjillings@1631
|
1752 time.setAttributeNode(secs);
|
nickjillings@1631
|
1753
|
nickjillings@1631
|
1754 hold.appendChild(date);
|
nickjillings@1631
|
1755 hold.appendChild(time);
|
nickjillings@1408
|
1756 return hold;
|
nickjillings@1631
|
1757
|
nickjillings@1604
|
1758 }
|
nickjillings@1604
|
1759
|
nickjillings@1580
|
1760 function Specification() {
|
nickjillings@1580
|
1761 // Handles the decoding of the project specification XML into a simple JavaScript Object.
|
nickjillings@1580
|
1762
|
nickjillings@1324
|
1763 this.interface = null;
|
nickjillings@1373
|
1764 this.projectReturn = "null";
|
nickjillings@1324
|
1765 this.randomiseOrder = null;
|
nickjillings@1324
|
1766 this.testPages = null;
|
nickjillings@1324
|
1767 this.pages = [];
|
nickjillings@1324
|
1768 this.metrics = null;
|
nickjillings@1324
|
1769 this.interfaces = null;
|
nickjillings@1324
|
1770 this.loudness = null;
|
nickjillings@1324
|
1771 this.errors = [];
|
nickjillings@1324
|
1772 this.schema = null;
|
nickjillings@1318
|
1773
|
nickjillings@1324
|
1774 this.processAttribute = function(attribute,schema)
|
nickjillings@1406
|
1775 {
|
nickjillings@1324
|
1776 // attribute is the string returned from getAttribute on the XML
|
nickjillings@1324
|
1777 // schema is the <xs:attribute> node
|
nickjillings@1324
|
1778 if (schema.getAttribute('name') == undefined && schema.getAttribute('ref') != undefined)
|
nickjillings@1406
|
1779 {
|
nickjillings@1348
|
1780 schema = this.schema.getAllElementsByName(schema.getAttribute('ref'))[0];
|
nickjillings@1324
|
1781 }
|
nickjillings@1324
|
1782 var defaultOpt = schema.getAttribute('default');
|
nickjillings@1324
|
1783 if (attribute == null) {
|
nickjillings@1324
|
1784 attribute = defaultOpt;
|
nickjillings@1324
|
1785 }
|
nickjillings@1324
|
1786 var dataType = schema.getAttribute('type');
|
nickjillings@1324
|
1787 if (typeof dataType == "string") { dataType = dataType.substr(3);}
|
nickjillings@1324
|
1788 else {dataType = "string";}
|
nickjillings@1324
|
1789 if (attribute == null)
|
nickjillings@1324
|
1790 {
|
nickjillings@1324
|
1791 return attribute;
|
nickjillings@1324
|
1792 }
|
nickjillings@1324
|
1793 switch(dataType)
|
nickjillings@1324
|
1794 {
|
nickjillings@1324
|
1795 case "boolean":
|
nickjillings@1324
|
1796 if (attribute == 'true'){attribute = true;}else{attribute=false;}
|
nickjillings@1324
|
1797 break;
|
nickjillings@1324
|
1798 case "negativeInteger":
|
nickjillings@1324
|
1799 case "positiveInteger":
|
nickjillings@1324
|
1800 case "nonNegativeInteger":
|
nickjillings@1324
|
1801 case "nonPositiveInteger":
|
nickjillings@1324
|
1802 case "integer":
|
nickjillings@1324
|
1803 case "decimal":
|
nickjillings@1324
|
1804 case "short":
|
nickjillings@1324
|
1805 attribute = Number(attribute);
|
nickjillings@1324
|
1806 break;
|
nickjillings@1324
|
1807 case "string":
|
nickjillings@1324
|
1808 default:
|
nickjillings@1324
|
1809 attribute = String(attribute);
|
nickjillings@1324
|
1810 break;
|
nickjillings@1324
|
1811 }
|
nickjillings@1324
|
1812 return attribute;
|
nickjillings@1406
|
1813 };
|
nickjillings@1411
|
1814
|
nickjillings@1406
|
1815 this.decode = function(projectXML) {
|
nickjillings@1324
|
1816 this.errors = [];
|
nickjillings@1580
|
1817 // projectXML - DOM Parsed document
|
nickjillings@2052
|
1818 this.projectXML = projectXML.childNodes[0];
|
nickjillings@1580
|
1819 var setupNode = projectXML.getElementsByTagName('setup')[0];
|
nickjillings@1348
|
1820 var schemaSetup = this.schema.getAllElementsByName('setup')[0];
|
nickjillings@1324
|
1821 // First decode the attributes
|
nickjillings@1348
|
1822 var attributes = schemaSetup.getAllElementsByTagName('xs:attribute');
|
nickjillings@1324
|
1823 for (var i in attributes)
|
nickjillings@1520
|
1824 {
|
nickjillings@1324
|
1825 if (isNaN(Number(i)) == true){break;}
|
nickjillings@1324
|
1826 var attributeName = attributes[i].getAttribute('name');
|
nickjillings@1324
|
1827 var projectAttr = setupNode.getAttribute(attributeName);
|
nickjillings@1324
|
1828 projectAttr = this.processAttribute(projectAttr,attributes[i]);
|
nickjillings@1324
|
1829 switch(typeof projectAttr)
|
nickjillings@1432
|
1830 {
|
nickjillings@1324
|
1831 case "number":
|
nickjillings@1324
|
1832 case "boolean":
|
nickjillings@1324
|
1833 eval('this.'+attributeName+' = '+projectAttr);
|
nickjillings@1324
|
1834 break;
|
nickjillings@1324
|
1835 case "string":
|
nickjillings@1324
|
1836 eval('this.'+attributeName+' = "'+projectAttr+'"');
|
nickjillings@1324
|
1837 break;
|
nickjillings@1432
|
1838 }
|
nickjillings@1324
|
1839
|
nickjillings@1406
|
1840 }
|
nickjillings@1406
|
1841
|
nickjillings@1370
|
1842 this.metrics = new this.metricNode();
|
nickjillings@1580
|
1843
|
nickjillings@1324
|
1844 this.metrics.decode(this,setupNode.getElementsByTagName('metric')[0]);
|
nickjillings@1324
|
1845
|
nickjillings@1324
|
1846 // Now process the survey node options
|
nickjillings@1324
|
1847 var survey = setupNode.getElementsByTagName('survey');
|
nickjillings@1324
|
1848 for (var i in survey) {
|
nickjillings@1324
|
1849 if (isNaN(Number(i)) == true){break;}
|
nickjillings@1324
|
1850 var location = survey[i].getAttribute('location');
|
nickjillings@1324
|
1851 if (location == 'pre' || location == 'before')
|
nickjillings@1324
|
1852 {
|
nickjillings@1324
|
1853 if (this.preTest != null){this.errors.push("Already a pre/before test survey defined! Ignoring second!!");}
|
nickjillings@1324
|
1854 else {
|
nickjillings@1324
|
1855 this.preTest = new this.surveyNode();
|
nickjillings@1370
|
1856 this.preTest.decode(this,survey[i]);
|
nickjillings@1324
|
1857 }
|
nickjillings@1324
|
1858 } else if (location == 'post' || location == 'after') {
|
nickjillings@1324
|
1859 if (this.postTest != null){this.errors.push("Already a post/after test survey defined! Ignoring second!!");}
|
nickjillings@1324
|
1860 else {
|
nickjillings@1324
|
1861 this.postTest = new this.surveyNode();
|
nickjillings@1370
|
1862 this.postTest.decode(this,survey[i]);
|
nickjillings@1324
|
1863 }
|
nickjillings@1580
|
1864 }
|
nickjillings@1580
|
1865 }
|
nickjillings@1580
|
1866
|
nickjillings@1324
|
1867 var interfaceNode = setupNode.getElementsByTagName('interface');
|
nickjillings@1324
|
1868 if (interfaceNode.length > 1)
|
nickjillings@1324
|
1869 {
|
nickjillings@1324
|
1870 this.errors.push("Only one <interface> node in the <setup> node allowed! Others except first ingnored!");
|
nickjillings@1324
|
1871 }
|
nickjillings@1324
|
1872 this.interfaces = new this.interfaceNode();
|
nickjillings@1324
|
1873 if (interfaceNode.length != 0)
|
nickjillings@1324
|
1874 {
|
nickjillings@1324
|
1875 interfaceNode = interfaceNode[0];
|
nickjillings@1348
|
1876 this.interfaces.decode(this,interfaceNode,this.schema.getAllElementsByName('interface')[1]);
|
nickjillings@1556
|
1877 }
|
nickjillings@1556
|
1878
|
nickjillings@1324
|
1879 // Page tags
|
nickjillings@1324
|
1880 var pageTags = projectXML.getElementsByTagName('page');
|
nickjillings@1348
|
1881 var pageSchema = this.schema.getAllElementsByName('page')[0];
|
nickjillings@1324
|
1882 for (var i=0; i<pageTags.length; i++)
|
nickjillings@1520
|
1883 {
|
nickjillings@1324
|
1884 var node = new this.page();
|
nickjillings@1324
|
1885 node.decode(this,pageTags[i],pageSchema);
|
nickjillings@1324
|
1886 this.pages.push(node);
|
nickjillings@1520
|
1887 }
|
nickjillings@1580
|
1888 };
|
nickjillings@1580
|
1889
|
nickjillings@1406
|
1890 this.encode = function()
|
nickjillings@1406
|
1891 {
|
nickjillings@1372
|
1892 var RootDocument = document.implementation.createDocument(null,"waet");
|
nickjillings@1372
|
1893 var root = RootDocument.children[0];
|
nickjillings@1372
|
1894 root.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
|
nickjillings@1372
|
1895 root.setAttribute("xsi:noNamespaceSchemaLocation","test-schema.xsd");
|
nickjillings@1324
|
1896 // Build setup node
|
nickjillings@1372
|
1897 var setup = RootDocument.createElement("setup");
|
nickjillings@1372
|
1898 var schemaSetup = this.schema.getAllElementsByName('setup')[0];
|
nickjillings@1372
|
1899 // First decode the attributes
|
nickjillings@1372
|
1900 var attributes = schemaSetup.getAllElementsByTagName('xs:attribute');
|
nickjillings@1372
|
1901 for (var i=0; i<attributes.length; i++)
|
nickjillings@1372
|
1902 {
|
nickjillings@1372
|
1903 var name = attributes[i].getAttribute("name");
|
nickjillings@1372
|
1904 if (name == undefined) {
|
nickjillings@1372
|
1905 name = attributes[i].getAttribute("ref");
|
nickjillings@1372
|
1906 }
|
nickjillings@1372
|
1907 if(eval("this."+name+" != undefined") || attributes[i].getAttribute("use") == "required")
|
nickjillings@1372
|
1908 {
|
nickjillings@1372
|
1909 eval("setup.setAttribute('"+name+"',this."+name+")");
|
nickjillings@1372
|
1910 }
|
nickjillings@1372
|
1911 }
|
nickjillings@1372
|
1912 root.appendChild(setup);
|
nickjillings@1372
|
1913 // Survey node
|
nickjillings@1372
|
1914 setup.appendChild(this.preTest.encode(RootDocument));
|
nickjillings@1372
|
1915 setup.appendChild(this.postTest.encode(RootDocument));
|
nickjillings@1372
|
1916 setup.appendChild(this.metrics.encode(RootDocument));
|
nickjillings@1372
|
1917 setup.appendChild(this.interfaces.encode(RootDocument));
|
nickjillings@1372
|
1918 for (var page of this.pages)
|
nickjillings@1372
|
1919 {
|
nickjillings@1372
|
1920 root.appendChild(page.encode(RootDocument));
|
nickjillings@1372
|
1921 }
|
nickjillings@1372
|
1922 return RootDocument;
|
nickjillings@1406
|
1923 };
|
nickjillings@1406
|
1924
|
nickjillings@1324
|
1925 this.surveyNode = function() {
|
nickjillings@1324
|
1926 this.location = null;
|
nickjillings@1580
|
1927 this.options = [];
|
nickjillings@1370
|
1928 this.schema = specification.schema.getAllElementsByName('survey')[0];
|
nickjillings@1580
|
1929
|
nickjillings@1406
|
1930 this.OptionNode = function() {
|
nickjillings@1406
|
1931 this.type = undefined;
|
nickjillings@1370
|
1932 this.schema = specification.schema.getAllElementsByName('surveyentry')[0];
|
nickjillings@1406
|
1933 this.id = undefined;
|
nickjillings@1406
|
1934 this.mandatory = undefined;
|
nickjillings@1406
|
1935 this.statement = undefined;
|
nickjillings@1406
|
1936 this.boxsize = undefined;
|
nickjillings@1406
|
1937 this.options = [];
|
nickjillings@1406
|
1938 this.min = undefined;
|
nickjillings@1406
|
1939 this.max = undefined;
|
nickjillings@1406
|
1940 this.step = undefined;
|
nickjillings@1406
|
1941
|
nickjillings@1370
|
1942 this.decode = function(parent,child)
|
nickjillings@1406
|
1943 {
|
nickjillings@1370
|
1944 var attributeMap = this.schema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1324
|
1945 for (var i in attributeMap){
|
nickjillings@1324
|
1946 if(isNaN(Number(i)) == true){break;}
|
nickjillings@1324
|
1947 var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref');
|
nickjillings@1324
|
1948 var projectAttr = child.getAttribute(attributeName);
|
nickjillings@1324
|
1949 projectAttr = parent.processAttribute(projectAttr,attributeMap[i]);
|
nickjillings@1324
|
1950 switch(typeof projectAttr)
|
nickjillings@1324
|
1951 {
|
nickjillings@1324
|
1952 case "number":
|
nickjillings@1324
|
1953 case "boolean":
|
nickjillings@1324
|
1954 eval('this.'+attributeName+' = '+projectAttr);
|
nickjillings@1324
|
1955 break;
|
nickjillings@1324
|
1956 case "string":
|
nickjillings@1324
|
1957 eval('this.'+attributeName+' = "'+projectAttr+'"');
|
nickjillings@1324
|
1958 break;
|
nickjillings@1406
|
1959 }
|
nickjillings@1324
|
1960 }
|
nickjillings@1324
|
1961 this.statement = child.getElementsByTagName('statement')[0].textContent;
|
nickjillings@1324
|
1962 if (this.type == "checkbox" || this.type == "radio") {
|
nickjillings@1324
|
1963 var children = child.getElementsByTagName('option');
|
nickjillings@1324
|
1964 if (children.length == null) {
|
nickjillings@1406
|
1965 console.log('Malformed' +child.nodeName+ 'entry');
|
nickjillings@1406
|
1966 this.statement = 'Malformed' +child.nodeName+ 'entry';
|
nickjillings@1406
|
1967 this.type = 'statement';
|
nickjillings@1406
|
1968 } else {
|
nickjillings@1406
|
1969 this.options = [];
|
nickjillings@1324
|
1970 for (var i in children)
|
nickjillings@1324
|
1971 {
|
nickjillings@1324
|
1972 if (isNaN(Number(i))==true){break;}
|
nickjillings@1324
|
1973 this.options.push({
|
nickjillings@1324
|
1974 name: children[i].getAttribute('name'),
|
nickjillings@1324
|
1975 text: children[i].textContent
|
nickjillings@1324
|
1976 });
|
nickjillings@1406
|
1977 }
|
nickjillings@1406
|
1978 }
|
nickjillings@2030
|
1979 }
|
nickjillings@1406
|
1980 };
|
nickjillings@1406
|
1981
|
nickjillings@1372
|
1982 this.exportXML = function(doc)
|
nickjillings@1406
|
1983 {
|
nickjillings@2111
|
1984 var node = doc.createElement('surveyentry');
|
nickjillings@1324
|
1985 node.setAttribute('type',this.type);
|
nickjillings@1372
|
1986 var statement = doc.createElement('statement');
|
nickjillings@1324
|
1987 statement.textContent = this.statement;
|
nickjillings@1324
|
1988 node.appendChild(statement);
|
nickjillings@1406
|
1989 switch(this.type)
|
nickjillings@1406
|
1990 {
|
nickjillings@1406
|
1991 case "statement":
|
nickjillings@1406
|
1992 break;
|
nickjillings@1406
|
1993 case "question":
|
nickjillings@2111
|
1994 node.id = this.id;
|
nickjillings@2111
|
1995 if (this.mandatory != undefined) { node.setAttribute("mandatory",this.mandatory);}
|
nickjillings@2111
|
1996 if (this.boxsize != undefined) {node.setAttribute("boxsize",this.boxsize);}
|
nickjillings@2111
|
1997 break;
|
nickjillings@2111
|
1998 case "number":
|
nickjillings@2111
|
1999 node.id = this.id;
|
nickjillings@2111
|
2000 if (this.mandatory != undefined) { node.setAttribute("mandatory",this.mandatory);}
|
nickjillings@2111
|
2001 if (this.min != undefined) {node.setAttribute("min", this.min);}
|
nickjillings@2111
|
2002 if (this.max != undefined) {node.setAttribute("max", this.max);}
|
nickjillings@2111
|
2003 break;
|
nickjillings@1406
|
2004 case "checkbox":
|
nickjillings@1318
|
2005 case "radio":
|
nickjillings@1406
|
2006 node.id = this.id;
|
nickjillings@1406
|
2007 for (var i=0; i<this.options.length; i++)
|
nickjillings@1406
|
2008 {
|
nickjillings@1406
|
2009 var option = this.options[i];
|
nickjillings@1372
|
2010 var optionNode = doc.createElement("option");
|
nickjillings@1406
|
2011 optionNode.setAttribute("name",option.name);
|
nickjillings@1406
|
2012 optionNode.textContent = option.text;
|
nickjillings@1406
|
2013 node.appendChild(optionNode);
|
nickjillings@1406
|
2014 }
|
nickjillings@1406
|
2015 break;
|
nickjillings@1588
|
2016 }
|
nickjillings@1406
|
2017 return node;
|
nickjillings@1406
|
2018 };
|
nickjillings@1406
|
2019 };
|
nickjillings@1370
|
2020 this.decode = function(parent,xml) {
|
nickjillings@1324
|
2021 this.location = xml.getAttribute('location');
|
nickjillings@1324
|
2022 if (this.location == 'before'){this.location = 'pre';}
|
nickjillings@1324
|
2023 else if (this.location == 'after'){this.location = 'post';}
|
nickjillings@1324
|
2024 for (var i in xml.children)
|
nickjillings@1324
|
2025 {
|
nickjillings@1324
|
2026 if(isNaN(Number(i))==true){break;}
|
nickjillings@1406
|
2027 var node = new this.OptionNode();
|
nickjillings@1370
|
2028 node.decode(parent,xml.children[i]);
|
nickjillings@1406
|
2029 this.options.push(node);
|
nickjillings@1324
|
2030 }
|
nickjillings@1324
|
2031 };
|
nickjillings@1372
|
2032 this.encode = function(doc) {
|
nickjillings@1372
|
2033 var node = doc.createElement('survey');
|
nickjillings@1324
|
2034 node.setAttribute('location',this.location);
|
nickjillings@1324
|
2035 for (var i=0; i<this.options.length; i++)
|
nickjillings@1324
|
2036 {
|
nickjillings@1372
|
2037 node.appendChild(this.options[i].exportXML(doc));
|
nickjillings@1324
|
2038 }
|
nickjillings@1324
|
2039 return node;
|
nickjillings@1324
|
2040 };
|
nickjillings@1324
|
2041 };
|
nickjillings@1324
|
2042
|
nickjillings@1324
|
2043 this.interfaceNode = function()
|
nickjillings@1324
|
2044 {
|
nickjillings@1324
|
2045 this.title = null;
|
nickjillings@1324
|
2046 this.name = null;
|
nickjillings@1324
|
2047 this.options = [];
|
nickjillings@1324
|
2048 this.scales = [];
|
nickjillings@1370
|
2049 this.schema = specification.schema.getAllElementsByName('interface')[1];
|
nickjillings@1324
|
2050
|
nickjillings@1370
|
2051 this.decode = function(parent,xml) {
|
nickjillings@1324
|
2052 this.name = xml.getAttribute('name');
|
nickjillings@1324
|
2053 var titleNode = xml.getElementsByTagName('title');
|
nickjillings@1324
|
2054 if (titleNode.length == 1)
|
nickjillings@1324
|
2055 {
|
nickjillings@1324
|
2056 this.title = titleNode[0].textContent;
|
nickjillings@1324
|
2057 }
|
nickjillings@1324
|
2058 var interfaceOptionNodes = xml.getElementsByTagName('interfaceoption');
|
nickjillings@1324
|
2059 // Extract interfaceoption node schema
|
nickjillings@1370
|
2060 var interfaceOptionNodeSchema = this.schema.getAllElementsByName('interfaceoption')[0];
|
nickjillings@1348
|
2061 var attributeMap = interfaceOptionNodeSchema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1324
|
2062 for (var i=0; i<interfaceOptionNodes.length; i++)
|
nickjillings@1324
|
2063 {
|
nickjillings@1324
|
2064 var ioNode = interfaceOptionNodes[i];
|
nickjillings@1324
|
2065 var option = {};
|
nickjillings@1324
|
2066 for (var j=0; j<attributeMap.length; j++)
|
nickjillings@1324
|
2067 {
|
nickjillings@1324
|
2068 var attributeName = attributeMap[j].getAttribute('name') || attributeMap[j].getAttribute('ref');
|
nickjillings@1324
|
2069 var projectAttr = ioNode.getAttribute(attributeName);
|
nickjillings@1324
|
2070 projectAttr = parent.processAttribute(projectAttr,attributeMap[j]);
|
nickjillings@1324
|
2071 switch(typeof projectAttr)
|
nickjillings@1324
|
2072 {
|
nickjillings@1324
|
2073 case "number":
|
nickjillings@1324
|
2074 case "boolean":
|
nickjillings@1324
|
2075 eval('option.'+attributeName+' = '+projectAttr);
|
nickjillings@1324
|
2076 break;
|
nickjillings@1324
|
2077 case "string":
|
nickjillings@1324
|
2078 eval('option.'+attributeName+' = "'+projectAttr+'"');
|
nickjillings@1324
|
2079 break;
|
nickjillings@1324
|
2080 }
|
nickjillings@1324
|
2081 }
|
nickjillings@1324
|
2082 this.options.push(option);
|
nickjillings@1324
|
2083 }
|
nickjillings@1324
|
2084
|
nickjillings@1324
|
2085 // Now the scales nodes
|
nickjillings@1324
|
2086 var scaleParent = xml.getElementsByTagName('scales');
|
nickjillings@1324
|
2087 if (scaleParent.length == 1) {
|
nickjillings@1324
|
2088 scaleParent = scaleParent[0];
|
nickjillings@1324
|
2089 for (var i=0; i<scaleParent.children.length; i++) {
|
nickjillings@1324
|
2090 var child = scaleParent.children[i];
|
nickjillings@1324
|
2091 this.scales.push({
|
nickjillings@1324
|
2092 text: child.textContent,
|
nickjillings@1324
|
2093 position: Number(child.getAttribute('position'))
|
nickjillings@1324
|
2094 });
|
nickjillings@1406
|
2095 }
|
nickjillings@1580
|
2096 }
|
nickjillings@1580
|
2097 };
|
nickjillings@1324
|
2098
|
nickjillings@1372
|
2099 this.encode = function(doc) {
|
nickjillings@1372
|
2100 var node = doc.createElement("interface");
|
nickjillings@1372
|
2101 if (typeof name == "string")
|
nickjillings@1372
|
2102 node.setAttribute("name",this.name);
|
nickjillings@1372
|
2103 for (var option of this.options)
|
nickjillings@1372
|
2104 {
|
nickjillings@1372
|
2105 var child = doc.createElement("interfaceoption");
|
nickjillings@1372
|
2106 child.setAttribute("type",option.type);
|
nickjillings@1372
|
2107 child.setAttribute("name",option.name);
|
nickjillings@1372
|
2108 node.appendChild(child);
|
nickjillings@1372
|
2109 }
|
nickjillings@1372
|
2110 if (this.scales.length != 0) {
|
nickjillings@1372
|
2111 var scales = doc.createElement("scales");
|
nickjillings@1372
|
2112 for (var scale of this.scales)
|
nickjillings@1372
|
2113 {
|
nickjillings@1372
|
2114 var child = doc.createElement("scalelabel");
|
nickjillings@1372
|
2115 child.setAttribute("position",scale.position);
|
nickjillings@1372
|
2116 child.textContent = scale.text;
|
nickjillings@1372
|
2117 scales.appendChild(child);
|
nickjillings@1372
|
2118 }
|
nickjillings@1372
|
2119 node.appendChild(scales);
|
nickjillings@1372
|
2120 }
|
nickjillings@1372
|
2121 return node;
|
nickjillings@1324
|
2122 };
|
nickjillings@1580
|
2123 };
|
nickjillings@1580
|
2124
|
nickjillings@1370
|
2125 this.metricNode = function() {
|
nickjillings@1370
|
2126 this.enabled = [];
|
nickjillings@1370
|
2127 this.decode = function(parent, xml) {
|
nickjillings@1370
|
2128 var children = xml.getElementsByTagName('metricenable');
|
nickjillings@1370
|
2129 for (var i in children) {
|
nickjillings@1370
|
2130 if (isNaN(Number(i)) == true){break;}
|
nickjillings@1370
|
2131 this.enabled.push(children[i].textContent);
|
nickjillings@1370
|
2132 }
|
nickjillings@1370
|
2133 }
|
nickjillings@1372
|
2134 this.encode = function(doc) {
|
nickjillings@1372
|
2135 var node = doc.createElement('metric');
|
nickjillings@1370
|
2136 for (var i in this.enabled)
|
nickjillings@1370
|
2137 {
|
nickjillings@1370
|
2138 if (isNaN(Number(i)) == true){break;}
|
nickjillings@1372
|
2139 var child = doc.createElement('metricenable');
|
nickjillings@1370
|
2140 child.textContent = this.enabled[i];
|
nickjillings@1370
|
2141 node.appendChild(child);
|
nickjillings@1370
|
2142 }
|
nickjillings@1370
|
2143 return node;
|
nickjillings@1370
|
2144 }
|
nickjillings@1370
|
2145 }
|
nickjillings@1370
|
2146
|
nickjillings@1324
|
2147 this.page = function() {
|
nickjillings@1406
|
2148 this.presentedId = undefined;
|
nickjillings@1406
|
2149 this.id = undefined;
|
nickjillings@1406
|
2150 this.hostURL = undefined;
|
nickjillings@1406
|
2151 this.randomiseOrder = undefined;
|
nickjillings@1406
|
2152 this.loop = undefined;
|
nickjillings@1324
|
2153 this.showElementComments = undefined;
|
nickjillings@1406
|
2154 this.outsideReference = null;
|
nickjillings@1432
|
2155 this.loudness = null;
|
nickjillings@1324
|
2156 this.preTest = null;
|
nickjillings@1324
|
2157 this.postTest = null;
|
nickjillings@1406
|
2158 this.interfaces = [];
|
nickjillings@1406
|
2159 this.commentBoxPrefix = "Comment on track";
|
nickjillings@1406
|
2160 this.audioElements = [];
|
nickjillings@1406
|
2161 this.commentQuestions = [];
|
nickjillings@1370
|
2162 this.schema = specification.schema.getAllElementsByName("page")[0];
|
nickjillings@1406
|
2163
|
nickjillings@1406
|
2164 this.decode = function(parent,xml)
|
nickjillings@1406
|
2165 {
|
nickjillings@1348
|
2166 var attributeMap = this.schema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1324
|
2167 for (var i=0; i<attributeMap.length; i++)
|
nickjillings@1432
|
2168 {
|
nickjillings@1324
|
2169 var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref');
|
nickjillings@1324
|
2170 var projectAttr = xml.getAttribute(attributeName);
|
nickjillings@1324
|
2171 projectAttr = parent.processAttribute(projectAttr,attributeMap[i]);
|
nickjillings@1324
|
2172 switch(typeof projectAttr)
|
nickjillings@1395
|
2173 {
|
nickjillings@1324
|
2174 case "number":
|
nickjillings@1324
|
2175 case "boolean":
|
nickjillings@1324
|
2176 eval('this.'+attributeName+' = '+projectAttr);
|
nickjillings@1324
|
2177 break;
|
nickjillings@1324
|
2178 case "string":
|
nickjillings@1324
|
2179 eval('this.'+attributeName+' = "'+projectAttr+'"');
|
nickjillings@1324
|
2180 break;
|
nickjillings@1406
|
2181 }
|
nickjillings@1406
|
2182 }
|
nickjillings@1406
|
2183
|
nickjillings@1324
|
2184 // Get the Comment Box Prefix
|
nickjillings@1324
|
2185 var CBP = xml.getElementsByTagName('commentboxprefix');
|
nickjillings@1324
|
2186 if (CBP.length != 0) {
|
nickjillings@1324
|
2187 this.commentBoxPrefix = CBP[0].textContent;
|
nickjillings@1441
|
2188 }
|
nickjillings@1441
|
2189
|
nickjillings@1324
|
2190 // Now decode the interfaces
|
nickjillings@1324
|
2191 var interfaceNode = xml.getElementsByTagName('interface');
|
nickjillings@1324
|
2192 for (var i=0; i<interfaceNode.length; i++)
|
nickjillings@1324
|
2193 {
|
nickjillings@1324
|
2194 var node = new parent.interfaceNode();
|
nickjillings@1348
|
2195 node.decode(this,interfaceNode[i],parent.schema.getAllElementsByName('interface')[1]);
|
nickjillings@1324
|
2196 this.interfaces.push(node);
|
nickjillings@1324
|
2197 }
|
nickjillings@1411
|
2198
|
nickjillings@1324
|
2199 // Now process the survey node options
|
nickjillings@1324
|
2200 var survey = xml.getElementsByTagName('survey');
|
nickjillings@1348
|
2201 var surveySchema = parent.schema.getAllElementsByName('survey')[0];
|
nickjillings@1324
|
2202 for (var i in survey) {
|
nickjillings@1324
|
2203 if (isNaN(Number(i)) == true){break;}
|
nickjillings@1324
|
2204 var location = survey[i].getAttribute('location');
|
nickjillings@1324
|
2205 if (location == 'pre' || location == 'before')
|
nickjillings@1324
|
2206 {
|
nickjillings@1324
|
2207 if (this.preTest != null){this.errors.push("Already a pre/before test survey defined! Ignoring second!!");}
|
nickjillings@1324
|
2208 else {
|
nickjillings@1324
|
2209 this.preTest = new parent.surveyNode();
|
nickjillings@1324
|
2210 this.preTest.decode(parent,survey[i],surveySchema);
|
nickjillings@1324
|
2211 }
|
nickjillings@1324
|
2212 } else if (location == 'post' || location == 'after') {
|
nickjillings@1324
|
2213 if (this.postTest != null){this.errors.push("Already a post/after test survey defined! Ignoring second!!");}
|
nickjillings@1324
|
2214 else {
|
nickjillings@1324
|
2215 this.postTest = new parent.surveyNode();
|
nickjillings@1324
|
2216 this.postTest.decode(parent,survey[i],surveySchema);
|
nickjillings@1324
|
2217 }
|
nickjillings@1324
|
2218 }
|
nickjillings@1324
|
2219 }
|
nickjillings@1324
|
2220
|
nickjillings@1324
|
2221 // Now process the audioelement tags
|
nickjillings@1324
|
2222 var audioElements = xml.getElementsByTagName('audioelement');
|
nickjillings@1324
|
2223 for (var i=0; i<audioElements.length; i++)
|
nickjillings@1324
|
2224 {
|
nickjillings@1324
|
2225 var node = new this.audioElementNode();
|
nickjillings@1370
|
2226 node.decode(this,audioElements[i]);
|
nickjillings@1324
|
2227 this.audioElements.push(node);
|
nickjillings@1324
|
2228 }
|
nickjillings@1324
|
2229
|
nickjillings@1324
|
2230 // Now decode the commentquestions
|
nickjillings@1324
|
2231 var commentQuestions = xml.getElementsByTagName('commentquestion');
|
nickjillings@1324
|
2232 for (var i=0; i<commentQuestions.length; i++)
|
nickjillings@1324
|
2233 {
|
nickjillings@1406
|
2234 var node = new this.commentQuestionNode();
|
nickjillings@1370
|
2235 node.decode(parent,commentQuestions[i]);
|
nickjillings@1406
|
2236 this.commentQuestions.push(node);
|
nickjillings@1580
|
2237 }
|
nickjillings@1580
|
2238 };
|
nickjillings@1580
|
2239
|
nickjillings@1406
|
2240 this.encode = function(root)
|
nickjillings@1406
|
2241 {
|
nickjillings@1372
|
2242 var AHNode = root.createElement("page");
|
nickjillings@1372
|
2243 // First decode the attributes
|
nickjillings@1372
|
2244 var attributes = this.schema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1372
|
2245 for (var i=0; i<attributes.length; i++)
|
nickjillings@1372
|
2246 {
|
nickjillings@1372
|
2247 var name = attributes[i].getAttribute("name");
|
nickjillings@1372
|
2248 if (name == undefined) {
|
nickjillings@1372
|
2249 name = attributes[i].getAttribute("ref");
|
nickjillings@1372
|
2250 }
|
nickjillings@1372
|
2251 if(eval("this."+name+" != undefined") || attributes[i].getAttribute("use") == "required")
|
nickjillings@1372
|
2252 {
|
nickjillings@1372
|
2253 eval("AHNode.setAttribute('"+name+"',this."+name+")");
|
nickjillings@1372
|
2254 }
|
nickjillings@1372
|
2255 }
|
nickjillings@1432
|
2256 if(this.loudness != null) {AHNode.setAttribute("loudness",this.loudness);}
|
nickjillings@1372
|
2257 // <commentboxprefix>
|
nickjillings@1372
|
2258 var commentboxprefix = root.createElement("commentboxprefix");
|
nickjillings@1372
|
2259 commentboxprefix.textContent = this.commentBoxPrefix;
|
nickjillings@1372
|
2260 AHNode.appendChild(commentboxprefix);
|
nickjillings@1372
|
2261
|
nickjillings@1406
|
2262 for (var i=0; i<this.interfaces.length; i++)
|
nickjillings@1404
|
2263 {
|
nickjillings@1406
|
2264 AHNode.appendChild(this.interfaces[i].encode(root));
|
nickjillings@1406
|
2265 }
|
nickjillings@1558
|
2266
|
nickjillings@1406
|
2267 for (var i=0; i<this.audioElements.length; i++) {
|
nickjillings@1406
|
2268 AHNode.appendChild(this.audioElements[i].encode(root));
|
nickjillings@1406
|
2269 }
|
nickjillings@1406
|
2270 // Create <CommentQuestion>
|
nickjillings@1406
|
2271 for (var i=0; i<this.commentQuestions.length; i++)
|
nickjillings@1455
|
2272 {
|
nickjillings@1372
|
2273 AHNode.appendChild(this.commentQuestions[i].encode(root));
|
nickjillings@1406
|
2274 }
|
nickjillings@1406
|
2275
|
nickjillings@1372
|
2276 AHNode.appendChild(this.preTest.encode(root));
|
nickjillings@1372
|
2277 AHNode.appendChild(this.postTest.encode(root));
|
nickjillings@1406
|
2278 return AHNode;
|
nickjillings@1406
|
2279 };
|
nickjillings@1406
|
2280
|
nickjillings@1324
|
2281 this.commentQuestionNode = function() {
|
nickjillings@1324
|
2282 this.id = null;
|
nickjillings@1324
|
2283 this.type = undefined;
|
nickjillings@1406
|
2284 this.options = [];
|
nickjillings@1324
|
2285 this.statement = undefined;
|
nickjillings@1370
|
2286 this.schema = specification.schema.getAllElementsByName('commentquestion')[0];
|
nickjillings@1370
|
2287 this.decode = function(parent,xml)
|
nickjillings@1406
|
2288 {
|
nickjillings@1324
|
2289 this.id = xml.id;
|
nickjillings@1324
|
2290 this.type = xml.getAttribute('type');
|
nickjillings@1324
|
2291 this.statement = xml.getElementsByTagName('statement')[0].textContent;
|
nickjillings@1324
|
2292 var optNodes = xml.getElementsByTagName('option');
|
nickjillings@1324
|
2293 for (var i=0; i<optNodes.length; i++)
|
nickjillings@1324
|
2294 {
|
nickjillings@1324
|
2295 var optNode = optNodes[i];
|
nickjillings@1324
|
2296 this.options.push({
|
nickjillings@1324
|
2297 name: optNode.getAttribute('name'),
|
nickjillings@1324
|
2298 text: optNode.textContent
|
nickjillings@1324
|
2299 });
|
nickjillings@1406
|
2300 }
|
nickjillings@1406
|
2301 };
|
nickjillings@1324
|
2302
|
nickjillings@1406
|
2303 this.encode = function(root)
|
nickjillings@1406
|
2304 {
|
nickjillings@1372
|
2305 var node = root.createElement("commentquestion");
|
nickjillings@1372
|
2306 node.id = this.id;
|
nickjillings@1372
|
2307 node.setAttribute("type",this.type);
|
nickjillings@1372
|
2308 var statement = root.createElement("statement");
|
nickjillings@1372
|
2309 statement.textContent = this.statement;
|
nickjillings@1372
|
2310 node.appendChild(statement);
|
nickjillings@1372
|
2311 for (var option of this.options)
|
nickjillings@1372
|
2312 {
|
nickjillings@1372
|
2313 var child = root.createElement("option");
|
nickjillings@1372
|
2314 child.setAttribute("name",option.name);
|
nickjillings@1372
|
2315 child.textContent = option.text;
|
nickjillings@1372
|
2316 node.appendChild(child);
|
nickjillings@1372
|
2317 }
|
nickjillings@1372
|
2318 return node;
|
nickjillings@1406
|
2319 };
|
nickjillings@1406
|
2320 };
|
nickjillings@1406
|
2321
|
nickjillings@1406
|
2322 this.audioElementNode = function() {
|
nickjillings@1406
|
2323 this.url = null;
|
nickjillings@1406
|
2324 this.id = null;
|
nickjillings@1406
|
2325 this.parent = null;
|
nickjillings@1324
|
2326 this.type = null;
|
nickjillings@1310
|
2327 this.marker = null;
|
nickjillings@1406
|
2328 this.enforce = false;
|
nickjillings@2130
|
2329 this.gain = 0.0;
|
nickjillings@1370
|
2330 this.schema = specification.schema.getAllElementsByName('audioelement')[0];;
|
nickjillings@1324
|
2331 this.parent = null;
|
nickjillings@1406
|
2332 this.decode = function(parent,xml)
|
nickjillings@1406
|
2333 {
|
nickjillings@1406
|
2334 this.parent = parent;
|
nickjillings@1348
|
2335 var attributeMap = this.schema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1324
|
2336 for (var i=0; i<attributeMap.length; i++)
|
nickjillings@1426
|
2337 {
|
nickjillings@1324
|
2338 var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref');
|
nickjillings@1324
|
2339 var projectAttr = xml.getAttribute(attributeName);
|
nickjillings@1324
|
2340 projectAttr = specification.processAttribute(projectAttr,attributeMap[i]);
|
nickjillings@1324
|
2341 switch(typeof projectAttr)
|
nickjillings@1406
|
2342 {
|
nickjillings@1324
|
2343 case "number":
|
nickjillings@1324
|
2344 case "boolean":
|
nickjillings@1324
|
2345 eval('this.'+attributeName+' = '+projectAttr);
|
nickjillings@1324
|
2346 break;
|
nickjillings@1324
|
2347 case "string":
|
nickjillings@1324
|
2348 eval('this.'+attributeName+' = "'+projectAttr+'"');
|
nickjillings@1324
|
2349 break;
|
nickjillings@1455
|
2350 }
|
nickjillings@1455
|
2351 }
|
nickjillings@1324
|
2352
|
nickjillings@1406
|
2353 };
|
nickjillings@1406
|
2354 this.encode = function(root)
|
nickjillings@1406
|
2355 {
|
nickjillings@1372
|
2356 var AENode = root.createElement("audioelement");
|
nickjillings@1372
|
2357 var attributes = this.schema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1372
|
2358 for (var i=0; i<attributes.length; i++)
|
nickjillings@1372
|
2359 {
|
nickjillings@1372
|
2360 var name = attributes[i].getAttribute("name");
|
nickjillings@1372
|
2361 if (name == undefined) {
|
nickjillings@1372
|
2362 name = attributes[i].getAttribute("ref");
|
nickjillings@1372
|
2363 }
|
nickjillings@1372
|
2364 if(eval("this."+name+" != undefined") || attributes[i].getAttribute("use") == "required")
|
nickjillings@1372
|
2365 {
|
nickjillings@1372
|
2366 eval("AENode.setAttribute('"+name+"',this."+name+")");
|
nickjillings@1372
|
2367 }
|
nickjillings@1372
|
2368 }
|
nickjillings@1406
|
2369 return AENode;
|
nickjillings@1406
|
2370 };
|
nickjillings@1580
|
2371 };
|
nickjillings@1580
|
2372 };
|
nickjillings@1580
|
2373 }
|
nickjillings@1406
|
2374
|
nickjillings@1582
|
2375 function Interface(specificationObject) {
|
nickjillings@1580
|
2376 // This handles the bindings between the interface and the audioEngineContext;
|
nickjillings@1582
|
2377 this.specification = specificationObject;
|
nickjillings@1582
|
2378 this.insertPoint = document.getElementById("topLevelBody");
|
nickjillings@1580
|
2379
|
nickjillings@1324
|
2380 this.newPage = function(audioHolderObject,store)
|
nickjillings@1407
|
2381 {
|
nickjillings@1369
|
2382 audioEngineContext.newTestPage(audioHolderObject,store);
|
nickjillings@2117
|
2383 interfaceContext.commentBoxes.deleteCommentBoxes();
|
nickjillings@1407
|
2384 interfaceContext.deleteCommentQuestions();
|
nickjillings@1324
|
2385 loadTest(audioHolderObject,store);
|
nickjillings@1407
|
2386 };
|
nickjillings@1407
|
2387
|
nickjillings@1582
|
2388 // Bounded by interface!!
|
nickjillings@1582
|
2389 // Interface object MUST have an exportXMLDOM method which returns the various DOM levels
|
nickjillings@1582
|
2390 // For example, APE returns the slider position normalised in a <value> tag.
|
nickjillings@1582
|
2391 this.interfaceObjects = [];
|
nickjillings@1582
|
2392 this.interfaceObject = function(){};
|
nickjillings@1582
|
2393
|
nickjillings@1525
|
2394 this.resizeWindow = function(event)
|
nickjillings@1525
|
2395 {
|
nickjillings@1421
|
2396 popup.resize(event);
|
nickjillings@1525
|
2397 for(var i=0; i<this.commentBoxes.length; i++)
|
nickjillings@1525
|
2398 {this.commentBoxes[i].resize();}
|
nickjillings@1525
|
2399 for(var i=0; i<this.commentQuestions.length; i++)
|
nickjillings@1525
|
2400 {this.commentQuestions[i].resize();}
|
nickjillings@1525
|
2401 try
|
nickjillings@1525
|
2402 {
|
nickjillings@1525
|
2403 resizeWindow(event);
|
nickjillings@1525
|
2404 }
|
nickjillings@1525
|
2405 catch(err)
|
nickjillings@1525
|
2406 {
|
nickjillings@1525
|
2407 console.log("Warning - Interface does not have Resize option");
|
nickjillings@1525
|
2408 console.log(err);
|
nickjillings@1525
|
2409 }
|
nickjillings@1525
|
2410 };
|
nickjillings@1525
|
2411
|
nickjillings@1465
|
2412 this.returnNavigator = function()
|
nickjillings@1465
|
2413 {
|
nickjillings@1362
|
2414 var node = storage.document.createElement("navigator");
|
nickjillings@1362
|
2415 var platform = storage.document.createElement("platform");
|
nickjillings@1465
|
2416 platform.textContent = navigator.platform;
|
nickjillings@1362
|
2417 var vendor = storage.document.createElement("vendor");
|
nickjillings@1465
|
2418 vendor.textContent = navigator.vendor;
|
nickjillings@1362
|
2419 var userAgent = storage.document.createElement("uagent");
|
nickjillings@1465
|
2420 userAgent.textContent = navigator.userAgent;
|
nickjillings@1362
|
2421 var screen = storage.document.createElement("window");
|
nickjillings@1362
|
2422 screen.setAttribute('innerWidth',window.innerWidth);
|
nickjillings@1362
|
2423 screen.setAttribute('innerHeight',window.innerHeight);
|
nickjillings@1465
|
2424 node.appendChild(platform);
|
nickjillings@1465
|
2425 node.appendChild(vendor);
|
nickjillings@1465
|
2426 node.appendChild(userAgent);
|
nickjillings@1362
|
2427 node.appendChild(screen);
|
nickjillings@1465
|
2428 return node;
|
nickjillings@1465
|
2429 };
|
nickjillings@1465
|
2430
|
nickjillings@2117
|
2431 this.commentBoxes = new function() {
|
nickjillings@2117
|
2432 this.boxes = [];
|
nickjillings@2117
|
2433 this.injectPoint = null;
|
nickjillings@2117
|
2434 this.elementCommentBox = function(audioObject) {
|
nickjillings@2117
|
2435 var element = audioObject.specification;
|
nickjillings@2117
|
2436 this.audioObject = audioObject;
|
nickjillings@2117
|
2437 this.id = audioObject.id;
|
nickjillings@2117
|
2438 var audioHolderObject = audioObject.specification.parent;
|
nickjillings@2117
|
2439 // Create document objects to hold the comment boxes
|
nickjillings@2117
|
2440 this.trackComment = document.createElement('div');
|
nickjillings@2117
|
2441 this.trackComment.className = 'comment-div';
|
nickjillings@2117
|
2442 this.trackComment.id = 'comment-div-'+audioObject.id;
|
nickjillings@2117
|
2443 // Create a string next to each comment asking for a comment
|
nickjillings@2117
|
2444 this.trackString = document.createElement('span');
|
nickjillings@2117
|
2445 this.trackString.innerHTML = audioHolderObject.commentBoxPrefix+' '+audioObject.interfaceDOM.getPresentedId();
|
nickjillings@2117
|
2446 // Create the HTML5 comment box 'textarea'
|
nickjillings@2117
|
2447 this.trackCommentBox = document.createElement('textarea');
|
nickjillings@2117
|
2448 this.trackCommentBox.rows = '4';
|
nickjillings@2117
|
2449 this.trackCommentBox.cols = '100';
|
nickjillings@2117
|
2450 this.trackCommentBox.name = 'trackComment'+audioObject.id;
|
nickjillings@2117
|
2451 this.trackCommentBox.className = 'trackComment';
|
nickjillings@2117
|
2452 var br = document.createElement('br');
|
nickjillings@2117
|
2453 // Add to the holder.
|
nickjillings@2117
|
2454 this.trackComment.appendChild(this.trackString);
|
nickjillings@2117
|
2455 this.trackComment.appendChild(br);
|
nickjillings@2117
|
2456 this.trackComment.appendChild(this.trackCommentBox);
|
nickjillings@2117
|
2457
|
nickjillings@2117
|
2458 this.exportXMLDOM = function() {
|
nickjillings@2117
|
2459 var root = document.createElement('comment');
|
nickjillings@2117
|
2460 var question = document.createElement('question');
|
nickjillings@2117
|
2461 question.textContent = this.trackString.textContent;
|
nickjillings@2117
|
2462 var response = document.createElement('response');
|
nickjillings@2117
|
2463 response.textContent = this.trackCommentBox.value;
|
nickjillings@2117
|
2464 console.log("Comment frag-"+this.id+": "+response.textContent);
|
nickjillings@2117
|
2465 root.appendChild(question);
|
nickjillings@2117
|
2466 root.appendChild(response);
|
nickjillings@2117
|
2467 return root;
|
nickjillings@2117
|
2468 };
|
nickjillings@2117
|
2469 this.resize = function()
|
nickjillings@2117
|
2470 {
|
nickjillings@2117
|
2471 var boxwidth = (window.innerWidth-100)/2;
|
nickjillings@2117
|
2472 if (boxwidth >= 600)
|
nickjillings@2117
|
2473 {
|
nickjillings@2117
|
2474 boxwidth = 600;
|
nickjillings@2117
|
2475 }
|
nickjillings@2117
|
2476 else if (boxwidth < 400)
|
nickjillings@2117
|
2477 {
|
nickjillings@2117
|
2478 boxwidth = 400;
|
nickjillings@2117
|
2479 }
|
nickjillings@2117
|
2480 this.trackComment.style.width = boxwidth+"px";
|
nickjillings@2117
|
2481 this.trackCommentBox.style.width = boxwidth-6+"px";
|
nickjillings@2117
|
2482 };
|
nickjillings@2117
|
2483 this.resize();
|
nickjillings@2117
|
2484 };
|
nickjillings@2117
|
2485 this.createCommentBox = function(audioObject) {
|
nickjillings@2117
|
2486 var node = new this.elementCommentBox(audioObject);
|
nickjillings@2117
|
2487 this.boxes.push(node);
|
nickjillings@2117
|
2488 audioObject.commentDOM = node;
|
nickjillings@2117
|
2489 return node;
|
nickjillings@2117
|
2490 };
|
nickjillings@2117
|
2491 this.sortCommentBoxes = function() {
|
nickjillings@2117
|
2492 this.boxes.sort(function(a,b){return a.id - b.id;});
|
nickjillings@2117
|
2493 };
|
nickjillings@2117
|
2494
|
nickjillings@2117
|
2495 this.showCommentBoxes = function(inject, sort) {
|
nickjillings@2117
|
2496 this.injectPoint = inject;
|
nickjillings@2117
|
2497 if (sort) {this.sortCommentBoxes();}
|
nickjillings@2117
|
2498 for (var box of this.boxes) {
|
nickjillings@2117
|
2499 inject.appendChild(box.trackComment);
|
nickjillings@2117
|
2500 }
|
nickjillings@2117
|
2501 };
|
nickjillings@2117
|
2502
|
nickjillings@2117
|
2503 this.deleteCommentBoxes = function() {
|
nickjillings@2117
|
2504 if (this.injectPoint != null) {
|
nickjillings@2117
|
2505 for (var box of this.boxes) {
|
nickjillings@2117
|
2506 this.injectPoint.removeChild(box.trackComment);
|
nickjillings@2117
|
2507 }
|
nickjillings@2117
|
2508 this.injectPoint = null;
|
nickjillings@2117
|
2509 }
|
nickjillings@2117
|
2510 this.boxes = [];
|
nickjillings@2117
|
2511 };
|
nickjillings@2117
|
2512 }
|
nickjillings@1582
|
2513
|
nickjillings@2032
|
2514 this.commentQuestions = [];
|
nickjillings@2032
|
2515
|
nickjillings@2032
|
2516 this.commentBox = function(commentQuestion) {
|
nickjillings@2032
|
2517 this.specification = commentQuestion;
|
nickjillings@2032
|
2518 // Create document objects to hold the comment boxes
|
nickjillings@2032
|
2519 this.holder = document.createElement('div');
|
nickjillings@2032
|
2520 this.holder.className = 'comment-div';
|
nickjillings@2032
|
2521 // Create a string next to each comment asking for a comment
|
nickjillings@2032
|
2522 this.string = document.createElement('span');
|
nickjillings@1324
|
2523 this.string.innerHTML = commentQuestion.statement;
|
nickjillings@2032
|
2524 // Create the HTML5 comment box 'textarea'
|
nickjillings@2032
|
2525 this.textArea = document.createElement('textarea');
|
nickjillings@2032
|
2526 this.textArea.rows = '4';
|
nickjillings@2032
|
2527 this.textArea.cols = '100';
|
nickjillings@2032
|
2528 this.textArea.className = 'trackComment';
|
nickjillings@2032
|
2529 var br = document.createElement('br');
|
nickjillings@2032
|
2530 // Add to the holder.
|
nickjillings@2032
|
2531 this.holder.appendChild(this.string);
|
nickjillings@2032
|
2532 this.holder.appendChild(br);
|
nickjillings@2032
|
2533 this.holder.appendChild(this.textArea);
|
nickjillings@2032
|
2534
|
nickjillings@2097
|
2535 this.exportXMLDOM = function(storePoint) {
|
nickjillings@2097
|
2536 var root = storePoint.parent.document.createElement('comment');
|
nickjillings@2032
|
2537 root.id = this.specification.id;
|
nickjillings@2032
|
2538 root.setAttribute('type',this.specification.type);
|
b@2059
|
2539 console.log("Question: "+this.string.textContent);
|
b@2059
|
2540 console.log("Response: "+root.textContent);
|
nickjillings@2097
|
2541 var question = storePoint.parent.document.createElement('question');
|
nickjillings@2097
|
2542 question.textContent = this.string.textContent;
|
nickjillings@2097
|
2543 var response = storePoint.parent.document.createElement('response');
|
nickjillings@2097
|
2544 response.textContent = this.textArea.value;
|
nickjillings@2097
|
2545 root.appendChild(question);
|
nickjillings@2097
|
2546 root.appendChild(response);
|
nickjillings@2097
|
2547 storePoint.XMLDOM.appendChild(root);
|
nickjillings@2032
|
2548 return root;
|
nickjillings@2032
|
2549 };
|
nickjillings@1525
|
2550 this.resize = function()
|
nickjillings@1525
|
2551 {
|
nickjillings@1525
|
2552 var boxwidth = (window.innerWidth-100)/2;
|
nickjillings@1525
|
2553 if (boxwidth >= 600)
|
nickjillings@1525
|
2554 {
|
nickjillings@1525
|
2555 boxwidth = 600;
|
nickjillings@1525
|
2556 }
|
nickjillings@1525
|
2557 else if (boxwidth < 400)
|
nickjillings@1525
|
2558 {
|
nickjillings@1525
|
2559 boxwidth = 400;
|
nickjillings@1525
|
2560 }
|
nickjillings@1525
|
2561 this.holder.style.width = boxwidth+"px";
|
nickjillings@1525
|
2562 this.textArea.style.width = boxwidth-6+"px";
|
nickjillings@1525
|
2563 };
|
nickjillings@1525
|
2564 this.resize();
|
nickjillings@2032
|
2565 };
|
nickjillings@2032
|
2566
|
nickjillings@2032
|
2567 this.radioBox = function(commentQuestion) {
|
nickjillings@2032
|
2568 this.specification = commentQuestion;
|
nickjillings@2032
|
2569 // Create document objects to hold the comment boxes
|
nickjillings@2032
|
2570 this.holder = document.createElement('div');
|
nickjillings@2032
|
2571 this.holder.className = 'comment-div';
|
nickjillings@2032
|
2572 // Create a string next to each comment asking for a comment
|
nickjillings@2032
|
2573 this.string = document.createElement('span');
|
nickjillings@2032
|
2574 this.string.innerHTML = commentQuestion.statement;
|
nickjillings@2032
|
2575 var br = document.createElement('br');
|
nickjillings@2032
|
2576 // Add to the holder.
|
nickjillings@2032
|
2577 this.holder.appendChild(this.string);
|
nickjillings@2032
|
2578 this.holder.appendChild(br);
|
nickjillings@2032
|
2579 this.options = [];
|
nickjillings@2032
|
2580 this.inputs = document.createElement('div');
|
nickjillings@2032
|
2581 this.span = document.createElement('div');
|
nickjillings@2032
|
2582 this.inputs.align = 'center';
|
nickjillings@2032
|
2583 this.inputs.style.marginLeft = '12px';
|
nickjillings@2032
|
2584 this.span.style.marginLeft = '12px';
|
nickjillings@2032
|
2585 this.span.align = 'center';
|
nickjillings@2032
|
2586 this.span.style.marginTop = '15px';
|
nickjillings@2032
|
2587
|
nickjillings@2032
|
2588 var optCount = commentQuestion.options.length;
|
nickjillings@1324
|
2589 for (var optNode of commentQuestion.options)
|
nickjillings@2032
|
2590 {
|
nickjillings@2032
|
2591 var div = document.createElement('div');
|
nickjillings@1524
|
2592 div.style.width = '80px';
|
nickjillings@2032
|
2593 div.style.float = 'left';
|
nickjillings@2032
|
2594 var input = document.createElement('input');
|
nickjillings@2032
|
2595 input.type = 'radio';
|
nickjillings@2032
|
2596 input.name = commentQuestion.id;
|
nickjillings@1324
|
2597 input.setAttribute('setvalue',optNode.name);
|
nickjillings@2032
|
2598 input.className = 'comment-radio';
|
nickjillings@2032
|
2599 div.appendChild(input);
|
nickjillings@2032
|
2600 this.inputs.appendChild(div);
|
nickjillings@2032
|
2601
|
nickjillings@2032
|
2602
|
nickjillings@2032
|
2603 div = document.createElement('div');
|
nickjillings@1524
|
2604 div.style.width = '80px';
|
nickjillings@2032
|
2605 div.style.float = 'left';
|
nickjillings@2032
|
2606 div.align = 'center';
|
nickjillings@2032
|
2607 var span = document.createElement('span');
|
nickjillings@1324
|
2608 span.textContent = optNode.text;
|
nickjillings@2032
|
2609 span.className = 'comment-radio-span';
|
nickjillings@2032
|
2610 div.appendChild(span);
|
nickjillings@2032
|
2611 this.span.appendChild(div);
|
nickjillings@2032
|
2612 this.options.push(input);
|
nickjillings@2032
|
2613 }
|
nickjillings@2032
|
2614 this.holder.appendChild(this.span);
|
nickjillings@2032
|
2615 this.holder.appendChild(this.inputs);
|
nickjillings@2032
|
2616
|
nickjillings@2097
|
2617 this.exportXMLDOM = function(storePoint) {
|
nickjillings@2097
|
2618 var root = storePoint.parent.document.createElement('comment');
|
nickjillings@2032
|
2619 root.id = this.specification.id;
|
nickjillings@2032
|
2620 root.setAttribute('type',this.specification.type);
|
nickjillings@2032
|
2621 var question = document.createElement('question');
|
nickjillings@2032
|
2622 question.textContent = this.string.textContent;
|
nickjillings@2032
|
2623 var response = document.createElement('response');
|
nickjillings@2032
|
2624 var i=0;
|
nickjillings@2032
|
2625 while(this.options[i].checked == false) {
|
nickjillings@2032
|
2626 i++;
|
nickjillings@2032
|
2627 if (i >= this.options.length) {
|
nickjillings@2032
|
2628 break;
|
nickjillings@2032
|
2629 }
|
nickjillings@2032
|
2630 }
|
nickjillings@2032
|
2631 if (i >= this.options.length) {
|
nickjillings@2032
|
2632 response.textContent = 'null';
|
nickjillings@2032
|
2633 } else {
|
nickjillings@2032
|
2634 response.textContent = this.options[i].getAttribute('setvalue');
|
nickjillings@2032
|
2635 response.setAttribute('number',i);
|
nickjillings@2032
|
2636 }
|
nickjillings@1572
|
2637 console.log('Comment: '+question.textContent);
|
nickjillings@1572
|
2638 console.log('Response: '+response.textContent);
|
nickjillings@2032
|
2639 root.appendChild(question);
|
nickjillings@2032
|
2640 root.appendChild(response);
|
nickjillings@2097
|
2641 storePoint.XMLDOM.appendChild(root);
|
nickjillings@2032
|
2642 return root;
|
nickjillings@2032
|
2643 };
|
nickjillings@1525
|
2644 this.resize = function()
|
nickjillings@1525
|
2645 {
|
nickjillings@1525
|
2646 var boxwidth = (window.innerWidth-100)/2;
|
nickjillings@1525
|
2647 if (boxwidth >= 600)
|
nickjillings@1525
|
2648 {
|
nickjillings@1525
|
2649 boxwidth = 600;
|
nickjillings@1525
|
2650 }
|
nickjillings@1525
|
2651 else if (boxwidth < 400)
|
nickjillings@1525
|
2652 {
|
nickjillings@1525
|
2653 boxwidth = 400;
|
nickjillings@1525
|
2654 }
|
nickjillings@1525
|
2655 this.holder.style.width = boxwidth+"px";
|
nickjillings@1525
|
2656 var text = this.holder.children[2];
|
nickjillings@1525
|
2657 var options = this.holder.children[3];
|
nickjillings@1525
|
2658 var optCount = options.children.length;
|
nickjillings@1525
|
2659 var spanMargin = Math.floor(((boxwidth-20-(optCount*80))/(optCount))/2)+'px';
|
nickjillings@1525
|
2660 var options = options.firstChild;
|
nickjillings@1525
|
2661 var text = text.firstChild;
|
nickjillings@1525
|
2662 options.style.marginRight = spanMargin;
|
nickjillings@1525
|
2663 options.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2664 text.style.marginRight = spanMargin;
|
nickjillings@1525
|
2665 text.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2666 while(options.nextSibling != undefined)
|
nickjillings@1525
|
2667 {
|
nickjillings@1525
|
2668 options = options.nextSibling;
|
nickjillings@1525
|
2669 text = text.nextSibling;
|
nickjillings@1525
|
2670 options.style.marginRight = spanMargin;
|
nickjillings@1525
|
2671 options.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2672 text.style.marginRight = spanMargin;
|
nickjillings@1525
|
2673 text.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2674 }
|
nickjillings@1525
|
2675 };
|
nickjillings@1525
|
2676 this.resize();
|
nickjillings@2032
|
2677 };
|
nickjillings@2032
|
2678
|
nickjillings@1572
|
2679 this.checkboxBox = function(commentQuestion) {
|
nickjillings@1572
|
2680 this.specification = commentQuestion;
|
nickjillings@1572
|
2681 // Create document objects to hold the comment boxes
|
nickjillings@1572
|
2682 this.holder = document.createElement('div');
|
nickjillings@1572
|
2683 this.holder.className = 'comment-div';
|
nickjillings@1572
|
2684 // Create a string next to each comment asking for a comment
|
nickjillings@1572
|
2685 this.string = document.createElement('span');
|
nickjillings@1572
|
2686 this.string.innerHTML = commentQuestion.statement;
|
nickjillings@1572
|
2687 var br = document.createElement('br');
|
nickjillings@1572
|
2688 // Add to the holder.
|
nickjillings@1572
|
2689 this.holder.appendChild(this.string);
|
nickjillings@1572
|
2690 this.holder.appendChild(br);
|
nickjillings@1572
|
2691 this.options = [];
|
nickjillings@1572
|
2692 this.inputs = document.createElement('div');
|
nickjillings@1572
|
2693 this.span = document.createElement('div');
|
nickjillings@1572
|
2694 this.inputs.align = 'center';
|
nickjillings@1572
|
2695 this.inputs.style.marginLeft = '12px';
|
nickjillings@1572
|
2696 this.span.style.marginLeft = '12px';
|
nickjillings@1572
|
2697 this.span.align = 'center';
|
nickjillings@1572
|
2698 this.span.style.marginTop = '15px';
|
nickjillings@1572
|
2699
|
nickjillings@1572
|
2700 var optCount = commentQuestion.options.length;
|
nickjillings@1572
|
2701 for (var i=0; i<optCount; i++)
|
nickjillings@1572
|
2702 {
|
nickjillings@1572
|
2703 var div = document.createElement('div');
|
nickjillings@1524
|
2704 div.style.width = '80px';
|
nickjillings@1572
|
2705 div.style.float = 'left';
|
nickjillings@1572
|
2706 var input = document.createElement('input');
|
nickjillings@1572
|
2707 input.type = 'checkbox';
|
nickjillings@1572
|
2708 input.name = commentQuestion.id;
|
nickjillings@1572
|
2709 input.setAttribute('setvalue',commentQuestion.options[i].name);
|
nickjillings@1572
|
2710 input.className = 'comment-radio';
|
nickjillings@1572
|
2711 div.appendChild(input);
|
nickjillings@1572
|
2712 this.inputs.appendChild(div);
|
nickjillings@1572
|
2713
|
nickjillings@1572
|
2714
|
nickjillings@1572
|
2715 div = document.createElement('div');
|
nickjillings@1524
|
2716 div.style.width = '80px';
|
nickjillings@1572
|
2717 div.style.float = 'left';
|
nickjillings@1572
|
2718 div.align = 'center';
|
nickjillings@1572
|
2719 var span = document.createElement('span');
|
nickjillings@1572
|
2720 span.textContent = commentQuestion.options[i].text;
|
nickjillings@1572
|
2721 span.className = 'comment-radio-span';
|
nickjillings@1572
|
2722 div.appendChild(span);
|
nickjillings@1572
|
2723 this.span.appendChild(div);
|
nickjillings@1572
|
2724 this.options.push(input);
|
nickjillings@1572
|
2725 }
|
nickjillings@1572
|
2726 this.holder.appendChild(this.span);
|
nickjillings@1572
|
2727 this.holder.appendChild(this.inputs);
|
nickjillings@1572
|
2728
|
nickjillings@2097
|
2729 this.exportXMLDOM = function(storePoint) {
|
nickjillings@2097
|
2730 var root = storePoint.parent.document.createElement('comment');
|
nickjillings@1572
|
2731 root.id = this.specification.id;
|
nickjillings@1572
|
2732 root.setAttribute('type',this.specification.type);
|
nickjillings@1572
|
2733 var question = document.createElement('question');
|
nickjillings@1572
|
2734 question.textContent = this.string.textContent;
|
nickjillings@1572
|
2735 root.appendChild(question);
|
nickjillings@1572
|
2736 console.log('Comment: '+question.textContent);
|
nickjillings@1572
|
2737 for (var i=0; i<this.options.length; i++) {
|
nickjillings@1572
|
2738 var response = document.createElement('response');
|
nickjillings@1572
|
2739 response.textContent = this.options[i].checked;
|
nickjillings@1572
|
2740 response.setAttribute('name',this.options[i].getAttribute('setvalue'));
|
nickjillings@1572
|
2741 root.appendChild(response);
|
nickjillings@1572
|
2742 console.log('Response '+response.getAttribute('name') +': '+response.textContent);
|
nickjillings@1572
|
2743 }
|
nickjillings@2097
|
2744 storePoint.XMLDOM.appendChild(root);
|
nickjillings@1572
|
2745 return root;
|
nickjillings@1572
|
2746 };
|
nickjillings@1525
|
2747 this.resize = function()
|
nickjillings@1525
|
2748 {
|
nickjillings@1525
|
2749 var boxwidth = (window.innerWidth-100)/2;
|
nickjillings@1525
|
2750 if (boxwidth >= 600)
|
nickjillings@1525
|
2751 {
|
nickjillings@1525
|
2752 boxwidth = 600;
|
nickjillings@1525
|
2753 }
|
nickjillings@1525
|
2754 else if (boxwidth < 400)
|
nickjillings@1525
|
2755 {
|
nickjillings@1525
|
2756 boxwidth = 400;
|
nickjillings@1525
|
2757 }
|
nickjillings@1525
|
2758 this.holder.style.width = boxwidth+"px";
|
nickjillings@1525
|
2759 var text = this.holder.children[2];
|
nickjillings@1525
|
2760 var options = this.holder.children[3];
|
nickjillings@1525
|
2761 var optCount = options.children.length;
|
nickjillings@1525
|
2762 var spanMargin = Math.floor(((boxwidth-20-(optCount*80))/(optCount))/2)+'px';
|
nickjillings@1525
|
2763 var options = options.firstChild;
|
nickjillings@1525
|
2764 var text = text.firstChild;
|
nickjillings@1525
|
2765 options.style.marginRight = spanMargin;
|
nickjillings@1525
|
2766 options.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2767 text.style.marginRight = spanMargin;
|
nickjillings@1525
|
2768 text.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2769 while(options.nextSibling != undefined)
|
nickjillings@1525
|
2770 {
|
nickjillings@1525
|
2771 options = options.nextSibling;
|
nickjillings@1525
|
2772 text = text.nextSibling;
|
nickjillings@1525
|
2773 options.style.marginRight = spanMargin;
|
nickjillings@1525
|
2774 options.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2775 text.style.marginRight = spanMargin;
|
nickjillings@1525
|
2776 text.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2777 }
|
nickjillings@1525
|
2778 };
|
nickjillings@1525
|
2779 this.resize();
|
nickjillings@1572
|
2780 };
|
nickjillings@1570
|
2781
|
nickjillings@2032
|
2782 this.createCommentQuestion = function(element) {
|
nickjillings@2032
|
2783 var node;
|
nickjillings@1324
|
2784 if (element.type == 'question') {
|
nickjillings@2032
|
2785 node = new this.commentBox(element);
|
nickjillings@2032
|
2786 } else if (element.type == 'radio') {
|
nickjillings@2032
|
2787 node = new this.radioBox(element);
|
nickjillings@1572
|
2788 } else if (element.type == 'checkbox') {
|
nickjillings@1572
|
2789 node = new this.checkboxBox(element);
|
nickjillings@2032
|
2790 }
|
nickjillings@2032
|
2791 this.commentQuestions.push(node);
|
nickjillings@2032
|
2792 return node;
|
nickjillings@2032
|
2793 };
|
nickjillings@1564
|
2794
|
nickjillings@2051
|
2795 this.deleteCommentQuestions = function()
|
nickjillings@2051
|
2796 {
|
nickjillings@2051
|
2797 this.commentQuestions = [];
|
nickjillings@2051
|
2798 };
|
nickjillings@2051
|
2799
|
nickjillings@1564
|
2800 this.playhead = new function()
|
nickjillings@1564
|
2801 {
|
nickjillings@1564
|
2802 this.object = document.createElement('div');
|
nickjillings@1564
|
2803 this.object.className = 'playhead';
|
nickjillings@1564
|
2804 this.object.align = 'left';
|
nickjillings@1564
|
2805 var curTime = document.createElement('div');
|
nickjillings@1564
|
2806 curTime.style.width = '50px';
|
nickjillings@1564
|
2807 this.curTimeSpan = document.createElement('span');
|
nickjillings@1564
|
2808 this.curTimeSpan.textContent = '00:00';
|
nickjillings@1564
|
2809 curTime.appendChild(this.curTimeSpan);
|
nickjillings@1564
|
2810 this.object.appendChild(curTime);
|
nickjillings@1564
|
2811 this.scrubberTrack = document.createElement('div');
|
nickjillings@1564
|
2812 this.scrubberTrack.className = 'playhead-scrub-track';
|
nickjillings@1564
|
2813
|
nickjillings@1564
|
2814 this.scrubberHead = document.createElement('div');
|
nickjillings@1564
|
2815 this.scrubberHead.id = 'playhead-scrubber';
|
nickjillings@1564
|
2816 this.scrubberTrack.appendChild(this.scrubberHead);
|
nickjillings@1564
|
2817 this.object.appendChild(this.scrubberTrack);
|
nickjillings@1564
|
2818
|
nickjillings@1564
|
2819 this.timePerPixel = 0;
|
nickjillings@1564
|
2820 this.maxTime = 0;
|
nickjillings@1564
|
2821
|
nickjillings@1567
|
2822 this.playbackObject;
|
nickjillings@1567
|
2823
|
nickjillings@1567
|
2824 this.setTimePerPixel = function(audioObject) {
|
nickjillings@1564
|
2825 //maxTime must be in seconds
|
nickjillings@1567
|
2826 this.playbackObject = audioObject;
|
nickjillings@1410
|
2827 this.maxTime = audioObject.buffer.buffer.duration;
|
nickjillings@1564
|
2828 var width = 490; //500 - 10, 5 each side of the tracker head
|
nickjillings@1567
|
2829 this.timePerPixel = this.maxTime/490;
|
nickjillings@1567
|
2830 if (this.maxTime < 60) {
|
nickjillings@1564
|
2831 this.curTimeSpan.textContent = '0.00';
|
nickjillings@1564
|
2832 } else {
|
nickjillings@1564
|
2833 this.curTimeSpan.textContent = '00:00';
|
nickjillings@1564
|
2834 }
|
nickjillings@1564
|
2835 };
|
nickjillings@1564
|
2836
|
nickjillings@1567
|
2837 this.update = function() {
|
nickjillings@1564
|
2838 // Update the playhead position, startPlay must be called
|
nickjillings@1564
|
2839 if (this.timePerPixel > 0) {
|
nickjillings@1567
|
2840 var time = this.playbackObject.getCurrentPosition();
|
nickjillings@1367
|
2841 if (time > 0 && time < this.maxTime) {
|
nickjillings@1530
|
2842 var width = 490;
|
nickjillings@1530
|
2843 var pix = Math.floor(time/this.timePerPixel);
|
nickjillings@1530
|
2844 this.scrubberHead.style.left = pix+'px';
|
nickjillings@1530
|
2845 if (this.maxTime > 60.0) {
|
nickjillings@1530
|
2846 var secs = time%60;
|
nickjillings@1530
|
2847 var mins = Math.floor((time-secs)/60);
|
nickjillings@1530
|
2848 secs = secs.toString();
|
nickjillings@1530
|
2849 secs = secs.substr(0,2);
|
nickjillings@1530
|
2850 mins = mins.toString();
|
nickjillings@1530
|
2851 this.curTimeSpan.textContent = mins+':'+secs;
|
nickjillings@1530
|
2852 } else {
|
nickjillings@1530
|
2853 time = time.toString();
|
nickjillings@1530
|
2854 this.curTimeSpan.textContent = time.substr(0,4);
|
nickjillings@1530
|
2855 }
|
nickjillings@1564
|
2856 } else {
|
nickjillings@1530
|
2857 this.scrubberHead.style.left = '0px';
|
nickjillings@1530
|
2858 if (this.maxTime < 60) {
|
nickjillings@1530
|
2859 this.curTimeSpan.textContent = '0.00';
|
nickjillings@1530
|
2860 } else {
|
nickjillings@1530
|
2861 this.curTimeSpan.textContent = '00:00';
|
nickjillings@1530
|
2862 }
|
nickjillings@1564
|
2863 }
|
nickjillings@1564
|
2864 }
|
nickjillings@1564
|
2865 };
|
nickjillings@1567
|
2866
|
nickjillings@1567
|
2867 this.interval = undefined;
|
nickjillings@1567
|
2868
|
nickjillings@1567
|
2869 this.start = function() {
|
nickjillings@1567
|
2870 if (this.playbackObject != undefined && this.interval == undefined) {
|
nickjillings@1530
|
2871 if (this.maxTime < 60) {
|
nickjillings@1530
|
2872 this.interval = setInterval(function(){interfaceContext.playhead.update();},10);
|
nickjillings@1530
|
2873 } else {
|
nickjillings@1530
|
2874 this.interval = setInterval(function(){interfaceContext.playhead.update();},100);
|
nickjillings@1530
|
2875 }
|
nickjillings@1567
|
2876 }
|
nickjillings@1567
|
2877 };
|
nickjillings@1567
|
2878 this.stop = function() {
|
nickjillings@1567
|
2879 clearInterval(this.interval);
|
nickjillings@1567
|
2880 this.interval = undefined;
|
nickjillings@2101
|
2881 this.scrubberHead.style.left = '0px';
|
nickjillings@1530
|
2882 if (this.maxTime < 60) {
|
nickjillings@1530
|
2883 this.curTimeSpan.textContent = '0.00';
|
nickjillings@1530
|
2884 } else {
|
nickjillings@1530
|
2885 this.curTimeSpan.textContent = '00:00';
|
nickjillings@1530
|
2886 }
|
nickjillings@1567
|
2887 };
|
nickjillings@1564
|
2888 };
|
nickjillings@1354
|
2889
|
nickjillings@1354
|
2890 this.volume = new function()
|
nickjillings@1354
|
2891 {
|
nickjillings@1354
|
2892 // An in-built volume module which can be viewed on page
|
nickjillings@1354
|
2893 // Includes trackers on page-by-page data
|
nickjillings@1354
|
2894 // Volume does NOT reset to 0dB on each page load
|
nickjillings@1354
|
2895 this.valueLin = 1.0;
|
nickjillings@1354
|
2896 this.valueDB = 0.0;
|
nickjillings@1354
|
2897 this.object = document.createElement('div');
|
nickjillings@1354
|
2898 this.object.id = 'master-volume-holder';
|
nickjillings@1354
|
2899 this.slider = document.createElement('input');
|
nickjillings@1354
|
2900 this.slider.id = 'master-volume-control';
|
nickjillings@1354
|
2901 this.slider.type = 'range';
|
nickjillings@1354
|
2902 this.valueText = document.createElement('span');
|
nickjillings@1354
|
2903 this.valueText.id = 'master-volume-feedback';
|
nickjillings@1354
|
2904 this.valueText.textContent = '0dB';
|
nickjillings@1354
|
2905
|
nickjillings@1354
|
2906 this.slider.min = -60;
|
nickjillings@1354
|
2907 this.slider.max = 12;
|
nickjillings@1354
|
2908 this.slider.value = 0;
|
nickjillings@1354
|
2909 this.slider.step = 1;
|
nickjillings@1354
|
2910 this.slider.onmousemove = function(event)
|
nickjillings@1354
|
2911 {
|
nickjillings@1354
|
2912 interfaceContext.volume.valueDB = event.currentTarget.value;
|
nickjillings@1354
|
2913 interfaceContext.volume.valueLin = decibelToLinear(interfaceContext.volume.valueDB);
|
nickjillings@1354
|
2914 interfaceContext.volume.valueText.textContent = interfaceContext.volume.valueDB+'dB';
|
nickjillings@1354
|
2915 audioEngineContext.outputGain.gain.value = interfaceContext.volume.valueLin;
|
nickjillings@1354
|
2916 }
|
nickjillings@1354
|
2917 this.slider.onmouseup = function(event)
|
nickjillings@1354
|
2918 {
|
nickjillings@2100
|
2919 var storePoint = testState.currentStore.XMLDOM.getElementsByTagName('metric')[0].getAllElementsByName('volumeTracker');
|
nickjillings@1354
|
2920 if (storePoint.length == 0)
|
nickjillings@1354
|
2921 {
|
nickjillings@1354
|
2922 storePoint = storage.document.createElement('metricresult');
|
nickjillings@1354
|
2923 storePoint.setAttribute('name','volumeTracker');
|
nickjillings@2100
|
2924 testState.currentStore.XMLDOM.getElementsByTagName('metric')[0].appendChild(storePoint);
|
nickjillings@1354
|
2925 }
|
nickjillings@1354
|
2926 else {
|
nickjillings@1354
|
2927 storePoint = storePoint[0];
|
nickjillings@1354
|
2928 }
|
nickjillings@1354
|
2929 var node = storage.document.createElement('movement');
|
nickjillings@1354
|
2930 node.setAttribute('test-time',audioEngineContext.timer.getTestTime());
|
nickjillings@1354
|
2931 node.setAttribute('volume',interfaceContext.volume.valueDB);
|
nickjillings@1354
|
2932 node.setAttribute('format','dBFS');
|
nickjillings@1354
|
2933 storePoint.appendChild(node);
|
nickjillings@1354
|
2934 }
|
nickjillings@1354
|
2935
|
nickjillings@1355
|
2936 var title = document.createElement('div');
|
nickjillings@1355
|
2937 title.innerHTML = '<span>Master Volume Control</span>';
|
nickjillings@1355
|
2938 title.style.fontSize = '0.75em';
|
nickjillings@1355
|
2939 title.style.width = "100%";
|
nickjillings@1355
|
2940 title.align = 'center';
|
nickjillings@1355
|
2941 this.object.appendChild(title);
|
nickjillings@1355
|
2942
|
nickjillings@1354
|
2943 this.object.appendChild(this.slider);
|
nickjillings@1354
|
2944 this.object.appendChild(this.valueText);
|
nickjillings@1354
|
2945 }
|
nickjillings@2049
|
2946 // Global Checkers
|
nickjillings@2049
|
2947 // These functions will help enforce the checkers
|
nickjillings@2049
|
2948 this.checkHiddenAnchor = function()
|
nickjillings@2049
|
2949 {
|
nickjillings@1324
|
2950 for (var ao of audioEngineContext.audioObjects)
|
nickjillings@2049
|
2951 {
|
nickjillings@1324
|
2952 if (ao.specification.type == "anchor")
|
nickjillings@2049
|
2953 {
|
nickjillings@1325
|
2954 if (ao.interfaceDOM.getValue() > (ao.specification.marker/100) && ao.specification.marker > 0) {
|
nickjillings@1324
|
2955 // Anchor is not set below
|
nickjillings@1324
|
2956 console.log('Anchor node not below marker value');
|
nickjillings@1324
|
2957 alert('Please keep listening');
|
nickjillings@1367
|
2958 this.storeErrorNode('Anchor node not below marker value');
|
nickjillings@1324
|
2959 return false;
|
nickjillings@1324
|
2960 }
|
nickjillings@2049
|
2961 }
|
nickjillings@2049
|
2962 }
|
nickjillings@2049
|
2963 return true;
|
nickjillings@2049
|
2964 };
|
nickjillings@2049
|
2965
|
nickjillings@2049
|
2966 this.checkHiddenReference = function()
|
nickjillings@2049
|
2967 {
|
nickjillings@1324
|
2968 for (var ao of audioEngineContext.audioObjects)
|
nickjillings@2049
|
2969 {
|
nickjillings@1324
|
2970 if (ao.specification.type == "reference")
|
nickjillings@2049
|
2971 {
|
nickjillings@1325
|
2972 if (ao.interfaceDOM.getValue() < (ao.specification.marker/100) && ao.specification.marker > 0) {
|
nickjillings@1324
|
2973 // Anchor is not set below
|
nickjillings@1367
|
2974 console.log('Reference node not above marker value');
|
nickjillings@1367
|
2975 this.storeErrorNode('Reference node not above marker value');
|
nickjillings@1324
|
2976 alert('Please keep listening');
|
nickjillings@1324
|
2977 return false;
|
nickjillings@1324
|
2978 }
|
nickjillings@2049
|
2979 }
|
nickjillings@2049
|
2980 }
|
nickjillings@2049
|
2981 return true;
|
nickjillings@2049
|
2982 };
|
nickjillings@1474
|
2983
|
nickjillings@1474
|
2984 this.checkFragmentsFullyPlayed = function ()
|
nickjillings@1474
|
2985 {
|
nickjillings@1474
|
2986 // Checks the entire file has been played back
|
nickjillings@1474
|
2987 // NOTE ! This will return true IF playback is Looped!!!
|
nickjillings@1474
|
2988 if (audioEngineContext.loopPlayback)
|
nickjillings@1474
|
2989 {
|
nickjillings@1474
|
2990 console.log("WARNING - Looped source: Cannot check fragments are fully played");
|
nickjillings@1474
|
2991 return true;
|
nickjillings@1474
|
2992 }
|
nickjillings@1474
|
2993 var check_pass = true;
|
nickjillings@1474
|
2994 var error_obj = [];
|
nickjillings@1474
|
2995 for (var i = 0; i<audioEngineContext.audioObjects.length; i++)
|
nickjillings@1474
|
2996 {
|
nickjillings@1474
|
2997 var object = audioEngineContext.audioObjects[i];
|
nickjillings@1393
|
2998 var time = object.buffer.buffer.duration;
|
nickjillings@1474
|
2999 var metric = object.metric;
|
nickjillings@1474
|
3000 var passed = false;
|
nickjillings@1474
|
3001 for (var j=0; j<metric.listenTracker.length; j++)
|
nickjillings@1474
|
3002 {
|
nickjillings@1474
|
3003 var bt = metric.listenTracker[j].getElementsByTagName('buffertime');
|
nickjillings@1474
|
3004 var start_time = Number(bt[0].getAttribute('start'));
|
nickjillings@1474
|
3005 var stop_time = Number(bt[0].getAttribute('stop'));
|
nickjillings@1474
|
3006 var delta = stop_time - start_time;
|
nickjillings@1474
|
3007 if (delta >= time)
|
nickjillings@1474
|
3008 {
|
nickjillings@1474
|
3009 passed = true;
|
nickjillings@1474
|
3010 break;
|
nickjillings@1474
|
3011 }
|
nickjillings@1474
|
3012 }
|
nickjillings@1474
|
3013 if (passed == false)
|
nickjillings@1474
|
3014 {
|
nickjillings@1474
|
3015 check_pass = false;
|
nickjillings@1340
|
3016 console.log("Continue listening to track-"+audioEngineContext.audioObjects.interfaceDOM.getPresentedId());
|
nickjillings@1340
|
3017 error_obj.push(audioEngineContext.audioObjects.interfaceDOM.getPresentedId());
|
nickjillings@1474
|
3018 }
|
nickjillings@1474
|
3019 }
|
nickjillings@1474
|
3020 if (check_pass == false)
|
nickjillings@1474
|
3021 {
|
nickjillings@1393
|
3022 var str_start = "You have not completely listened to fragments ";
|
nickjillings@1474
|
3023 for (var i=0; i<error_obj.length; i++)
|
nickjillings@1474
|
3024 {
|
nickjillings@1474
|
3025 str_start += error_obj[i];
|
nickjillings@1474
|
3026 if (i != error_obj.length-1)
|
nickjillings@1474
|
3027 {
|
nickjillings@1474
|
3028 str_start += ', ';
|
nickjillings@1474
|
3029 }
|
nickjillings@1474
|
3030 }
|
nickjillings@1474
|
3031 str_start += ". Please keep listening";
|
nickjillings@1474
|
3032 console.log("[ALERT]: "+str_start);
|
nickjillings@1367
|
3033 this.storeErrorNode("[ALERT]: "+str_start);
|
nickjillings@1474
|
3034 alert(str_start);
|
nickjillings@1474
|
3035 }
|
nickjillings@1474
|
3036 };
|
nickjillings@1399
|
3037 this.checkAllMoved = function()
|
nickjillings@1399
|
3038 {
|
nickjillings@1399
|
3039 var str = "You have not moved ";
|
nickjillings@1399
|
3040 var failed = [];
|
nickjillings@1340
|
3041 for (var ao of audioEngineContext.audioObjects)
|
nickjillings@1399
|
3042 {
|
nickjillings@1340
|
3043 if(ao.metric.wasMoved == false && ao.interfaceDOM.canMove() == true)
|
nickjillings@1399
|
3044 {
|
nickjillings@1340
|
3045 failed.push(ao.interfaceDOM.getPresentedId());
|
nickjillings@1399
|
3046 }
|
nickjillings@1399
|
3047 }
|
nickjillings@1399
|
3048 if (failed.length == 0)
|
nickjillings@1399
|
3049 {
|
nickjillings@1399
|
3050 return true;
|
nickjillings@1399
|
3051 } else if (failed.length == 1)
|
nickjillings@1399
|
3052 {
|
nickjillings@1399
|
3053 str += 'track '+failed[0];
|
nickjillings@1399
|
3054 } else {
|
nickjillings@1399
|
3055 str += 'tracks ';
|
nickjillings@1399
|
3056 for (var i=0; i<failed.length-1; i++)
|
nickjillings@1399
|
3057 {
|
nickjillings@1399
|
3058 str += failed[i]+', ';
|
nickjillings@1399
|
3059 }
|
nickjillings@1399
|
3060 str += 'and '+failed[i];
|
nickjillings@1399
|
3061 }
|
nickjillings@1399
|
3062 str +='.';
|
nickjillings@1399
|
3063 alert(str);
|
nickjillings@1399
|
3064 console.log(str);
|
nickjillings@1367
|
3065 this.storeErrorNode(str);
|
nickjillings@1399
|
3066 return false;
|
nickjillings@1399
|
3067 };
|
nickjillings@1399
|
3068 this.checkAllPlayed = function()
|
nickjillings@1399
|
3069 {
|
nickjillings@1399
|
3070 var str = "You have not played ";
|
nickjillings@1399
|
3071 var failed = [];
|
nickjillings@1340
|
3072 for (var ao of audioEngineContext.audioObjects)
|
nickjillings@1399
|
3073 {
|
nickjillings@1340
|
3074 if(ao.metric.wasListenedTo == false)
|
nickjillings@1399
|
3075 {
|
nickjillings@1340
|
3076 failed.push(ao.interfaceDOM.getPresentedId());
|
nickjillings@1399
|
3077 }
|
nickjillings@1399
|
3078 }
|
nickjillings@1399
|
3079 if (failed.length == 0)
|
nickjillings@1399
|
3080 {
|
nickjillings@1399
|
3081 return true;
|
nickjillings@1399
|
3082 } else if (failed.length == 1)
|
nickjillings@1399
|
3083 {
|
nickjillings@1399
|
3084 str += 'track '+failed[0];
|
nickjillings@1399
|
3085 } else {
|
nickjillings@1399
|
3086 str += 'tracks ';
|
nickjillings@1399
|
3087 for (var i=0; i<failed.length-1; i++)
|
nickjillings@1399
|
3088 {
|
nickjillings@1399
|
3089 str += failed[i]+', ';
|
nickjillings@1399
|
3090 }
|
nickjillings@1399
|
3091 str += 'and '+failed[i];
|
nickjillings@1399
|
3092 }
|
nickjillings@1399
|
3093 str +='.';
|
nickjillings@1399
|
3094 alert(str);
|
nickjillings@1399
|
3095 console.log(str);
|
nickjillings@1367
|
3096 this.storeErrorNode(str);
|
nickjillings@1399
|
3097 return false;
|
nickjillings@1399
|
3098 };
|
nickjillings@1367
|
3099
|
nickjillings@1367
|
3100 this.storeErrorNode = function(errorMessage)
|
nickjillings@1367
|
3101 {
|
nickjillings@1367
|
3102 var time = audioEngineContext.timer.getTestTime();
|
nickjillings@1367
|
3103 var node = storage.document.createElement('error');
|
nickjillings@1367
|
3104 node.setAttribute('time',time);
|
nickjillings@1367
|
3105 node.textContent = errorMessage;
|
nickjillings@1367
|
3106 testState.currentStore.XMLDOM.appendChild(node);
|
nickjillings@1367
|
3107 };
|
nickjillings@1324
|
3108 }
|
nickjillings@1324
|
3109
|
nickjillings@1324
|
3110 function Storage()
|
nickjillings@1324
|
3111 {
|
nickjillings@1324
|
3112 // Holds results in XML format until ready for collection
|
nickjillings@1324
|
3113 this.globalPreTest = null;
|
nickjillings@1324
|
3114 this.globalPostTest = null;
|
nickjillings@1324
|
3115 this.testPages = [];
|
nickjillings@1324
|
3116 this.document = document.implementation.createDocument(null,"waetresult");
|
nickjillings@2118
|
3117 this.root = this.document.childNodes[0];
|
nickjillings@1324
|
3118 this.state = 0;
|
nickjillings@1324
|
3119
|
nickjillings@2147
|
3120 this.initialise = function(sessionKey)
|
nickjillings@1324
|
3121 {
|
nickjillings@1342
|
3122 if (specification.preTest != undefined){this.globalPreTest = new this.surveyNode(this,this.root,specification.preTest);}
|
nickjillings@1342
|
3123 if (specification.postTest != undefined){this.globalPostTest = new this.surveyNode(this,this.root,specification.postTest);}
|
nickjillings@2147
|
3124 if (sessionKey == undefined) {
|
nickjillings@2147
|
3125 // We need to get the sessionKey
|
nickjillings@2147
|
3126 this.SessionKey.generateKey();
|
nickjillings@2147
|
3127 } else {
|
nickjillings@2147
|
3128 this.SessionKey.key = sessionKey;
|
nickjillings@2147
|
3129 }
|
nickjillings@1324
|
3130 };
|
nickjillings@2147
|
3131
|
nickjillings@2147
|
3132 this.SessionKey = {
|
nickjillings@2147
|
3133 key: null,
|
nickjillings@2147
|
3134 request: new XMLHttpRequest(),
|
nickjillings@2147
|
3135 parent: this,
|
nickjillings@2147
|
3136 handleEvent: function() {
|
nickjillings@2147
|
3137 var parse = new DOMParser();
|
nickjillings@2147
|
3138 var xml = parse.parseFromString(this.request.response,"text/xml");
|
nickjillings@2147
|
3139 if (xml.getAllElementsByTagName("state")[0].textContent == "OK") {
|
nickjillings@2147
|
3140 this.key = xml.getAllElementsByTagName("key")[0].textContent;
|
nickjillings@2147
|
3141 } else {
|
nickjillings@2147
|
3142 this.generateKey();
|
nickjillings@2147
|
3143 }
|
nickjillings@2147
|
3144 },
|
nickjillings@2147
|
3145 generateKey: function() {
|
nickjillings@2147
|
3146 var temp_key = randomString(32);
|
nickjillings@2147
|
3147 this.request.open("GET","keygen.php?key="+temp_key,true);
|
nickjillings@2147
|
3148 this.request.addEventListener("load",this);
|
nickjillings@2147
|
3149 this.request.send();
|
nickjillings@2149
|
3150 },
|
nickjillings@2149
|
3151 postData: function(nodeName,id,xml) {
|
nickjillings@2149
|
3152 // nodeName: the node name to find
|
nickjillings@2149
|
3153 // id: the id of the node (null if location==root)
|
nickjillings@2149
|
3154 // xml: the XML node to append
|
nickjillings@2149
|
3155 if (this.key != null) {
|
nickjillings@2149
|
3156 var postXML = new XMLHttpRequest;
|
nickjillings@2149
|
3157 postXML.open("POST","intermediate.php?key="+this.key+"&node="+nodeName+"&id="+id);
|
nickjillings@2149
|
3158 postXML.setRequestHeader('Content-Type','text/xml');
|
nickjillings@2149
|
3159 postXML.onerror = function() {
|
nickjillings@2149
|
3160 console.log("Error posting: "+this.responseText);
|
nickjillings@2149
|
3161 }
|
nickjillings@2149
|
3162 var parent = document.createElement("div");
|
nickjillings@2149
|
3163 parent.appendChild(xml);
|
nickjillings@2149
|
3164 postXML.send([parent.innerHTML]);
|
nickjillings@2149
|
3165 }
|
nickjillings@2147
|
3166 }
|
nickjillings@2147
|
3167 }
|
nickjillings@1324
|
3168
|
nickjillings@1324
|
3169 this.createTestPageStore = function(specification)
|
nickjillings@1324
|
3170 {
|
nickjillings@1324
|
3171 var store = new this.pageNode(this,specification);
|
nickjillings@1324
|
3172 this.testPages.push(store);
|
nickjillings@1324
|
3173 return this.testPages[this.testPages.length-1];
|
nickjillings@1324
|
3174 };
|
nickjillings@1324
|
3175
|
nickjillings@1324
|
3176 this.surveyNode = function(parent,root,specification)
|
nickjillings@1324
|
3177 {
|
nickjillings@1324
|
3178 this.specification = specification;
|
nickjillings@1324
|
3179 this.parent = parent;
|
nickjillings@1324
|
3180 this.XMLDOM = this.parent.document.createElement('survey');
|
nickjillings@1324
|
3181 this.XMLDOM.setAttribute('location',this.specification.location);
|
nickjillings@1324
|
3182 for (var optNode of this.specification.options)
|
nickjillings@1324
|
3183 {
|
nickjillings@1324
|
3184 if (optNode.type != 'statement')
|
nickjillings@1324
|
3185 {
|
nickjillings@1324
|
3186 var node = this.parent.document.createElement('surveyresult');
|
nickjillings@1324
|
3187 node.id = optNode.id;
|
nickjillings@1324
|
3188 node.setAttribute('type',optNode.type);
|
nickjillings@1324
|
3189 this.XMLDOM.appendChild(node);
|
nickjillings@1324
|
3190 }
|
nickjillings@1324
|
3191 }
|
nickjillings@1324
|
3192 root.appendChild(this.XMLDOM);
|
nickjillings@1324
|
3193
|
nickjillings@1324
|
3194 this.postResult = function(node)
|
nickjillings@1324
|
3195 {
|
nickjillings@1324
|
3196 // From popup: node is the popupOption node containing both spec. and results
|
nickjillings@1324
|
3197 // ID is the position
|
nickjillings@1324
|
3198 if (node.specification.type == 'statement'){return;}
|
nickjillings@1324
|
3199 var surveyresult = this.parent.document.getElementById(node.specification.id);
|
nickjillings@1324
|
3200 switch(node.specification.type)
|
nickjillings@1324
|
3201 {
|
nickjillings@1324
|
3202 case "number":
|
nickjillings@1324
|
3203 case "question":
|
nickjillings@1324
|
3204 var child = this.parent.document.createElement('response');
|
nickjillings@1324
|
3205 child.textContent = node.response;
|
nickjillings@1324
|
3206 surveyresult.appendChild(child);
|
nickjillings@1324
|
3207 break;
|
nickjillings@1324
|
3208 case "radio":
|
nickjillings@1324
|
3209 var child = this.parent.document.createElement('response');
|
nickjillings@1324
|
3210 child.setAttribute('name',node.response.name);
|
nickjillings@1324
|
3211 child.textContent = node.response.text;
|
nickjillings@1324
|
3212 surveyresult.appendChild(child);
|
nickjillings@1324
|
3213 break;
|
nickjillings@1324
|
3214 case "checkbox":
|
nickjillings@1324
|
3215 for (var i=0; i<node.response.length; i++)
|
nickjillings@1324
|
3216 {
|
nickjillings@1324
|
3217 var checkNode = this.parent.document.createElement('response');
|
nickjillings@1347
|
3218 checkNode.setAttribute('name',node.response[i].name);
|
nickjillings@1347
|
3219 checkNode.setAttribute('checked',node.response[i].checked);
|
nickjillings@1326
|
3220 surveyresult.appendChild(checkNode);
|
nickjillings@1324
|
3221 }
|
nickjillings@1324
|
3222 break;
|
nickjillings@1324
|
3223 }
|
nickjillings@1324
|
3224 };
|
nickjillings@2149
|
3225
|
nickjillings@2149
|
3226 this.finish = function() {
|
nickjillings@2149
|
3227 if (this.parent.document != undefined) {
|
nickjillings@2149
|
3228 this.parent.SessionKey.postData("waetresult",null,this.XMLDOM);
|
nickjillings@2149
|
3229 }
|
nickjillings@2149
|
3230 };
|
nickjillings@1324
|
3231 };
|
nickjillings@1324
|
3232
|
nickjillings@1324
|
3233 this.pageNode = function(parent,specification)
|
nickjillings@1324
|
3234 {
|
nickjillings@1324
|
3235 // Create one store per test page
|
nickjillings@1324
|
3236 this.specification = specification;
|
nickjillings@1324
|
3237 this.parent = parent;
|
nickjillings@1324
|
3238 this.XMLDOM = this.parent.document.createElement('page');
|
nickjillings@1324
|
3239 this.XMLDOM.setAttribute('id',specification.id);
|
nickjillings@1324
|
3240 this.XMLDOM.setAttribute('presentedId',specification.presentedId);
|
nickjillings@1345
|
3241 if (specification.preTest != undefined){this.preTest = new this.parent.surveyNode(this.parent,this.XMLDOM,this.specification.preTest);}
|
nickjillings@1345
|
3242 if (specification.postTest != undefined){this.postTest = new this.parent.surveyNode(this.parent,this.XMLDOM,this.specification.postTest);}
|
nickjillings@1324
|
3243
|
nickjillings@1324
|
3244 // Add any page metrics
|
nickjillings@1324
|
3245 var page_metric = this.parent.document.createElement('metric');
|
nickjillings@1324
|
3246 this.XMLDOM.appendChild(page_metric);
|
nickjillings@1324
|
3247
|
nickjillings@1324
|
3248 // Add the audioelement
|
nickjillings@1324
|
3249 for (var element of this.specification.audioElements)
|
nickjillings@1324
|
3250 {
|
nickjillings@1324
|
3251 var aeNode = this.parent.document.createElement('audioelement');
|
nickjillings@1324
|
3252 aeNode.id = element.id;
|
nickjillings@1324
|
3253 aeNode.setAttribute('type',element.type);
|
nickjillings@1324
|
3254 aeNode.setAttribute('url', element.url);
|
nickjillings@1324
|
3255 aeNode.setAttribute('gain', element.gain);
|
nickjillings@1324
|
3256 if (element.type == 'anchor' || element.type == 'reference')
|
nickjillings@1324
|
3257 {
|
nickjillings@1324
|
3258 if (element.marker > 0)
|
nickjillings@1324
|
3259 {
|
nickjillings@1324
|
3260 aeNode.setAttribute('marker',element.marker);
|
nickjillings@1324
|
3261 }
|
nickjillings@1324
|
3262 }
|
nickjillings@1324
|
3263 var ae_metric = this.parent.document.createElement('metric');
|
nickjillings@1324
|
3264 aeNode.appendChild(ae_metric);
|
nickjillings@1324
|
3265 this.XMLDOM.appendChild(aeNode);
|
nickjillings@1324
|
3266 }
|
nickjillings@1324
|
3267
|
nickjillings@1324
|
3268 this.parent.root.appendChild(this.XMLDOM);
|
nickjillings@2149
|
3269
|
nickjillings@2149
|
3270 this.finish = function() {
|
nickjillings@2149
|
3271 this.parent.SessionKey.postData("waetresult",null,this.XMLDOM);
|
nickjillings@2149
|
3272 }
|
nickjillings@1324
|
3273 };
|
nickjillings@1324
|
3274 this.finish = function()
|
nickjillings@1324
|
3275 {
|
nickjillings@1324
|
3276 if (this.state == 0)
|
nickjillings@1324
|
3277 {
|
nickjillings@1324
|
3278 var projectDocument = specification.projectXML;
|
nickjillings@1324
|
3279 projectDocument.setAttribute('file-name',url);
|
nickjillings@1324
|
3280 this.root.appendChild(projectDocument);
|
nickjillings@1324
|
3281 this.root.appendChild(returnDateNode());
|
nickjillings@1324
|
3282 this.root.appendChild(interfaceContext.returnNavigator());
|
nickjillings@1324
|
3283 }
|
nickjillings@1324
|
3284 this.state = 1;
|
nickjillings@1324
|
3285 return this.root;
|
nickjillings@1324
|
3286 };
|
nickjillings@1324
|
3287 }
|