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