nickjillings@1682
|
1 /**
|
nickjillings@1682
|
2 * core.js
|
nickjillings@1682
|
3 *
|
nickjillings@1682
|
4 * Main script to run, calls all other core functions and manages loading/store to backend.
|
nickjillings@1682
|
5 * Also contains all global variables.
|
nickjillings@1682
|
6 */
|
nickjillings@1682
|
7
|
nickjillings@1682
|
8 /* create the web audio API context and store in audioContext*/
|
nickjillings@1643
|
9 var audioContext; // Hold the browser web audio API
|
nickjillings@1643
|
10 var projectXML; // Hold the parsed setup XML
|
nickjillings@1324
|
11 var schemaXSD; // Hold the parsed schema XSD
|
nickjillings@1581
|
12 var specification;
|
nickjillings@1582
|
13 var interfaceContext;
|
nickjillings@1324
|
14 var storage;
|
nickjillings@1622
|
15 var popup; // Hold the interfacePopup object
|
nickjillings@1634
|
16 var testState;
|
nickjillings@1655
|
17 var currentTrackOrder = []; // Hold the current XML tracks in their (randomised) order
|
nickjillings@1643
|
18 var audioEngineContext; // The custome AudioEngine object
|
nickjillings@1643
|
19 var projectReturn; // Hold the URL for the return
|
nickjillings@2013
|
20
|
nickjillings@1318
|
21
|
nickjillings@1318
|
22 // Add a prototype to the bufferSourceNode to reference to the audioObject holding it
|
nickjillings@1318
|
23 AudioBufferSourceNode.prototype.owner = undefined;
|
nickjillings@2101
|
24 // Add a prototype to the bufferSourceNode to hold when the object was given a play command
|
nickjillings@2101
|
25 AudioBufferSourceNode.prototype.playbackStartTime = undefined;
|
nickjillings@1318
|
26 // Add a prototype to the bufferNode to hold the desired LINEAR gain
|
nickjillings@1320
|
27 AudioBuffer.prototype.playbackGain = undefined;
|
nickjillings@1318
|
28 // Add a prototype to the bufferNode to hold the computed LUFS loudness
|
nickjillings@1318
|
29 AudioBuffer.prototype.lufs = undefined;
|
nickjillings@1318
|
30
|
nickjillings@1348
|
31 // Firefox does not have an XMLDocument.prototype.getElementsByName
|
nickjillings@1348
|
32 // and there is no searchAll style command, this custom function will
|
nickjillings@1348
|
33 // search all children recusrively for the name. Used for XSD where all
|
nickjillings@1348
|
34 // element nodes must have a name and therefore can pull the schema node
|
nickjillings@1348
|
35 XMLDocument.prototype.getAllElementsByName = function(name)
|
nickjillings@1348
|
36 {
|
nickjillings@1348
|
37 name = String(name);
|
nickjillings@1348
|
38 var selected = this.documentElement.getAllElementsByName(name);
|
nickjillings@1348
|
39 return selected;
|
nickjillings@1348
|
40 }
|
nickjillings@1348
|
41
|
nickjillings@1348
|
42 Element.prototype.getAllElementsByName = function(name)
|
nickjillings@1348
|
43 {
|
nickjillings@1348
|
44 name = String(name);
|
nickjillings@1348
|
45 var selected = [];
|
nickjillings@1348
|
46 var node = this.firstElementChild;
|
nickjillings@1348
|
47 while(node != null)
|
nickjillings@1348
|
48 {
|
nickjillings@1348
|
49 if (node.getAttribute('name') == name)
|
nickjillings@1348
|
50 {
|
nickjillings@1348
|
51 selected.push(node);
|
nickjillings@1348
|
52 }
|
nickjillings@1348
|
53 if (node.childElementCount > 0)
|
nickjillings@1348
|
54 {
|
nickjillings@1348
|
55 selected = selected.concat(node.getAllElementsByName(name));
|
nickjillings@1348
|
56 }
|
nickjillings@1348
|
57 node = node.nextElementSibling;
|
nickjillings@1348
|
58 }
|
nickjillings@1348
|
59 return selected;
|
nickjillings@1348
|
60 }
|
nickjillings@1348
|
61
|
nickjillings@1348
|
62 XMLDocument.prototype.getAllElementsByTagName = function(name)
|
nickjillings@1348
|
63 {
|
nickjillings@1348
|
64 name = String(name);
|
nickjillings@1348
|
65 var selected = this.documentElement.getAllElementsByTagName(name);
|
nickjillings@1348
|
66 return selected;
|
nickjillings@1348
|
67 }
|
nickjillings@1348
|
68
|
nickjillings@1348
|
69 Element.prototype.getAllElementsByTagName = function(name)
|
nickjillings@1348
|
70 {
|
nickjillings@1348
|
71 name = String(name);
|
nickjillings@1348
|
72 var selected = [];
|
nickjillings@1348
|
73 var node = this.firstElementChild;
|
nickjillings@1348
|
74 while(node != null)
|
nickjillings@1348
|
75 {
|
nickjillings@1348
|
76 if (node.nodeName == name)
|
nickjillings@1348
|
77 {
|
nickjillings@1348
|
78 selected.push(node);
|
nickjillings@1348
|
79 }
|
nickjillings@1348
|
80 if (node.childElementCount > 0)
|
nickjillings@1348
|
81 {
|
nickjillings@1348
|
82 selected = selected.concat(node.getAllElementsByTagName(name));
|
nickjillings@1348
|
83 }
|
nickjillings@1348
|
84 node = node.nextElementSibling;
|
nickjillings@1348
|
85 }
|
nickjillings@1348
|
86 return selected;
|
nickjillings@1348
|
87 }
|
nickjillings@1348
|
88
|
nickjillings@1348
|
89 // Firefox does not have an XMLDocument.prototype.getElementsByName
|
nickjillings@1348
|
90 if (typeof XMLDocument.prototype.getElementsByName != "function") {
|
nickjillings@1348
|
91 XMLDocument.prototype.getElementsByName = function(name)
|
nickjillings@1348
|
92 {
|
nickjillings@1348
|
93 name = String(name);
|
nickjillings@1348
|
94 var node = this.documentElement.firstElementChild;
|
nickjillings@1348
|
95 var selected = [];
|
nickjillings@1348
|
96 while(node != null)
|
nickjillings@1348
|
97 {
|
nickjillings@1348
|
98 if (node.getAttribute('name') == name)
|
nickjillings@1348
|
99 {
|
nickjillings@1348
|
100 selected.push(node);
|
nickjillings@1348
|
101 }
|
nickjillings@1348
|
102 node = node.nextElementSibling;
|
nickjillings@1348
|
103 }
|
nickjillings@1348
|
104 return selected;
|
nickjillings@1348
|
105 }
|
nickjillings@1348
|
106 }
|
nickjillings@1348
|
107
|
nickjillings@1682
|
108 window.onload = function() {
|
nickjillings@1682
|
109 // Function called once the browser has loaded all files.
|
nickjillings@1682
|
110 // This should perform any initial commands such as structure / loading documents
|
nickjillings@1682
|
111
|
nickjillings@1682
|
112 // Create a web audio API context
|
nickjillings@1701
|
113 // Fixed for cross-browser support
|
nickjillings@1701
|
114 var AudioContext = window.AudioContext || window.webkitAudioContext;
|
nickjillings@1688
|
115 audioContext = new AudioContext;
|
nickjillings@1682
|
116
|
nickjillings@1634
|
117 // Create test state
|
nickjillings@1634
|
118 testState = new stateMachine();
|
nickjillings@1634
|
119
|
nickjillings@1622
|
120 // Create the popup interface object
|
nickjillings@1622
|
121 popup = new interfacePopup();
|
nickjillings@1370
|
122
|
nickjillings@1370
|
123 // Create the specification object
|
nickjillings@1581
|
124 specification = new Specification();
|
nickjillings@1582
|
125
|
nickjillings@1582
|
126 // Create the interface object
|
nickjillings@1582
|
127 interfaceContext = new Interface(specification);
|
nickjillings@1324
|
128
|
nickjillings@1324
|
129 // Create the storage object
|
nickjillings@1324
|
130 storage = new Storage();
|
nickjillings@1410
|
131 // Define window callbacks for interface
|
nickjillings@1410
|
132 window.onresize = function(event){interfaceContext.resizeWindow(event);};
|
nickjillings@1697
|
133 };
|
nickjillings@1682
|
134
|
nickjillings@1408
|
135 function loadProjectSpec(url) {
|
nickjillings@1408
|
136 // Load the project document from the given URL, decode the XML and instruct audioEngine to get audio data
|
nickjillings@1408
|
137 // If url is null, request client to upload project XML document
|
nickjillings@1324
|
138 var xmlhttp = new XMLHttpRequest();
|
nickjillings@1324
|
139 xmlhttp.open("GET",'test-schema.xsd',true);
|
nickjillings@1324
|
140 xmlhttp.onload = function()
|
nickjillings@1324
|
141 {
|
nickjillings@1324
|
142 schemaXSD = xmlhttp.response;
|
nickjillings@1324
|
143 var parse = new DOMParser();
|
nickjillings@1324
|
144 specification.schema = parse.parseFromString(xmlhttp.response,'text/xml');
|
nickjillings@1324
|
145 var r = new XMLHttpRequest();
|
nickjillings@1324
|
146 r.open('GET',url,true);
|
nickjillings@1324
|
147 r.onload = function() {
|
nickjillings@1324
|
148 loadProjectSpecCallback(r.response);
|
nickjillings@1324
|
149 };
|
nickjillings@2110
|
150 r.onerror = function() {
|
nickjillings@2110
|
151 document.getElementsByTagName('body')[0].innerHTML = null;
|
nickjillings@2110
|
152 var msg = document.createElement("h3");
|
nickjillings@2110
|
153 msg.textContent = "FATAL ERROR";
|
nickjillings@2110
|
154 var span = document.createElement("p");
|
nickjillings@2110
|
155 span.textContent = "There was an error when loading your XML file. Please check your path in the URL. After the path to this page, there should be '?url=path/to/your/file.xml'. Check the spelling of your filename as well. If you are still having issues, check the log of the python server or your webserver distribution for 404 codes for your file.";
|
nickjillings@2110
|
156 document.getElementsByTagName('body')[0].appendChild(msg);
|
nickjillings@2110
|
157 document.getElementsByTagName('body')[0].appendChild(span);
|
nickjillings@2110
|
158 }
|
nickjillings@1324
|
159 r.send();
|
nickjillings@1408
|
160 };
|
nickjillings@1324
|
161 xmlhttp.send();
|
nickjillings@1408
|
162 };
|
nickjillings@1408
|
163
|
nickjillings@1408
|
164 function loadProjectSpecCallback(response) {
|
nickjillings@1408
|
165 // Function called after asynchronous download of XML project specification
|
nickjillings@1408
|
166 //var decode = $.parseXML(response);
|
nickjillings@1408
|
167 //projectXML = $(decode);
|
nickjillings@1408
|
168
|
nickjillings@2147
|
169 // Check if XML is new or a resumption
|
nickjillings@2147
|
170 var parse = new DOMParser();
|
nickjillings@2147
|
171 var responseDocument = parse.parseFromString(response,'text/xml');
|
nickjillings@2147
|
172 var errorNode = responseDocument.getElementsByTagName('parsererror');
|
nickjillings@1443
|
173 if (errorNode.length >= 1)
|
nickjillings@1443
|
174 {
|
nickjillings@1443
|
175 var msg = document.createElement("h3");
|
nickjillings@1443
|
176 msg.textContent = "FATAL ERROR";
|
nickjillings@1443
|
177 var span = document.createElement("span");
|
nickjillings@1443
|
178 span.textContent = "The XML parser returned the following errors when decoding your XML file";
|
nickjillings@1445
|
179 document.getElementsByTagName('body')[0].innerHTML = null;
|
nickjillings@1443
|
180 document.getElementsByTagName('body')[0].appendChild(msg);
|
nickjillings@1443
|
181 document.getElementsByTagName('body')[0].appendChild(span);
|
nickjillings@1443
|
182 document.getElementsByTagName('body')[0].appendChild(errorNode[0]);
|
nickjillings@1443
|
183 return;
|
nickjillings@1443
|
184 }
|
nickjillings@2169
|
185 if (responseDocument == undefined) {
|
nickjillings@2169
|
186 var msg = document.createElement("h3");
|
nickjillings@2169
|
187 msg.textContent = "FATAL ERROR";
|
nickjillings@2169
|
188 var span = document.createElement("span");
|
nickjillings@2169
|
189 span.textContent = "The project XML was not decoded properly, try refreshing your browser and clearing caches. If the problem persists, contact the test creator.";
|
nickjillings@2169
|
190 document.getElementsByTagName('body')[0].innerHTML = null;
|
nickjillings@2169
|
191 document.getElementsByTagName('body')[0].appendChild(msg);
|
nickjillings@2169
|
192 document.getElementsByTagName('body')[0].appendChild(span);
|
nickjillings@2169
|
193 return;
|
nickjillings@2169
|
194 }
|
nickjillings@2147
|
195 if (responseDocument.children[0].nodeName == "waet") {
|
nickjillings@2147
|
196 // document is a specification
|
nickjillings@2147
|
197
|
nickjillings@2147
|
198 // Perform XML schema validation
|
nickjillings@2147
|
199 var Module = {
|
nickjillings@2147
|
200 xml: response,
|
nickjillings@2147
|
201 schema: schemaXSD,
|
nickjillings@2147
|
202 arguments:["--noout", "--schema", 'test-schema.xsd','document.xml']
|
nickjillings@2147
|
203 };
|
nickjillings@2147
|
204 projectXML = responseDocument;
|
nickjillings@2147
|
205 var xmllint = validateXML(Module);
|
nickjillings@2147
|
206 console.log(xmllint);
|
nickjillings@2147
|
207 if(xmllint != 'document.xml validates\n')
|
nickjillings@2147
|
208 {
|
nickjillings@2147
|
209 document.getElementsByTagName('body')[0].innerHTML = null;
|
nickjillings@2147
|
210 var msg = document.createElement("h3");
|
nickjillings@2147
|
211 msg.textContent = "FATAL ERROR";
|
nickjillings@2147
|
212 var span = document.createElement("h4");
|
nickjillings@2147
|
213 span.textContent = "The XML validator returned the following errors when decoding your XML file";
|
nickjillings@2147
|
214 document.getElementsByTagName('body')[0].appendChild(msg);
|
nickjillings@2147
|
215 document.getElementsByTagName('body')[0].appendChild(span);
|
nickjillings@2147
|
216 xmllint = xmllint.split('\n');
|
nickjillings@2147
|
217 for (var i in xmllint)
|
nickjillings@2147
|
218 {
|
nickjillings@2147
|
219 document.getElementsByTagName('body')[0].appendChild(document.createElement('br'));
|
nickjillings@2147
|
220 var span = document.createElement("span");
|
nickjillings@2147
|
221 span.textContent = xmllint[i];
|
nickjillings@2147
|
222 document.getElementsByTagName('body')[0].appendChild(span);
|
nickjillings@2147
|
223 }
|
nickjillings@2147
|
224 return;
|
nickjillings@2147
|
225 }
|
nickjillings@2149
|
226 // Build the specification
|
nickjillings@2149
|
227 specification.decode(projectXML);
|
nickjillings@2147
|
228 // Generate the session-key
|
nickjillings@2147
|
229 storage.initialise();
|
nickjillings@2147
|
230
|
nickjillings@2147
|
231 } else if (responseDocument.children[0].nodeName == "waetresult") {
|
nickjillings@2147
|
232 // document is a result
|
nickjillings@1294
|
233 projectXML = document.implementation.createDocument(null,"waet");
|
nickjillings@1294
|
234 projectXML.children[0].appendChild(responseDocument.getElementsByTagName('waet')[0].getElementsByTagName("setup")[0].cloneNode(true));
|
nickjillings@1294
|
235 var child = responseDocument.children[0].children[0];
|
nickjillings@1294
|
236 while (child != null) {
|
nickjillings@1294
|
237 if (child.nodeName == "survey") {
|
nickjillings@1294
|
238 // One of the global survey elements
|
nickjillings@1294
|
239 if (child.getAttribute("state") == "complete") {
|
nickjillings@1294
|
240 // We need to remove this survey from <setup>
|
nickjillings@1294
|
241 var location = child.getAttribute("location");
|
nickjillings@1294
|
242 var globalSurveys = projectXML.getElementsByTagName("setup")[0].getElementsByTagName("survey")[0];
|
nickjillings@1294
|
243 while(globalSurveys != null) {
|
nickjillings@1294
|
244 if (location == "pre" || location == "before") {
|
nickjillings@1294
|
245 if (globalSurveys.getAttribute("location") == "pre" || globalSurveys.getAttribute("location") == "before") {
|
nickjillings@1294
|
246 projectXML.getElementsByTagName("setup")[0].removeChild(globalSurveys);
|
nickjillings@1294
|
247 break;
|
nickjillings@1294
|
248 }
|
nickjillings@1294
|
249 } else {
|
nickjillings@1294
|
250 if (globalSurveys.getAttribute("location") == "post" || globalSurveys.getAttribute("location") == "after") {
|
nickjillings@1294
|
251 projectXML.getElementsByTagName("setup")[0].removeChild(globalSurveys);
|
nickjillings@1294
|
252 break;
|
nickjillings@1294
|
253 }
|
nickjillings@1294
|
254 }
|
nickjillings@1294
|
255 globalSurveys = globalSurveys.nextElementSibling;
|
nickjillings@1294
|
256 }
|
nickjillings@1294
|
257 } else {
|
nickjillings@1294
|
258 // We need to complete this, so it must be regenerated by store
|
nickjillings@1294
|
259 var copy = child;
|
nickjillings@1294
|
260 child = child.previousElementSibling;
|
nickjillings@1294
|
261 responseDocument.children[0].removeChild(copy);
|
nickjillings@1294
|
262 }
|
nickjillings@1294
|
263 } else if (child.nodeName == "page") {
|
nickjillings@1294
|
264 if (child.getAttribute("state") == "empty") {
|
nickjillings@1294
|
265 // We need to complete this page
|
nickjillings@1294
|
266 projectXML.children[0].appendChild(responseDocument.getElementById(child.getAttribute("ref")).cloneNode(true));
|
nickjillings@1294
|
267 var copy = child;
|
nickjillings@1294
|
268 child = child.previousElementSibling;
|
nickjillings@1294
|
269 responseDocument.children[0].removeChild(copy);
|
nickjillings@1294
|
270 }
|
nickjillings@1294
|
271 }
|
nickjillings@1294
|
272 child = child.nextElementSibling;
|
nickjillings@1294
|
273 }
|
nickjillings@2149
|
274 // Build the specification
|
nickjillings@2149
|
275 specification.decode(projectXML);
|
nickjillings@1294
|
276 // Use the original
|
nickjillings@1294
|
277 storage.initialise(responseDocument);
|
nickjillings@2147
|
278 }
|
nickjillings@1339
|
279 /// CHECK FOR SAMPLE RATE COMPATIBILITY
|
nickjillings@1339
|
280 if (specification.sampleRate != undefined) {
|
nickjillings@1339
|
281 if (Number(specification.sampleRate) != audioContext.sampleRate) {
|
nickjillings@1339
|
282 var errStr = 'Sample rates do not match! Requested '+Number(specification.sampleRate)+', got '+audioContext.sampleRate+'. Please set the sample rate to match before completing this test.';
|
nickjillings@1339
|
283 alert(errStr);
|
nickjillings@1339
|
284 return;
|
nickjillings@1339
|
285 }
|
nickjillings@1339
|
286 }
|
nickjillings@1408
|
287
|
nickjillings@1408
|
288 // Detect the interface to use and load the relevant javascripts.
|
nickjillings@1408
|
289 var interfaceJS = document.createElement('script');
|
nickjillings@1408
|
290 interfaceJS.setAttribute("type","text/javascript");
|
nickjillings@1329
|
291 switch(specification.interface)
|
nickjillings@1329
|
292 {
|
nickjillings@1329
|
293 case "APE":
|
nickjillings@2161
|
294 interfaceJS.setAttribute("src","interfaces/ape.js");
|
nickjillings@2161
|
295
|
nickjillings@2161
|
296 // APE comes with a css file
|
nickjillings@2161
|
297 var css = document.createElement('link');
|
nickjillings@2161
|
298 css.rel = 'stylesheet';
|
nickjillings@2161
|
299 css.type = 'text/css';
|
nickjillings@2161
|
300 css.href = 'interfaces/ape.css';
|
nickjillings@2161
|
301
|
nickjillings@2161
|
302 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@2161
|
303 break;
|
nickjillings@2161
|
304
|
nickjillings@1329
|
305 case "MUSHRA":
|
nickjillings@2161
|
306 interfaceJS.setAttribute("src","interfaces/mushra.js");
|
nickjillings@2161
|
307
|
nickjillings@2161
|
308 // MUSHRA comes with a css file
|
nickjillings@2161
|
309 var css = document.createElement('link');
|
nickjillings@2161
|
310 css.rel = 'stylesheet';
|
nickjillings@2161
|
311 css.type = 'text/css';
|
nickjillings@2161
|
312 css.href = 'interfaces/mushra.css';
|
nickjillings@2161
|
313
|
nickjillings@2161
|
314 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@2161
|
315 break;
|
nickjillings@1329
|
316
|
nickjillings@1329
|
317 case "AB":
|
nickjillings@2161
|
318 interfaceJS.setAttribute("src","interfaces/AB.js");
|
nickjillings@2161
|
319
|
nickjillings@2161
|
320 // AB comes with a css file
|
nickjillings@2161
|
321 var css = document.createElement('link');
|
nickjillings@2161
|
322 css.rel = 'stylesheet';
|
nickjillings@2161
|
323 css.type = 'text/css';
|
nickjillings@2161
|
324 css.href = 'interfaces/AB.css';
|
nickjillings@2161
|
325
|
nickjillings@2161
|
326 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@2161
|
327 break;
|
nickjillings@2161
|
328
|
nickjillings@2161
|
329 case "ABX":
|
nickjillings@2161
|
330 interfaceJS.setAttribute("src","interfaces/ABX.js");
|
nickjillings@2161
|
331
|
nickjillings@2161
|
332 // AB comes with a css file
|
nickjillings@2161
|
333 var css = document.createElement('link');
|
nickjillings@2161
|
334 css.rel = 'stylesheet';
|
nickjillings@2161
|
335 css.type = 'text/css';
|
nickjillings@2161
|
336 css.href = 'interfaces/ABX.css';
|
nickjillings@2161
|
337
|
nickjillings@2161
|
338 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@2161
|
339 break;
|
nickjillings@2161
|
340
|
nickjillings@1345
|
341 case "Bipolar":
|
nickjillings@1345
|
342 case "ACR":
|
nickjillings@1345
|
343 case "DCR":
|
nickjillings@1345
|
344 case "CCR":
|
nickjillings@1343
|
345 case "ABC":
|
nickjillings@2161
|
346 // Above enumerate to horizontal sliders
|
nickjillings@2161
|
347 interfaceJS.setAttribute("src","interfaces/horizontal-sliders.js");
|
nickjillings@2161
|
348
|
nickjillings@2161
|
349 // horizontal-sliders comes with a css file
|
nickjillings@2161
|
350 var css = document.createElement('link');
|
nickjillings@2161
|
351 css.rel = 'stylesheet';
|
nickjillings@2161
|
352 css.type = 'text/css';
|
nickjillings@2161
|
353 css.href = 'interfaces/horizontal-sliders.css';
|
nickjillings@2161
|
354
|
nickjillings@2161
|
355 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@2161
|
356 break;
|
nickjillings@1345
|
357 case "discrete":
|
nickjillings@1345
|
358 case "likert":
|
nickjillings@2161
|
359 // Above enumerate to horizontal discrete radios
|
nickjillings@2161
|
360 interfaceJS.setAttribute("src","interfaces/discrete.js");
|
nickjillings@2161
|
361
|
nickjillings@2161
|
362 // horizontal-sliders comes with a css file
|
nickjillings@2161
|
363 var css = document.createElement('link');
|
nickjillings@2161
|
364 css.rel = 'stylesheet';
|
nickjillings@2161
|
365 css.type = 'text/css';
|
nickjillings@2161
|
366 css.href = 'interfaces/discrete.css';
|
nickjillings@2161
|
367
|
nickjillings@2161
|
368 document.getElementsByTagName("head")[0].appendChild(css);
|
nickjillings@2161
|
369 break;
|
nickjillings@1408
|
370 }
|
nickjillings@1408
|
371 document.getElementsByTagName("head")[0].appendChild(interfaceJS);
|
nickjillings@1408
|
372
|
nickjillings@1410
|
373 // Create the audio engine object
|
nickjillings@1410
|
374 audioEngineContext = new AudioEngine(specification);
|
nickjillings@1408
|
375 }
|
nickjillings@1408
|
376
|
nickjillings@1408
|
377 function createProjectSave(destURL) {
|
nickjillings@2167
|
378 // Clear the window.onbeforeunload
|
nickjillings@2167
|
379 window.onbeforeunload = null;
|
nickjillings@1408
|
380 // Save the data from interface into XML and send to destURL
|
nickjillings@1408
|
381 // If destURL is null then download XML in client
|
nickjillings@1408
|
382 // Now time to render file locally
|
nickjillings@1408
|
383 var xmlDoc = interfaceXMLSave();
|
nickjillings@1408
|
384 var parent = document.createElement("div");
|
nickjillings@1408
|
385 parent.appendChild(xmlDoc);
|
nickjillings@1408
|
386 var file = [parent.innerHTML];
|
nickjillings@2150
|
387 if (destURL == "local") {
|
nickjillings@1408
|
388 var bb = new Blob(file,{type : 'application/xml'});
|
nickjillings@1408
|
389 var dnlk = window.URL.createObjectURL(bb);
|
nickjillings@1408
|
390 var a = document.createElement("a");
|
nickjillings@1408
|
391 a.hidden = '';
|
nickjillings@1408
|
392 a.href = dnlk;
|
nickjillings@1408
|
393 a.download = "save.xml";
|
nickjillings@1408
|
394 a.textContent = "Save File";
|
nickjillings@1408
|
395
|
nickjillings@1408
|
396 popup.showPopup();
|
nickjillings@1332
|
397 popup.popupContent.innerHTML = "</span>Please save the file below to give to your test supervisor</span><br>";
|
nickjillings@1408
|
398 popup.popupContent.appendChild(a);
|
nickjillings@1408
|
399 } else {
|
nickjillings@1408
|
400 var xmlhttp = new XMLHttpRequest;
|
nickjillings@1293
|
401 xmlhttp.open("POST","\save.php?key="+storage.SessionKey.key,true);
|
nickjillings@1408
|
402 xmlhttp.setRequestHeader('Content-Type', 'text/xml');
|
nickjillings@1408
|
403 xmlhttp.onerror = function(){
|
nickjillings@1408
|
404 console.log('Error saving file to server! Presenting download locally');
|
nickjillings@1293
|
405 createProjectSave("local");
|
nickjillings@1408
|
406 };
|
nickjillings@2150
|
407 xmlhttp.onload = function() {
|
nickjillings@2150
|
408 console.log(xmlhttp);
|
nickjillings@2150
|
409 if (this.status >= 300) {
|
nickjillings@2150
|
410 console.log("WARNING - Could not update at this time");
|
nickjillings@1293
|
411 createProjectSave("local");
|
nickjillings@2150
|
412 } else {
|
nickjillings@2150
|
413 var parser = new DOMParser();
|
nickjillings@2150
|
414 var xmlDoc = parser.parseFromString(xmlhttp.responseText, "application/xml");
|
nickjillings@2150
|
415 var response = xmlDoc.getElementsByTagName('response')[0];
|
nickjillings@2150
|
416 if (response.getAttribute("state") == "OK") {
|
nickjillings@2150
|
417 var file = response.getElementsByTagName("file")[0];
|
nickjillings@2150
|
418 console.log("Save: OK, written "+file.getAttribute("bytes")+"B");
|
nickjillings@2155
|
419 popup.popupContent.textContent = "Thank you. Your session has been saved.";
|
nickjillings@2150
|
420 } else {
|
nickjillings@2150
|
421 var message = response.getElementsByTagName("message");
|
nickjillings@2150
|
422 console.log("Save: Error! "+message.textContent);
|
nickjillings@2150
|
423 createProjectSave("local");
|
nickjillings@2150
|
424 }
|
nickjillings@2150
|
425 }
|
nickjillings@2150
|
426 };
|
nickjillings@1408
|
427 xmlhttp.send(file);
|
nickjillings@1332
|
428 popup.showPopup();
|
nickjillings@1332
|
429 popup.popupContent.innerHTML = null;
|
nickjillings@1332
|
430 popup.popupContent.textContent = "Submitting. Please Wait";
|
nickjillings@2106
|
431 popup.hideNextButton();
|
nickjillings@2106
|
432 popup.hidePreviousButton();
|
nickjillings@1408
|
433 }
|
nickjillings@1408
|
434 }
|
nickjillings@1408
|
435
|
nickjillings@1408
|
436 function errorSessionDump(msg){
|
nickjillings@1408
|
437 // Create the partial interface XML save
|
nickjillings@1408
|
438 // Include error node with message on why the dump occured
|
nickjillings@1443
|
439 popup.showPopup();
|
nickjillings@1443
|
440 popup.popupContent.innerHTML = null;
|
nickjillings@1443
|
441 var err = document.createElement('error');
|
nickjillings@1443
|
442 var parent = document.createElement("div");
|
nickjillings@1443
|
443 if (typeof msg === "object")
|
nickjillings@1443
|
444 {
|
nickjillings@1443
|
445 err.appendChild(msg);
|
nickjillings@1443
|
446 popup.popupContent.appendChild(msg);
|
nickjillings@1443
|
447
|
nickjillings@1443
|
448 } else {
|
nickjillings@1443
|
449 err.textContent = msg;
|
nickjillings@1443
|
450 popup.popupContent.innerHTML = "ERROR : "+msg;
|
nickjillings@1443
|
451 }
|
nickjillings@1408
|
452 var xmlDoc = interfaceXMLSave();
|
nickjillings@1408
|
453 xmlDoc.appendChild(err);
|
nickjillings@1408
|
454 parent.appendChild(xmlDoc);
|
nickjillings@1408
|
455 var file = [parent.innerHTML];
|
nickjillings@1408
|
456 var bb = new Blob(file,{type : 'application/xml'});
|
nickjillings@1408
|
457 var dnlk = window.URL.createObjectURL(bb);
|
nickjillings@1408
|
458 var a = document.createElement("a");
|
nickjillings@1408
|
459 a.hidden = '';
|
nickjillings@1408
|
460 a.href = dnlk;
|
nickjillings@1408
|
461 a.download = "save.xml";
|
nickjillings@1408
|
462 a.textContent = "Save File";
|
nickjillings@1408
|
463
|
nickjillings@1443
|
464
|
nickjillings@1443
|
465
|
nickjillings@1408
|
466 popup.popupContent.appendChild(a);
|
nickjillings@1408
|
467 }
|
nickjillings@1408
|
468
|
nickjillings@1408
|
469 // Only other global function which must be defined in the interface class. Determines how to create the XML document.
|
nickjillings@1408
|
470 function interfaceXMLSave(){
|
nickjillings@1408
|
471 // Create the XML string to be exported with results
|
nickjillings@1324
|
472 return storage.finish();
|
nickjillings@1408
|
473 }
|
nickjillings@1408
|
474
|
nickjillings@1426
|
475 function linearToDecibel(gain)
|
nickjillings@1426
|
476 {
|
nickjillings@1426
|
477 return 20.0*Math.log10(gain);
|
nickjillings@1426
|
478 }
|
nickjillings@1426
|
479
|
nickjillings@1426
|
480 function decibelToLinear(gain)
|
nickjillings@1426
|
481 {
|
nickjillings@1426
|
482 return Math.pow(10,gain/20.0);
|
nickjillings@1426
|
483 }
|
nickjillings@1426
|
484
|
nickjillings@2147
|
485 function randomString(length) {
|
nickjillings@2147
|
486 return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1);
|
nickjillings@2147
|
487 }
|
nickjillings@2147
|
488
|
nickjillings@1622
|
489 function interfacePopup() {
|
nickjillings@1622
|
490 // Creates an object to manage the popup
|
nickjillings@1622
|
491 this.popup = null;
|
nickjillings@1622
|
492 this.popupContent = null;
|
nickjillings@1526
|
493 this.popupTitle = null;
|
nickjillings@1526
|
494 this.popupResponse = null;
|
nickjillings@1574
|
495 this.buttonProceed = null;
|
nickjillings@2034
|
496 this.buttonPrevious = null;
|
nickjillings@1622
|
497 this.popupOptions = null;
|
nickjillings@1622
|
498 this.currentIndex = null;
|
nickjillings@1324
|
499 this.node = null;
|
nickjillings@1324
|
500 this.store = null;
|
nickjillings@1422
|
501 $(window).keypress(function(e){
|
nickjillings@1422
|
502 if (e.keyCode == 13 && popup.popup.style.visibility == 'visible')
|
nickjillings@1422
|
503 {
|
nickjillings@1422
|
504 console.log(e);
|
nickjillings@1422
|
505 popup.buttonProceed.onclick();
|
nickjillings@1424
|
506 e.preventDefault();
|
nickjillings@1422
|
507 }
|
nickjillings@1422
|
508 });
|
nickjillings@1581
|
509
|
nickjillings@1622
|
510 this.createPopup = function(){
|
nickjillings@1622
|
511 // Create popup window interface
|
nickjillings@1622
|
512 var insertPoint = document.getElementById("topLevelBody");
|
nickjillings@1622
|
513
|
nickjillings@1379
|
514 this.popup = document.getElementById('popupHolder');
|
nickjillings@1622
|
515 this.popup.style.left = (window.innerWidth/2)-250 + 'px';
|
nickjillings@1622
|
516 this.popup.style.top = (window.innerHeight/2)-125 + 'px';
|
nickjillings@1622
|
517
|
nickjillings@1379
|
518 this.popupContent = document.getElementById('popupContent');
|
nickjillings@1622
|
519
|
nickjillings@1379
|
520 this.popupTitle = document.getElementById('popupTitle');
|
nickjillings@1526
|
521
|
nickjillings@1379
|
522 this.popupResponse = document.getElementById('popupResponse');
|
nickjillings@1526
|
523
|
nickjillings@1379
|
524 this.buttonProceed = document.getElementById('popup-proceed');
|
nickjillings@1574
|
525 this.buttonProceed.onclick = function(){popup.proceedClicked();};
|
nickjillings@2034
|
526
|
nickjillings@1379
|
527 this.buttonPrevious = document.getElementById('popup-previous');
|
nickjillings@2034
|
528 this.buttonPrevious.onclick = function(){popup.previousClick();};
|
nickjillings@2034
|
529
|
nickjillings@1379
|
530 this.hidePopup();
|
nickjillings@1379
|
531
|
nickjillings@1581
|
532 this.popup.style.zIndex = -1;
|
nickjillings@1581
|
533 this.popup.style.visibility = 'hidden';
|
nickjillings@1622
|
534 };
|
nickjillings@1621
|
535
|
nickjillings@1622
|
536 this.showPopup = function(){
|
nickjillings@1581
|
537 if (this.popup == null) {
|
nickjillings@1622
|
538 this.createPopup();
|
nickjillings@1622
|
539 }
|
nickjillings@1622
|
540 this.popup.style.zIndex = 3;
|
nickjillings@1622
|
541 this.popup.style.visibility = 'visible';
|
nickjillings@1622
|
542 var blank = document.getElementsByClassName('testHalt')[0];
|
nickjillings@1622
|
543 blank.style.zIndex = 2;
|
nickjillings@1622
|
544 blank.style.visibility = 'visible';
|
nickjillings@1622
|
545 };
|
nickjillings@1622
|
546
|
nickjillings@1622
|
547 this.hidePopup = function(){
|
nickjillings@1622
|
548 this.popup.style.zIndex = -1;
|
nickjillings@1622
|
549 this.popup.style.visibility = 'hidden';
|
nickjillings@1622
|
550 var blank = document.getElementsByClassName('testHalt')[0];
|
nickjillings@1622
|
551 blank.style.zIndex = -2;
|
nickjillings@1622
|
552 blank.style.visibility = 'hidden';
|
nickjillings@1526
|
553 this.buttonPrevious.style.visibility = 'inherit';
|
nickjillings@1622
|
554 };
|
nickjillings@1622
|
555
|
nickjillings@1622
|
556 this.postNode = function() {
|
nickjillings@1622
|
557 // This will take the node from the popupOptions and display it
|
nickjillings@1622
|
558 var node = this.popupOptions[this.currentIndex];
|
nickjillings@1526
|
559 this.popupResponse.innerHTML = null;
|
nickjillings@1324
|
560 this.popupTitle.textContent = node.specification.statement;
|
nickjillings@1324
|
561 if (node.specification.type == 'question') {
|
nickjillings@1622
|
562 var textArea = document.createElement('textarea');
|
nickjillings@1324
|
563 switch (node.specification.boxsize) {
|
nickjillings@2030
|
564 case 'small':
|
nickjillings@2030
|
565 textArea.cols = "20";
|
nickjillings@2030
|
566 textArea.rows = "1";
|
nickjillings@2030
|
567 break;
|
nickjillings@2030
|
568 case 'normal':
|
nickjillings@2030
|
569 textArea.cols = "30";
|
nickjillings@2030
|
570 textArea.rows = "2";
|
nickjillings@2030
|
571 break;
|
nickjillings@2030
|
572 case 'large':
|
nickjillings@2030
|
573 textArea.cols = "40";
|
nickjillings@2030
|
574 textArea.rows = "5";
|
nickjillings@2030
|
575 break;
|
nickjillings@2030
|
576 case 'huge':
|
nickjillings@2030
|
577 textArea.cols = "50";
|
nickjillings@2030
|
578 textArea.rows = "10";
|
nickjillings@2030
|
579 break;
|
nickjillings@2030
|
580 }
|
nickjillings@1361
|
581 if (node.response == undefined) {
|
nickjillings@1361
|
582 node.response = "";
|
nickjillings@1361
|
583 } else {
|
nickjillings@1361
|
584 textArea.value = node.response;
|
nickjillings@1361
|
585 }
|
nickjillings@1526
|
586 this.popupResponse.appendChild(textArea);
|
nickjillings@1526
|
587 textArea.focus();
|
nickjillings@1382
|
588 this.popupResponse.style.textAlign="center";
|
nickjillings@1382
|
589 this.popupResponse.style.left="0%";
|
nickjillings@1324
|
590 } else if (node.specification.type == 'checkbox') {
|
nickjillings@1361
|
591 if (node.response == undefined) {
|
nickjillings@1361
|
592 node.response = Array(node.specification.options.length);
|
nickjillings@1361
|
593 }
|
nickjillings@1361
|
594 var index = 0;
|
nickjillings@1382
|
595 var max_w = 0;
|
nickjillings@1324
|
596 for (var option of node.specification.options) {
|
nickjillings@1588
|
597 var input = document.createElement('input');
|
nickjillings@2093
|
598 input.id = option.name;
|
nickjillings@1588
|
599 input.type = 'checkbox';
|
nickjillings@1588
|
600 var span = document.createElement('span');
|
nickjillings@1588
|
601 span.textContent = option.text;
|
nickjillings@1588
|
602 var hold = document.createElement('div');
|
nickjillings@1588
|
603 hold.setAttribute('name','option');
|
nickjillings@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@1318
|
1779
|
nickjillings@2165
|
1780 this.processAttribute = function(attribute,schema,schemaRoot)
|
nickjillings@1406
|
1781 {
|
nickjillings@1324
|
1782 // attribute is the string returned from getAttribute on the XML
|
nickjillings@1324
|
1783 // schema is the <xs:attribute> node
|
nickjillings@1324
|
1784 if (schema.getAttribute('name') == undefined && schema.getAttribute('ref') != undefined)
|
nickjillings@1406
|
1785 {
|
nickjillings@2165
|
1786 schema = schemaRoot.getAllElementsByName(schema.getAttribute('ref'))[0];
|
nickjillings@1324
|
1787 }
|
nickjillings@1324
|
1788 var defaultOpt = schema.getAttribute('default');
|
nickjillings@1324
|
1789 if (attribute == null) {
|
nickjillings@1324
|
1790 attribute = defaultOpt;
|
nickjillings@1324
|
1791 }
|
nickjillings@1324
|
1792 var dataType = schema.getAttribute('type');
|
nickjillings@1324
|
1793 if (typeof dataType == "string") { dataType = dataType.substr(3);}
|
nickjillings@1324
|
1794 else {dataType = "string";}
|
nickjillings@1324
|
1795 if (attribute == null)
|
nickjillings@1324
|
1796 {
|
nickjillings@1324
|
1797 return attribute;
|
nickjillings@1324
|
1798 }
|
nickjillings@1324
|
1799 switch(dataType)
|
nickjillings@1324
|
1800 {
|
nickjillings@1324
|
1801 case "boolean":
|
nickjillings@1324
|
1802 if (attribute == 'true'){attribute = true;}else{attribute=false;}
|
nickjillings@1324
|
1803 break;
|
nickjillings@1324
|
1804 case "negativeInteger":
|
nickjillings@1324
|
1805 case "positiveInteger":
|
nickjillings@1324
|
1806 case "nonNegativeInteger":
|
nickjillings@1324
|
1807 case "nonPositiveInteger":
|
nickjillings@1324
|
1808 case "integer":
|
nickjillings@1324
|
1809 case "decimal":
|
nickjillings@1324
|
1810 case "short":
|
nickjillings@1324
|
1811 attribute = Number(attribute);
|
nickjillings@1324
|
1812 break;
|
nickjillings@1324
|
1813 case "string":
|
nickjillings@1324
|
1814 default:
|
nickjillings@1324
|
1815 attribute = String(attribute);
|
nickjillings@1324
|
1816 break;
|
nickjillings@1324
|
1817 }
|
nickjillings@1324
|
1818 return attribute;
|
nickjillings@1406
|
1819 };
|
nickjillings@1411
|
1820
|
nickjillings@1406
|
1821 this.decode = function(projectXML) {
|
nickjillings@1324
|
1822 this.errors = [];
|
nickjillings@1580
|
1823 // projectXML - DOM Parsed document
|
nickjillings@2052
|
1824 this.projectXML = projectXML.childNodes[0];
|
nickjillings@1580
|
1825 var setupNode = projectXML.getElementsByTagName('setup')[0];
|
nickjillings@1348
|
1826 var schemaSetup = this.schema.getAllElementsByName('setup')[0];
|
nickjillings@1324
|
1827 // First decode the attributes
|
nickjillings@1348
|
1828 var attributes = schemaSetup.getAllElementsByTagName('xs:attribute');
|
nickjillings@1324
|
1829 for (var i in attributes)
|
nickjillings@1520
|
1830 {
|
nickjillings@1324
|
1831 if (isNaN(Number(i)) == true){break;}
|
nickjillings@2165
|
1832 var attributeName = attributes[i].getAttribute('name') || attributes[i].getAttribute('ref');
|
nickjillings@1324
|
1833 var projectAttr = setupNode.getAttribute(attributeName);
|
nickjillings@2165
|
1834 projectAttr = this.processAttribute(projectAttr,attributes[i],this.schema);
|
nickjillings@1324
|
1835 switch(typeof projectAttr)
|
nickjillings@1432
|
1836 {
|
nickjillings@1324
|
1837 case "number":
|
nickjillings@1324
|
1838 case "boolean":
|
nickjillings@1324
|
1839 eval('this.'+attributeName+' = '+projectAttr);
|
nickjillings@1324
|
1840 break;
|
nickjillings@1324
|
1841 case "string":
|
nickjillings@1324
|
1842 eval('this.'+attributeName+' = "'+projectAttr+'"');
|
nickjillings@1324
|
1843 break;
|
nickjillings@1432
|
1844 }
|
nickjillings@1324
|
1845
|
nickjillings@1406
|
1846 }
|
nickjillings@1406
|
1847
|
nickjillings@1370
|
1848 this.metrics = new this.metricNode();
|
nickjillings@1580
|
1849
|
nickjillings@1324
|
1850 this.metrics.decode(this,setupNode.getElementsByTagName('metric')[0]);
|
nickjillings@1324
|
1851
|
nickjillings@1324
|
1852 // Now process the survey node options
|
nickjillings@1324
|
1853 var survey = setupNode.getElementsByTagName('survey');
|
nickjillings@1324
|
1854 for (var i in survey) {
|
nickjillings@1324
|
1855 if (isNaN(Number(i)) == true){break;}
|
nickjillings@1324
|
1856 var location = survey[i].getAttribute('location');
|
nickjillings@1324
|
1857 if (location == 'pre' || location == 'before')
|
nickjillings@1324
|
1858 {
|
nickjillings@1324
|
1859 if (this.preTest != null){this.errors.push("Already a pre/before test survey defined! Ignoring second!!");}
|
nickjillings@1324
|
1860 else {
|
nickjillings@1324
|
1861 this.preTest = new this.surveyNode();
|
nickjillings@1370
|
1862 this.preTest.decode(this,survey[i]);
|
nickjillings@1324
|
1863 }
|
nickjillings@1324
|
1864 } else if (location == 'post' || location == 'after') {
|
nickjillings@1324
|
1865 if (this.postTest != null){this.errors.push("Already a post/after test survey defined! Ignoring second!!");}
|
nickjillings@1324
|
1866 else {
|
nickjillings@1324
|
1867 this.postTest = new this.surveyNode();
|
nickjillings@1370
|
1868 this.postTest.decode(this,survey[i]);
|
nickjillings@1324
|
1869 }
|
nickjillings@1580
|
1870 }
|
nickjillings@1580
|
1871 }
|
nickjillings@1580
|
1872
|
nickjillings@1324
|
1873 var interfaceNode = setupNode.getElementsByTagName('interface');
|
nickjillings@1324
|
1874 if (interfaceNode.length > 1)
|
nickjillings@1324
|
1875 {
|
nickjillings@1324
|
1876 this.errors.push("Only one <interface> node in the <setup> node allowed! Others except first ingnored!");
|
nickjillings@1324
|
1877 }
|
nickjillings@1324
|
1878 this.interfaces = new this.interfaceNode();
|
nickjillings@1324
|
1879 if (interfaceNode.length != 0)
|
nickjillings@1324
|
1880 {
|
nickjillings@1324
|
1881 interfaceNode = interfaceNode[0];
|
nickjillings@1348
|
1882 this.interfaces.decode(this,interfaceNode,this.schema.getAllElementsByName('interface')[1]);
|
nickjillings@1556
|
1883 }
|
nickjillings@1556
|
1884
|
nickjillings@1324
|
1885 // Page tags
|
nickjillings@1324
|
1886 var pageTags = projectXML.getElementsByTagName('page');
|
nickjillings@1348
|
1887 var pageSchema = this.schema.getAllElementsByName('page')[0];
|
nickjillings@1324
|
1888 for (var i=0; i<pageTags.length; i++)
|
nickjillings@1520
|
1889 {
|
nickjillings@1324
|
1890 var node = new this.page();
|
nickjillings@1324
|
1891 node.decode(this,pageTags[i],pageSchema);
|
nickjillings@1324
|
1892 this.pages.push(node);
|
nickjillings@1520
|
1893 }
|
nickjillings@1580
|
1894 };
|
nickjillings@1580
|
1895
|
nickjillings@1406
|
1896 this.encode = function()
|
nickjillings@1406
|
1897 {
|
nickjillings@1372
|
1898 var RootDocument = document.implementation.createDocument(null,"waet");
|
nickjillings@1372
|
1899 var root = RootDocument.children[0];
|
nickjillings@1372
|
1900 root.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
|
nickjillings@1372
|
1901 root.setAttribute("xsi:noNamespaceSchemaLocation","test-schema.xsd");
|
nickjillings@1324
|
1902 // Build setup node
|
nickjillings@1372
|
1903 var setup = RootDocument.createElement("setup");
|
nickjillings@1372
|
1904 var schemaSetup = this.schema.getAllElementsByName('setup')[0];
|
nickjillings@1372
|
1905 // First decode the attributes
|
nickjillings@1372
|
1906 var attributes = schemaSetup.getAllElementsByTagName('xs:attribute');
|
nickjillings@1372
|
1907 for (var i=0; i<attributes.length; i++)
|
nickjillings@1372
|
1908 {
|
nickjillings@1372
|
1909 var name = attributes[i].getAttribute("name");
|
nickjillings@1372
|
1910 if (name == undefined) {
|
nickjillings@1372
|
1911 name = attributes[i].getAttribute("ref");
|
nickjillings@1372
|
1912 }
|
nickjillings@1372
|
1913 if(eval("this."+name+" != undefined") || attributes[i].getAttribute("use") == "required")
|
nickjillings@1372
|
1914 {
|
nickjillings@1372
|
1915 eval("setup.setAttribute('"+name+"',this."+name+")");
|
nickjillings@1372
|
1916 }
|
nickjillings@1372
|
1917 }
|
nickjillings@1372
|
1918 root.appendChild(setup);
|
nickjillings@1372
|
1919 // Survey node
|
nickjillings@1372
|
1920 setup.appendChild(this.preTest.encode(RootDocument));
|
nickjillings@1372
|
1921 setup.appendChild(this.postTest.encode(RootDocument));
|
nickjillings@1372
|
1922 setup.appendChild(this.metrics.encode(RootDocument));
|
nickjillings@1372
|
1923 setup.appendChild(this.interfaces.encode(RootDocument));
|
nickjillings@1372
|
1924 for (var page of this.pages)
|
nickjillings@1372
|
1925 {
|
nickjillings@1372
|
1926 root.appendChild(page.encode(RootDocument));
|
nickjillings@1372
|
1927 }
|
nickjillings@1372
|
1928 return RootDocument;
|
nickjillings@1406
|
1929 };
|
nickjillings@1406
|
1930
|
nickjillings@1324
|
1931 this.surveyNode = function() {
|
nickjillings@1324
|
1932 this.location = null;
|
nickjillings@1580
|
1933 this.options = [];
|
nickjillings@2165
|
1934 this.parent = null;
|
nickjillings@1370
|
1935 this.schema = specification.schema.getAllElementsByName('survey')[0];
|
nickjillings@1580
|
1936
|
nickjillings@1406
|
1937 this.OptionNode = function() {
|
nickjillings@1406
|
1938 this.type = undefined;
|
nickjillings@1370
|
1939 this.schema = specification.schema.getAllElementsByName('surveyentry')[0];
|
nickjillings@1406
|
1940 this.id = undefined;
|
nickjillings@2156
|
1941 this.name = undefined;
|
nickjillings@1406
|
1942 this.mandatory = undefined;
|
nickjillings@1406
|
1943 this.statement = undefined;
|
nickjillings@1406
|
1944 this.boxsize = undefined;
|
nickjillings@1406
|
1945 this.options = [];
|
nickjillings@1406
|
1946 this.min = undefined;
|
nickjillings@1406
|
1947 this.max = undefined;
|
nickjillings@1406
|
1948 this.step = undefined;
|
nickjillings@1406
|
1949
|
nickjillings@1370
|
1950 this.decode = function(parent,child)
|
nickjillings@1406
|
1951 {
|
nickjillings@1370
|
1952 var attributeMap = this.schema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1324
|
1953 for (var i in attributeMap){
|
nickjillings@1324
|
1954 if(isNaN(Number(i)) == true){break;}
|
nickjillings@1324
|
1955 var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref');
|
nickjillings@1324
|
1956 var projectAttr = child.getAttribute(attributeName);
|
nickjillings@2165
|
1957 projectAttr = parent.processAttribute(projectAttr,attributeMap[i],parent.schema);
|
nickjillings@1324
|
1958 switch(typeof projectAttr)
|
nickjillings@1324
|
1959 {
|
nickjillings@1324
|
1960 case "number":
|
nickjillings@1324
|
1961 case "boolean":
|
nickjillings@1324
|
1962 eval('this.'+attributeName+' = '+projectAttr);
|
nickjillings@1324
|
1963 break;
|
nickjillings@1324
|
1964 case "string":
|
nickjillings@1324
|
1965 eval('this.'+attributeName+' = "'+projectAttr+'"');
|
nickjillings@1324
|
1966 break;
|
nickjillings@1406
|
1967 }
|
nickjillings@1324
|
1968 }
|
nickjillings@1324
|
1969 this.statement = child.getElementsByTagName('statement')[0].textContent;
|
nickjillings@1324
|
1970 if (this.type == "checkbox" || this.type == "radio") {
|
nickjillings@1324
|
1971 var children = child.getElementsByTagName('option');
|
nickjillings@1324
|
1972 if (children.length == null) {
|
nickjillings@1406
|
1973 console.log('Malformed' +child.nodeName+ 'entry');
|
nickjillings@1406
|
1974 this.statement = 'Malformed' +child.nodeName+ 'entry';
|
nickjillings@1406
|
1975 this.type = 'statement';
|
nickjillings@1406
|
1976 } else {
|
nickjillings@1406
|
1977 this.options = [];
|
nickjillings@1324
|
1978 for (var i in children)
|
nickjillings@1324
|
1979 {
|
nickjillings@1324
|
1980 if (isNaN(Number(i))==true){break;}
|
nickjillings@1324
|
1981 this.options.push({
|
nickjillings@1324
|
1982 name: children[i].getAttribute('name'),
|
nickjillings@1324
|
1983 text: children[i].textContent
|
nickjillings@1324
|
1984 });
|
nickjillings@1406
|
1985 }
|
nickjillings@1406
|
1986 }
|
nickjillings@2030
|
1987 }
|
nickjillings@1406
|
1988 };
|
nickjillings@1406
|
1989
|
nickjillings@1372
|
1990 this.exportXML = function(doc)
|
nickjillings@1406
|
1991 {
|
nickjillings@2111
|
1992 var node = doc.createElement('surveyentry');
|
nickjillings@1324
|
1993 node.setAttribute('type',this.type);
|
nickjillings@1372
|
1994 var statement = doc.createElement('statement');
|
nickjillings@1324
|
1995 statement.textContent = this.statement;
|
nickjillings@1324
|
1996 node.appendChild(statement);
|
nickjillings@2162
|
1997 node.id = this.id;
|
nickjillings@2162
|
1998 if (this.name != undefined) { node.setAttribute("name",this.name);}
|
nickjillings@2162
|
1999 if (this.mandatory != undefined) { node.setAttribute("mandatory",this.mandatory);}
|
nickjillings@2162
|
2000 node.id = this.id;
|
nickjillings@2162
|
2001 if (this.name != undefined) {node.setAttribute("name",this.name);}
|
nickjillings@2162
|
2002 switch(this.type)
|
nickjillings@2162
|
2003 {
|
nickjillings@2156
|
2004 case "checkbox":
|
nickjillings@2156
|
2005 case "radio":
|
nickjillings@2156
|
2006 for (var i=0; i<this.options.length; i++)
|
nickjillings@2156
|
2007 {
|
nickjillings@2156
|
2008 var option = this.options[i];
|
nickjillings@2156
|
2009 var optionNode = doc.createElement("option");
|
nickjillings@2156
|
2010 optionNode.setAttribute("name",option.name);
|
nickjillings@2156
|
2011 optionNode.textContent = option.text;
|
nickjillings@2156
|
2012 node.appendChild(optionNode);
|
nickjillings@2156
|
2013 }
|
nickjillings@2162
|
2014 case "number":
|
nickjillings@2162
|
2015 if (this.min != undefined) {node.setAttribute("min", this.min);}
|
nickjillings@2162
|
2016 if (this.max != undefined) {node.setAttribute("max", this.max);}
|
nickjillings@2162
|
2017 case "question":
|
nickjillings@2162
|
2018 if (this.boxsize != undefined) {node.setAttribute("boxsize",this.boxsize);}
|
nickjillings@2162
|
2019 if (this.mandatory != undefined) {node.setAttribute("mandatory",this.mandatory);}
|
nickjillings@2162
|
2020 default:
|
nickjillings@2156
|
2021 break;
|
nickjillings@2156
|
2022 }
|
nickjillings@1406
|
2023 return node;
|
nickjillings@1406
|
2024 };
|
nickjillings@1406
|
2025 };
|
nickjillings@1370
|
2026 this.decode = function(parent,xml) {
|
nickjillings@2165
|
2027 this.parent = parent;
|
nickjillings@1324
|
2028 this.location = xml.getAttribute('location');
|
nickjillings@1324
|
2029 if (this.location == 'before'){this.location = 'pre';}
|
nickjillings@1324
|
2030 else if (this.location == 'after'){this.location = 'post';}
|
nickjillings@1324
|
2031 for (var i in xml.children)
|
nickjillings@1324
|
2032 {
|
nickjillings@1324
|
2033 if(isNaN(Number(i))==true){break;}
|
nickjillings@1406
|
2034 var node = new this.OptionNode();
|
nickjillings@1370
|
2035 node.decode(parent,xml.children[i]);
|
nickjillings@1406
|
2036 this.options.push(node);
|
nickjillings@1324
|
2037 }
|
nickjillings@1324
|
2038 };
|
nickjillings@1372
|
2039 this.encode = function(doc) {
|
nickjillings@1372
|
2040 var node = doc.createElement('survey');
|
nickjillings@1324
|
2041 node.setAttribute('location',this.location);
|
nickjillings@1324
|
2042 for (var i=0; i<this.options.length; i++)
|
nickjillings@1324
|
2043 {
|
nickjillings@1372
|
2044 node.appendChild(this.options[i].exportXML(doc));
|
nickjillings@1324
|
2045 }
|
nickjillings@1324
|
2046 return node;
|
nickjillings@1324
|
2047 };
|
nickjillings@1324
|
2048 };
|
nickjillings@1324
|
2049
|
nickjillings@1324
|
2050 this.interfaceNode = function()
|
nickjillings@1324
|
2051 {
|
nickjillings@1324
|
2052 this.title = null;
|
nickjillings@1324
|
2053 this.name = null;
|
nickjillings@1324
|
2054 this.options = [];
|
nickjillings@1324
|
2055 this.scales = [];
|
nickjillings@1370
|
2056 this.schema = specification.schema.getAllElementsByName('interface')[1];
|
nickjillings@1324
|
2057
|
nickjillings@1370
|
2058 this.decode = function(parent,xml) {
|
nickjillings@1324
|
2059 this.name = xml.getAttribute('name');
|
nickjillings@1324
|
2060 var titleNode = xml.getElementsByTagName('title');
|
nickjillings@1324
|
2061 if (titleNode.length == 1)
|
nickjillings@1324
|
2062 {
|
nickjillings@1324
|
2063 this.title = titleNode[0].textContent;
|
nickjillings@1324
|
2064 }
|
nickjillings@1324
|
2065 var interfaceOptionNodes = xml.getElementsByTagName('interfaceoption');
|
nickjillings@1324
|
2066 // Extract interfaceoption node schema
|
nickjillings@1370
|
2067 var interfaceOptionNodeSchema = this.schema.getAllElementsByName('interfaceoption')[0];
|
nickjillings@1348
|
2068 var attributeMap = interfaceOptionNodeSchema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1324
|
2069 for (var i=0; i<interfaceOptionNodes.length; i++)
|
nickjillings@1324
|
2070 {
|
nickjillings@1324
|
2071 var ioNode = interfaceOptionNodes[i];
|
nickjillings@1324
|
2072 var option = {};
|
nickjillings@1324
|
2073 for (var j=0; j<attributeMap.length; j++)
|
nickjillings@1324
|
2074 {
|
nickjillings@1324
|
2075 var attributeName = attributeMap[j].getAttribute('name') || attributeMap[j].getAttribute('ref');
|
nickjillings@1324
|
2076 var projectAttr = ioNode.getAttribute(attributeName);
|
nickjillings@2165
|
2077 if(parent.processAttribute) {
|
nickjillings@2165
|
2078 parent.processAttribute(projectAttr, attributeMap[j], parent.schema)
|
nickjillings@2165
|
2079 } else {
|
nickjillings@2165
|
2080 parent.parent.processAttribute(projectAttr, attributeMap[j], parent.parent.schema)
|
nickjillings@2165
|
2081 }
|
nickjillings@1324
|
2082 switch(typeof projectAttr)
|
nickjillings@1324
|
2083 {
|
nickjillings@1324
|
2084 case "number":
|
nickjillings@1324
|
2085 case "boolean":
|
nickjillings@1324
|
2086 eval('option.'+attributeName+' = '+projectAttr);
|
nickjillings@1324
|
2087 break;
|
nickjillings@1324
|
2088 case "string":
|
nickjillings@1324
|
2089 eval('option.'+attributeName+' = "'+projectAttr+'"');
|
nickjillings@1324
|
2090 break;
|
nickjillings@1324
|
2091 }
|
nickjillings@1324
|
2092 }
|
nickjillings@1324
|
2093 this.options.push(option);
|
nickjillings@1324
|
2094 }
|
nickjillings@1324
|
2095
|
nickjillings@1324
|
2096 // Now the scales nodes
|
nickjillings@1324
|
2097 var scaleParent = xml.getElementsByTagName('scales');
|
nickjillings@1324
|
2098 if (scaleParent.length == 1) {
|
nickjillings@1324
|
2099 scaleParent = scaleParent[0];
|
nickjillings@1324
|
2100 for (var i=0; i<scaleParent.children.length; i++) {
|
nickjillings@1324
|
2101 var child = scaleParent.children[i];
|
nickjillings@1324
|
2102 this.scales.push({
|
nickjillings@1324
|
2103 text: child.textContent,
|
nickjillings@1324
|
2104 position: Number(child.getAttribute('position'))
|
nickjillings@1324
|
2105 });
|
nickjillings@1406
|
2106 }
|
nickjillings@1580
|
2107 }
|
nickjillings@1580
|
2108 };
|
nickjillings@1324
|
2109
|
nickjillings@1372
|
2110 this.encode = function(doc) {
|
nickjillings@1372
|
2111 var node = doc.createElement("interface");
|
nickjillings@1372
|
2112 if (typeof name == "string")
|
nickjillings@1372
|
2113 node.setAttribute("name",this.name);
|
nickjillings@1372
|
2114 for (var option of this.options)
|
nickjillings@1372
|
2115 {
|
nickjillings@1372
|
2116 var child = doc.createElement("interfaceoption");
|
nickjillings@1372
|
2117 child.setAttribute("type",option.type);
|
nickjillings@1372
|
2118 child.setAttribute("name",option.name);
|
nickjillings@1372
|
2119 node.appendChild(child);
|
nickjillings@1372
|
2120 }
|
nickjillings@1372
|
2121 if (this.scales.length != 0) {
|
nickjillings@1372
|
2122 var scales = doc.createElement("scales");
|
nickjillings@1372
|
2123 for (var scale of this.scales)
|
nickjillings@1372
|
2124 {
|
nickjillings@1372
|
2125 var child = doc.createElement("scalelabel");
|
nickjillings@1372
|
2126 child.setAttribute("position",scale.position);
|
nickjillings@1372
|
2127 child.textContent = scale.text;
|
nickjillings@1372
|
2128 scales.appendChild(child);
|
nickjillings@1372
|
2129 }
|
nickjillings@1372
|
2130 node.appendChild(scales);
|
nickjillings@1372
|
2131 }
|
nickjillings@1372
|
2132 return node;
|
nickjillings@1324
|
2133 };
|
nickjillings@1580
|
2134 };
|
nickjillings@1580
|
2135
|
nickjillings@1370
|
2136 this.metricNode = function() {
|
nickjillings@1370
|
2137 this.enabled = [];
|
nickjillings@1370
|
2138 this.decode = function(parent, xml) {
|
nickjillings@1370
|
2139 var children = xml.getElementsByTagName('metricenable');
|
nickjillings@1370
|
2140 for (var i in children) {
|
nickjillings@1370
|
2141 if (isNaN(Number(i)) == true){break;}
|
nickjillings@1370
|
2142 this.enabled.push(children[i].textContent);
|
nickjillings@1370
|
2143 }
|
nickjillings@1370
|
2144 }
|
nickjillings@1372
|
2145 this.encode = function(doc) {
|
nickjillings@1372
|
2146 var node = doc.createElement('metric');
|
nickjillings@1370
|
2147 for (var i in this.enabled)
|
nickjillings@1370
|
2148 {
|
nickjillings@1370
|
2149 if (isNaN(Number(i)) == true){break;}
|
nickjillings@1372
|
2150 var child = doc.createElement('metricenable');
|
nickjillings@1370
|
2151 child.textContent = this.enabled[i];
|
nickjillings@1370
|
2152 node.appendChild(child);
|
nickjillings@1370
|
2153 }
|
nickjillings@1370
|
2154 return node;
|
nickjillings@1370
|
2155 }
|
nickjillings@1370
|
2156 }
|
nickjillings@1370
|
2157
|
nickjillings@1324
|
2158 this.page = function() {
|
nickjillings@1406
|
2159 this.presentedId = undefined;
|
nickjillings@1406
|
2160 this.id = undefined;
|
nickjillings@1406
|
2161 this.hostURL = undefined;
|
nickjillings@1406
|
2162 this.randomiseOrder = undefined;
|
nickjillings@1406
|
2163 this.loop = undefined;
|
nickjillings@1324
|
2164 this.showElementComments = undefined;
|
nickjillings@1406
|
2165 this.outsideReference = null;
|
nickjillings@1432
|
2166 this.loudness = null;
|
nickjillings@1295
|
2167 this.label = null;
|
nickjillings@1324
|
2168 this.preTest = null;
|
nickjillings@1324
|
2169 this.postTest = null;
|
nickjillings@1406
|
2170 this.interfaces = [];
|
nickjillings@1406
|
2171 this.commentBoxPrefix = "Comment on track";
|
nickjillings@1406
|
2172 this.audioElements = [];
|
nickjillings@1406
|
2173 this.commentQuestions = [];
|
nickjillings@1370
|
2174 this.schema = specification.schema.getAllElementsByName("page")[0];
|
nickjillings@2165
|
2175 this.parent = null;
|
nickjillings@1406
|
2176
|
nickjillings@1406
|
2177 this.decode = function(parent,xml)
|
nickjillings@1406
|
2178 {
|
nickjillings@2165
|
2179 this.parent = parent;
|
nickjillings@1348
|
2180 var attributeMap = this.schema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1324
|
2181 for (var i=0; i<attributeMap.length; i++)
|
nickjillings@1432
|
2182 {
|
nickjillings@1324
|
2183 var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref');
|
nickjillings@1324
|
2184 var projectAttr = xml.getAttribute(attributeName);
|
nickjillings@2165
|
2185 projectAttr = parent.processAttribute(projectAttr,attributeMap[i],parent.schema);
|
nickjillings@1324
|
2186 switch(typeof projectAttr)
|
nickjillings@1395
|
2187 {
|
nickjillings@1324
|
2188 case "number":
|
nickjillings@1324
|
2189 case "boolean":
|
nickjillings@1324
|
2190 eval('this.'+attributeName+' = '+projectAttr);
|
nickjillings@1324
|
2191 break;
|
nickjillings@1324
|
2192 case "string":
|
nickjillings@1324
|
2193 eval('this.'+attributeName+' = "'+projectAttr+'"');
|
nickjillings@1324
|
2194 break;
|
nickjillings@1406
|
2195 }
|
nickjillings@1406
|
2196 }
|
nickjillings@1406
|
2197
|
nickjillings@1324
|
2198 // Get the Comment Box Prefix
|
nickjillings@1324
|
2199 var CBP = xml.getElementsByTagName('commentboxprefix');
|
nickjillings@1324
|
2200 if (CBP.length != 0) {
|
nickjillings@1324
|
2201 this.commentBoxPrefix = CBP[0].textContent;
|
nickjillings@1441
|
2202 }
|
nickjillings@1441
|
2203
|
nickjillings@1324
|
2204 // Now decode the interfaces
|
nickjillings@1324
|
2205 var interfaceNode = xml.getElementsByTagName('interface');
|
nickjillings@1324
|
2206 for (var i=0; i<interfaceNode.length; i++)
|
nickjillings@1324
|
2207 {
|
nickjillings@1324
|
2208 var node = new parent.interfaceNode();
|
nickjillings@1348
|
2209 node.decode(this,interfaceNode[i],parent.schema.getAllElementsByName('interface')[1]);
|
nickjillings@1324
|
2210 this.interfaces.push(node);
|
nickjillings@1324
|
2211 }
|
nickjillings@1411
|
2212
|
nickjillings@1324
|
2213 // Now process the survey node options
|
nickjillings@1324
|
2214 var survey = xml.getElementsByTagName('survey');
|
nickjillings@1348
|
2215 var surveySchema = parent.schema.getAllElementsByName('survey')[0];
|
nickjillings@1324
|
2216 for (var i in survey) {
|
nickjillings@1324
|
2217 if (isNaN(Number(i)) == true){break;}
|
nickjillings@1324
|
2218 var location = survey[i].getAttribute('location');
|
nickjillings@1324
|
2219 if (location == 'pre' || location == 'before')
|
nickjillings@1324
|
2220 {
|
nickjillings@1324
|
2221 if (this.preTest != null){this.errors.push("Already a pre/before test survey defined! Ignoring second!!");}
|
nickjillings@1324
|
2222 else {
|
nickjillings@1324
|
2223 this.preTest = new parent.surveyNode();
|
nickjillings@1324
|
2224 this.preTest.decode(parent,survey[i],surveySchema);
|
nickjillings@1324
|
2225 }
|
nickjillings@1324
|
2226 } else if (location == 'post' || location == 'after') {
|
nickjillings@1324
|
2227 if (this.postTest != null){this.errors.push("Already a post/after test survey defined! Ignoring second!!");}
|
nickjillings@1324
|
2228 else {
|
nickjillings@1324
|
2229 this.postTest = new parent.surveyNode();
|
nickjillings@1324
|
2230 this.postTest.decode(parent,survey[i],surveySchema);
|
nickjillings@1324
|
2231 }
|
nickjillings@1324
|
2232 }
|
nickjillings@1324
|
2233 }
|
nickjillings@1324
|
2234
|
nickjillings@1324
|
2235 // Now process the audioelement tags
|
nickjillings@1324
|
2236 var audioElements = xml.getElementsByTagName('audioelement');
|
nickjillings@1324
|
2237 for (var i=0; i<audioElements.length; i++)
|
nickjillings@1324
|
2238 {
|
nickjillings@1324
|
2239 var node = new this.audioElementNode();
|
nickjillings@1370
|
2240 node.decode(this,audioElements[i]);
|
nickjillings@1324
|
2241 this.audioElements.push(node);
|
nickjillings@1324
|
2242 }
|
nickjillings@1324
|
2243
|
nickjillings@1324
|
2244 // Now decode the commentquestions
|
nickjillings@1324
|
2245 var commentQuestions = xml.getElementsByTagName('commentquestion');
|
nickjillings@1324
|
2246 for (var i=0; i<commentQuestions.length; i++)
|
nickjillings@1324
|
2247 {
|
nickjillings@1406
|
2248 var node = new this.commentQuestionNode();
|
nickjillings@1370
|
2249 node.decode(parent,commentQuestions[i]);
|
nickjillings@1406
|
2250 this.commentQuestions.push(node);
|
nickjillings@1580
|
2251 }
|
nickjillings@1580
|
2252 };
|
nickjillings@1580
|
2253
|
nickjillings@1406
|
2254 this.encode = function(root)
|
nickjillings@1406
|
2255 {
|
nickjillings@1372
|
2256 var AHNode = root.createElement("page");
|
nickjillings@1372
|
2257 // First decode the attributes
|
nickjillings@1372
|
2258 var attributes = this.schema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1372
|
2259 for (var i=0; i<attributes.length; i++)
|
nickjillings@1372
|
2260 {
|
nickjillings@1372
|
2261 var name = attributes[i].getAttribute("name");
|
nickjillings@1372
|
2262 if (name == undefined) {
|
nickjillings@1372
|
2263 name = attributes[i].getAttribute("ref");
|
nickjillings@1372
|
2264 }
|
nickjillings@1372
|
2265 if(eval("this."+name+" != undefined") || attributes[i].getAttribute("use") == "required")
|
nickjillings@1372
|
2266 {
|
nickjillings@1372
|
2267 eval("AHNode.setAttribute('"+name+"',this."+name+")");
|
nickjillings@1372
|
2268 }
|
nickjillings@1372
|
2269 }
|
nickjillings@1432
|
2270 if(this.loudness != null) {AHNode.setAttribute("loudness",this.loudness);}
|
nickjillings@1372
|
2271 // <commentboxprefix>
|
nickjillings@1372
|
2272 var commentboxprefix = root.createElement("commentboxprefix");
|
nickjillings@1372
|
2273 commentboxprefix.textContent = this.commentBoxPrefix;
|
nickjillings@1372
|
2274 AHNode.appendChild(commentboxprefix);
|
nickjillings@1372
|
2275
|
nickjillings@1406
|
2276 for (var i=0; i<this.interfaces.length; i++)
|
nickjillings@1404
|
2277 {
|
nickjillings@1406
|
2278 AHNode.appendChild(this.interfaces[i].encode(root));
|
nickjillings@1406
|
2279 }
|
nickjillings@1558
|
2280
|
nickjillings@1406
|
2281 for (var i=0; i<this.audioElements.length; i++) {
|
nickjillings@1406
|
2282 AHNode.appendChild(this.audioElements[i].encode(root));
|
nickjillings@1406
|
2283 }
|
nickjillings@1406
|
2284 // Create <CommentQuestion>
|
nickjillings@1406
|
2285 for (var i=0; i<this.commentQuestions.length; i++)
|
nickjillings@1455
|
2286 {
|
nickjillings@1372
|
2287 AHNode.appendChild(this.commentQuestions[i].encode(root));
|
nickjillings@1406
|
2288 }
|
nickjillings@1406
|
2289
|
nickjillings@1372
|
2290 AHNode.appendChild(this.preTest.encode(root));
|
nickjillings@1372
|
2291 AHNode.appendChild(this.postTest.encode(root));
|
nickjillings@1406
|
2292 return AHNode;
|
nickjillings@1406
|
2293 };
|
nickjillings@1406
|
2294
|
nickjillings@1324
|
2295 this.commentQuestionNode = function() {
|
nickjillings@1324
|
2296 this.id = null;
|
nickjillings@2156
|
2297 this.name = undefined;
|
nickjillings@1324
|
2298 this.type = undefined;
|
nickjillings@1406
|
2299 this.options = [];
|
nickjillings@1324
|
2300 this.statement = undefined;
|
nickjillings@1370
|
2301 this.schema = specification.schema.getAllElementsByName('commentquestion')[0];
|
nickjillings@1370
|
2302 this.decode = function(parent,xml)
|
nickjillings@1406
|
2303 {
|
nickjillings@1324
|
2304 this.id = xml.id;
|
nickjillings@2156
|
2305 this.name = xml.getAttribute('name');
|
nickjillings@1324
|
2306 this.type = xml.getAttribute('type');
|
nickjillings@1324
|
2307 this.statement = xml.getElementsByTagName('statement')[0].textContent;
|
nickjillings@1324
|
2308 var optNodes = xml.getElementsByTagName('option');
|
nickjillings@1324
|
2309 for (var i=0; i<optNodes.length; i++)
|
nickjillings@1324
|
2310 {
|
nickjillings@1324
|
2311 var optNode = optNodes[i];
|
nickjillings@1324
|
2312 this.options.push({
|
nickjillings@1324
|
2313 name: optNode.getAttribute('name'),
|
nickjillings@1324
|
2314 text: optNode.textContent
|
nickjillings@1324
|
2315 });
|
nickjillings@1406
|
2316 }
|
nickjillings@1406
|
2317 };
|
nickjillings@1324
|
2318
|
nickjillings@1406
|
2319 this.encode = function(root)
|
nickjillings@1406
|
2320 {
|
nickjillings@1372
|
2321 var node = root.createElement("commentquestion");
|
nickjillings@1372
|
2322 node.id = this.id;
|
nickjillings@1372
|
2323 node.setAttribute("type",this.type);
|
nickjillings@2156
|
2324 if (this.name != undefined){node.setAttribute("name",this.name);}
|
nickjillings@1372
|
2325 var statement = root.createElement("statement");
|
nickjillings@1372
|
2326 statement.textContent = this.statement;
|
nickjillings@1372
|
2327 node.appendChild(statement);
|
nickjillings@1372
|
2328 for (var option of this.options)
|
nickjillings@1372
|
2329 {
|
nickjillings@1372
|
2330 var child = root.createElement("option");
|
nickjillings@1372
|
2331 child.setAttribute("name",option.name);
|
nickjillings@1372
|
2332 child.textContent = option.text;
|
nickjillings@1372
|
2333 node.appendChild(child);
|
nickjillings@1372
|
2334 }
|
nickjillings@1372
|
2335 return node;
|
nickjillings@1406
|
2336 };
|
nickjillings@1406
|
2337 };
|
nickjillings@1406
|
2338
|
nickjillings@1406
|
2339 this.audioElementNode = function() {
|
nickjillings@1406
|
2340 this.url = null;
|
nickjillings@1406
|
2341 this.id = null;
|
nickjillings@2156
|
2342 this.name = null;
|
nickjillings@1406
|
2343 this.parent = null;
|
nickjillings@1324
|
2344 this.type = null;
|
nickjillings@1310
|
2345 this.marker = null;
|
nickjillings@1406
|
2346 this.enforce = false;
|
nickjillings@2130
|
2347 this.gain = 0.0;
|
nickjillings@1370
|
2348 this.schema = specification.schema.getAllElementsByName('audioelement')[0];;
|
nickjillings@1324
|
2349 this.parent = null;
|
nickjillings@1406
|
2350 this.decode = function(parent,xml)
|
nickjillings@1406
|
2351 {
|
nickjillings@1406
|
2352 this.parent = parent;
|
nickjillings@1348
|
2353 var attributeMap = this.schema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1324
|
2354 for (var i=0; i<attributeMap.length; i++)
|
nickjillings@1426
|
2355 {
|
nickjillings@1324
|
2356 var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref');
|
nickjillings@1324
|
2357 var projectAttr = xml.getAttribute(attributeName);
|
nickjillings@2165
|
2358 projectAttr = parent.parent.processAttribute(projectAttr,attributeMap[i],parent.parent.schema);
|
nickjillings@1324
|
2359 switch(typeof projectAttr)
|
nickjillings@1406
|
2360 {
|
nickjillings@1324
|
2361 case "number":
|
nickjillings@1324
|
2362 case "boolean":
|
nickjillings@1324
|
2363 eval('this.'+attributeName+' = '+projectAttr);
|
nickjillings@1324
|
2364 break;
|
nickjillings@1324
|
2365 case "string":
|
nickjillings@1324
|
2366 eval('this.'+attributeName+' = "'+projectAttr+'"');
|
nickjillings@1324
|
2367 break;
|
nickjillings@1455
|
2368 }
|
nickjillings@1455
|
2369 }
|
nickjillings@1324
|
2370
|
nickjillings@1406
|
2371 };
|
nickjillings@1406
|
2372 this.encode = function(root)
|
nickjillings@1406
|
2373 {
|
nickjillings@1372
|
2374 var AENode = root.createElement("audioelement");
|
nickjillings@1372
|
2375 var attributes = this.schema.getAllElementsByTagName('xs:attribute');
|
nickjillings@1372
|
2376 for (var i=0; i<attributes.length; i++)
|
nickjillings@1372
|
2377 {
|
nickjillings@1372
|
2378 var name = attributes[i].getAttribute("name");
|
nickjillings@1372
|
2379 if (name == undefined) {
|
nickjillings@1372
|
2380 name = attributes[i].getAttribute("ref");
|
nickjillings@1372
|
2381 }
|
nickjillings@1372
|
2382 if(eval("this."+name+" != undefined") || attributes[i].getAttribute("use") == "required")
|
nickjillings@1372
|
2383 {
|
nickjillings@1372
|
2384 eval("AENode.setAttribute('"+name+"',this."+name+")");
|
nickjillings@1372
|
2385 }
|
nickjillings@1372
|
2386 }
|
nickjillings@1406
|
2387 return AENode;
|
nickjillings@1406
|
2388 };
|
nickjillings@1580
|
2389 };
|
nickjillings@1580
|
2390 };
|
nickjillings@1580
|
2391 }
|
nickjillings@1406
|
2392
|
nickjillings@1582
|
2393 function Interface(specificationObject) {
|
nickjillings@1580
|
2394 // This handles the bindings between the interface and the audioEngineContext;
|
nickjillings@1582
|
2395 this.specification = specificationObject;
|
nickjillings@1582
|
2396 this.insertPoint = document.getElementById("topLevelBody");
|
nickjillings@1580
|
2397
|
nickjillings@1324
|
2398 this.newPage = function(audioHolderObject,store)
|
nickjillings@1407
|
2399 {
|
nickjillings@1369
|
2400 audioEngineContext.newTestPage(audioHolderObject,store);
|
nickjillings@2117
|
2401 interfaceContext.commentBoxes.deleteCommentBoxes();
|
nickjillings@1407
|
2402 interfaceContext.deleteCommentQuestions();
|
nickjillings@1324
|
2403 loadTest(audioHolderObject,store);
|
nickjillings@1407
|
2404 };
|
nickjillings@1407
|
2405
|
nickjillings@1582
|
2406 // Bounded by interface!!
|
nickjillings@1582
|
2407 // Interface object MUST have an exportXMLDOM method which returns the various DOM levels
|
nickjillings@1582
|
2408 // For example, APE returns the slider position normalised in a <value> tag.
|
nickjillings@1582
|
2409 this.interfaceObjects = [];
|
nickjillings@1582
|
2410 this.interfaceObject = function(){};
|
nickjillings@1582
|
2411
|
nickjillings@1525
|
2412 this.resizeWindow = function(event)
|
nickjillings@1525
|
2413 {
|
nickjillings@1421
|
2414 popup.resize(event);
|
nickjillings@1525
|
2415 for(var i=0; i<this.commentBoxes.length; i++)
|
nickjillings@1525
|
2416 {this.commentBoxes[i].resize();}
|
nickjillings@1525
|
2417 for(var i=0; i<this.commentQuestions.length; i++)
|
nickjillings@1525
|
2418 {this.commentQuestions[i].resize();}
|
nickjillings@1525
|
2419 try
|
nickjillings@1525
|
2420 {
|
nickjillings@1525
|
2421 resizeWindow(event);
|
nickjillings@1525
|
2422 }
|
nickjillings@1525
|
2423 catch(err)
|
nickjillings@1525
|
2424 {
|
nickjillings@1525
|
2425 console.log("Warning - Interface does not have Resize option");
|
nickjillings@1525
|
2426 console.log(err);
|
nickjillings@1525
|
2427 }
|
nickjillings@1525
|
2428 };
|
nickjillings@1525
|
2429
|
nickjillings@1465
|
2430 this.returnNavigator = function()
|
nickjillings@1465
|
2431 {
|
nickjillings@1362
|
2432 var node = storage.document.createElement("navigator");
|
nickjillings@1362
|
2433 var platform = storage.document.createElement("platform");
|
nickjillings@1465
|
2434 platform.textContent = navigator.platform;
|
nickjillings@1362
|
2435 var vendor = storage.document.createElement("vendor");
|
nickjillings@1465
|
2436 vendor.textContent = navigator.vendor;
|
nickjillings@1362
|
2437 var userAgent = storage.document.createElement("uagent");
|
nickjillings@1465
|
2438 userAgent.textContent = navigator.userAgent;
|
nickjillings@1362
|
2439 var screen = storage.document.createElement("window");
|
nickjillings@1362
|
2440 screen.setAttribute('innerWidth',window.innerWidth);
|
nickjillings@1362
|
2441 screen.setAttribute('innerHeight',window.innerHeight);
|
nickjillings@1465
|
2442 node.appendChild(platform);
|
nickjillings@1465
|
2443 node.appendChild(vendor);
|
nickjillings@1465
|
2444 node.appendChild(userAgent);
|
nickjillings@1362
|
2445 node.appendChild(screen);
|
nickjillings@1465
|
2446 return node;
|
nickjillings@1465
|
2447 };
|
nickjillings@2170
|
2448
|
nickjillings@2170
|
2449 this.returnDateNode = function()
|
nickjillings@2170
|
2450 {
|
nickjillings@2170
|
2451 // Create an XML Node for the Date and Time a test was conducted
|
nickjillings@2170
|
2452 // Structure is
|
nickjillings@2170
|
2453 // <datetime>
|
nickjillings@2170
|
2454 // <date year="##" month="##" day="##">DD/MM/YY</date>
|
nickjillings@2170
|
2455 // <time hour="##" minute="##" sec="##">HH:MM:SS</time>
|
nickjillings@2170
|
2456 // </datetime>
|
nickjillings@2170
|
2457 var dateTime = new Date();
|
nickjillings@2170
|
2458 var hold = storage.document.createElement("datetime");
|
nickjillings@2170
|
2459 var date = storage.document.createElement("date");
|
nickjillings@2170
|
2460 var time = storage.document.createElement("time");
|
nickjillings@2170
|
2461 date.setAttribute('year',dateTime.getFullYear());
|
nickjillings@2170
|
2462 date.setAttribute('month',dateTime.getMonth()+1);
|
nickjillings@2170
|
2463 date.setAttribute('day',dateTime.getDate());
|
nickjillings@2170
|
2464 time.setAttribute('hour',dateTime.getHours());
|
nickjillings@2175
|
2465 time.setAttribute('minute',dateTime.getMinutes());
|
nickjillings@2170
|
2466 time.setAttribute('secs',dateTime.getSeconds());
|
nickjillings@2170
|
2467
|
nickjillings@2170
|
2468 hold.appendChild(date);
|
nickjillings@2170
|
2469 hold.appendChild(time);
|
nickjillings@2170
|
2470 return hold;
|
nickjillings@2170
|
2471
|
nickjillings@2170
|
2472 }
|
nickjillings@1465
|
2473
|
nickjillings@2117
|
2474 this.commentBoxes = new function() {
|
nickjillings@2117
|
2475 this.boxes = [];
|
nickjillings@2117
|
2476 this.injectPoint = null;
|
nickjillings@2117
|
2477 this.elementCommentBox = function(audioObject) {
|
nickjillings@2117
|
2478 var element = audioObject.specification;
|
nickjillings@2117
|
2479 this.audioObject = audioObject;
|
nickjillings@2117
|
2480 this.id = audioObject.id;
|
nickjillings@2117
|
2481 var audioHolderObject = audioObject.specification.parent;
|
nickjillings@2117
|
2482 // Create document objects to hold the comment boxes
|
nickjillings@2117
|
2483 this.trackComment = document.createElement('div');
|
nickjillings@2117
|
2484 this.trackComment.className = 'comment-div';
|
nickjillings@2117
|
2485 this.trackComment.id = 'comment-div-'+audioObject.id;
|
nickjillings@2117
|
2486 // Create a string next to each comment asking for a comment
|
nickjillings@2117
|
2487 this.trackString = document.createElement('span');
|
nickjillings@2117
|
2488 this.trackString.innerHTML = audioHolderObject.commentBoxPrefix+' '+audioObject.interfaceDOM.getPresentedId();
|
nickjillings@2117
|
2489 // Create the HTML5 comment box 'textarea'
|
nickjillings@2117
|
2490 this.trackCommentBox = document.createElement('textarea');
|
nickjillings@2117
|
2491 this.trackCommentBox.rows = '4';
|
nickjillings@2117
|
2492 this.trackCommentBox.cols = '100';
|
nickjillings@2117
|
2493 this.trackCommentBox.name = 'trackComment'+audioObject.id;
|
nickjillings@2117
|
2494 this.trackCommentBox.className = 'trackComment';
|
nickjillings@2117
|
2495 var br = document.createElement('br');
|
nickjillings@2117
|
2496 // Add to the holder.
|
nickjillings@2117
|
2497 this.trackComment.appendChild(this.trackString);
|
nickjillings@2117
|
2498 this.trackComment.appendChild(br);
|
nickjillings@2117
|
2499 this.trackComment.appendChild(this.trackCommentBox);
|
nickjillings@2117
|
2500
|
nickjillings@2117
|
2501 this.exportXMLDOM = function() {
|
nickjillings@2117
|
2502 var root = document.createElement('comment');
|
nickjillings@2117
|
2503 var question = document.createElement('question');
|
nickjillings@2117
|
2504 question.textContent = this.trackString.textContent;
|
nickjillings@2117
|
2505 var response = document.createElement('response');
|
nickjillings@2117
|
2506 response.textContent = this.trackCommentBox.value;
|
nickjillings@2117
|
2507 console.log("Comment frag-"+this.id+": "+response.textContent);
|
nickjillings@2117
|
2508 root.appendChild(question);
|
nickjillings@2117
|
2509 root.appendChild(response);
|
nickjillings@2117
|
2510 return root;
|
nickjillings@2117
|
2511 };
|
nickjillings@2117
|
2512 this.resize = function()
|
nickjillings@2117
|
2513 {
|
nickjillings@2117
|
2514 var boxwidth = (window.innerWidth-100)/2;
|
nickjillings@2117
|
2515 if (boxwidth >= 600)
|
nickjillings@2117
|
2516 {
|
nickjillings@2117
|
2517 boxwidth = 600;
|
nickjillings@2117
|
2518 }
|
nickjillings@2117
|
2519 else if (boxwidth < 400)
|
nickjillings@2117
|
2520 {
|
nickjillings@2117
|
2521 boxwidth = 400;
|
nickjillings@2117
|
2522 }
|
nickjillings@2117
|
2523 this.trackComment.style.width = boxwidth+"px";
|
nickjillings@2117
|
2524 this.trackCommentBox.style.width = boxwidth-6+"px";
|
nickjillings@2117
|
2525 };
|
nickjillings@2117
|
2526 this.resize();
|
nickjillings@2117
|
2527 };
|
nickjillings@2117
|
2528 this.createCommentBox = function(audioObject) {
|
nickjillings@2117
|
2529 var node = new this.elementCommentBox(audioObject);
|
nickjillings@2117
|
2530 this.boxes.push(node);
|
nickjillings@2117
|
2531 audioObject.commentDOM = node;
|
nickjillings@2117
|
2532 return node;
|
nickjillings@2117
|
2533 };
|
nickjillings@2117
|
2534 this.sortCommentBoxes = function() {
|
nickjillings@2117
|
2535 this.boxes.sort(function(a,b){return a.id - b.id;});
|
nickjillings@2117
|
2536 };
|
nickjillings@2117
|
2537
|
nickjillings@2117
|
2538 this.showCommentBoxes = function(inject, sort) {
|
nickjillings@2117
|
2539 this.injectPoint = inject;
|
nickjillings@2117
|
2540 if (sort) {this.sortCommentBoxes();}
|
nickjillings@2117
|
2541 for (var box of this.boxes) {
|
nickjillings@2117
|
2542 inject.appendChild(box.trackComment);
|
nickjillings@2117
|
2543 }
|
nickjillings@2117
|
2544 };
|
nickjillings@2117
|
2545
|
nickjillings@2117
|
2546 this.deleteCommentBoxes = function() {
|
nickjillings@2117
|
2547 if (this.injectPoint != null) {
|
nickjillings@2117
|
2548 for (var box of this.boxes) {
|
nickjillings@2117
|
2549 this.injectPoint.removeChild(box.trackComment);
|
nickjillings@2117
|
2550 }
|
nickjillings@2117
|
2551 this.injectPoint = null;
|
nickjillings@2117
|
2552 }
|
nickjillings@2117
|
2553 this.boxes = [];
|
nickjillings@2117
|
2554 };
|
nickjillings@2117
|
2555 }
|
nickjillings@1582
|
2556
|
nickjillings@2032
|
2557 this.commentQuestions = [];
|
nickjillings@2032
|
2558
|
nickjillings@2032
|
2559 this.commentBox = function(commentQuestion) {
|
nickjillings@2032
|
2560 this.specification = commentQuestion;
|
nickjillings@2032
|
2561 // Create document objects to hold the comment boxes
|
nickjillings@2032
|
2562 this.holder = document.createElement('div');
|
nickjillings@2032
|
2563 this.holder.className = 'comment-div';
|
nickjillings@2032
|
2564 // Create a string next to each comment asking for a comment
|
nickjillings@2032
|
2565 this.string = document.createElement('span');
|
nickjillings@1324
|
2566 this.string.innerHTML = commentQuestion.statement;
|
nickjillings@2032
|
2567 // Create the HTML5 comment box 'textarea'
|
nickjillings@2032
|
2568 this.textArea = document.createElement('textarea');
|
nickjillings@2032
|
2569 this.textArea.rows = '4';
|
nickjillings@2032
|
2570 this.textArea.cols = '100';
|
nickjillings@2032
|
2571 this.textArea.className = 'trackComment';
|
nickjillings@2032
|
2572 var br = document.createElement('br');
|
nickjillings@2032
|
2573 // Add to the holder.
|
nickjillings@2032
|
2574 this.holder.appendChild(this.string);
|
nickjillings@2032
|
2575 this.holder.appendChild(br);
|
nickjillings@2032
|
2576 this.holder.appendChild(this.textArea);
|
nickjillings@2032
|
2577
|
nickjillings@2097
|
2578 this.exportXMLDOM = function(storePoint) {
|
nickjillings@2097
|
2579 var root = storePoint.parent.document.createElement('comment');
|
nickjillings@2032
|
2580 root.id = this.specification.id;
|
nickjillings@2032
|
2581 root.setAttribute('type',this.specification.type);
|
b@2059
|
2582 console.log("Question: "+this.string.textContent);
|
b@2059
|
2583 console.log("Response: "+root.textContent);
|
nickjillings@2097
|
2584 var question = storePoint.parent.document.createElement('question');
|
nickjillings@2097
|
2585 question.textContent = this.string.textContent;
|
nickjillings@2097
|
2586 var response = storePoint.parent.document.createElement('response');
|
nickjillings@2097
|
2587 response.textContent = this.textArea.value;
|
nickjillings@2097
|
2588 root.appendChild(question);
|
nickjillings@2097
|
2589 root.appendChild(response);
|
nickjillings@2097
|
2590 storePoint.XMLDOM.appendChild(root);
|
nickjillings@2032
|
2591 return root;
|
nickjillings@2032
|
2592 };
|
nickjillings@1525
|
2593 this.resize = function()
|
nickjillings@1525
|
2594 {
|
nickjillings@1525
|
2595 var boxwidth = (window.innerWidth-100)/2;
|
nickjillings@1525
|
2596 if (boxwidth >= 600)
|
nickjillings@1525
|
2597 {
|
nickjillings@1525
|
2598 boxwidth = 600;
|
nickjillings@1525
|
2599 }
|
nickjillings@1525
|
2600 else if (boxwidth < 400)
|
nickjillings@1525
|
2601 {
|
nickjillings@1525
|
2602 boxwidth = 400;
|
nickjillings@1525
|
2603 }
|
nickjillings@1525
|
2604 this.holder.style.width = boxwidth+"px";
|
nickjillings@1525
|
2605 this.textArea.style.width = boxwidth-6+"px";
|
nickjillings@1525
|
2606 };
|
nickjillings@1525
|
2607 this.resize();
|
nickjillings@2032
|
2608 };
|
nickjillings@2032
|
2609
|
nickjillings@2032
|
2610 this.radioBox = function(commentQuestion) {
|
nickjillings@2032
|
2611 this.specification = commentQuestion;
|
nickjillings@2032
|
2612 // Create document objects to hold the comment boxes
|
nickjillings@2032
|
2613 this.holder = document.createElement('div');
|
nickjillings@2032
|
2614 this.holder.className = 'comment-div';
|
nickjillings@2032
|
2615 // Create a string next to each comment asking for a comment
|
nickjillings@2032
|
2616 this.string = document.createElement('span');
|
nickjillings@2032
|
2617 this.string.innerHTML = commentQuestion.statement;
|
nickjillings@2032
|
2618 var br = document.createElement('br');
|
nickjillings@2032
|
2619 // Add to the holder.
|
nickjillings@2032
|
2620 this.holder.appendChild(this.string);
|
nickjillings@2032
|
2621 this.holder.appendChild(br);
|
nickjillings@2032
|
2622 this.options = [];
|
nickjillings@2032
|
2623 this.inputs = document.createElement('div');
|
nickjillings@2032
|
2624 this.span = document.createElement('div');
|
nickjillings@2032
|
2625 this.inputs.align = 'center';
|
nickjillings@2032
|
2626 this.inputs.style.marginLeft = '12px';
|
nickjillings@2032
|
2627 this.span.style.marginLeft = '12px';
|
nickjillings@2032
|
2628 this.span.align = 'center';
|
nickjillings@2032
|
2629 this.span.style.marginTop = '15px';
|
nickjillings@2032
|
2630
|
nickjillings@2032
|
2631 var optCount = commentQuestion.options.length;
|
nickjillings@1324
|
2632 for (var optNode of commentQuestion.options)
|
nickjillings@2032
|
2633 {
|
nickjillings@2032
|
2634 var div = document.createElement('div');
|
nickjillings@1524
|
2635 div.style.width = '80px';
|
nickjillings@2032
|
2636 div.style.float = 'left';
|
nickjillings@2032
|
2637 var input = document.createElement('input');
|
nickjillings@2032
|
2638 input.type = 'radio';
|
nickjillings@2032
|
2639 input.name = commentQuestion.id;
|
nickjillings@1324
|
2640 input.setAttribute('setvalue',optNode.name);
|
nickjillings@2032
|
2641 input.className = 'comment-radio';
|
nickjillings@2032
|
2642 div.appendChild(input);
|
nickjillings@2032
|
2643 this.inputs.appendChild(div);
|
nickjillings@2032
|
2644
|
nickjillings@2032
|
2645
|
nickjillings@2032
|
2646 div = document.createElement('div');
|
nickjillings@1524
|
2647 div.style.width = '80px';
|
nickjillings@2032
|
2648 div.style.float = 'left';
|
nickjillings@2032
|
2649 div.align = 'center';
|
nickjillings@2032
|
2650 var span = document.createElement('span');
|
nickjillings@1324
|
2651 span.textContent = optNode.text;
|
nickjillings@2032
|
2652 span.className = 'comment-radio-span';
|
nickjillings@2032
|
2653 div.appendChild(span);
|
nickjillings@2032
|
2654 this.span.appendChild(div);
|
nickjillings@2032
|
2655 this.options.push(input);
|
nickjillings@2032
|
2656 }
|
nickjillings@2032
|
2657 this.holder.appendChild(this.span);
|
nickjillings@2032
|
2658 this.holder.appendChild(this.inputs);
|
nickjillings@2032
|
2659
|
nickjillings@2097
|
2660 this.exportXMLDOM = function(storePoint) {
|
nickjillings@2097
|
2661 var root = storePoint.parent.document.createElement('comment');
|
nickjillings@2032
|
2662 root.id = this.specification.id;
|
nickjillings@2032
|
2663 root.setAttribute('type',this.specification.type);
|
nickjillings@2032
|
2664 var question = document.createElement('question');
|
nickjillings@2032
|
2665 question.textContent = this.string.textContent;
|
nickjillings@2032
|
2666 var response = document.createElement('response');
|
nickjillings@2032
|
2667 var i=0;
|
nickjillings@2032
|
2668 while(this.options[i].checked == false) {
|
nickjillings@2032
|
2669 i++;
|
nickjillings@2032
|
2670 if (i >= this.options.length) {
|
nickjillings@2032
|
2671 break;
|
nickjillings@2032
|
2672 }
|
nickjillings@2032
|
2673 }
|
nickjillings@2032
|
2674 if (i >= this.options.length) {
|
nickjillings@2032
|
2675 response.textContent = 'null';
|
nickjillings@2032
|
2676 } else {
|
nickjillings@2032
|
2677 response.textContent = this.options[i].getAttribute('setvalue');
|
nickjillings@2032
|
2678 response.setAttribute('number',i);
|
nickjillings@2032
|
2679 }
|
nickjillings@1572
|
2680 console.log('Comment: '+question.textContent);
|
nickjillings@1572
|
2681 console.log('Response: '+response.textContent);
|
nickjillings@2032
|
2682 root.appendChild(question);
|
nickjillings@2032
|
2683 root.appendChild(response);
|
nickjillings@2097
|
2684 storePoint.XMLDOM.appendChild(root);
|
nickjillings@2032
|
2685 return root;
|
nickjillings@2032
|
2686 };
|
nickjillings@1525
|
2687 this.resize = function()
|
nickjillings@1525
|
2688 {
|
nickjillings@1525
|
2689 var boxwidth = (window.innerWidth-100)/2;
|
nickjillings@1525
|
2690 if (boxwidth >= 600)
|
nickjillings@1525
|
2691 {
|
nickjillings@1525
|
2692 boxwidth = 600;
|
nickjillings@1525
|
2693 }
|
nickjillings@1525
|
2694 else if (boxwidth < 400)
|
nickjillings@1525
|
2695 {
|
nickjillings@1525
|
2696 boxwidth = 400;
|
nickjillings@1525
|
2697 }
|
nickjillings@1525
|
2698 this.holder.style.width = boxwidth+"px";
|
nickjillings@1525
|
2699 var text = this.holder.children[2];
|
nickjillings@1525
|
2700 var options = this.holder.children[3];
|
nickjillings@1525
|
2701 var optCount = options.children.length;
|
nickjillings@1525
|
2702 var spanMargin = Math.floor(((boxwidth-20-(optCount*80))/(optCount))/2)+'px';
|
nickjillings@1525
|
2703 var options = options.firstChild;
|
nickjillings@1525
|
2704 var text = text.firstChild;
|
nickjillings@1525
|
2705 options.style.marginRight = spanMargin;
|
nickjillings@1525
|
2706 options.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2707 text.style.marginRight = spanMargin;
|
nickjillings@1525
|
2708 text.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2709 while(options.nextSibling != undefined)
|
nickjillings@1525
|
2710 {
|
nickjillings@1525
|
2711 options = options.nextSibling;
|
nickjillings@1525
|
2712 text = text.nextSibling;
|
nickjillings@1525
|
2713 options.style.marginRight = spanMargin;
|
nickjillings@1525
|
2714 options.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2715 text.style.marginRight = spanMargin;
|
nickjillings@1525
|
2716 text.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2717 }
|
nickjillings@1525
|
2718 };
|
nickjillings@1525
|
2719 this.resize();
|
nickjillings@2032
|
2720 };
|
nickjillings@2032
|
2721
|
nickjillings@1572
|
2722 this.checkboxBox = function(commentQuestion) {
|
nickjillings@1572
|
2723 this.specification = commentQuestion;
|
nickjillings@1572
|
2724 // Create document objects to hold the comment boxes
|
nickjillings@1572
|
2725 this.holder = document.createElement('div');
|
nickjillings@1572
|
2726 this.holder.className = 'comment-div';
|
nickjillings@1572
|
2727 // Create a string next to each comment asking for a comment
|
nickjillings@1572
|
2728 this.string = document.createElement('span');
|
nickjillings@1572
|
2729 this.string.innerHTML = commentQuestion.statement;
|
nickjillings@1572
|
2730 var br = document.createElement('br');
|
nickjillings@1572
|
2731 // Add to the holder.
|
nickjillings@1572
|
2732 this.holder.appendChild(this.string);
|
nickjillings@1572
|
2733 this.holder.appendChild(br);
|
nickjillings@1572
|
2734 this.options = [];
|
nickjillings@1572
|
2735 this.inputs = document.createElement('div');
|
nickjillings@1572
|
2736 this.span = document.createElement('div');
|
nickjillings@1572
|
2737 this.inputs.align = 'center';
|
nickjillings@1572
|
2738 this.inputs.style.marginLeft = '12px';
|
nickjillings@1572
|
2739 this.span.style.marginLeft = '12px';
|
nickjillings@1572
|
2740 this.span.align = 'center';
|
nickjillings@1572
|
2741 this.span.style.marginTop = '15px';
|
nickjillings@1572
|
2742
|
nickjillings@1572
|
2743 var optCount = commentQuestion.options.length;
|
nickjillings@1572
|
2744 for (var i=0; i<optCount; i++)
|
nickjillings@1572
|
2745 {
|
nickjillings@1572
|
2746 var div = document.createElement('div');
|
nickjillings@1524
|
2747 div.style.width = '80px';
|
nickjillings@1572
|
2748 div.style.float = 'left';
|
nickjillings@1572
|
2749 var input = document.createElement('input');
|
nickjillings@1572
|
2750 input.type = 'checkbox';
|
nickjillings@1572
|
2751 input.name = commentQuestion.id;
|
nickjillings@1572
|
2752 input.setAttribute('setvalue',commentQuestion.options[i].name);
|
nickjillings@1572
|
2753 input.className = 'comment-radio';
|
nickjillings@1572
|
2754 div.appendChild(input);
|
nickjillings@1572
|
2755 this.inputs.appendChild(div);
|
nickjillings@1572
|
2756
|
nickjillings@1572
|
2757
|
nickjillings@1572
|
2758 div = document.createElement('div');
|
nickjillings@1524
|
2759 div.style.width = '80px';
|
nickjillings@1572
|
2760 div.style.float = 'left';
|
nickjillings@1572
|
2761 div.align = 'center';
|
nickjillings@1572
|
2762 var span = document.createElement('span');
|
nickjillings@1572
|
2763 span.textContent = commentQuestion.options[i].text;
|
nickjillings@1572
|
2764 span.className = 'comment-radio-span';
|
nickjillings@1572
|
2765 div.appendChild(span);
|
nickjillings@1572
|
2766 this.span.appendChild(div);
|
nickjillings@1572
|
2767 this.options.push(input);
|
nickjillings@1572
|
2768 }
|
nickjillings@1572
|
2769 this.holder.appendChild(this.span);
|
nickjillings@1572
|
2770 this.holder.appendChild(this.inputs);
|
nickjillings@1572
|
2771
|
nickjillings@2097
|
2772 this.exportXMLDOM = function(storePoint) {
|
nickjillings@2097
|
2773 var root = storePoint.parent.document.createElement('comment');
|
nickjillings@1572
|
2774 root.id = this.specification.id;
|
nickjillings@1572
|
2775 root.setAttribute('type',this.specification.type);
|
nickjillings@1572
|
2776 var question = document.createElement('question');
|
nickjillings@1572
|
2777 question.textContent = this.string.textContent;
|
nickjillings@1572
|
2778 root.appendChild(question);
|
nickjillings@1572
|
2779 console.log('Comment: '+question.textContent);
|
nickjillings@1572
|
2780 for (var i=0; i<this.options.length; i++) {
|
nickjillings@1572
|
2781 var response = document.createElement('response');
|
nickjillings@1572
|
2782 response.textContent = this.options[i].checked;
|
nickjillings@1572
|
2783 response.setAttribute('name',this.options[i].getAttribute('setvalue'));
|
nickjillings@1572
|
2784 root.appendChild(response);
|
nickjillings@1572
|
2785 console.log('Response '+response.getAttribute('name') +': '+response.textContent);
|
nickjillings@1572
|
2786 }
|
nickjillings@2097
|
2787 storePoint.XMLDOM.appendChild(root);
|
nickjillings@1572
|
2788 return root;
|
nickjillings@1572
|
2789 };
|
nickjillings@1525
|
2790 this.resize = function()
|
nickjillings@1525
|
2791 {
|
nickjillings@1525
|
2792 var boxwidth = (window.innerWidth-100)/2;
|
nickjillings@1525
|
2793 if (boxwidth >= 600)
|
nickjillings@1525
|
2794 {
|
nickjillings@1525
|
2795 boxwidth = 600;
|
nickjillings@1525
|
2796 }
|
nickjillings@1525
|
2797 else if (boxwidth < 400)
|
nickjillings@1525
|
2798 {
|
nickjillings@1525
|
2799 boxwidth = 400;
|
nickjillings@1525
|
2800 }
|
nickjillings@1525
|
2801 this.holder.style.width = boxwidth+"px";
|
nickjillings@1525
|
2802 var text = this.holder.children[2];
|
nickjillings@1525
|
2803 var options = this.holder.children[3];
|
nickjillings@1525
|
2804 var optCount = options.children.length;
|
nickjillings@1525
|
2805 var spanMargin = Math.floor(((boxwidth-20-(optCount*80))/(optCount))/2)+'px';
|
nickjillings@1525
|
2806 var options = options.firstChild;
|
nickjillings@1525
|
2807 var text = text.firstChild;
|
nickjillings@1525
|
2808 options.style.marginRight = spanMargin;
|
nickjillings@1525
|
2809 options.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2810 text.style.marginRight = spanMargin;
|
nickjillings@1525
|
2811 text.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2812 while(options.nextSibling != undefined)
|
nickjillings@1525
|
2813 {
|
nickjillings@1525
|
2814 options = options.nextSibling;
|
nickjillings@1525
|
2815 text = text.nextSibling;
|
nickjillings@1525
|
2816 options.style.marginRight = spanMargin;
|
nickjillings@1525
|
2817 options.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2818 text.style.marginRight = spanMargin;
|
nickjillings@1525
|
2819 text.style.marginLeft = spanMargin;
|
nickjillings@1525
|
2820 }
|
nickjillings@1525
|
2821 };
|
nickjillings@1525
|
2822 this.resize();
|
nickjillings@1572
|
2823 };
|
nickjillings@1570
|
2824
|
nickjillings@2032
|
2825 this.createCommentQuestion = function(element) {
|
nickjillings@2032
|
2826 var node;
|
nickjillings@1324
|
2827 if (element.type == 'question') {
|
nickjillings@2032
|
2828 node = new this.commentBox(element);
|
nickjillings@2032
|
2829 } else if (element.type == 'radio') {
|
nickjillings@2032
|
2830 node = new this.radioBox(element);
|
nickjillings@1572
|
2831 } else if (element.type == 'checkbox') {
|
nickjillings@1572
|
2832 node = new this.checkboxBox(element);
|
nickjillings@2032
|
2833 }
|
nickjillings@2032
|
2834 this.commentQuestions.push(node);
|
nickjillings@2032
|
2835 return node;
|
nickjillings@2032
|
2836 };
|
nickjillings@1564
|
2837
|
nickjillings@2051
|
2838 this.deleteCommentQuestions = function()
|
nickjillings@2051
|
2839 {
|
nickjillings@2051
|
2840 this.commentQuestions = [];
|
nickjillings@2051
|
2841 };
|
nickjillings@2176
|
2842
|
nickjillings@2176
|
2843 this.outsideReferenceDOM = function(audioObject,index,inject)
|
nickjillings@2176
|
2844 {
|
nickjillings@2176
|
2845 this.parent = audioObject;
|
nickjillings@2176
|
2846 this.outsideReferenceHolder = document.createElement('button');
|
nickjillings@2176
|
2847 this.outsideReferenceHolder.id = 'outside-reference';
|
nickjillings@2176
|
2848 this.outsideReferenceHolder.className = 'outside-reference';
|
nickjillings@2176
|
2849 this.outsideReferenceHolder.setAttribute('track-id',index);
|
nickjillings@2176
|
2850 this.outsideReferenceHolder.textContent = "Play Reference";
|
nickjillings@2176
|
2851 this.outsideReferenceHolder.disabled = true;
|
nickjillings@2176
|
2852
|
nickjillings@2176
|
2853 this.outsideReferenceHolder.onclick = function(event)
|
nickjillings@2176
|
2854 {
|
nickjillings@2176
|
2855 audioEngineContext.play(event.currentTarget.getAttribute('track-id'));
|
nickjillings@2176
|
2856 };
|
nickjillings@2176
|
2857 inject.appendChild(this.outsideReferenceHolder);
|
nickjillings@2176
|
2858 this.enable = function()
|
nickjillings@2176
|
2859 {
|
nickjillings@2176
|
2860 if (this.parent.state == 1)
|
nickjillings@2176
|
2861 {
|
nickjillings@2176
|
2862 this.outsideReferenceHolder.disabled = false;
|
nickjillings@2176
|
2863 }
|
nickjillings@2176
|
2864 };
|
nickjillings@2176
|
2865 this.updateLoading = function(progress)
|
nickjillings@2176
|
2866 {
|
nickjillings@2176
|
2867 if (progress != 100)
|
nickjillings@2176
|
2868 {
|
nickjillings@2176
|
2869 progress = String(progress);
|
nickjillings@2176
|
2870 progress = progress.split('.')[0];
|
nickjillings@2176
|
2871 this.outsideReferenceHolder.textContent = progress+'%';
|
nickjillings@2176
|
2872 } else {
|
nickjillings@2176
|
2873 this.outsideReferenceHolder.textContent = "Play Reference";
|
nickjillings@2176
|
2874 }
|
nickjillings@2176
|
2875 };
|
nickjillings@2176
|
2876 this.startPlayback = function()
|
nickjillings@2176
|
2877 {
|
nickjillings@2176
|
2878 // Called when playback has begun
|
nickjillings@2176
|
2879 $('.track-slider').removeClass('track-slider-playing');
|
nickjillings@2176
|
2880 $('.comment-div').removeClass('comment-box-playing');
|
nickjillings@2176
|
2881 this.outsideReferenceHolder.style.backgroundColor = "#FDD";
|
nickjillings@2176
|
2882 };
|
nickjillings@2176
|
2883 this.stopPlayback = function()
|
nickjillings@2176
|
2884 {
|
nickjillings@2176
|
2885 // Called when playback has stopped. This gets called even if playback never started!
|
nickjillings@2176
|
2886 this.outsideReferenceHolder.style.backgroundColor = "";
|
nickjillings@2176
|
2887 };
|
nickjillings@2176
|
2888 this.exportXMLDOM = function(audioObject)
|
nickjillings@2176
|
2889 {
|
nickjillings@2176
|
2890 return null;
|
nickjillings@2176
|
2891 };
|
nickjillings@2176
|
2892 this.getValue = function()
|
nickjillings@2176
|
2893 {
|
nickjillings@2176
|
2894 return 0;
|
nickjillings@2176
|
2895 };
|
nickjillings@2176
|
2896 this.getPresentedId = function()
|
nickjillings@2176
|
2897 {
|
nickjillings@2176
|
2898 return 'Reference';
|
nickjillings@2176
|
2899 };
|
nickjillings@2176
|
2900 this.canMove = function()
|
nickjillings@2176
|
2901 {
|
nickjillings@2176
|
2902 return false;
|
nickjillings@2176
|
2903 };
|
nickjillings@2176
|
2904 this.error = function() {
|
nickjillings@2176
|
2905 // audioObject has an error!!
|
nickjillings@2176
|
2906 this.outsideReferenceHolder.textContent = "Error";
|
nickjillings@2176
|
2907 this.outsideReferenceHolder.style.backgroundColor = "#F00";
|
nickjillings@2176
|
2908 }
|
nickjillings@2176
|
2909 }
|
nickjillings@2051
|
2910
|
nickjillings@1564
|
2911 this.playhead = new function()
|
nickjillings@1564
|
2912 {
|
nickjillings@1564
|
2913 this.object = document.createElement('div');
|
nickjillings@1564
|
2914 this.object.className = 'playhead';
|
nickjillings@1564
|
2915 this.object.align = 'left';
|
nickjillings@1564
|
2916 var curTime = document.createElement('div');
|
nickjillings@1564
|
2917 curTime.style.width = '50px';
|
nickjillings@1564
|
2918 this.curTimeSpan = document.createElement('span');
|
nickjillings@1564
|
2919 this.curTimeSpan.textContent = '00:00';
|
nickjillings@1564
|
2920 curTime.appendChild(this.curTimeSpan);
|
nickjillings@1564
|
2921 this.object.appendChild(curTime);
|
nickjillings@1564
|
2922 this.scrubberTrack = document.createElement('div');
|
nickjillings@1564
|
2923 this.scrubberTrack.className = 'playhead-scrub-track';
|
nickjillings@1564
|
2924
|
nickjillings@1564
|
2925 this.scrubberHead = document.createElement('div');
|
nickjillings@1564
|
2926 this.scrubberHead.id = 'playhead-scrubber';
|
nickjillings@1564
|
2927 this.scrubberTrack.appendChild(this.scrubberHead);
|
nickjillings@1564
|
2928 this.object.appendChild(this.scrubberTrack);
|
nickjillings@1564
|
2929
|
nickjillings@1564
|
2930 this.timePerPixel = 0;
|
nickjillings@1564
|
2931 this.maxTime = 0;
|
nickjillings@1564
|
2932
|
nickjillings@1567
|
2933 this.playbackObject;
|
nickjillings@1567
|
2934
|
nickjillings@1567
|
2935 this.setTimePerPixel = function(audioObject) {
|
nickjillings@1564
|
2936 //maxTime must be in seconds
|
nickjillings@1567
|
2937 this.playbackObject = audioObject;
|
nickjillings@1410
|
2938 this.maxTime = audioObject.buffer.buffer.duration;
|
nickjillings@1564
|
2939 var width = 490; //500 - 10, 5 each side of the tracker head
|
nickjillings@1567
|
2940 this.timePerPixel = this.maxTime/490;
|
nickjillings@1567
|
2941 if (this.maxTime < 60) {
|
nickjillings@1564
|
2942 this.curTimeSpan.textContent = '0.00';
|
nickjillings@1564
|
2943 } else {
|
nickjillings@1564
|
2944 this.curTimeSpan.textContent = '00:00';
|
nickjillings@1564
|
2945 }
|
nickjillings@1564
|
2946 };
|
nickjillings@1564
|
2947
|
nickjillings@1567
|
2948 this.update = function() {
|
nickjillings@1564
|
2949 // Update the playhead position, startPlay must be called
|
nickjillings@1564
|
2950 if (this.timePerPixel > 0) {
|
nickjillings@1567
|
2951 var time = this.playbackObject.getCurrentPosition();
|
nickjillings@1367
|
2952 if (time > 0 && time < this.maxTime) {
|
nickjillings@1530
|
2953 var width = 490;
|
nickjillings@1530
|
2954 var pix = Math.floor(time/this.timePerPixel);
|
nickjillings@1530
|
2955 this.scrubberHead.style.left = pix+'px';
|
nickjillings@1530
|
2956 if (this.maxTime > 60.0) {
|
nickjillings@1530
|
2957 var secs = time%60;
|
nickjillings@1530
|
2958 var mins = Math.floor((time-secs)/60);
|
nickjillings@1530
|
2959 secs = secs.toString();
|
nickjillings@1530
|
2960 secs = secs.substr(0,2);
|
nickjillings@1530
|
2961 mins = mins.toString();
|
nickjillings@1530
|
2962 this.curTimeSpan.textContent = mins+':'+secs;
|
nickjillings@1530
|
2963 } else {
|
nickjillings@1530
|
2964 time = time.toString();
|
nickjillings@1530
|
2965 this.curTimeSpan.textContent = time.substr(0,4);
|
nickjillings@1530
|
2966 }
|
nickjillings@1564
|
2967 } else {
|
nickjillings@1530
|
2968 this.scrubberHead.style.left = '0px';
|
nickjillings@1530
|
2969 if (this.maxTime < 60) {
|
nickjillings@1530
|
2970 this.curTimeSpan.textContent = '0.00';
|
nickjillings@1530
|
2971 } else {
|
nickjillings@1530
|
2972 this.curTimeSpan.textContent = '00:00';
|
nickjillings@1530
|
2973 }
|
nickjillings@1564
|
2974 }
|
nickjillings@1564
|
2975 }
|
nickjillings@1564
|
2976 };
|
nickjillings@1567
|
2977
|
nickjillings@1567
|
2978 this.interval = undefined;
|
nickjillings@1567
|
2979
|
nickjillings@1567
|
2980 this.start = function() {
|
nickjillings@1567
|
2981 if (this.playbackObject != undefined && this.interval == undefined) {
|
nickjillings@1530
|
2982 if (this.maxTime < 60) {
|
nickjillings@1530
|
2983 this.interval = setInterval(function(){interfaceContext.playhead.update();},10);
|
nickjillings@1530
|
2984 } else {
|
nickjillings@1530
|
2985 this.interval = setInterval(function(){interfaceContext.playhead.update();},100);
|
nickjillings@1530
|
2986 }
|
nickjillings@1567
|
2987 }
|
nickjillings@1567
|
2988 };
|
nickjillings@1567
|
2989 this.stop = function() {
|
nickjillings@1567
|
2990 clearInterval(this.interval);
|
nickjillings@1567
|
2991 this.interval = undefined;
|
nickjillings@2101
|
2992 this.scrubberHead.style.left = '0px';
|
nickjillings@1530
|
2993 if (this.maxTime < 60) {
|
nickjillings@1530
|
2994 this.curTimeSpan.textContent = '0.00';
|
nickjillings@1530
|
2995 } else {
|
nickjillings@1530
|
2996 this.curTimeSpan.textContent = '00:00';
|
nickjillings@1530
|
2997 }
|
nickjillings@1567
|
2998 };
|
nickjillings@1564
|
2999 };
|
nickjillings@1354
|
3000
|
nickjillings@1354
|
3001 this.volume = new function()
|
nickjillings@1354
|
3002 {
|
nickjillings@1354
|
3003 // An in-built volume module which can be viewed on page
|
nickjillings@1354
|
3004 // Includes trackers on page-by-page data
|
nickjillings@1354
|
3005 // Volume does NOT reset to 0dB on each page load
|
nickjillings@1354
|
3006 this.valueLin = 1.0;
|
nickjillings@1354
|
3007 this.valueDB = 0.0;
|
nickjillings@1354
|
3008 this.object = document.createElement('div');
|
nickjillings@1354
|
3009 this.object.id = 'master-volume-holder';
|
nickjillings@1354
|
3010 this.slider = document.createElement('input');
|
nickjillings@1354
|
3011 this.slider.id = 'master-volume-control';
|
nickjillings@1354
|
3012 this.slider.type = 'range';
|
nickjillings@1354
|
3013 this.valueText = document.createElement('span');
|
nickjillings@1354
|
3014 this.valueText.id = 'master-volume-feedback';
|
nickjillings@1354
|
3015 this.valueText.textContent = '0dB';
|
nickjillings@1354
|
3016
|
nickjillings@1354
|
3017 this.slider.min = -60;
|
nickjillings@1354
|
3018 this.slider.max = 12;
|
nickjillings@1354
|
3019 this.slider.value = 0;
|
nickjillings@1354
|
3020 this.slider.step = 1;
|
nickjillings@1354
|
3021 this.slider.onmousemove = function(event)
|
nickjillings@1354
|
3022 {
|
nickjillings@1354
|
3023 interfaceContext.volume.valueDB = event.currentTarget.value;
|
nickjillings@1354
|
3024 interfaceContext.volume.valueLin = decibelToLinear(interfaceContext.volume.valueDB);
|
nickjillings@1354
|
3025 interfaceContext.volume.valueText.textContent = interfaceContext.volume.valueDB+'dB';
|
nickjillings@1354
|
3026 audioEngineContext.outputGain.gain.value = interfaceContext.volume.valueLin;
|
nickjillings@1354
|
3027 }
|
nickjillings@1354
|
3028 this.slider.onmouseup = function(event)
|
nickjillings@1354
|
3029 {
|
nickjillings@2100
|
3030 var storePoint = testState.currentStore.XMLDOM.getElementsByTagName('metric')[0].getAllElementsByName('volumeTracker');
|
nickjillings@1354
|
3031 if (storePoint.length == 0)
|
nickjillings@1354
|
3032 {
|
nickjillings@1354
|
3033 storePoint = storage.document.createElement('metricresult');
|
nickjillings@1354
|
3034 storePoint.setAttribute('name','volumeTracker');
|
nickjillings@2100
|
3035 testState.currentStore.XMLDOM.getElementsByTagName('metric')[0].appendChild(storePoint);
|
nickjillings@1354
|
3036 }
|
nickjillings@1354
|
3037 else {
|
nickjillings@1354
|
3038 storePoint = storePoint[0];
|
nickjillings@1354
|
3039 }
|
nickjillings@1354
|
3040 var node = storage.document.createElement('movement');
|
nickjillings@1354
|
3041 node.setAttribute('test-time',audioEngineContext.timer.getTestTime());
|
nickjillings@1354
|
3042 node.setAttribute('volume',interfaceContext.volume.valueDB);
|
nickjillings@1354
|
3043 node.setAttribute('format','dBFS');
|
nickjillings@1354
|
3044 storePoint.appendChild(node);
|
nickjillings@1354
|
3045 }
|
nickjillings@1354
|
3046
|
nickjillings@1355
|
3047 var title = document.createElement('div');
|
nickjillings@1355
|
3048 title.innerHTML = '<span>Master Volume Control</span>';
|
nickjillings@1355
|
3049 title.style.fontSize = '0.75em';
|
nickjillings@1355
|
3050 title.style.width = "100%";
|
nickjillings@1355
|
3051 title.align = 'center';
|
nickjillings@1355
|
3052 this.object.appendChild(title);
|
nickjillings@1355
|
3053
|
nickjillings@1354
|
3054 this.object.appendChild(this.slider);
|
nickjillings@1354
|
3055 this.object.appendChild(this.valueText);
|
nickjillings@1354
|
3056 }
|
nickjillings@2049
|
3057 // Global Checkers
|
nickjillings@2049
|
3058 // These functions will help enforce the checkers
|
nickjillings@2049
|
3059 this.checkHiddenAnchor = function()
|
nickjillings@2049
|
3060 {
|
nickjillings@1324
|
3061 for (var ao of audioEngineContext.audioObjects)
|
nickjillings@2049
|
3062 {
|
nickjillings@1324
|
3063 if (ao.specification.type == "anchor")
|
nickjillings@2049
|
3064 {
|
nickjillings@1325
|
3065 if (ao.interfaceDOM.getValue() > (ao.specification.marker/100) && ao.specification.marker > 0) {
|
nickjillings@1324
|
3066 // Anchor is not set below
|
nickjillings@1324
|
3067 console.log('Anchor node not below marker value');
|
nickjillings@1324
|
3068 alert('Please keep listening');
|
nickjillings@1367
|
3069 this.storeErrorNode('Anchor node not below marker value');
|
nickjillings@1324
|
3070 return false;
|
nickjillings@1324
|
3071 }
|
nickjillings@2049
|
3072 }
|
nickjillings@2049
|
3073 }
|
nickjillings@2049
|
3074 return true;
|
nickjillings@2049
|
3075 };
|
nickjillings@2049
|
3076
|
nickjillings@2049
|
3077 this.checkHiddenReference = function()
|
nickjillings@2049
|
3078 {
|
nickjillings@1324
|
3079 for (var ao of audioEngineContext.audioObjects)
|
nickjillings@2049
|
3080 {
|
nickjillings@1324
|
3081 if (ao.specification.type == "reference")
|
nickjillings@2049
|
3082 {
|
nickjillings@1325
|
3083 if (ao.interfaceDOM.getValue() < (ao.specification.marker/100) && ao.specification.marker > 0) {
|
nickjillings@1324
|
3084 // Anchor is not set below
|
nickjillings@1367
|
3085 console.log('Reference node not above marker value');
|
nickjillings@1367
|
3086 this.storeErrorNode('Reference node not above marker value');
|
nickjillings@1324
|
3087 alert('Please keep listening');
|
nickjillings@1324
|
3088 return false;
|
nickjillings@1324
|
3089 }
|
nickjillings@2049
|
3090 }
|
nickjillings@2049
|
3091 }
|
nickjillings@2049
|
3092 return true;
|
nickjillings@2049
|
3093 };
|
nickjillings@1474
|
3094
|
nickjillings@1474
|
3095 this.checkFragmentsFullyPlayed = function ()
|
nickjillings@1474
|
3096 {
|
nickjillings@1474
|
3097 // Checks the entire file has been played back
|
nickjillings@1474
|
3098 // NOTE ! This will return true IF playback is Looped!!!
|
nickjillings@1474
|
3099 if (audioEngineContext.loopPlayback)
|
nickjillings@1474
|
3100 {
|
nickjillings@1474
|
3101 console.log("WARNING - Looped source: Cannot check fragments are fully played");
|
nickjillings@1474
|
3102 return true;
|
nickjillings@1474
|
3103 }
|
nickjillings@1474
|
3104 var check_pass = true;
|
nickjillings@1474
|
3105 var error_obj = [];
|
nickjillings@1474
|
3106 for (var i = 0; i<audioEngineContext.audioObjects.length; i++)
|
nickjillings@1474
|
3107 {
|
nickjillings@1474
|
3108 var object = audioEngineContext.audioObjects[i];
|
nickjillings@1393
|
3109 var time = object.buffer.buffer.duration;
|
nickjillings@1474
|
3110 var metric = object.metric;
|
nickjillings@1474
|
3111 var passed = false;
|
nickjillings@1474
|
3112 for (var j=0; j<metric.listenTracker.length; j++)
|
nickjillings@1474
|
3113 {
|
nickjillings@1474
|
3114 var bt = metric.listenTracker[j].getElementsByTagName('buffertime');
|
nickjillings@1474
|
3115 var start_time = Number(bt[0].getAttribute('start'));
|
nickjillings@1474
|
3116 var stop_time = Number(bt[0].getAttribute('stop'));
|
nickjillings@1474
|
3117 var delta = stop_time - start_time;
|
nickjillings@1474
|
3118 if (delta >= time)
|
nickjillings@1474
|
3119 {
|
nickjillings@1474
|
3120 passed = true;
|
nickjillings@1474
|
3121 break;
|
nickjillings@1474
|
3122 }
|
nickjillings@1474
|
3123 }
|
nickjillings@1474
|
3124 if (passed == false)
|
nickjillings@1474
|
3125 {
|
nickjillings@1474
|
3126 check_pass = false;
|
nickjillings@1290
|
3127 console.log("Continue listening to track-"+object.interfaceDOM.getPresentedId());
|
nickjillings@1290
|
3128 error_obj.push(object.interfaceDOM.getPresentedId());
|
nickjillings@1474
|
3129 }
|
nickjillings@1474
|
3130 }
|
nickjillings@1474
|
3131 if (check_pass == false)
|
nickjillings@1474
|
3132 {
|
nickjillings@1393
|
3133 var str_start = "You have not completely listened to fragments ";
|
nickjillings@1474
|
3134 for (var i=0; i<error_obj.length; i++)
|
nickjillings@1474
|
3135 {
|
nickjillings@1474
|
3136 str_start += error_obj[i];
|
nickjillings@1474
|
3137 if (i != error_obj.length-1)
|
nickjillings@1474
|
3138 {
|
nickjillings@1474
|
3139 str_start += ', ';
|
nickjillings@1474
|
3140 }
|
nickjillings@1474
|
3141 }
|
nickjillings@1474
|
3142 str_start += ". Please keep listening";
|
nickjillings@1474
|
3143 console.log("[ALERT]: "+str_start);
|
nickjillings@1367
|
3144 this.storeErrorNode("[ALERT]: "+str_start);
|
nickjillings@1474
|
3145 alert(str_start);
|
nickjillings@1474
|
3146 }
|
nickjillings@1474
|
3147 };
|
nickjillings@1399
|
3148 this.checkAllMoved = function()
|
nickjillings@1399
|
3149 {
|
nickjillings@1399
|
3150 var str = "You have not moved ";
|
nickjillings@1399
|
3151 var failed = [];
|
nickjillings@1340
|
3152 for (var ao of audioEngineContext.audioObjects)
|
nickjillings@1399
|
3153 {
|
nickjillings@1340
|
3154 if(ao.metric.wasMoved == false && ao.interfaceDOM.canMove() == true)
|
nickjillings@1399
|
3155 {
|
nickjillings@1340
|
3156 failed.push(ao.interfaceDOM.getPresentedId());
|
nickjillings@1399
|
3157 }
|
nickjillings@1399
|
3158 }
|
nickjillings@1399
|
3159 if (failed.length == 0)
|
nickjillings@1399
|
3160 {
|
nickjillings@1399
|
3161 return true;
|
nickjillings@1399
|
3162 } else if (failed.length == 1)
|
nickjillings@1399
|
3163 {
|
nickjillings@1399
|
3164 str += 'track '+failed[0];
|
nickjillings@1399
|
3165 } else {
|
nickjillings@1399
|
3166 str += 'tracks ';
|
nickjillings@1399
|
3167 for (var i=0; i<failed.length-1; i++)
|
nickjillings@1399
|
3168 {
|
nickjillings@1399
|
3169 str += failed[i]+', ';
|
nickjillings@1399
|
3170 }
|
nickjillings@1399
|
3171 str += 'and '+failed[i];
|
nickjillings@1399
|
3172 }
|
nickjillings@1399
|
3173 str +='.';
|
nickjillings@1399
|
3174 alert(str);
|
nickjillings@1399
|
3175 console.log(str);
|
nickjillings@1367
|
3176 this.storeErrorNode(str);
|
nickjillings@1399
|
3177 return false;
|
nickjillings@1399
|
3178 };
|
nickjillings@1399
|
3179 this.checkAllPlayed = function()
|
nickjillings@1399
|
3180 {
|
nickjillings@1399
|
3181 var str = "You have not played ";
|
nickjillings@1399
|
3182 var failed = [];
|
nickjillings@1340
|
3183 for (var ao of audioEngineContext.audioObjects)
|
nickjillings@1399
|
3184 {
|
nickjillings@1340
|
3185 if(ao.metric.wasListenedTo == false)
|
nickjillings@1399
|
3186 {
|
nickjillings@1340
|
3187 failed.push(ao.interfaceDOM.getPresentedId());
|
nickjillings@1399
|
3188 }
|
nickjillings@1399
|
3189 }
|
nickjillings@1399
|
3190 if (failed.length == 0)
|
nickjillings@1399
|
3191 {
|
nickjillings@1399
|
3192 return true;
|
nickjillings@1399
|
3193 } else if (failed.length == 1)
|
nickjillings@1399
|
3194 {
|
nickjillings@1399
|
3195 str += 'track '+failed[0];
|
nickjillings@1399
|
3196 } else {
|
nickjillings@1399
|
3197 str += 'tracks ';
|
nickjillings@1399
|
3198 for (var i=0; i<failed.length-1; i++)
|
nickjillings@1399
|
3199 {
|
nickjillings@1399
|
3200 str += failed[i]+', ';
|
nickjillings@1399
|
3201 }
|
nickjillings@1399
|
3202 str += 'and '+failed[i];
|
nickjillings@1399
|
3203 }
|
nickjillings@1399
|
3204 str +='.';
|
nickjillings@1399
|
3205 alert(str);
|
nickjillings@1399
|
3206 console.log(str);
|
nickjillings@1367
|
3207 this.storeErrorNode(str);
|
nickjillings@1399
|
3208 return false;
|
nickjillings@1399
|
3209 };
|
nickjillings@1367
|
3210
|
nickjillings@1367
|
3211 this.storeErrorNode = function(errorMessage)
|
nickjillings@1367
|
3212 {
|
nickjillings@1367
|
3213 var time = audioEngineContext.timer.getTestTime();
|
nickjillings@1367
|
3214 var node = storage.document.createElement('error');
|
nickjillings@1367
|
3215 node.setAttribute('time',time);
|
nickjillings@1367
|
3216 node.textContent = errorMessage;
|
nickjillings@1367
|
3217 testState.currentStore.XMLDOM.appendChild(node);
|
nickjillings@1367
|
3218 };
|
nickjillings@1324
|
3219 }
|
nickjillings@1324
|
3220
|
nickjillings@1324
|
3221 function Storage()
|
nickjillings@1324
|
3222 {
|
nickjillings@1324
|
3223 // Holds results in XML format until ready for collection
|
nickjillings@1324
|
3224 this.globalPreTest = null;
|
nickjillings@1324
|
3225 this.globalPostTest = null;
|
nickjillings@1324
|
3226 this.testPages = [];
|
nickjillings@1294
|
3227 this.document = null;
|
nickjillings@1294
|
3228 this.root = null;
|
nickjillings@1324
|
3229 this.state = 0;
|
nickjillings@1324
|
3230
|
nickjillings@1294
|
3231 this.initialise = function(existingStore)
|
nickjillings@1324
|
3232 {
|
nickjillings@1294
|
3233 if (existingStore == undefined) {
|
nickjillings@2147
|
3234 // We need to get the sessionKey
|
nickjillings@2147
|
3235 this.SessionKey.generateKey();
|
nickjillings@1294
|
3236 this.document = document.implementation.createDocument(null,"waetresult");
|
nickjillings@1294
|
3237 this.root = this.document.childNodes[0];
|
nickjillings@2150
|
3238 var projectDocument = specification.projectXML;
|
nickjillings@2150
|
3239 projectDocument.setAttribute('file-name',url);
|
nickjillings@2150
|
3240 this.root.appendChild(projectDocument);
|
nickjillings@2170
|
3241 this.root.appendChild(interfaceContext.returnDateNode());
|
nickjillings@2150
|
3242 this.root.appendChild(interfaceContext.returnNavigator());
|
nickjillings@2147
|
3243 } else {
|
nickjillings@1294
|
3244 this.document = existingStore;
|
nickjillings@1294
|
3245 this.root = existingStore.children[0];
|
nickjillings@1294
|
3246 this.SessionKey.key = this.root.getAttribute("key");
|
nickjillings@2147
|
3247 }
|
nickjillings@2150
|
3248 if (specification.preTest != undefined){this.globalPreTest = new this.surveyNode(this,this.root,specification.preTest);}
|
nickjillings@1294
|
3249 if (specification.postTest != undefined){this.globalPostTest = new this.surveyNode(this,this.root,specification.postTest);}
|
nickjillings@1324
|
3250 };
|
nickjillings@2147
|
3251
|
nickjillings@2147
|
3252 this.SessionKey = {
|
nickjillings@2147
|
3253 key: null,
|
nickjillings@2147
|
3254 request: new XMLHttpRequest(),
|
nickjillings@2147
|
3255 parent: this,
|
nickjillings@2147
|
3256 handleEvent: function() {
|
nickjillings@2147
|
3257 var parse = new DOMParser();
|
nickjillings@2147
|
3258 var xml = parse.parseFromString(this.request.response,"text/xml");
|
nickjillings@2147
|
3259 if (xml.getAllElementsByTagName("state")[0].textContent == "OK") {
|
nickjillings@2147
|
3260 this.key = xml.getAllElementsByTagName("key")[0].textContent;
|
nickjillings@2150
|
3261 this.parent.root.setAttribute("key",this.key);
|
nickjillings@2150
|
3262 this.parent.root.setAttribute("state","empty");
|
nickjillings@2147
|
3263 } else {
|
nickjillings@2147
|
3264 this.generateKey();
|
nickjillings@2147
|
3265 }
|
nickjillings@2147
|
3266 },
|
nickjillings@2147
|
3267 generateKey: function() {
|
nickjillings@2147
|
3268 var temp_key = randomString(32);
|
nickjillings@2147
|
3269 this.request.open("GET","keygen.php?key="+temp_key,true);
|
nickjillings@2147
|
3270 this.request.addEventListener("load",this);
|
nickjillings@2147
|
3271 this.request.send();
|
nickjillings@2149
|
3272 },
|
nickjillings@2150
|
3273 update: function() {
|
nickjillings@2150
|
3274 this.parent.root.setAttribute("state","update");
|
nickjillings@2150
|
3275 var xmlhttp = new XMLHttpRequest();
|
nickjillings@2150
|
3276 xmlhttp.open("POST",specification.projectReturn+"?key="+this.key);
|
nickjillings@2150
|
3277 xmlhttp.setRequestHeader('Content-Type', 'text/xml');
|
nickjillings@2150
|
3278 xmlhttp.onerror = function(){
|
nickjillings@2150
|
3279 console.log('Error updating file to server!');
|
nickjillings@2150
|
3280 };
|
nickjillings@2150
|
3281 var hold = document.createElement("div");
|
nickjillings@2150
|
3282 var clone = this.parent.root.cloneNode(true);
|
nickjillings@2150
|
3283 hold.appendChild(clone);
|
nickjillings@2150
|
3284 xmlhttp.onload = function() {
|
nickjillings@2150
|
3285 if (this.status >= 300) {
|
nickjillings@2150
|
3286 console.log("WARNING - Could not update at this time");
|
nickjillings@2150
|
3287 } else {
|
nickjillings@2150
|
3288 var parser = new DOMParser();
|
nickjillings@2150
|
3289 var xmlDoc = parser.parseFromString(xmlhttp.responseText, "application/xml");
|
nickjillings@2150
|
3290 var response = xmlDoc.getElementsByTagName('response')[0];
|
nickjillings@2150
|
3291 if (response.getAttribute("state") == "OK") {
|
nickjillings@2150
|
3292 var file = response.getElementsByTagName("file")[0];
|
nickjillings@2150
|
3293 console.log("Intermediate save: OK, written "+file.getAttribute("bytes")+"B");
|
nickjillings@2150
|
3294 } else {
|
nickjillings@2150
|
3295 var message = response.getElementsByTagName("message");
|
nickjillings@2150
|
3296 console.log("Intermediate save: Error! "+message.textContent);
|
nickjillings@2150
|
3297 }
|
nickjillings@2149
|
3298 }
|
nickjillings@2149
|
3299 }
|
nickjillings@2150
|
3300 xmlhttp.send([hold.innerHTML]);
|
nickjillings@2147
|
3301 }
|
nickjillings@2147
|
3302 }
|
nickjillings@1324
|
3303
|
nickjillings@1324
|
3304 this.createTestPageStore = function(specification)
|
nickjillings@1324
|
3305 {
|
nickjillings@1324
|
3306 var store = new this.pageNode(this,specification);
|
nickjillings@1324
|
3307 this.testPages.push(store);
|
nickjillings@1324
|
3308 return this.testPages[this.testPages.length-1];
|
nickjillings@1324
|
3309 };
|
nickjillings@1324
|
3310
|
nickjillings@1324
|
3311 this.surveyNode = function(parent,root,specification)
|
nickjillings@1324
|
3312 {
|
nickjillings@1324
|
3313 this.specification = specification;
|
nickjillings@1324
|
3314 this.parent = parent;
|
nickjillings@1294
|
3315 this.state = "empty";
|
nickjillings@1324
|
3316 this.XMLDOM = this.parent.document.createElement('survey');
|
nickjillings@1324
|
3317 this.XMLDOM.setAttribute('location',this.specification.location);
|
nickjillings@1294
|
3318 this.XMLDOM.setAttribute("state",this.state);
|
nickjillings@1324
|
3319 for (var optNode of this.specification.options)
|
nickjillings@1324
|
3320 {
|
nickjillings@1324
|
3321 if (optNode.type != 'statement')
|
nickjillings@1324
|
3322 {
|
nickjillings@1324
|
3323 var node = this.parent.document.createElement('surveyresult');
|
nickjillings@1294
|
3324 node.setAttribute("ref",optNode.id);
|
nickjillings@1324
|
3325 node.setAttribute('type',optNode.type);
|
nickjillings@1324
|
3326 this.XMLDOM.appendChild(node);
|
nickjillings@1324
|
3327 }
|
nickjillings@1324
|
3328 }
|
nickjillings@1324
|
3329 root.appendChild(this.XMLDOM);
|
nickjillings@1324
|
3330
|
nickjillings@1324
|
3331 this.postResult = function(node)
|
nickjillings@1324
|
3332 {
|
nickjillings@1324
|
3333 // From popup: node is the popupOption node containing both spec. and results
|
nickjillings@1324
|
3334 // ID is the position
|
nickjillings@1324
|
3335 if (node.specification.type == 'statement'){return;}
|
nickjillings@1294
|
3336 var surveyresult = this.XMLDOM.children[0];
|
nickjillings@1294
|
3337 while(surveyresult != null) {
|
nickjillings@1294
|
3338 if (surveyresult.getAttribute("ref") == node.specification.id)
|
nickjillings@1294
|
3339 {
|
nickjillings@1294
|
3340 break;
|
nickjillings@1294
|
3341 }
|
nickjillings@1294
|
3342 surveyresult = surveyresult.nextElementSibling;
|
nickjillings@1294
|
3343 }
|
nickjillings@1324
|
3344 switch(node.specification.type)
|
nickjillings@1324
|
3345 {
|
nickjillings@1324
|
3346 case "number":
|
nickjillings@1324
|
3347 case "question":
|
nickjillings@1324
|
3348 var child = this.parent.document.createElement('response');
|
nickjillings@1324
|
3349 child.textContent = node.response;
|
nickjillings@1324
|
3350 surveyresult.appendChild(child);
|
nickjillings@1324
|
3351 break;
|
nickjillings@1324
|
3352 case "radio":
|
nickjillings@1324
|
3353 var child = this.parent.document.createElement('response');
|
nickjillings@1324
|
3354 child.setAttribute('name',node.response.name);
|
nickjillings@1324
|
3355 child.textContent = node.response.text;
|
nickjillings@1324
|
3356 surveyresult.appendChild(child);
|
nickjillings@1324
|
3357 break;
|
nickjillings@1324
|
3358 case "checkbox":
|
nickjillings@1324
|
3359 for (var i=0; i<node.response.length; i++)
|
nickjillings@1324
|
3360 {
|
nickjillings@1324
|
3361 var checkNode = this.parent.document.createElement('response');
|
nickjillings@1347
|
3362 checkNode.setAttribute('name',node.response[i].name);
|
nickjillings@1347
|
3363 checkNode.setAttribute('checked',node.response[i].checked);
|
nickjillings@1326
|
3364 surveyresult.appendChild(checkNode);
|
nickjillings@1324
|
3365 }
|
nickjillings@1324
|
3366 break;
|
nickjillings@1324
|
3367 }
|
nickjillings@1324
|
3368 };
|
nickjillings@1294
|
3369 this.complete = function() {
|
nickjillings@1294
|
3370 this.state = "complete";
|
nickjillings@1294
|
3371 this.XMLDOM.setAttribute("state",this.state);
|
nickjillings@1294
|
3372 }
|
nickjillings@1324
|
3373 };
|
nickjillings@1324
|
3374
|
nickjillings@1324
|
3375 this.pageNode = function(parent,specification)
|
nickjillings@1324
|
3376 {
|
nickjillings@1324
|
3377 // Create one store per test page
|
nickjillings@1324
|
3378 this.specification = specification;
|
nickjillings@1324
|
3379 this.parent = parent;
|
nickjillings@1294
|
3380 this.state = "empty";
|
nickjillings@1324
|
3381 this.XMLDOM = this.parent.document.createElement('page');
|
nickjillings@1294
|
3382 this.XMLDOM.setAttribute('ref',specification.id);
|
nickjillings@1324
|
3383 this.XMLDOM.setAttribute('presentedId',specification.presentedId);
|
nickjillings@1294
|
3384 this.XMLDOM.setAttribute("state",this.state);
|
nickjillings@1345
|
3385 if (specification.preTest != undefined){this.preTest = new this.parent.surveyNode(this.parent,this.XMLDOM,this.specification.preTest);}
|
nickjillings@1345
|
3386 if (specification.postTest != undefined){this.postTest = new this.parent.surveyNode(this.parent,this.XMLDOM,this.specification.postTest);}
|
nickjillings@1324
|
3387
|
nickjillings@1324
|
3388 // Add any page metrics
|
nickjillings@1324
|
3389 var page_metric = this.parent.document.createElement('metric');
|
nickjillings@1324
|
3390 this.XMLDOM.appendChild(page_metric);
|
nickjillings@1324
|
3391
|
nickjillings@1324
|
3392 // Add the audioelement
|
nickjillings@1324
|
3393 for (var element of this.specification.audioElements)
|
nickjillings@1324
|
3394 {
|
nickjillings@1324
|
3395 var aeNode = this.parent.document.createElement('audioelement');
|
nickjillings@1294
|
3396 aeNode.setAttribute('ref',element.id);
|
nickjillings@1294
|
3397 if (element.name != undefined){aeNode.setAttribute('name',element.name)};
|
nickjillings@1324
|
3398 aeNode.setAttribute('type',element.type);
|
nickjillings@1324
|
3399 aeNode.setAttribute('url', element.url);
|
nickjillings@1324
|
3400 aeNode.setAttribute('gain', element.gain);
|
nickjillings@1324
|
3401 if (element.type == 'anchor' || element.type == 'reference')
|
nickjillings@1324
|
3402 {
|
nickjillings@1324
|
3403 if (element.marker > 0)
|
nickjillings@1324
|
3404 {
|
nickjillings@1324
|
3405 aeNode.setAttribute('marker',element.marker);
|
nickjillings@1324
|
3406 }
|
nickjillings@1324
|
3407 }
|
nickjillings@1324
|
3408 var ae_metric = this.parent.document.createElement('metric');
|
nickjillings@1324
|
3409 aeNode.appendChild(ae_metric);
|
nickjillings@1324
|
3410 this.XMLDOM.appendChild(aeNode);
|
nickjillings@1324
|
3411 }
|
nickjillings@1324
|
3412
|
nickjillings@1324
|
3413 this.parent.root.appendChild(this.XMLDOM);
|
nickjillings@1294
|
3414
|
nickjillings@1294
|
3415 this.complete = function() {
|
nickjillings@1294
|
3416 this.state = "complete";
|
nickjillings@1294
|
3417 this.XMLDOM.setAttribute("state","complete");
|
nickjillings@1294
|
3418 }
|
nickjillings@1324
|
3419 };
|
nickjillings@2150
|
3420 this.update = function() {
|
nickjillings@2150
|
3421 this.SessionKey.update();
|
nickjillings@2150
|
3422 }
|
nickjillings@1324
|
3423 this.finish = function()
|
nickjillings@1324
|
3424 {
|
nickjillings@1324
|
3425 if (this.state == 0)
|
nickjillings@1324
|
3426 {
|
nickjillings@2150
|
3427 this.update();
|
nickjillings@1324
|
3428 }
|
nickjillings@1324
|
3429 this.state = 1;
|
nickjillings@1324
|
3430 return this.root;
|
nickjillings@1324
|
3431 };
|
nickjillings@1324
|
3432 }
|