comparison interfaces/ape.js @ 3009:1ced6e0cb9ac

Refactorised ape.js. Now uses modular system to manage interface (WIP)
author Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk>
date Fri, 04 Aug 2017 10:03:56 +0200
parents 64a5603831e2
children 7bbf1b1bfd95
comparison
equal deleted inserted replaced
3008:166c5aef020c 3009:1ced6e0cb9ac
5 5
6 /*globals window,interfaceContext, document, audioEngineContext, console, $, Interface, testState, storage, specification */ 6 /*globals window,interfaceContext, document, audioEngineContext, console, $, Interface, testState, storage, specification */
7 /*globals metricTracker */ 7 /*globals metricTracker */
8 // Once this is loaded and parsed, begin execution 8 // Once this is loaded and parsed, begin execution
9 loadInterface(); 9 loadInterface();
10 window.APE = undefined;
10 11
11 function loadInterface() { 12 function loadInterface() {
12 13
13 // Get the dimensions of the screen available to the page 14 // Get the dimensions of the screen available to the page
14 var width = window.innerWidth; 15 var width = window.innerWidth;
122 console.log(str); 123 console.log(str);
123 } 124 }
124 return state; 125 return state;
125 }; 126 };
126 127
127 Interface.prototype.objectSelected = null;
128 Interface.prototype.objectMoved = false;
129 Interface.prototype.selectObject = function (object) {
130 if (this.objectSelected === null) {
131 this.objectSelected = object;
132 this.objectMoved = false;
133 }
134 };
135 Interface.prototype.moveObject = function () {
136 if (this.objectMoved === false) {
137 this.objectMoved = true;
138 }
139 };
140 Interface.prototype.releaseObject = function () {
141 this.objectSelected = null;
142 this.objectMoved = false;
143 };
144 Interface.prototype.getSelectedObject = function () {
145 return this.objectSelected;
146 };
147 Interface.prototype.hasSelectedObjectMoved = function () {
148 return this.objectMoved;
149 };
150
151 // Bindings for slider interfaces
152 Interface.prototype.interfaceSliders = [];
153
154 // Bindings for audioObjects 128 // Bindings for audioObjects
155 129
156 // Create the top div for the Title element 130 // Create the top div for the Title element
157 var titleAttr = specification.title; 131 var titleAttr = specification.title;
158 var title = document.createElement('div'); 132 var title = document.createElement('div');
218 testContent.appendChild(sliderHolder); 192 testContent.appendChild(sliderHolder);
219 testContent.appendChild(feedbackHolder); 193 testContent.appendChild(feedbackHolder);
220 interfaceContext.insertPoint.appendChild(testContent); 194 interfaceContext.insertPoint.appendChild(testContent);
221 195
222 // Load the full interface 196 // Load the full interface
197 window.APE = new ape();
223 testState.initialise(); 198 testState.initialise();
224 testState.advanceState(); 199 testState.advanceState();
225
226 } 200 }
227 201
228 function loadTest(audioHolderObject) { 202 function loadTest(audioHolderObject) {
203 APE.clear();
229 var width = window.innerWidth; 204 var width = window.innerWidth;
230 var height = window.innerHeight; 205 var height = window.innerHeight;
231 var id = audioHolderObject.id; 206 var id = audioHolderObject.id;
232 207
233 interfaceContext.interfaceSliders = []; 208 interfaceContext.interfaceSliders = [];
244 // Set the page title 219 // Set the page title
245 if (typeof audioHolderObject.title == "string" && audioHolderObject.title.length > 0) { 220 if (typeof audioHolderObject.title == "string" && audioHolderObject.title.length > 0) {
246 document.getElementById("test-title").textContent = audioHolderObject.title; 221 document.getElementById("test-title").textContent = audioHolderObject.title;
247 } 222 }
248 223
249
250 // Delete outside reference 224 // Delete outside reference
251 document.getElementById("outside-reference-holder").innerHTML = ""; 225 document.getElementById("outside-reference-holder").innerHTML = "";
252 226
253 var interfaceObj = interfaceContext.getCombinedInterfaces(audioHolderObject); 227 var interfaceObj = interfaceContext.getCombinedInterfaces(audioHolderObject);
254 interfaceObj.forEach(function (interfaceObjectInstance) {
255 // Create the div box to center align
256 interfaceContext.interfaceSliders.push(new interfaceSliderHolder(interfaceObjectInstance, audioHolderObject));
257 });
258 interfaceObj.forEach(function (interface) { 228 interfaceObj.forEach(function (interface) {
259 interface.options.forEach(function (option) { 229 interface.options.forEach(function (option) {
260 if (option.type == "show") { 230 if (option.type == "show") {
261 switch (option.name) { 231 switch (option.name) {
262 case "playhead": 232 case "playhead":
296 266
297 var commentShow = audioHolderObject.elementComments; 267 var commentShow = audioHolderObject.elementComments;
298 268
299 var loopPlayback = audioHolderObject.loop; 269 var loopPlayback = audioHolderObject.loop;
300 270
301 var currentTestHolder = document.createElement('audioHolder'); 271 APE.initialisePage(audioHolderObject);
302 currentTestHolder.id = audioHolderObject.id;
303 currentTestHolder.repeatCount = audioHolderObject.repeatCount;
304
305 // Find all the audioElements from the audioHolder
306 $(audioHolderObject.audioElements).each(function (index, element) {
307 // Find URL of track
308 // In this jQuery loop, variable 'this' holds the current audioElement.
309 var audioObject = audioEngineContext.newTrack(element);
310 // Check if an outside reference
311 if (element.type == 'outside-reference') {
312 // Construct outside reference;
313 var orNode = new outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder"));
314 audioObject.bindInterface(orNode);
315 } else {
316 // Create a slider per track
317 var sliderNode = new sliderObject(audioObject, interfaceObj, index);
318 audioObject.bindInterface(sliderNode);
319 interfaceContext.commentBoxes.createCommentBox(audioObject);
320 }
321 });
322
323 // Initialse the interfaceSlider object metrics
324
325 $('.track-slider').mousedown(function (event) {
326 interfaceContext.selectObject($(this)[0]);
327 });
328 $('.track-slider').on('touchstart', null, function (event) {
329 interfaceContext.selectObject($(this)[0]);
330 });
331
332 $('.track-slider').mousemove(function (event) {
333 event.preventDefault();
334 });
335
336 $('.slider').mousemove(function (event) {
337 event.preventDefault();
338 var obj = interfaceContext.getSelectedObject();
339 if (obj === null) {
340 return;
341 }
342 var move = event.clientX - 6;
343 var w = $(event.currentTarget).width();
344 move = Math.max(50, move);
345 move = Math.min(w + 50, move);
346 $(obj).css("left", move + "px");
347 interfaceContext.moveObject();
348 });
349
350 $('.slider').on('touchmove', null, function (event) {
351 event.preventDefault();
352 var obj = interfaceContext.getSelectedObject();
353 if (obj === null) {
354 return;
355 }
356 var move = event.originalEvent.targetTouches[0].clientX - 6;
357 var w = $(event.currentTarget).width();
358 move = Math.max(50, move);
359 move = Math.min(w + 50, move);
360 $(obj).css("left", move + "px");
361 interfaceContext.moveObject();
362 });
363
364 $(document).mouseup(function (event) {
365 event.preventDefault();
366 var obj = interfaceContext.getSelectedObject();
367 if (obj === null) {
368 return;
369 }
370 var interfaceID = obj.parentElement.getAttribute("interfaceid");
371 var trackID = obj.getAttribute("trackindex");
372 var id;
373 if (interfaceContext.hasSelectedObjectMoved() === true) {
374 var l = $(obj).css("left");
375 id = obj.getAttribute('trackIndex');
376 var time = audioEngineContext.timer.getTestTime();
377 var rate = convSliderPosToRate(obj);
378 audioEngineContext.audioObjects[id].metric.moved(time, rate);
379 interfaceContext.interfaceSliders[interfaceID].metrics[trackID].moved(time, rate);
380 console.log("slider " + id + " moved to " + rate + ' (' + time + ')');
381 obj.setAttribute("slider-value", convSliderPosToRate(obj));
382 } else {
383 id = Number(obj.attributes.trackIndex.value);
384 //audioEngineContext.metric.sliderPlayed(id);
385 audioEngineContext.play(id);
386 }
387 interfaceContext.releaseObject();
388 });
389
390 $('.slider').on('touchend', null, function (event) {
391 var obj = interfaceContext.getSelectedObject();
392 if (obj === null) {
393 return;
394 }
395 var interfaceID = obj.parentElement.getAttribute("interfaceid");
396 var trackID = obj.getAttribute("trackindex");
397 if (interfaceContext.hasSelectedObjectMoved() === true) {
398 var l = $(obj).css("left");
399 var id = obj.getAttribute('trackIndex');
400 var time = audioEngineContext.timer.getTestTime();
401 var rate = convSliderPosToRate(obj);
402 audioEngineContext.audioObjects[id].metric.moved(time, rate);
403 interfaceContext.interfaceSliders[interfaceID].metrics[trackID].moved(time, rate);
404 console.log("slider " + id + " moved to " + rate + ' (' + time + ')');
405 }
406 interfaceContext.releaseObject();
407 });
408 272
409 var interfaceList = audioHolderObject.interfaces.concat(specification.interfaces); 273 var interfaceList = audioHolderObject.interfaces.concat(specification.interfaces);
410 for (var k = 0; k < interfaceList.length; k++) { 274 for (var k = 0; k < interfaceList.length; k++) {
411 for (var i = 0; i < interfaceList[k].options.length; i++) { 275 for (var i = 0; i < interfaceList[k].options.length; i++) {
412 if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'playhead') { 276 if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'playhead') {
445 }); 309 });
446 310
447 //testWaitIndicator(); 311 //testWaitIndicator();
448 } 312 }
449 313
450 function interfaceSliderHolder(interfaceObject, page) { 314 function ape() {
451 this.sliders = []; 315 var axis = []
452 this.metrics = []; 316 var DOMRoot = document.getElementById("slider-holder");
453 this.id = document.getElementsByClassName("sliderCanvasDiv").length; 317 var AOIs = [];
454 this.name = interfaceObject.name; 318 var page = undefined;
455 this.interfaceObject = interfaceObject; 319
456 this.sliderDOM = document.createElement('div'); 320 function audioObjectInterface(audioObject, parent) {
457 this.sliderDOM.className = 'sliderCanvasDiv'; 321 // The audioObject communicates with this object
458 this.sliderDOM.id = 'sliderCanvasHolder-' + this.id; 322 var playing = false;
459 this.imageHolder = (function () { 323 var sliders = [];
460 var imageController = {}; 324 this.enable = function () {
461 imageController.root = document.createElement("div"); 325 sliders.forEach(function (s) {
462 imageController.root.className = "imageController"; 326 s.enable();
463 imageController.img = document.createElement("img"); 327 })
464 imageController.root.appendChild(imageController.img); 328 }
465 imageController.setImage = function (src) { 329
466 imageController.img.src = ""; 330 this.updateLoading = function (p) {
467 if (typeof src !== "string" || src.length === undefined) { 331 sliders.forEach(function (s) {
332 s.updateLoading(p);
333 })
334 }
335
336 this.startPlayback = function () {
337 playing = true;
338 sliders.forEach(function (s) {
339 s.playing();
340 });
341 }
342
343 this.stopPlayback = function () {
344 playing = false;
345 sliders.forEach(function (s) {
346 s.stopped();
347 });
348 }
349
350 this.getValue = function () {
351 return sliders[0].value();
352 }
353
354 this.getPresentedId = function () {
355 return sliders[0].label;
356 }
357
358 this.canMove = function () {
359 return true;
360 }
361
362 this.exportXMLDOM = function (audioObject) {
363 var elements = [];
364 sliders.forEach(function (s) {
365 elements.push(s.exportXMLDOM());
366 });
367 return elements;
368 }
369
370 this.error = function () {
371 sliders.forEach(function (s) {
372 s.error();
373 });
374 }
375
376 this.addSlider = function (s) {
377 sliders.push(s);
378 }
379
380 this.clicked = function (event) {
381 if (!playing) {
382 audioEngineContext.play(audioObject.id);
383 } else {
384 audioEngineContext.stop();
385 }
386 playing = !playing;
387 }
388
389 this.pageXMLSave = function (store) {
390 var inject = audioObject.storeDOM.getElementsByTagName("metric")[0];
391 sliders.forEach(function (s) {
392 s.pageXMLSave(inject);
393 });
394 }
395
396 }
397
398 function axisObject(interfaceObject, parent) {
399
400 function sliderInterface(AOI, axisInterface) {
401 var trackObj = document.createElement('div');
402 var labelHolder = document.createElement("span");
403 var label = "";
404 var metric = new metricTracker(this);
405 trackObj.align = "center";
406 trackObj.className = 'track-slider track-slider-disabled';
407 trackObj.appendChild(labelHolder);
408 trackObj.style.left = (Math.random() * $(sliderRail).width()) - 50 + "px";
409 axisInterface.sliderRail.appendChild(trackObj);
410 metric.initialise(this.value);
411 this.setLabel = function (s) {
412 label = s;
413 }
414 this.resize = function (event) {
415 var width = $(axisInterface.sliderRail).width();
416 var w = Number(value * width + 50);
417 trackObj.style.left = String(w) + "px";
418 }
419 this.playing = function () {
420 trackObj.classList.add("track-slider-playing");
421 }
422 this.stopped = function () {
423 trackObj.classList.remove("track-slider-playing");
424 }
425 this.enable = function () {
426 trackObj.addEventListener("mousedown", this);
427 trackObj.addEventListener("mouseup", this);
428 trackObj.addEventListener("touchstart", this);
429 trackObj.classList.remove("track-slider-disabled");
430 labelHolder.textContent = label;
431 }
432 this.updateLoading = function (progress) {
433 labelHolder.textContent = progress + "%";
434 }
435 this.exportXMLDOM = function () {
436 var node = storage.document.createElement('value');
437 node.setAttribute("interface-name", axisInterface.name)
438 node.textContent = this.value();
439 return node;
440 }
441 this.error = function () {
442 trackObj.classList.add("error-colour");
443 trackObj.removeEventListener("mousedown");
444 trackObj.removeEventListener("mouseup");
445 trackObj.removeEventListener("touchstart");
446 }
447 var timing = undefined;
448 this.handleEvent = function (e) {
449 // This is only for the mousedown / touchdown
450 if (e.preventDefault) {
451 e.preventDefault();
452 }
453 if (e.type == "mousedown" || e.type == "touchstart") {
454 axisInterface.mousedown(this);
455 } else if (e.type == "mouseup") {
456 axisInterface.mouseup(this);
457 }
458 }
459 this.clicked = function (e) {
460 AOI.clicked();
461 }
462 this.pageXMLSave = function (inject) {
463 var nodes = metric.exportXMLDOM(inject);
464 nodes.forEach(function (elem) {
465 var name = elem.getAttribute("name");
466 if (name == "elementTracker" || name == "elementTrackerFull" || name == "elementInitialPosition" || name == "elementFlagMoved") {
467 mrnodes[j].setAttribute("interface-name", axisInterface.name);
468 }
469 });
470 }
471 Object.defineProperties(this, {
472 "DOM": {
473 "value": trackObj
474 },
475 "value": {
476 "value": function () {
477 var maxPix = $(axisInterface.sliderRail).width();
478 var pix = trackObj.style.left.substr(0, trackObj.style.left.length - 2);
479 return (pix - 50) / maxPix;
480 }
481 },
482 "moveToPixel": {
483 "value": function (pix) {
484 var t = audioEngineContext.timer.getTestTime();
485 trackObj.style.left = String(pix) + "px";
486 metric.moved(t, this.value);
487 }
488 },
489 "label": {
490 "get": function () {
491 return label;
492 },
493 "set": function () {}
494 }
495 });
496 }
497
498 function createScaleMarkers(interfaceObject, root, w) {
499 interfaceObject.scales.forEach(function (scaleObj) {
500 var position = Number(scaleObj.position) * 0.01;
501 var pixelPosition = (position * w) + 50;
502 var scaleDOM = document.createElement('span');
503 scaleDOM.className = "ape-marker-text";
504 scaleDOM.textContent = scaleObj.text;
505 scaleDOM.setAttribute('value', position);
506 root.appendChild(scaleDOM);
507 scaleDOM.style.left = Math.floor((pixelPosition - ($(scaleDOM).width() / 2))) + 'px';
508 }, this);
509 }
510 var sliders = [];
511 var UI = {
512 selected: undefined,
513 startTime: undefined
514 }
515 this.name = interfaceObject.name;
516 var DOMRoot = document.createElement("div");
517 DOMRoot.className = "sliderCanvasDiv";
518 DOMRoot.id = "sliderCanvasHolder-" + this.name;
519 var sliders = [];
520
521 var axisTitle = document.createElement("div");
522 axisTitle.className = "pageTitle";
523 axisTitle.align = "center";
524 var titleSpan = document.createElement('span');
525 titleSpan.id = "pageTitle-" + this.name;
526 if (interfaceObject.title !== undefined && typeof interfaceObject.title == "string") {
527 titleSpan.textContent = interfaceObject.title;
528 } else {
529 titleSpan.textContent = "Axis " + String(this.id + 1);
530 }
531 axisTitle.appendChild(titleSpan);
532 DOMRoot.appendChild(axisTitle);
533
534 var imageHolder = (function () {
535 var imageController = {};
536 imageController.root = document.createElement("div");
537 imageController.root.className = "imageController";
538 imageController.img = document.createElement("img");
539 imageController.root.appendChild(imageController.img);
540 imageController.setImage = function (src) {
541 imageController.img.src = "";
542 if (typeof src !== "string" || src.length === undefined) {
543 return;
544 }
545 imageController.img.src = src;
546 };
547 return imageController;
548 })();
549 if (interfaceObject.image !== undefined || page.audioElements.some(function (a) {
550 return a.image !== undefined;
551 })) {
552 DOMRoot.appendChild(imageHolder.root);
553 imageHolder.setImage(interfaceObject.image);
554 }
555
556 // Now create the slider box to hold the fragment sliders
557 var sliderRail = document.createElement("div");
558 sliderRail.id = "sliderrail-" + this.name;
559 sliderRail.className = "slider";
560 sliderRail.align = "left";
561 DOMRoot.appendChild(sliderRail);
562
563 // Create the div to hold any scale objects
564 var scale = document.createElement("div");
565 scale.className = "sliderScale";
566 scale.id = "slider-scale-holder-" + this.name;
567 scale.slign = "left";
568 DOMRoot.appendChild(scale);
569 createScaleMarkers(interfaceObject, scale, $(sliderRail).width());
570
571 parent.getDOMRoot().appendChild(DOMRoot);
572
573 this.resize = function (event) {
574 var w = $(sliderRail).width();
575 var marginsize = 50;
576 sliders.forEach(function (s) {
577 s.resize();
578 });
579 scale.innerHTML = "";
580 createScaleMarkers(interfaceObject, scale, $(sliderRail).width());
581 }
582 this.playing = function (id) {
583 var node = audioEngineContext.audioObjects.find(function (a) {
584 return a.id == id;
585 });
586 if (node === undefined) {
587 this.imageHolder.setImage(interfaceObject.image || "");
468 return; 588 return;
469 } 589 }
470 imageController.img.src = src; 590 var imgurl = node.specification.image || interfaceObject.image || "";
471 }; 591 this.imageHolder.setImage(imgurl);
472 return imageController; 592 }
473 })(); 593 this.stopped = function () {
474 594 var imgurl = interfaceObject.image || "";
475 var pagetitle = document.createElement('div'); 595 this.imageHolder.setImage(imgurl);
476 pagetitle.className = "pageTitle"; 596 }
477 pagetitle.align = "center"; 597 this.addSlider = function (aoi) {
478 var titleSpan = document.createElement('span'); 598 var node = new sliderInterface(aoi, this);
479 titleSpan.id = "pageTitle-" + this.id; 599 sliders.push(node);
480 if (interfaceObject.title !== undefined && typeof interfaceObject.title == "string") { 600 return node;
481 titleSpan.textContent = interfaceObject.title; 601 }
482 } else { 602 this.mousedown = function (sliderUI) {
483 titleSpan.textContent = "Axis " + String(this.id + 1); 603 UI.selected = sliderUI;
484 } 604 UI.startTime = new Date();
485 pagetitle.appendChild(titleSpan); 605 }
486 this.sliderDOM.appendChild(pagetitle); 606 this.mouseup = function (sliderUI) {
487 607 var delta = new Date() - UI.startTime;
488 if (interfaceObject.image !== undefined || page.audioElements.some(function (a) { 608 if (delta < 200) {
489 return a.image !== undefined; 609 UI.selected.clicked();
490 })) { 610 }
491 this.sliderDOM.appendChild(this.imageHolder.root); 611 UI.selected = undefined;
492 this.imageHolder.setImage(interfaceObject.image); 612 UI.startTime = undefined;
493 } 613 }
494 // Create the slider box to hold the slider elements 614 this.handleEvent = function (event) {
495 this.canvas = document.createElement('div'); 615 if (event.preventDefault) {
496 if (this.name !== undefined) 616 event.preventDefault();
497 this.canvas.id = 'slider-' + this.name; 617 }
498 else 618 if (UI.selected === undefined) {
499 this.canvas.id = 'slider-' + this.id; 619 return;
500 this.canvas.setAttribute("interfaceid", this.id); 620 }
501 this.canvas.className = 'slider'; 621 if (event.type == "mousemove") {
502 this.canvas.align = "left"; 622 var move = event.clientX - 6;
503 this.canvas.addEventListener('dragover', function (event) { 623 var w = $(sliderRail).width();
504 event.preventDefault(); 624 move = Math.max(50, move);
505 event.dataTransfer.effectAllowed = 'none'; 625 move = Math.min(w + 50, move);
506 event.dataTransfer.dropEffect = 'copy'; 626 UI.selected.moveToPixel(move);
507 return false; 627 } else if (event.type == "touchmove") {
508 }, false); 628 var move = event.originalEvent.targetTouches[0].clientX - 6;
509 this.sliderDOM.appendChild(this.canvas); 629 var w = $(event.currentTarget).width();
510 630 move = Math.max(50, move);
511 // Create the div to hold any scale objects 631 move = Math.min(w + 50, move);
512 this.scale = document.createElement('div'); 632 UI.selected.moveToPixel(move);
513 this.scale.className = 'sliderScale'; 633 }
514 this.scale.id = 'sliderScaleHolder-' + this.id; 634 }
515 this.scale.align = 'left'; 635 sliderRail.addEventListener("mousemove", this);
516 this.sliderDOM.appendChild(this.scale); 636 sliderRail.addEventListener("touchmove", this);
517 var positionScale = this.canvas.style.width.substr(0, this.canvas.style.width.length - 2); 637 Object.defineProperties(this, {
518 var offset = 50; 638 "sliderRail": {
519 var dest = document.getElementById("slider-holder").appendChild(this.sliderDOM); 639 "value": sliderRail
520 interfaceObject.scales.forEach(function (scaleObj) { 640 }
521 var position = Number(scaleObj.position) * 0.01;
522 var pixelPosition = (position * $(this.canvas).width()) + offset;
523 var scaleDOM = document.createElement('span');
524 scaleDOM.className = "ape-marker-text";
525 scaleDOM.textContent = scaleObj.text;
526 scaleDOM.setAttribute('value', position);
527 this.scale.appendChild(scaleDOM);
528 scaleDOM.style.left = Math.floor((pixelPosition - ($(scaleDOM).width() / 2))) + 'px';
529 }, this);
530
531 this.createSliderObject = function (audioObject, label) {
532 var trackObj = document.createElement('div');
533 trackObj.align = "center";
534 trackObj.className = 'track-slider track-slider-disabled track-slider-' + audioObject.id;
535 trackObj.id = 'track-slider-' + this.id + '-' + audioObject.id;
536 trackObj.setAttribute('trackIndex', audioObject.id);
537 if (this.name !== undefined) {
538 trackObj.setAttribute('interface-name', this.name);
539 } else {
540 trackObj.setAttribute('interface-name', this.id);
541 }
542 var offset = 50;
543 // Distribute it randomnly
544 var w = window.innerWidth - (offset + 8) * 2;
545 w = Math.random() * w;
546 w = Math.floor(w + (offset + 8));
547 trackObj.style.left = w + 'px';
548 this.canvas.appendChild(trackObj);
549 this.sliders.push(trackObj);
550 this.metrics.push(new metricTracker(this));
551 var labelHolder = document.createElement("span");
552 labelHolder.textContent = label;
553 trackObj.appendChild(labelHolder);
554 var rate = convSliderPosToRate(trackObj);
555 this.metrics[this.metrics.length - 1].initialise(rate);
556 trackObj.setAttribute("slider-value", rate);
557 return trackObj;
558 };
559
560 this.resize = function (event) {
561 var sliderDiv = this.canvas;
562 var sliderScaleDiv = this.scale;
563 var width = $(sliderDiv).width();
564 var marginsize = 50;
565 // Move sliders into new position
566 this.sliders.forEach(function (slider, index) {
567 var pix = Number(slider.getAttribute("slider-value")) * width;
568 slider.style.left = (pix + marginsize) + 'px';
569 }); 641 });
570 642 }
571 // Move scale labels 643 this.getDOMRoot = function () {
572 for (var index = 0; index < this.scale.children.length; index++) { 644 return DOMRoot;
573 var scaleObj = this.scale.children[index]; 645 }
574 var position = Number(scaleObj.attributes.value.value); 646 this.getPage = function () {
575 var pixelPosition = (position * width) + marginsize; 647 return page;
576 scaleObj.style.left = Math.floor((pixelPosition - ($(scaleObj).width() / 2))) + 'px'; 648 }
577 } 649 this.clear = function () {
578 }; 650 page = undefined;
579 651 axis = [];
580 this.playing = function (id) { 652 AOIs = [];
581 var node = audioEngineContext.audioObjects.find(function (a) { 653 DOMRoot.innerHTML = "";
582 return a.id == id; 654 }
655 this.initialisePage = function (page_init) {
656 this.clear();
657 page = page_init;
658 var interfaceObj = interfaceContext.getCombinedInterfaces(page);
659 // Create each of the interface axis
660 interfaceObj.forEach(function (i) {
661 var node = new axisObject(i, this);
662 axis.push(node);
663 }, this);
664
665 // Create the audioObject interface objects for each aO.
666 page.audioElements.forEach(function (element, index) {
667 var audioObject = audioEngineContext.newTrack(element);
668 if (element.type == 'outside-reference') {
669 // Construct outside reference;
670 var orNode = new outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder"));
671 audioObject.bindInterface(orNode);
672 } else {
673 var aoi = new audioObjectInterface(audioObject, this);
674 var label = interfaceContext.getLabel(page.label, index, page.labelStart);
675 axis.forEach(function (a) {
676 var node = a.addSlider(aoi);
677 node.setLabel(label);
678 aoi.addSlider(node);
679 audioObject.bindInterface(aoi);
680 });
681 }
583 }); 682 });
584 if (node === undefined) { 683 }
585 this.imageHolder.setImage(interfaceObject.image || ""); 684 this.pageXMLSave = function (store, pageSpecification) {
586 return; 685 AOIs.forEach(function (ao) {
587 } 686 ao.pageXMLSave(store);
588 var imgurl = node.specification.image || interfaceObject.image || "";
589 this.imageHolder.setImage(imgurl);
590 }
591 }
592
593 function sliderObject(audioObject, interfaceObjects, index) {
594 // Create a new slider object;
595 this.parent = audioObject;
596 this.trackSliderObjects = [];
597 this.label = interfaceContext.getLabel(audioObject.specification.parent.label, index, audioObject.specification.parent.labelStart);
598 this.playing = false;
599 for (var i = 0; i < interfaceContext.interfaceSliders.length; i++) {
600 var trackObj = interfaceContext.interfaceSliders[i].createSliderObject(audioObject, this.label);
601 this.trackSliderObjects.push(trackObj);
602 }
603
604 // Onclick, switch playback to that track
605
606 this.enable = function () {
607 if (this.parent.state == 1) {
608 $(this.trackSliderObjects).each(function (i, trackObj) {
609 $(trackObj).removeClass('track-slider-disabled');
610 });
611 }
612 };
613 this.updateLoading = function (progress) {
614 if (progress != 100) {
615 progress = String(progress);
616 progress = progress.split('.')[0];
617 this.trackSliderObjects[0].children[0].textContent = progress + '%';
618 } else {
619 this.trackSliderObjects[0].children[0].textContent = this.label;
620 }
621 };
622 this.startPlayback = function () {
623 $('.track-slider').removeClass('track-slider-playing');
624 var name = ".track-slider-" + this.parent.id;
625 $(name).addClass('track-slider-playing');
626 interfaceContext.commentBoxes.highlightById(audioObject.id);
627 $('.outside-reference').removeClass('track-slider-playing');
628 this.playing = true;
629
630 if (this.parent.specification.parent.playOne || specification.playOne) {
631 $('.track-slider').addClass('track-slider-disabled');
632 $('.outside-reference').addClass('track-slider-disabled');
633 }
634 interfaceContext.interfaceSliders.forEach(function (ts) {
635 ts.playing(this.parent.id);
636 }, this);
637 };
638 this.stopPlayback = function () {
639 if (this.playing) {
640 this.playing = false;
641 var name = ".track-slider-" + this.parent.id;
642 $(name).removeClass('track-slider-playing');
643 $('.track-slider').removeClass('track-slider-disabled');
644 $('.outside-reference').removeClass('track-slider-disabled');
645 var box = interfaceContext.commentBoxes.boxes.find(function (a) {
646 return a.id === audioObject.id;
647 });
648 if (box) {
649 box.highlight(false);
650 }
651 }
652 };
653 this.exportXMLDOM = function (audioObject) {
654 // Called by the audioObject holding this element. Must be present
655 var obj = [];
656 $(this.trackSliderObjects).each(function (i, trackObj) {
657 var node = storage.document.createElement('value');
658 if (trackObj.getAttribute("interface-name") !== "null") {
659 node.setAttribute("interface-name", trackObj.getAttribute("interface-name"));
660 }
661 node.textContent = convSliderPosToRate(trackObj);
662 obj.push(node);
663 }); 687 });
664 688 }
665 return obj;
666 };
667 this.getValue = function () {
668 return convSliderPosToRate(this.trackSliderObjects[0]);
669 };
670 this.getPresentedId = function () {
671 return this.label;
672 };
673 this.canMove = function () {
674 return true;
675 };
676 this.error = function () {
677 // audioObject has an error!!
678 this.playback.textContent = "Error";
679 $(this.playback).addClass("error-colour");
680 };
681 } 689 }
682 690
683 function outsideReferenceDOM(audioObject, index, inject) { 691 function outsideReferenceDOM(audioObject, index, inject) {
684 this.parent = audioObject; 692 this.parent = audioObject;
685 this.outsideReferenceHolder = document.createElement('div'); 693 this.outsideReferenceHolder = document.createElement('div');
831 // You can use this space to add any extra nodes to your XML <audioHolder> saves 839 // You can use this space to add any extra nodes to your XML <audioHolder> saves
832 // Get the current <page> information in store (remember to appendChild your data to it) 840 // Get the current <page> information in store (remember to appendChild your data to it)
833 // pageSpecification is the current page node configuration 841 // pageSpecification is the current page node configuration
834 // To create new XML nodes, use storage.document.createElement(); 842 // To create new XML nodes, use storage.document.createElement();
835 843
836 if (interfaceContext.interfaceSliders.length == 1) { 844 APE.pageXMLSave(store, pageSpecification);
837 // If there is only one axis, there only needs to be one metric return
838 return;
839 }
840 var audioelements = store.getElementsByTagName("audioelement");
841 for (var i = 0; i < audioelements.length; i++) {
842 // Have to append the metric specific nodes
843 if (pageSpecification.outsideReference === undefined || pageSpecification.outsideReference.id != audioelements[i].id) {
844 var inject = audioelements[i].getElementsByTagName("metric");
845 if (inject.length === 0) {
846 inject = storage.document.createElement("metric");
847 } else {
848 inject = inject[0];
849 }
850 for (var k = 0; k < interfaceContext.interfaceSliders.length; k++) {
851 var mrnodes = interfaceContext.interfaceSliders[k].metrics[i].exportXMLDOM(inject);
852 for (var j = 0; j < mrnodes.length; j++) {
853 var name = mrnodes[j].getAttribute("name");
854 if (name == "elementTracker" || name == "elementTrackerFull" || name == "elementInitialPosition" || name == "elementFlagMoved") {
855 if (interfaceContext.interfaceSliders[k].name !== null) {
856 mrnodes[j].setAttribute("interface-name", interfaceContext.interfaceSliders[k].name);
857 }
858 mrnodes[j].setAttribute("interface-id", k);
859 }
860 }
861 }
862 }
863 }
864 } 845 }