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