comparison interfaces/ABX.js @ 2538:464c6c6692d6

Beautified entire project.
author Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk>
date Mon, 14 Nov 2016 14:17:03 +0000
parents 42abe6eddfb5
children 342ef7948c47
comparison
equal deleted inserted replaced
2536:527020a63203 2538:464c6c6692d6
5 5
6 // Once this is loaded and parsed, begin execution 6 // Once this is loaded and parsed, begin execution
7 loadInterface(); 7 loadInterface();
8 8
9 function loadInterface() { 9 function loadInterface() {
10 // Use this to do any one-time page / element construction. For instance, placing any stationary text objects, 10 // Use this to do any one-time page / element construction. For instance, placing any stationary text objects,
11 // holding div's, or setting up any nodes which are present for the entire test sequence 11 // holding div's, or setting up any nodes which are present for the entire test sequence
12 12
13 interfaceContext.insertPoint.innerHTML = ""; // Clear the current schema 13 interfaceContext.insertPoint.innerHTML = ""; // Clear the current schema
14 14
15 Interface.prototype.checkScaleRange = function(min, max) { 15 Interface.prototype.checkScaleRange = function (min, max) {
16 var page = testState.getCurrentTestPage(); 16 var page = testState.getCurrentTestPage();
17 var audioObjects = audioEngineContext.audioObjects; 17 var audioObjects = audioEngineContext.audioObjects;
18 var state = true; 18 var state = true;
19 var str = "Please keep listening. "; 19 var str = "Please keep listening. ";
20 var minRanking = Infinity; 20 var minRanking = Infinity;
21 var maxRanking = -Infinity; 21 var maxRanking = -Infinity;
22 for (var ao of audioObjects) { 22 for (var ao of audioObjects) {
23 var rank = ao.interfaceDOM.getValue(); 23 var rank = ao.interfaceDOM.getValue();
24 if (rank < minRanking) {minRanking = rank;} 24 if (rank < minRanking) {
25 if (rank > maxRanking) {maxRanking = rank;} 25 minRanking = rank;
26 } 26 }
27 if (maxRanking*100 < max) { 27 if (rank > maxRanking) {
28 maxRanking = rank;
29 }
30 }
31 if (maxRanking * 100 < max) {
28 str += "At least one fragment must be selected." 32 str += "At least one fragment must be selected."
29 state = false; 33 state = false;
30 } 34 }
31 if (!state) { 35 if (!state) {
32 console.log(str); 36 console.log(str);
33 this.storeErrorNode(str); 37 this.storeErrorNode(str);
34 interfaceContext.lightbox.post("Message",str); 38 interfaceContext.lightbox.post("Message", str);
35 } 39 }
36 return state; 40 return state;
37 } 41 }
38 42
39 // Custom comparator Object 43 // Custom comparator Object
40 Interface.prototype.comparator = null; 44 Interface.prototype.comparator = null;
41 45
42 // The injection point into the HTML page 46 // The injection point into the HTML page
43 interfaceContext.insertPoint = document.getElementById("topLevelBody"); 47 interfaceContext.insertPoint = document.getElementById("topLevelBody");
44 var testContent = document.createElement('div'); 48 var testContent = document.createElement('div');
45 testContent.id = 'testContent'; 49 testContent.id = 'testContent';
46 50
47 // Create the top div for the Title element 51 // Create the top div for the Title element
48 var titleAttr = specification.title; 52 var titleAttr = specification.title;
49 var title = document.createElement('div'); 53 var title = document.createElement('div');
50 title.className = "title"; 54 title.className = "title";
51 title.align = "center"; 55 title.align = "center";
52 var titleSpan = document.createElement('span'); 56 var titleSpan = document.createElement('span');
53 titleSpan.id = "test-title"; 57 titleSpan.id = "test-title";
54 58
55 // Set title to that defined in XML, else set to default 59 // Set title to that defined in XML, else set to default
56 if (titleAttr != undefined) { 60 if (titleAttr != undefined) {
57 titleSpan.textContent = titleAttr; 61 titleSpan.textContent = titleAttr;
58 } else { 62 } else {
59 titleSpan.textContent = 'Listening test'; 63 titleSpan.textContent = 'Listening test';
60 } 64 }
61 // Insert the titleSpan element into the title div element. 65 // Insert the titleSpan element into the title div element.
62 title.appendChild(titleSpan); 66 title.appendChild(titleSpan);
63 67
64 var pagetitle = document.createElement('div'); 68 var pagetitle = document.createElement('div');
65 pagetitle.className = "pageTitle"; 69 pagetitle.className = "pageTitle";
66 pagetitle.align = "center"; 70 pagetitle.align = "center";
67 var titleSpan = document.createElement('span'); 71 var titleSpan = document.createElement('span');
68 titleSpan.id = "pageTitle"; 72 titleSpan.id = "pageTitle";
69 pagetitle.appendChild(titleSpan); 73 pagetitle.appendChild(titleSpan);
70 74
71 // Create Interface buttons! 75 // Create Interface buttons!
72 var interfaceButtons = document.createElement('div'); 76 var interfaceButtons = document.createElement('div');
73 interfaceButtons.id = 'interface-buttons'; 77 interfaceButtons.id = 'interface-buttons';
74 interfaceButtons.style.height = '25px'; 78 interfaceButtons.style.height = '25px';
75 79
76 // Create playback start/stop points 80 // Create playback start/stop points
77 var playback = document.createElement("button"); 81 var playback = document.createElement("button");
78 playback.innerHTML = 'Stop'; 82 playback.innerHTML = 'Stop';
79 playback.id = 'playback-button'; 83 playback.id = 'playback-button';
80 playback.style.float = 'left'; 84 playback.style.float = 'left';
81 // onclick function. Check if it is playing or not, call the correct function in the 85 // onclick function. Check if it is playing or not, call the correct function in the
82 // audioEngine, change the button text to reflect the next state. 86 // audioEngine, change the button text to reflect the next state.
83 playback.onclick = function() { 87 playback.onclick = function () {
84 if (audioEngineContext.status == 1) { 88 if (audioEngineContext.status == 1) {
85 audioEngineContext.stop(); 89 audioEngineContext.stop();
86 this.innerHTML = 'Stop'; 90 this.innerHTML = 'Stop';
87 var time = audioEngineContext.timer.getTestTime(); 91 var time = audioEngineContext.timer.getTestTime();
88 console.log('Stopped at ' + time); // DEBUG/SAFETY 92 console.log('Stopped at ' + time); // DEBUG/SAFETY
89 } 93 }
90 }; 94 };
91 // Append the interface buttons into the interfaceButtons object. 95 // Append the interface buttons into the interfaceButtons object.
92 interfaceButtons.appendChild(playback); 96 interfaceButtons.appendChild(playback);
93 97
94 // Global parent for the comment boxes on the page 98 // Global parent for the comment boxes on the page
95 var feedbackHolder = document.createElement('div'); 99 var feedbackHolder = document.createElement('div');
96 feedbackHolder.id = 'feedbackHolder'; 100 feedbackHolder.id = 'feedbackHolder';
97 101
98 // Construct the AB Boxes 102 // Construct the AB Boxes
99 var boxes = document.createElement('div'); 103 var boxes = document.createElement('div');
100 boxes.align = "center"; 104 boxes.align = "center";
101 boxes.id = "box-holders"; 105 boxes.id = "box-holders";
102 boxes.style.float = "left"; 106 boxes.style.float = "left";
103 107
104 var submit = document.createElement('button'); 108 var submit = document.createElement('button');
105 submit.id = "submit"; 109 submit.id = "submit";
106 submit.onclick = buttonSubmitClick; 110 submit.onclick = buttonSubmitClick;
107 submit.className = "big-button"; 111 submit.className = "big-button";
108 submit.textContent = "submit"; 112 submit.textContent = "submit";
109 submit.style.position = "relative"; 113 submit.style.position = "relative";
110 submit.style.left = (window.innerWidth-250)/2 + 'px'; 114 submit.style.left = (window.innerWidth - 250) / 2 + 'px';
111 115
112 feedbackHolder.appendChild(boxes); 116 feedbackHolder.appendChild(boxes);
113 117
114 // Create holder for comment boxes 118 // Create holder for comment boxes
115 var comments = document.createElement("div"); 119 var comments = document.createElement("div");
116 comments.id = "comment-box-holder"; 120 comments.id = "comment-box-holder";
117 121
118 // Inject into HTML 122 // Inject into HTML
119 testContent.appendChild(title); // Insert the title 123 testContent.appendChild(title); // Insert the title
120 testContent.appendChild(pagetitle); 124 testContent.appendChild(pagetitle);
121 testContent.appendChild(interfaceButtons); 125 testContent.appendChild(interfaceButtons);
122 testContent.appendChild(feedbackHolder); 126 testContent.appendChild(feedbackHolder);
123 testContent.appendChild(submit); 127 testContent.appendChild(submit);
124 testContent.appendChild(comments); 128 testContent.appendChild(comments);
125 interfaceContext.insertPoint.appendChild(testContent); 129 interfaceContext.insertPoint.appendChild(testContent);
126 130
127 // Load the full interface 131 // Load the full interface
128 testState.initialise(); 132 testState.initialise();
129 testState.advanceState(); 133 testState.advanceState();
130 }; 134 };
131 135
132 function loadTest(page) 136 function loadTest(page) {
133 { 137 // Called each time a new test page is to be build. The page specification node is the only item passed in
134 // Called each time a new test page is to be build. The page specification node is the only item passed in
135 document.getElementById('box-holders').innerHTML = ""; 138 document.getElementById('box-holders').innerHTML = "";
136 139
137 var interfaceObj = page.interfaces; 140 var interfaceObj = page.interfaces;
138 if (interfaceObj.length > 1) 141 if (interfaceObj.length > 1) {
139 { 142 console.log("WARNING - This interface only supports one <interface> node per page. Using first interface node");
140 console.log("WARNING - This interface only supports one <interface> node per page. Using first interface node"); 143 }
141 } 144 interfaceObj = interfaceObj[0];
142 interfaceObj = interfaceObj[0]; 145
143
144 var commentHolder = document.getElementById("comment-box-holder"); 146 var commentHolder = document.getElementById("comment-box-holder");
145 commentHolder.innerHTML = ""; 147 commentHolder.innerHTML = "";
146 148
147 // Set the page title 149 // Set the page title
148 if (typeof page.title == "string" && page.title.length > 0) { 150 if (typeof page.title == "string" && page.title.length > 0) {
149 document.getElementById("test-title").textContent = page.title 151 document.getElementById("test-title").textContent = page.title
150 } 152 }
151 153
152 if(interfaceObj.title != null) 154 if (interfaceObj.title != null) {
153 { 155 document.getElementById("pageTitle").textContent = interfaceObj.title;
154 document.getElementById("pageTitle").textContent = interfaceObj.title; 156 }
155 } 157
156
157 interfaceContext.comparator = new comparator(page); 158 interfaceContext.comparator = new comparator(page);
158 159
159 var interfaceOptions = specification.interfaces.options.concat(interfaceObj.options); 160 var interfaceOptions = specification.interfaces.options.concat(interfaceObj.options);
160 for (var option of interfaceOptions) 161 for (var option of interfaceOptions) {
161 { 162 if (option.type == "show") {
162 if (option.type == "show") 163 switch (option.name) {
163 {
164 switch(option.name) {
165 case "playhead": 164 case "playhead":
166 var playbackHolder = document.getElementById('playback-holder'); 165 var playbackHolder = document.getElementById('playback-holder');
167 if (playbackHolder == null) 166 if (playbackHolder == null) {
168 {
169 playbackHolder = document.createElement('div'); 167 playbackHolder = document.createElement('div');
170 playbackHolder.style.width = "100%"; 168 playbackHolder.style.width = "100%";
171 playbackHolder.style.float = "left"; 169 playbackHolder.style.float = "left";
172 playbackHolder.align = 'center'; 170 playbackHolder.align = 'center';
173 playbackHolder.appendChild(interfaceContext.playhead.object); 171 playbackHolder.appendChild(interfaceContext.playhead.object);
174 feedbackHolder.appendChild(playbackHolder); 172 feedbackHolder.appendChild(playbackHolder);
175 } 173 }
176 break; 174 break;
177 case "page-count": 175 case "page-count":
178 var pagecountHolder = document.getElementById('page-count'); 176 var pagecountHolder = document.getElementById('page-count');
179 if (pagecountHolder == null) 177 if (pagecountHolder == null) {
180 {
181 pagecountHolder = document.createElement('div'); 178 pagecountHolder = document.createElement('div');
182 pagecountHolder.id = 'page-count'; 179 pagecountHolder.id = 'page-count';
183 } 180 }
184 pagecountHolder.innerHTML = '<span>Page '+(testState.stateIndex+1)+' of '+testState.stateMap.length+'</span>'; 181 pagecountHolder.innerHTML = '<span>Page ' + (testState.stateIndex + 1) + ' of ' + testState.stateMap.length + '</span>';
185 var inject = document.getElementById('interface-buttons'); 182 var inject = document.getElementById('interface-buttons');
186 inject.appendChild(pagecountHolder); 183 inject.appendChild(pagecountHolder);
187 break; 184 break;
188 case "volume": 185 case "volume":
189 if (document.getElementById('master-volume-holder') == null) 186 if (document.getElementById('master-volume-holder') == null) {
190 {
191 feedbackHolder.appendChild(interfaceContext.volume.object); 187 feedbackHolder.appendChild(interfaceContext.volume.object);
192 } 188 }
193 break; 189 break;
194 case "comments": 190 case "comments":
195 // Generate one comment box per presented page 191 // Generate one comment box per presented page
196 for (var element of audioEngineContext.audioObjects) 192 for (var element of audioEngineContext.audioObjects) {
197 {
198 interfaceContext.commentBoxes.createCommentBox(element); 193 interfaceContext.commentBoxes.createCommentBox(element);
199 } 194 }
200 interfaceContext.commentBoxes.showCommentBoxes(commentHolder,true); 195 interfaceContext.commentBoxes.showCommentBoxes(commentHolder, true);
201 break; 196 break;
202 } 197 }
203 } 198 }
204 } 199 }
205 200
206 $(page.commentQuestions).each(function(index,element) { 201 $(page.commentQuestions).each(function (index, element) {
207 var node = interfaceContext.createCommentQuestion(element); 202 var node = interfaceContext.createCommentQuestion(element);
208 commentHolder.appendChild(node.holder); 203 commentHolder.appendChild(node.holder);
209 }); 204 });
210 205
211 resizeWindow(null); 206 resizeWindow(null);
212 } 207 }
213 208
214 function comparator(page) 209 function comparator(page) {
215 {
216 // Build prototype constructor 210 // Build prototype constructor
217 this.interfaceObject = function(element,label) 211 this.interfaceObject = function (element, label) {
218 {
219 // An example node, you can make this however you want for each audioElement. 212 // An example node, you can make this however you want for each audioElement.
220 // However, every audioObject (audioEngineContext.audioObject) MUST have an interface object with the following 213 // However, every audioObject (audioEngineContext.audioObject) MUST have an interface object with the following
221 // You attach them by calling audioObject.bindInterface( ) 214 // You attach them by calling audioObject.bindInterface( )
222 this.parent = element; 215 this.parent = element;
223 this.id = element.id; 216 this.id = element.id;
224 this.value = 0; 217 this.value = 0;
225 this.disabled = true; 218 this.disabled = true;
226 this.box = document.createElement('div'); 219 this.box = document.createElement('div');
227 this.box.className = 'comparator-holder'; 220 this.box.className = 'comparator-holder';
228 this.box.setAttribute('track-id',element.id); 221 this.box.setAttribute('track-id', element.id);
229 this.box.id = 'comparator-'+label; 222 this.box.id = 'comparator-' + label;
230 this.selector = document.createElement('div'); 223 this.selector = document.createElement('div');
231 this.selector.className = 'comparator-selector disabled'; 224 this.selector.className = 'comparator-selector disabled';
232 var selectorText = document.createElement('span'); 225 var selectorText = document.createElement('span');
233 selectorText.textContent = label; 226 selectorText.textContent = label;
234 this.selector.appendChild(selectorText); 227 this.selector.appendChild(selectorText);
235 this.playback = document.createElement('button'); 228 this.playback = document.createElement('button');
236 this.playback.className = 'comparator-button'; 229 this.playback.className = 'comparator-button';
237 this.playback.disabled = true; 230 this.playback.disabled = true;
238 this.playback.textContent = "Listen"; 231 this.playback.textContent = "Listen";
239 this.box.appendChild(this.selector); 232 this.box.appendChild(this.selector);
240 this.box.appendChild(this.playback); 233 this.box.appendChild(this.playback);
241 this.selector.onclick = function(event) 234 this.selector.onclick = function (event) {
242 {
243 var label = event.currentTarget.children[0].textContent; 235 var label = event.currentTarget.children[0].textContent;
244 if (label == "X" || label == "x") {return;} 236 if (label == "X" || label == "x") {
245 var time = audioEngineContext.timer.getTestTime(); 237 return;
246 if ($(event.currentTarget).hasClass('disabled')) 238 }
247 { 239 var time = audioEngineContext.timer.getTestTime();
248 console.log("Please wait until sample has loaded"); 240 if ($(event.currentTarget).hasClass('disabled')) {
249 return; 241 console.log("Please wait until sample has loaded");
250 } 242 return;
251 if (audioEngineContext.status == 0) 243 }
252 { 244 if (audioEngineContext.status == 0) {
253 interfaceContext.lightbox.post("Message", "Please listen to the samples before making a selection"); 245 interfaceContext.lightbox.post("Message", "Please listen to the samples before making a selection");
254 console.log("Please listen to the samples before making a selection"); 246 console.log("Please listen to the samples before making a selection");
255 return; 247 return;
256 } 248 }
257 var id = event.currentTarget.parentElement.getAttribute('track-id'); 249 var id = event.currentTarget.parentElement.getAttribute('track-id');
258 interfaceContext.comparator.selected = id; 250 interfaceContext.comparator.selected = id;
259 if ($(event.currentTarget).hasClass("selected")) { 251 if ($(event.currentTarget).hasClass("selected")) {
260 $(".comparator-selector").removeClass('selected'); 252 $(".comparator-selector").removeClass('selected');
261 for (var i=0; i<interfaceContext.comparator.pair.length; i++) 253 for (var i = 0; i < interfaceContext.comparator.pair.length; i++) {
262 {
263 var obj = interfaceContext.comparator.pair[i]; 254 var obj = interfaceContext.comparator.pair[i];
264 obj.parent.metric.moved(time,0); 255 obj.parent.metric.moved(time, 0);
265 obj.value = 0; 256 obj.value = 0;
266 } 257 }
267 } else { 258 } else {
268 $(".comparator-selector").removeClass('selected'); 259 $(".comparator-selector").removeClass('selected');
269 $(event.currentTarget).addClass('selected'); 260 $(event.currentTarget).addClass('selected');
270 for (var i=0; i<interfaceContext.comparator.pair.length; i++) 261 for (var i = 0; i < interfaceContext.comparator.pair.length; i++) {
271 {
272 var obj = interfaceContext.comparator.pair[i]; 262 var obj = interfaceContext.comparator.pair[i];
273 if (i == id) { 263 if (i == id) {
274 obj.value = 1; 264 obj.value = 1;
275 } else { 265 } else {
276 obj.value = 0; 266 obj.value = 0;
277 } 267 }
278 obj.parent.metric.moved(time,obj.value); 268 obj.parent.metric.moved(time, obj.value);
279 } 269 }
280 console.log("Selected "+id+' ('+time+')'); 270 console.log("Selected " + id + ' (' + time + ')');
281 } 271 }
282 }; 272 };
283 this.playback.setAttribute("playstate","ready"); 273 this.playback.setAttribute("playstate", "ready");
284 this.playback.onclick = function(event) 274 this.playback.onclick = function (event) {
285 { 275 var id = event.currentTarget.parentElement.getAttribute('track-id');
286 var id = event.currentTarget.parentElement.getAttribute('track-id'); 276 if (event.currentTarget.getAttribute("playstate") == "ready") {
287 if (event.currentTarget.getAttribute("playstate") == "ready")
288 {
289 audioEngineContext.play(id); 277 audioEngineContext.play(id);
290 } else if (event.currentTarget.getAttribute("playstate") == "playing") { 278 } else if (event.currentTarget.getAttribute("playstate") == "playing") {
291 audioEngineContext.stop(); 279 audioEngineContext.stop();
292 } 280 }
293 281
294 }; 282 };
295 this.enable = function() 283 this.enable = function () {
296 {
297 // This is used to tell the interface object that playback of this node is ready 284 // This is used to tell the interface object that playback of this node is ready
298 if (this.parent.state == 1) 285 if (this.parent.state == 1) {
299 { 286 $(this.selector).removeClass('disabled');
300 $(this.selector).removeClass('disabled'); 287 this.playback.disabled = false;
301 this.playback.disabled = false; 288 }
302 } 289 };
303 }; 290 this.updateLoading = function (progress) {
304 this.updateLoading = function(progress)
305 {
306 // progress is a value from 0 to 100 indicating the current download state of media files 291 // progress is a value from 0 to 100 indicating the current download state of media files
307 if (progress != 100) 292 if (progress != 100) {
308 { 293 progress = String(progress);
309 progress = String(progress); 294 progress = progress.split('.')[0];
310 progress = progress.split('.')[0]; 295 this.playback.textContent = progress + '%';
311 this.playback.textContent = progress+'%'; 296 } else {
312 } else { 297 this.playback.textContent = "Play";
313 this.playback.textContent = "Play"; 298 }
314 } 299 };
315 }; 300 this.error = function () {
316 this.error = function() {
317 // audioObject has an error!! 301 // audioObject has an error!!
318 this.playback.textContent = "Error"; 302 this.playback.textContent = "Error";
319 $(this.playback).addClass("error-colour"); 303 $(this.playback).addClass("error-colour");
320 }; 304 };
321 this.startPlayback = function() 305 this.startPlayback = function () {
322 {
323 if (this.parent.specification.parent.playOne || specification.playOne) { 306 if (this.parent.specification.parent.playOne || specification.playOne) {
324 $('.comparator-button').text('Wait'); 307 $('.comparator-button').text('Wait');
325 $('.comparator-button').attr("disabled","true"); 308 $('.comparator-button').attr("disabled", "true");
326 $(this.playback).removeAttr("disabled"); 309 $(this.playback).removeAttr("disabled");
327 } else { 310 } else {
328 $('.comparator-button').text('Listen'); 311 $('.comparator-button').text('Listen');
329 } 312 }
330 $(this.playback).text('Stop'); 313 $(this.playback).text('Stop');
331 this.playback.setAttribute("playstate","playing"); 314 this.playback.setAttribute("playstate", "playing");
332 }; 315 };
333 this.stopPlayback = function() 316 this.stopPlayback = function () {
334 {
335 if (this.playback.getAttribute("playstate") == "playing") { 317 if (this.playback.getAttribute("playstate") == "playing") {
336 $('.comparator-button').text('Listen'); 318 $('.comparator-button').text('Listen');
337 $('.comparator-button').removeAttr("disabled"); 319 $('.comparator-button').removeAttr("disabled");
338 this.playback.setAttribute("playstate","ready"); 320 this.playback.setAttribute("playstate", "ready");
339 } 321 }
340 }; 322 };
341 this.getValue = function() 323 this.getValue = function () {
342 {
343 // Return the current value of the object. If there is no value, return 0 324 // Return the current value of the object. If there is no value, return 0
344 return this.value; 325 return this.value;
345 }; 326 };
346 this.getPresentedId = function() 327 this.getPresentedId = function () {
347 {
348 // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale 328 // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale
349 return this.selector.children[0].textContent; 329 return this.selector.children[0].textContent;
350 }; 330 };
351 this.canMove = function() 331 this.canMove = function () {
352 {
353 // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale. 332 // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale.
354 // These are checked primarily if the interface check option 'fragmentMoved' is enabled. 333 // These are checked primarily if the interface check option 'fragmentMoved' is enabled.
355 return false; 334 return false;
356 }; 335 };
357 this.exportXMLDOM = function(audioObject) { 336 this.exportXMLDOM = function (audioObject) {
358 // Called by the audioObject holding this element to export the interface <value> node. 337 // Called by the audioObject holding this element to export the interface <value> node.
359 // If there is no value node (such as outside reference), return null 338 // If there is no value node (such as outside reference), return null
360 // If there are multiple value nodes (such as multiple scale / 2D scales), return an array of nodes with each value node having an 'interfaceName' attribute 339 // If there are multiple value nodes (such as multiple scale / 2D scales), return an array of nodes with each value node having an 'interfaceName' attribute
361 // Use storage.document.createElement('value'); to generate the XML node. 340 // Use storage.document.createElement('value'); to generate the XML node.
362 var node = storage.document.createElement('value'); 341 var node = storage.document.createElement('value');
363 node.textContent = this.value; 342 node.textContent = this.value;
364 return node; 343 return node;
365 344
366 }; 345 };
367 this.error = function() { 346 this.error = function () {
368 // If there is an error with the audioObject, this will be called to indicate a failure 347 // If there is an error with the audioObject, this will be called to indicate a failure
369 } 348 }
370 }; 349 };
371 // Ensure there are only two comparisons per page 350 // Ensure there are only two comparisons per page
372 if (page.audioElements.length != 2) { 351 if (page.audioElements.length != 2) {
373 console.error('FATAL - There must be 2 <audioelement> nodes on each <page>: '+page.id); 352 console.error('FATAL - There must be 2 <audioelement> nodes on each <page>: ' + page.id);
374 return; 353 return;
375 } 354 }
376 // Build the three audio elements 355 // Build the three audio elements
377 this.pair = []; 356 this.pair = [];
378 this.X = null; 357 this.X = null;
379 this.boxHolders = document.getElementById('box-holders'); 358 this.boxHolders = document.getElementById('box-holders');
380 for (var index=0; index<page.audioElements.length; index++) { 359 for (var index = 0; index < page.audioElements.length; index++) {
381 var element = page.audioElements[index]; 360 var element = page.audioElements[index];
382 if (element.type != 'normal') 361 if (element.type != 'normal') {
383 { 362 console.log("WARNING - ABX can only have normal elements. Page " + page.id + ", Element " + element.id);
384 console.log("WARNING - ABX can only have normal elements. Page "+page.id+", Element "+element.id);
385 element.type = "normal"; 363 element.type = "normal";
386 } 364 }
387 var audioObject = audioEngineContext.newTrack(element); 365 var audioObject = audioEngineContext.newTrack(element);
388 var label; 366 var label;
389 switch(audioObject.specification.parent.label) { 367 switch (audioObject.specification.parent.label) {
390 case "none": 368 case "none":
391 label = ""; 369 label = "";
392 break; 370 break;
393 case "number": 371 case "number":
394 label = ""+index; 372 label = "" + index;
395 break; 373 break;
396 case "letter": 374 case "letter":
397 label = String.fromCharCode(97 + index); 375 label = String.fromCharCode(97 + index);
398 break; 376 break;
399 default: 377 default:
400 label = String.fromCharCode(65 + index); 378 label = String.fromCharCode(65 + index);
401 break; 379 break;
402 } 380 }
403 var node = new this.interfaceObject(audioObject,label); 381 var node = new this.interfaceObject(audioObject, label);
404 audioObject.bindInterface(node); 382 audioObject.bindInterface(node);
405 this.pair.push(node); 383 this.pair.push(node);
406 this.boxHolders.appendChild(node.box); 384 this.boxHolders.appendChild(node.box);
407 } 385 }
408 var elementId = Math.floor(Math.random() * 2); //Randomly pick A or B to be X 386 var elementId = Math.floor(Math.random() * 2); //Randomly pick A or B to be X
409 var element = new page.audioElementNode(specification); 387 var element = new page.audioElementNode(specification);
410 for (var atr in page.audioElements[elementId]) { 388 for (var atr in page.audioElements[elementId]) {
411 eval("element."+atr+" = page.audioElements[elementId]."+atr); 389 eval("element." + atr + " = page.audioElements[elementId]." + atr);
412 } 390 }
413 element.id += "-X"; 391 element.id += "-X";
414 if (typeof element.name == "string") {element.name+="-X";} 392 if (typeof element.name == "string") {
393 element.name += "-X";
394 }
415 page.audioElements.push(element); 395 page.audioElements.push(element);
416 // Create the save place-holder for the 'X' element 396 // Create the save place-holder for the 'X' element
417 var root = testState.currentStore.XMLDOM; 397 var root = testState.currentStore.XMLDOM;
418 var aeNode = storage.document.createElement('audioelement'); 398 var aeNode = storage.document.createElement('audioelement');
419 aeNode.setAttribute('ref',element.id); 399 aeNode.setAttribute('ref', element.id);
420 if (typeof element.name == "string"){aeNode.setAttribute('name',element.name);} 400 if (typeof element.name == "string") {
421 aeNode.setAttribute('type','normal'); 401 aeNode.setAttribute('name', element.name);
422 aeNode.setAttribute('url',element.url); 402 }
423 aeNode.setAttribute('gain',element.gain); 403 aeNode.setAttribute('type', 'normal');
404 aeNode.setAttribute('url', element.url);
405 aeNode.setAttribute('gain', element.gain);
424 aeNode.appendChild(storage.document.createElement('metric')); 406 aeNode.appendChild(storage.document.createElement('metric'));
425 root.appendChild(aeNode); 407 root.appendChild(aeNode);
426 // Build the 'X' element 408 // Build the 'X' element
427 var audioObject = audioEngineContext.newTrack(element); 409 var audioObject = audioEngineContext.newTrack(element);
428 var label; 410 var label;
429 switch(audioObject.specification.parent.label) { 411 switch (audioObject.specification.parent.label) {
430 case "letter": 412 case "letter":
431 label = "x"; 413 label = "x";
432 break; 414 break;
433 default: 415 default:
434 label = "X"; 416 label = "X";
435 break; 417 break;
436 } 418 }
437 var node = new this.interfaceObject(audioObject,label); 419 var node = new this.interfaceObject(audioObject, label);
438 node.box.children[0].classList.add('inactive'); 420 node.box.children[0].classList.add('inactive');
439 audioObject.bindInterface(node); 421 audioObject.bindInterface(node);
440 this.X = node; 422 this.X = node;
441 this.boxHolders.appendChild(node.box); 423 this.boxHolders.appendChild(node.box);
442 } 424 }
443 425
444 function resizeWindow(event) 426 function resizeWindow(event) {
445 { 427 document.getElementById('submit').style.left = (window.innerWidth - 250) / 2 + 'px';
446 document.getElementById('submit').style.left = (window.innerWidth-250)/2 + 'px'; 428 var numObj = 3;
447 var numObj = 3; 429 var boxW = numObj * 312;
448 var boxW = numObj*312;
449 var diff = window.innerWidth - boxW; 430 var diff = window.innerWidth - boxW;
450 while (diff < 0) 431 while (diff < 0) {
451 { 432 numObj = Math.ceil(numObj / 2);
452 numObj = Math.ceil(numObj/2); 433 boxW = numObj * 312;
453 boxW = numObj*312;
454 diff = window.innerWidth - boxW; 434 diff = window.innerWidth - boxW;
455 } 435 }
456 document.getElementById('box-holders').style.marginLeft = diff/2 + 'px'; 436 document.getElementById('box-holders').style.marginLeft = diff / 2 + 'px';
457 document.getElementById('box-holders').style.marginRight = diff/2 + 'px'; 437 document.getElementById('box-holders').style.marginRight = diff / 2 + 'px';
458 document.getElementById('box-holders').style.width = boxW + 'px'; 438 document.getElementById('box-holders').style.width = boxW + 'px';
459 } 439 }
460 440
461 function buttonSubmitClick() 441 function buttonSubmitClick() {
462 { 442 var checks = [];
463 var checks = []; 443 checks = checks.concat(testState.currentStateMap.interfaces[0].options);
464 checks = checks.concat(testState.currentStateMap.interfaces[0].options); 444 checks = checks.concat(specification.interfaces.options);
465 checks = checks.concat(specification.interfaces.options); 445 var canContinue = true;
466 var canContinue = true; 446
467 447 for (var i = 0; i < checks.length; i++) {
468 for (var i=0; i<checks.length; i++) { 448 if (checks[i].type == 'check') {
469 if (checks[i].type == 'check') 449 switch (checks[i].name) {
470 { 450 case 'fragmentPlayed':
471 switch(checks[i].name) { 451 // Check if all fragments have been played
472 case 'fragmentPlayed': 452 var checkState = interfaceContext.checkAllPlayed();
473 // Check if all fragments have been played 453 if (checkState == false) {
474 var checkState = interfaceContext.checkAllPlayed(); 454 canContinue = false;
475 if (checkState == false) {canContinue = false;} 455 }
476 break; 456 break;
477 case 'fragmentFullPlayback': 457 case 'fragmentFullPlayback':
478 // Check all fragments have been played to their full length 458 // Check all fragments have been played to their full length
479 var checkState = interfaceContext.checkFragmentsFullyPlayed(); 459 var checkState = interfaceContext.checkFragmentsFullyPlayed();
480 if (checkState == false) {canContinue = false;} 460 if (checkState == false) {
481 break; 461 canContinue = false;
482 case 'fragmentMoved': 462 }
483 // Check all fragment sliders have been moved. 463 break;
484 var checkState = interfaceContext.checkAllMoved(); 464 case 'fragmentMoved':
485 if (checkState == false) {canContinue = false;} 465 // Check all fragment sliders have been moved.
486 break; 466 var checkState = interfaceContext.checkAllMoved();
487 case 'fragmentComments': 467 if (checkState == false) {
488 // Check all fragment sliders have been moved. 468 canContinue = false;
489 var checkState = interfaceContext.checkAllCommented(); 469 }
490 if (checkState == false) {canContinue = false;} 470 break;
491 break; 471 case 'fragmentComments':
492 case 'scalerange': 472 // Check all fragment sliders have been moved.
493 // Check the scale has been used effectively 473 var checkState = interfaceContext.checkAllCommented();
494 var checkState = interfaceContext.checkScaleRange(checks[i].min,checks[i].max); 474 if (checkState == false) {
495 if (checkState == false) {canContinue = false;} 475 canContinue = false;
496 break; 476 }
497 default: 477 break;
498 console.log("WARNING - Check option "+checks[i].check+" is not supported on this interface"); 478 case 'scalerange':
499 break; 479 // Check the scale has been used effectively
500 } 480 var checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max);
501 481 if (checkState == false) {
502 } 482 canContinue = false;
503 if (!canContinue) {break;} 483 }
504 } 484 break;
505 if (canContinue) 485 default:
506 { 486 console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface");
507 if (audioEngineContext.status == 1) { 487 break;
508 var playback = document.getElementById('playback-button'); 488 }
509 playback.click(); 489
510 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options 490 }
511 } else 491 if (!canContinue) {
512 { 492 break;
513 if (audioEngineContext.timer.testStarted == false) 493 }
514 { 494 }
515 interfaceContext.lightbox.post("Warning",'You have not started the test! Please listen to a sample to begin the test!'); 495 if (canContinue) {
516 return; 496 if (audioEngineContext.status == 1) {
517 } 497 var playback = document.getElementById('playback-button');
518 } 498 playback.click();
519 testState.advanceState(); 499 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options
520 } 500 } else {
501 if (audioEngineContext.timer.testStarted == false) {
502 interfaceContext.lightbox.post("Warning", 'You have not started the test! Please listen to a sample to begin the test!');
503 return;
504 }
505 }
506 testState.advanceState();
507 }
521 } 508 }
522 509
523 function pageXMLSave(store, pageSpecification) 510 function pageXMLSave(store, pageSpecification) {
524 { 511 // MANDATORY
525 // MANDATORY 512 // Saves a specific test page
526 // Saves a specific test page 513 // You can use this space to add any extra nodes to your XML <audioHolder> saves
527 // You can use this space to add any extra nodes to your XML <audioHolder> saves 514 // Get the current <page> information in store (remember to appendChild your data to it)
528 // Get the current <page> information in store (remember to appendChild your data to it) 515 // pageSpecification is the current page node configuration
529 // pageSpecification is the current page node configuration 516 // To create new XML nodes, use storage.document.createElement();
530 // To create new XML nodes, use storage.document.createElement();
531 } 517 }