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