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