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