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