annotate interfaces/timeline.js @ 2607:342ef7948c47

#37. All interfaces use interfaceContext.getLabel to generate labels
author Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk>
date Mon, 14 Nov 2016 16:12:34 +0000
parents c8e6991951ad
children e3cf3c24149e
rev   line source
nicholas@2479 1 /**
nicholas@2479 2 * WAET Timeline
nicholas@2479 3 * This interface plots a waveform timeline per audio fragment on a page. Clicking on the fragment will generate a comment box for processing.
nicholas@2479 4 */
nicholas@2479 5
nicholas@2479 6 // Once this is loaded and parsed, begin execution
nicholas@2479 7 loadInterface();
nicholas@2479 8
nicholas@2479 9 function loadInterface() {
nicholas@2481 10 // Use this to do any one-time page / element construction. For instance, placing any stationary text objects,
nicholas@2481 11 // holding div's, or setting up any nodes which are present for the entire test sequence
nicholas@2481 12
nicholas@2479 13 interfaceContext.insertPoint.innerHTML = ""; // Clear the current schema
nicholas@2481 14
nicholas@2479 15 interfaceContext.insertPoint = document.getElementById("topLevelBody");
nicholas@2479 16 var testContent = document.createElement("div");
nicholas@2481 17
nicholas@2479 18 // Create the top div and Title element
nicholas@2479 19 var title = document.createElement("div");
nicholas@2479 20 title.className = "title";
nicholas@2479 21 title.align = "center";
nicholas@2479 22 var titleSpan = document.createElement("span");
nicholas@2479 23 titleSpan.id = "test-title";
nicholas@2479 24 titleSpan.textContent = "Listening Test";
nicholas@2479 25 title.appendChild(titleSpan);
nicholas@2481 26
nicholas@2479 27 var pagetitle = document.createElement("div");
nicholas@2479 28 pagetitle.className = "pageTitle";
nicholas@2479 29 pagetitle.align = "center";
nicholas@2479 30 titleSpan = document.createElement("span");
nicholas@2479 31 titleSpan.id = "page-title";
nicholas@2479 32 pagetitle.appendChild(titleSpan);
nicholas@2481 33
nicholas@2479 34 // Create Interface buttons
nicholas@2479 35 var interfaceButtons = document.createElement("div");
nicholas@2479 36 interfaceButtons.id = 'interface-buttons';
nicholas@2479 37 interfaceButtons.style.height = "25px";
nicholas@2481 38
nicholas@2479 39 // Create playback start/stop points
nicholas@2479 40 var playback = document.createElement("button");
nicholas@2479 41 playback.innerHTML = "Stop";
nicholas@2479 42 playback.id = "playback-button";
nicholas@2481 43 playback.onclick = function () {
nicholas@2479 44 if (audioEngineContext.status == 1) {
nicholas@2479 45 audioEngineContext.stop();
nicholas@2479 46 this.innerHTML = "Stop";
nicholas@2479 47 var time = audioEngineContext.timer.getTestTime();
nicholas@2481 48 console.log("Stopped at " + time);
nicholas@2479 49 }
nicholas@2479 50 };
nicholas@2479 51 // Create Submit (save) button
nicholas@2481 52 var submit = document.createElement("button");
nicholas@2481 53 submit.innerHTML = 'Next';
nicholas@2481 54 submit.onclick = buttonSubmitClick;
nicholas@2481 55 submit.id = 'submit-button';
nicholas@2481 56 submit.style.float = 'left';
nicholas@2481 57 // Append the interface buttons into the interfaceButtons object.
nicholas@2481 58 interfaceButtons.appendChild(playback);
nicholas@2481 59 interfaceButtons.appendChild(submit);
nicholas@2481 60
nicholas@2479 61 // Create outside reference holder
nicholas@2479 62 var outsideRef = document.createElement("div");
nicholas@2479 63 outsideRef.id = "outside-reference-holder";
nicholas@2481 64
nicholas@2479 65 // Create content point
nicholas@2479 66 var content = document.createElement("div");
nicholas@2479 67 content.id = "timeline-test-content";
nicholas@2481 68
nicholas@2479 69 //Inject
nicholas@2479 70 testContent.appendChild(title);
nicholas@2479 71 testContent.appendChild(pagetitle);
nicholas@2479 72 testContent.appendChild(interfaceButtons);
nicholas@2479 73 testContent.appendChild(outsideRef);
nicholas@2479 74 testContent.appendChild(content);
nicholas@2479 75 interfaceContext.insertPoint.appendChild(testContent);
nicholas@2481 76
nicholas@2479 77 // Load the full interface
nicholas@2481 78 testState.initialise();
nicholas@2481 79 testState.advanceState();
nicholas@2479 80 };
nicholas@2479 81
nicholas@2481 82 function loadTest(page) {
nicholas@2481 83 // Called each time a new test page is to be build. The page specification node is the only item passed in
nicholas@2479 84 var content = document.getElementById("timeline-test-content");
nicholas@2479 85 content.innerHTML = "";
nicholas@2479 86 var interfaceObj = page.interfaces;
nicholas@2481 87 if (interfaceObj.length > 1) {
nicholas@2479 88 console.log("WARNING - This interface only supports one <interface> node per page. Using first interface node");
nicholas@2479 89 }
nicholas@2479 90 interfaceObj = interfaceObj[0];
nicholas@2481 91
nicholas@2479 92 //Set the page title
nicholas@2481 93 if (typeof page.title == "string" && page.title.length > 0) {
nicholas@2479 94 document.getElementById("test-title").textContent = page.title;
nicholas@2479 95 }
nicholas@2481 96
nicholas@2479 97 if (interfaceObj.title != null) {
nicholas@2479 98 document.getElementById("page-title").textContent = interfaceObj.title;
nicholas@2479 99 }
nicholas@2481 100
nicholas@2479 101 // Delete outside reference
nicholas@2481 102 var outsideReferenceHolder = document.getElementById("outside-reference-holder");
nicholas@2479 103 outsideReferenceHolder.innerHTML = "";
nicholas@2481 104
nicholas@2479 105 var commentBoxPrefix = "Comment on track";
nicholas@2481 106 if (interfaceObj.commentBoxPrefix != undefined) {
nicholas@2481 107 commentBoxPrefix = interfaceObj.commentBoxPrefix;
nicholas@2481 108 }
nicholas@2607 109 var index = 0;
nicholas@2607 110 var interfaceScales = testState.currentStateMap.interfaces[0].scales;
nicholas@2607 111 var labelType = page.label;
nicholas@2607 112 if (labelType == "default") {
nicholas@2607 113 labelType = "number";
nicholas@2607 114 }
nicholas@2607 115 $(page.audioElements).each(function (pageIndex, element) {
nicholas@2479 116 var audioObject = audioEngineContext.newTrack(element);
nicholas@2479 117 if (page.audioElements.type == 'outside-reference') {
nicholas@2481 118 var refNode = interfaceContext.outsideReferenceDOM(audioObject, index, outsideReferenceHolder);
nicholas@2479 119 audioObject.bindInterface(orNode);
nicholas@2479 120 } else {
nicholas@2607 121 var label = interfaceContext.getLabel(labelType, index, page.labelStart);
nicholas@2481 122 var node = new interfaceObject(audioObject, label);
nicholas@2481 123
nicholas@2479 124 content.appendChild(node.DOM);
nicholas@2479 125 audioObject.bindInterface(node);
nicholas@2479 126 }
nicholas@2479 127 });
nicholas@2481 128
nicholas@2479 129 resizeWindow();
nicholas@2479 130 }
nicholas@2479 131
nicholas@2481 132 function interfaceObject(audioObject, labelstr) {
nicholas@2481 133 // Each audio object has a waveform guide and self-generated comments
nicholas@2479 134 this.parent = audioObject;
nicholas@2479 135 this.DOM = document.createElement("div");
nicholas@2479 136 this.DOM.className = "timeline-element";
nicholas@2479 137 this.DOM.id = audioObject.specification.id;
nicholas@2481 138
nicholas@2479 139 var root = document.createElement("div");
nicholas@2479 140 root.className = "timeline-element-content";
nicholas@2479 141 this.DOM.appendChild(root);
nicholas@2481 142
nicholas@2479 143 var label = document.createElement("div");
nicholas@2479 144 label.style.textAlign = "center";
nicholas@2479 145 var labelSpan = document.createElement("span");
nicholas@2481 146 labelSpan.textContent = "Fragment " + labelstr;
nicholas@2479 147 label.appendChild(labelSpan);
nicholas@2479 148 root.appendChild(label);
nicholas@2481 149
nicholas@2479 150 var canvasHolder = document.createElement("div");
nicholas@2479 151 canvasHolder.className = "timeline-element-canvas-holder";
nicholas@2479 152 var buttonHolder = document.createElement("div");
nicholas@2479 153 buttonHolder.className = "timeline-element-button-holder";
nicholas@2479 154 var commentHolder = document.createElement("div");
nicholas@2479 155 commentHolder.className = "timeline-element-comment-holder";
nicholas@2481 156
nicholas@2479 157 root.appendChild(canvasHolder);
nicholas@2479 158 root.appendChild(buttonHolder);
nicholas@2479 159 root.appendChild(commentHolder);
nicholas@2481 160
nicholas@2479 161 this.comments = {
nicholas@2479 162 parent: this,
nicholas@2479 163 list: [],
nicholas@2481 164 Comment: function (parent, time, str) {
nicholas@2479 165 this.parent = parent;
nicholas@2479 166 this.time = time;
nicholas@2479 167 this.DOM = document.createElement("div");
nicholas@2480 168 this.DOM.className = "comment-entry";
nicholas@2480 169 var titleHolder = document.createElement("div");
nicholas@2480 170 titleHolder.className = "comment-entry-header";
nicholas@2479 171 this.title = document.createElement("span");
nicholas@2479 172 if (str != undefined) {
nicholas@2479 173 this.title.textContent = str;
nicholas@2479 174 } else {
nicholas@2481 175 this.title.textContent = "Time: " + time.toFixed(2) + "s";
nicholas@2479 176 }
nicholas@2480 177 titleHolder.appendChild(this.title);
nicholas@2479 178 this.textarea = document.createElement("textarea");
nicholas@2480 179 this.textarea.className = "comment-entry-text";
nicholas@2480 180 this.DOM.appendChild(titleHolder);
nicholas@2479 181 this.DOM.appendChild(this.textarea);
nicholas@2481 182
nicholas@2480 183 this.clear = {
nicholas@2480 184 DOM: document.createElement("button"),
nicholas@2480 185 parent: this,
nicholas@2481 186 handleEvent: function () {
nicholas@2480 187 this.parent.parent.deleteComment(this.parent);
nicholas@2480 188 }
nicholas@2480 189 }
nicholas@2480 190 this.clear.DOM.textContent = "Delete";
nicholas@2481 191 this.clear.DOM.addEventListener("click", this.clear);
nicholas@2480 192 titleHolder.appendChild(this.clear.DOM);
nicholas@2481 193
nicholas@2481 194 this.resize = function () {
nicholas@2479 195 var w = window.innerWidth;
nicholas@2481 196 w = Math.min(w, 800);
nicholas@2481 197 w = Math.max(w, 200);
nicholas@2479 198 var elem_w = w / 2.5;
nicholas@2481 199 elem_w = Math.max(elem_w, 190);
nicholas@2481 200 this.DOM.style.width = elem_w + "px";
nicholas@2481 201 this.textarea.style.width = (elem_w - 5) + "px";
nicholas@2479 202 }
nicholas@2481 203 this.buildXML = function (root) {
nicholas@2480 204 //storage.document.createElement();
nicholas@2480 205 var node = storage.document.createElement("comment");
nicholas@2480 206 var question = storage.document.createElement("question");
nicholas@2480 207 var comment = storage.document.createElement("response");
nicholas@2481 208 node.setAttribute("time", this.time);
nicholas@2480 209 question.textContent = this.title.textContent;
nicholas@2480 210 comment.textContent = this.textarea.value;
nicholas@2480 211 node.appendChild(question);
nicholas@2480 212 node.appendChild(comment);
nicholas@2480 213 root.appendChild(node);
nicholas@2480 214 }
nicholas@2479 215 this.resize();
nicholas@2479 216 },
nicholas@2481 217 newComment: function (time) {
nicholas@2481 218 var node = new this.Comment(this, time);
nicholas@2479 219 this.list.push(node);
nicholas@2479 220 commentHolder.appendChild(node.DOM);
nicholas@2479 221 return node;
nicholas@2479 222 },
nicholas@2481 223 deleteComment: function (comment) {
nicholas@2481 224 var index = this.list.findIndex(function (element, index, array) {
nicholas@2481 225 if (element == comment) {
nicholas@2481 226 return true;
nicholas@2481 227 }
nicholas@2481 228 return false;
nicholas@2481 229 }, comment);
nicholas@2480 230 if (index == -1) {
nicholas@2480 231 return false;
nicholas@2480 232 }
nicholas@2481 233 var node = this.list.splice(index, 1);
nicholas@2480 234 comment.DOM.remove();
nicholas@2480 235 this.parent.canvas.drawMarkers();
nicholas@2480 236 return true;
nicholas@2479 237 },
nicholas@2481 238 clearList: function () {
nicholas@2481 239 while (this.list.length > 0) {
nicholas@2480 240 this.deleteComment(this.list[0]);
nicholas@2480 241 }
nicholas@2479 242 }
nicholas@2479 243 }
nicholas@2481 244
nicholas@2479 245 this.canvas = {
nicholas@2479 246 parent: this,
nicholas@2479 247 comments: this.comments,
nicholas@2479 248 layer1: document.createElement("canvas"),
nicholas@2479 249 layer2: document.createElement("canvas"),
nicholas@2479 250 layer3: document.createElement("canvas"),
nicholas@2479 251 layer4: document.createElement("canvas"),
nicholas@2481 252 resize: function (w) {
nicholas@2479 253 this.layer1.width = w;
nicholas@2479 254 this.layer2.width = w;
nicholas@2479 255 this.layer3.width = w;
nicholas@2479 256 this.layer4.width = w;
nicholas@2481 257 this.layer1.style.width = w + "px";
nicholas@2481 258 this.layer2.style.width = w + "px";
nicholas@2481 259 this.layer3.style.width = w + "px";
nicholas@2481 260 this.layer4.style.width = w + "px";
nicholas@2480 261 this.drawWaveform();
nicholas@2480 262 this.drawMarkers();
nicholas@2479 263 },
nicholas@2481 264 handleEvent: function (event) {
nicholas@2481 265 switch (event.currentTarget) {
nicholas@2479 266 case this.layer1:
nicholas@2481 267 switch (event.type) {
nicholas@2479 268 case "mousemove":
nicholas@2479 269 this.drawMouse(event);
nicholas@2479 270 break;
nicholas@2479 271 case "mouseleave":
nicholas@2479 272 this.clearCanvas(this.layer1);
nicholas@2479 273 break;
nicholas@2479 274 case "click":
nicholas@2479 275 var rect = this.layer1.getBoundingClientRect();
nicholas@2479 276 var pixX = event.clientX - rect.left;
nicholas@2481 277 var tpp = this.parent.parent.buffer.buffer.duration / this.layer1.width;
nicholas@2481 278 this.comments.newComment(pixX * tpp);
nicholas@2479 279 this.drawMarkers();
nicholas@2479 280 break;
nicholas@2479 281 }
nicholas@2479 282 break;
nicholas@2479 283 }
nicholas@2479 284 },
nicholas@2481 285 drawWaveform: function () {
nicholas@2480 286 if (this.parent.parent == undefined || this.parent.parent.buffer == undefined) {
nicholas@2480 287 return;
nicholas@2480 288 }
nicholas@2479 289 var buffer = this.parent.parent.buffer.buffer;
nicholas@2479 290 var context = this.layer4.getContext("2d");
nicholas@2479 291 context.lineWidth = 1;
nicholas@2479 292 context.strokeStyle = "#888";
nicholas@2481 293 context.clearRect(0, 0, this.layer4.width, this.layer4.height);
nicholas@2479 294 var data = buffer.getChannelData(0);
nicholas@2481 295 var t_per_pixel = buffer.duration / this.layer4.width;
nicholas@2481 296 var s_per_pixel = data.length / this.layer4.width;
nicholas@2479 297 var pixX = 0;
nicholas@2479 298 while (pixX < this.layer4.width) {
nicholas@2481 299 var start = Math.floor(s_per_pixel * pixX);
nicholas@2481 300 var end = Math.min(Math.ceil(s_per_pixel * (pixX + 1)), data.length);
nicholas@2481 301 var frame = data.subarray(start, end);
nicholas@2479 302 var min = frame[0];
nicholas@2479 303 var max = min;
nicholas@2481 304 for (var n = 0; n < frame.length; n++) {
nicholas@2481 305 if (frame[n] < min) {
nicholas@2481 306 min = frame[n];
nicholas@2481 307 }
nicholas@2481 308 if (frame[n] > max) {
nicholas@2481 309 max = frame[n];
nicholas@2481 310 }
nicholas@2479 311 }
nicholas@2479 312 // Assuming min/max normalised between [-1, 1] to map to [150, 0]
nicholas@2479 313 context.beginPath();
nicholas@2481 314 context.moveTo(pixX + 0.5, (min + 1) * -75 + 150);
nicholas@2481 315 context.lineTo(pixX + 0.5, (max + 1) * -75 + 150);
nicholas@2479 316 context.stroke();
nicholas@2479 317 pixX++;
nicholas@2479 318 }
nicholas@2479 319 },
nicholas@2481 320 drawMouse: function (event) {
nicholas@2479 321 var context = this.layer1.getContext("2d");
nicholas@2481 322 context.clearRect(0, 0, this.layer1.width, this.layer1.height);
nicholas@2479 323 var rect = this.layer1.getBoundingClientRect();
nicholas@2479 324 var pixX = event.clientX - rect.left;
nicholas@2481 325 pixX = Math.floor(pixX) - 0.5;
nicholas@2479 326 context.strokeStyle = "#800";
nicholas@2479 327 context.beginPath();
nicholas@2481 328 context.moveTo(pixX, 0);
nicholas@2481 329 context.lineTo(pixX, this.layer1.height);
nicholas@2479 330 context.stroke();
nicholas@2479 331 },
nicholas@2481 332 drawTicker: function () {
nicholas@2479 333 var context = this.layer2.getContext("2d");
nicholas@2481 334 context.clearRect(0, 0, this.layer2.width, this.layer2.height);
nicholas@2479 335 var time = this.parent.parent.getCurrentPosition();
nicholas@2479 336 var ratio = time / this.parent.parent.buffer.buffer.duration;
nicholas@2481 337 var pixX = Math.floor(ratio * this.layer2.width) + 0.5;
nicholas@2479 338 context.strokeStyle = "#080";
nicholas@2479 339 context.beginPath();
nicholas@2481 340 context.moveTo(pixX, 0);
nicholas@2481 341 context.lineTo(pixX, this.layer2.height);
nicholas@2479 342 context.stroke();
nicholas@2479 343 },
nicholas@2481 344 drawMarkers: function () {
nicholas@2480 345 if (this.parent.parent == undefined || this.parent.parent.buffer == undefined) {
nicholas@2480 346 return;
nicholas@2480 347 }
nicholas@2479 348 var context = this.layer3.getContext("2d");
nicholas@2481 349 context.clearRect(0, 0, this.layer3.width, this.layer3.height);
nicholas@2479 350 context.strokeStyle = "#008";
nicholas@2481 351 var tpp = this.parent.parent.buffer.buffer.duration / this.layer1.width;
nicholas@2481 352 for (var i = 0; i < this.comments.list.length; i++) {
nicholas@2479 353 var comment = this.comments.list[i];
nicholas@2481 354 var pixX = Math.floor(comment.time / tpp) + 0.5;
nicholas@2479 355 context.beginPath();
nicholas@2481 356 context.moveTo(pixX, 0);
nicholas@2481 357 context.lineTo(pixX, this.layer3.height);
nicholas@2479 358 context.stroke();
nicholas@2479 359 }
nicholas@2479 360 },
nicholas@2481 361 clearCanvas: function (canvas) {
nicholas@2479 362 var context = canvas.getContext("2d");
nicholas@2481 363 context.clearRect(0, 0, canvas.width, canvas.height);
nicholas@2479 364 }
nicholas@2479 365 }
nicholas@2479 366 this.canvas.layer1.className = "timeline-element-canvas canvas-layer1 canvas-disabled";
nicholas@2479 367 this.canvas.layer2.className = "timeline-element-canvas canvas-layer2";
nicholas@2479 368 this.canvas.layer3.className = "timeline-element-canvas canvas-layer3";
nicholas@2479 369 this.canvas.layer4.className = "timeline-element-canvas canvas-layer3";
nicholas@2479 370 this.canvas.layer1.height = "150";
nicholas@2479 371 this.canvas.layer2.height = "150";
nicholas@2479 372 this.canvas.layer3.height = "150";
nicholas@2479 373 this.canvas.layer4.height = "150";
nicholas@2479 374 canvasHolder.appendChild(this.canvas.layer1);
nicholas@2479 375 canvasHolder.appendChild(this.canvas.layer2);
nicholas@2479 376 canvasHolder.appendChild(this.canvas.layer3);
nicholas@2479 377 canvasHolder.appendChild(this.canvas.layer4);
nicholas@2481 378 this.canvas.layer1.addEventListener("mousemove", this.canvas);
nicholas@2481 379 this.canvas.layer1.addEventListener("mouseleave", this.canvas);
nicholas@2481 380 this.canvas.layer1.addEventListener("click", this.canvas);
nicholas@2481 381
nicholas@2479 382 var canvasIntervalID = null;
nicholas@2481 383
nicholas@2479 384 this.playButton = {
nicholas@2479 385 parent: this,
nicholas@2479 386 DOM: document.createElement("button"),
nicholas@2481 387 handleEvent: function (event) {
nicholas@2479 388 var id = this.parent.parent.id;
nicholas@2479 389 var str = this.DOM.textContent;
nicholas@2479 390 if (str == "Play") {
nicholas@2479 391 audioEngineContext.play(id);
nicholas@2479 392 } else if (str == "Stop") {
nicholas@2479 393 audioEngineContext.stop();
nicholas@2479 394 }
nicholas@2479 395 }
nicholas@2479 396 }
nicholas@2481 397 this.playButton.DOM.addEventListener("click", this.playButton);
nicholas@2479 398 this.playButton.DOM.className = "timeline-button timeline-button-disabled";
nicholas@2479 399 this.playButton.DOM.disabled = true;
nicholas@2479 400 this.playButton.DOM.textContent = "Wait";
nicholas@2481 401
nicholas@2479 402 buttonHolder.appendChild(this.playButton.DOM);
nicholas@2481 403
nicholas@2481 404 this.resize = function () {
nicholas@2479 405 var w = window.innerWidth;
nicholas@2481 406 w = Math.min(w, 800);
nicholas@2481 407 w = Math.max(w, 200);
nicholas@2481 408 root.style.width = w + "px";
nicholas@2481 409 var c_w = w - 100;
nicholas@2479 410 this.canvas.resize(c_w);
nicholas@2479 411 }
nicholas@2481 412
nicholas@2481 413 this.enable = function () {
nicholas@2481 414 // This is used to tell the interface object that playback of this node is ready
nicholas@2481 415 this.canvas.layer1.addEventListener("click", this.canvas);
nicholas@2479 416 this.canvas.layer1.className = "timeline-element-canvas canvas-layer1";
nicholas@2479 417 this.playButton.DOM.className = "timeline-button timeline-button-play";
nicholas@2479 418 this.playButton.DOM.textContent = "Play";
nicholas@2479 419 this.playButton.DOM.disabled = false;
nicholas@2481 420
nicholas@2479 421 this.canvas.drawWaveform();
nicholas@2481 422 };
nicholas@2481 423 this.updateLoading = function (progress) {
nicholas@2481 424 // progress is a value from 0 to 100 indicating the current download state of media files
nicholas@2479 425 progress = String(progress);
nicholas@2481 426 progress = progress.substr(0, 5);
nicholas@2481 427 this.playButton.DOM.textContent = "Loading: " + progress + '%';
nicholas@2481 428 };
nicholas@2481 429 this.startPlayback = function () {
nicholas@2479 430 // Called when playback has begun
nicholas@2481 431 canvasIntervalID = window.setInterval(this.canvas.drawTicker.bind(this.canvas), 100);
nicholas@2479 432 this.playButton.DOM.textContent = "Stop";
nicholas@2479 433 };
nicholas@2481 434 this.stopPlayback = function () {
nicholas@2479 435 // Called when playback has stopped. This gets called even if playback never started!
nicholas@2479 436 window.clearInterval(canvasIntervalID);
nicholas@2479 437 this.canvas.clearCanvas(this.canvas.layer2);
nicholas@2479 438 this.playButton.DOM.textContent = "Play";
nicholas@2479 439 };
nicholas@2481 440 this.getValue = function () {
nicholas@2481 441 // Return the current value of the object. If there is no value, return 0
nicholas@2479 442 return 0;
nicholas@2481 443 };
nicholas@2481 444 this.getPresentedId = function () {
nicholas@2481 445 // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale
nicholas@2479 446 return labelSpan.textContent;
nicholas@2481 447 };
nicholas@2481 448 this.canMove = function () {
nicholas@2481 449 // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale.
nicholas@2481 450 // These are checked primarily if the interface check option 'fragmentMoved' is enabled.
nicholas@2479 451 return false;
nicholas@2481 452 };
nicholas@2481 453 this.exportXMLDOM = function (audioObject) {
nicholas@2481 454 // Called by the audioObject holding this element to export the interface <value> node.
nicholas@2481 455 // If there is no value node (such as outside reference), return null
nicholas@2481 456 // 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
nicholas@2481 457 // Use storage.document.createElement('value'); to generate the XML node.
nicholas@2481 458 return null;
nicholas@2481 459 };
nicholas@2481 460 this.error = function () {
nicholas@2479 461 // If there is an error with the audioObject, this will be called to indicate a failure
nicholas@2479 462 }
nicholas@2479 463 };
nicholas@2479 464
nicholas@2481 465 function resizeWindow(event) {
nicholas@2481 466 // Called on every window resize event, use this to scale your page properly
nicholas@2481 467 for (var i = 0; i < audioEngineContext.audioObjects.length; i++) {
nicholas@2479 468 audioEngineContext.audioObjects[i].interfaceDOM.resize();
nicholas@2479 469 }
nicholas@2479 470 }
nicholas@2479 471
nicholas@2481 472 function buttonSubmitClick() {
nicholas@2481 473 if (audioEngineContext.timer.testStarted == false) {
nicholas@2481 474 interfaceContext.lightbox.post("Warning", 'You have not started the test! Please click play on a sample to begin the test!');
nicholas@2481 475 return;
nicholas@2481 476 }
nicholas@2481 477 var checks = [];
nicholas@2481 478 checks = checks.concat(testState.currentStateMap.interfaces[0].options);
nicholas@2481 479 checks = checks.concat(specification.interfaces.options);
nicholas@2481 480 var canContinue = true;
nicholas@2481 481 for (var i = 0; i < checks.length; i++) {
nicholas@2481 482 var checkState = true;
nicholas@2481 483 if (checks[i].type == 'check') {
nicholas@2481 484 switch (checks[i].name) {
nicholas@2481 485 case 'fragmentPlayed':
nicholas@2481 486 //Check if all fragments have been played
nicholas@2481 487 checkState = interfaceContext.checkAllPlayed();
nicholas@2481 488 break;
nicholas@2481 489 case 'fragmentFullPlayback':
nicholas@2481 490 //Check if all fragments have played to their full length
nicholas@2481 491 checkState = interfaceContext.checkFragmentsFullyPlayed();
nicholas@2481 492 break;
nicholas@2481 493 case 'fragmentComments':
nicholas@2481 494 checkState = interfaceContext.checkAllCommented();
nicholas@2481 495 break;
nicholas@2481 496 default:
nicholas@2481 497 console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface");
nicholas@2481 498 break;
nicholas@2481 499 }
nicholas@2481 500 if (checkState == false) {
nicholas@2569 501 canContinue = false;
nicholas@2481 502 }
nicholas@2481 503 }
nicholas@2481 504 if (!canContinue) {
nicholas@2481 505 return;
nicholas@2481 506 }
nicholas@2481 507 }
nicholas@2481 508
nicholas@2481 509 if (canContinue) {
nicholas@2481 510 if (audioEngineContext.status == 1) {
nicholas@2481 511 var playback = document.getElementById('playback-button');
nicholas@2481 512 playback.click();
nicholas@2481 513 // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options
nicholas@2481 514 }
nicholas@2481 515 testState.advanceState();
nicholas@2481 516 }
nicholas@2479 517 }
nicholas@2479 518
nicholas@2481 519 function pageXMLSave(store, pageSpecification) {
nicholas@2481 520 // MANDATORY
nicholas@2481 521 // Saves a specific test page
nicholas@2481 522 // You can use this space to add any extra nodes to your XML <audioHolder> saves
nicholas@2481 523 // Get the current <page> information in store (remember to appendChild your data to it)
nicholas@2481 524 // pageSpecification is the current page node configuration
nicholas@2481 525 // To create new XML nodes, use storage.document.createElement();
nicholas@2481 526
nicholas@2481 527 for (var i = 0; i < audioEngineContext.audioObjects.length; i++) {
nicholas@2480 528 var id = audioEngineContext.audioObjects[i].specification.id;
nicholas@2480 529 var commentsList = audioEngineContext.audioObjects[i].interfaceDOM.comments.list;
nicholas@2480 530 var root = audioEngineContext.audioObjects[i].storeDOM;
nicholas@2481 531 for (var j = 0; j < commentsList.length; j++) {
nicholas@2480 532 commentsList[j].buildXML(root);
nicholas@2480 533 }
nicholas@2480 534 }
nicholas@2481 535 }