# HG changeset patch # User Nicholas Jillings # Date 1492182172 -3600 # Node ID 2dfc19a33bbc1fccd44ff407b3b7b97f5e52c1b7 # Parent 549e2f97a4018ad0fa90675f5ca19e1421da72c1# Parent b9efbbe0d829f31def8ed1128c2da88bcee89e25 Merge branch 'master' into vnext # Conflicts: # js/core.js # js/specification.js diff -r b9efbbe0d829 -r 2dfc19a33bbc interfaces/AB.js --- a/interfaces/AB.js Thu Apr 13 11:36:24 2017 +0100 +++ b/interfaces/AB.js Fri Apr 14 16:02:52 2017 +0100 @@ -1,6 +1,6 @@ // Once this is loaded and parsed, begin execution loadInterface(); - +/*globals window, interfaceContext, testState, Interface, audioEngineContext, console, document, specification, $, storage*/ function loadInterface() { // Get the dimensions of the screen available to the page var width = window.innerWidth; @@ -10,34 +10,6 @@ // Custom comparator Object Interface.prototype.comparator = null; - Interface.prototype.checkScaleRange = function (min, max) { - var page = testState.getCurrentTestPage(); - var audioObjects = audioEngineContext.audioObjects; - var state = true; - var str = "Please keep listening. "; - var minRanking = Infinity; - var maxRanking = -Infinity; - for (var ao of audioObjects) { - var rank = ao.interfaceDOM.getValue(); - if (rank < minRanking) { - minRanking = rank; - } - if (rank > maxRanking) { - maxRanking = rank; - } - } - if (maxRanking * 100 < max) { - str += "At least one fragment must be selected." - state = false; - } - if (!state) { - console.log(str); - this.storeErrorNode(str); - interfaceContext.lightbox.post("Message", str); - } - return state; - } - // The injection point into the HTML page interfaceContext.insertPoint = document.getElementById("topLevelBody"); var testContent = document.createElement('div'); @@ -52,7 +24,7 @@ titleSpan.id = "test-title"; // Set title to that defined in XML, else set to default - if (titleAttr != undefined) { + if (titleAttr !== undefined) { titleSpan.textContent = titleAttr; } else { titleSpan.textContent = 'Listening test'; @@ -63,7 +35,8 @@ var pagetitle = document.createElement('div'); pagetitle.className = "pageTitle"; pagetitle.align = "center"; - var titleSpan = document.createElement('span'); + + titleSpan = document.createElement('span'); titleSpan.id = "pageTitle"; pagetitle.appendChild(titleSpan); @@ -150,10 +123,10 @@ // Set the page title if (typeof audioHolderObject.title == "string" && audioHolderObject.title.length > 0) { - document.getElementById("test-title").textContent = audioHolderObject.title + document.getElementById("test-title").textContent = audioHolderObject.title; } - if (interfaceObj.title != null) { + if (interfaceObj.title !== null) { document.getElementById("pageTitle").textContent = interfaceObj.title; } @@ -182,7 +155,7 @@ switch (option.name) { case "playhead": var playbackHolder = document.getElementById('playback-holder'); - if (playbackHolder == null) { + if (playbackHolder === null) { playbackHolder = document.createElement('div'); playbackHolder.id = 'playback-holder'; playbackHolder.style.width = "100%"; @@ -194,7 +167,7 @@ break; case "page-count": var pagecountHolder = document.getElementById('page-count'); - if (pagecountHolder == null) { + if (pagecountHolder === null) { pagecountHolder = document.createElement('div'); pagecountHolder.id = 'page-count'; document.getElementById('interface-buttons').appendChild(pagecountHolder); @@ -202,7 +175,7 @@ pagecountHolder.innerHTML = 'Page ' + (testState.stateIndex + 1) + ' of ' + testState.stateMap.length + ''; break; case "volume": - if (document.getElementById('master-volume-holder-float') == null) { + if (document.getElementById('master-volume-holder-float') === null) { feedbackHolder.appendChild(interfaceContext.volume.object); } break; @@ -246,51 +219,50 @@ this.playback.textContent = "Listen"; this.box.appendChild(this.selector); this.box.appendChild(this.playback); - this.selector.onclick = function (event) { + this.selectorClicked = function () { + var i; var time = audioEngineContext.timer.getTestTime(); - if ($(event.currentTarget).hasClass('disabled')) { + if (this.parent.state !== 1) { + interfaceContext.lightbox.post("Message", "Please wait for the sample to load"); console.log("Please wait until sample has loaded"); return; } - if (audioEngineContext.status == 0) { + if (audioEngineContext.status === 0) { interfaceContext.lightbox.post("Message", "Please listen to the samples before making a selection"); console.log("Please listen to the samples before making a selection"); return; } - var id = event.currentTarget.parentElement.getAttribute('track-id'); - interfaceContext.comparator.selected = id; - if ($(event.currentTarget).hasClass("selected")) { - $(".comparator-selector").removeClass('selected'); - for (var i = 0; i < interfaceContext.comparator.comparators.length; i++) { - var obj = interfaceContext.comparator.comparators[i]; - obj.parent.metric.moved(time, 0); - obj.value = 0; + interfaceContext.comparator.selected = this.id; + $(".comparator-selector").removeClass('selected'); + $(this.selector).addClass('selected'); + this.comparator.comparators.forEach(function (a) { + if (a !== this) { + a.value = 0; + } else { + a.value = 1; } - } else { - $(".comparator-selector").removeClass('selected'); - $(event.currentTarget).addClass('selected'); - for (var i = 0; i < interfaceContext.comparator.comparators.length; i++) { - var obj = interfaceContext.comparator.comparators[i]; - if (i == id) { - obj.value = 1; - } else { - obj.value = 0; - } - obj.parent.metric.moved(time, obj.value); - } - console.log("Selected " + id + ' (' + time + ')'); - } + a.parent.metric.moved(time, a.value); + }, this); + console.log("Selected " + this.id + ' (' + time + ')'); }; this.playback.setAttribute("playstate", "ready"); - this.playback.onclick = function (event) { - var id = event.currentTarget.parentElement.getAttribute('track-id'); - if (event.currentTarget.getAttribute("playstate") == "ready") { - audioEngineContext.play(id); - } else if (event.currentTarget.getAttribute("playstate") == "playing") { + this.playbackClicked = function () { + if (this.playback.getAttribute("playstate") == "ready") { + audioEngineContext.play(this.id); + } else if (this.playback.getAttribute("playstate") == "playing") { audioEngineContext.stop(); } }; + this.handleEvent = function (event) { + if (event.currentTarget === this.selector) { + this.selectorClicked(); + } else if (event.currentTarget === this.playback) { + this.playbackClicked(); + } + } + this.playback.addEventListener("click", this); + this.selector.addEventListener("click", this); this.enable = function () { if (this.parent.state == 1) { @@ -311,7 +283,7 @@ // audioObject has an error!! this.playback.textContent = "Error"; $(this.playback).addClass("error-colour"); - } + }; this.startPlayback = function () { if (this.parent.specification.parent.playOne || specification.playOne) { $('.comparator-button').text('Wait'); @@ -369,6 +341,11 @@ label = interfaceContext.getLabel(labelType, index, audioHolderObject.labelStart); } var node = new this.comparatorBox(audioObject, index, label); + Object.defineProperties(node, { + 'comparator': { + 'value': this + } + }); audioObject.bindInterface(node); this.comparators.push(node); this.boxHolders.appendChild(node.box); @@ -392,7 +369,7 @@ document.getElementById('box-holders').style.width = boxW + 'px'; var outsideRef = document.getElementById('outside-reference'); - if (outsideRef != null) { + if (outsideRef !== null) { outsideRef.style.left = (window.innerWidth - 120) / 2 + 'px'; } } @@ -403,41 +380,39 @@ for (var i = 0; i < checks.length; i++) { if (checks[i].type == 'check') { + var checkState; switch (checks[i].name) { case 'fragmentPlayed': // Check if all fragments have been played - var checkState = interfaceContext.checkAllPlayed(); - if (checkState == false) { + checkState = interfaceContext.checkAllPlayed(); + if (checkState === false) { canContinue = false; } break; case 'fragmentFullPlayback': // Check all fragments have been played to their full length - var checkState = interfaceContext.checkFragmentsFullyPlayed(); - if (checkState == false) { + checkState = interfaceContext.checkFragmentsFullyPlayed(); + if (checkState === false) { canContinue = false; } break; case 'fragmentMoved': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllMoved(); - if (checkState == false) { + checkState = interfaceContext.checkAllMoved(); + if (checkState === false) { canContinue = false; } break; case 'fragmentComments': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllCommented(); - if (checkState == false) { + checkState = interfaceContext.checkAllCommented(); + if (checkState === false) { canContinue = false; } break; case 'scalerange': // Check the scale has been used effectively - var checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max); - if (checkState == false) { - canContinue = false; - } + console.log("WARNING - Check 'scalerange' does not make sense in AB/ABX! Ignoring!"); break; default: console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); @@ -455,7 +430,7 @@ playback.click(); // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options } else { - if (audioEngineContext.timer.testStarted == false) { + if (audioEngineContext.timer.testStarted === false) { interfaceContext.lightbox.post("Warning", 'You have not started the test! Please click play on a sample to begin the test!'); return; } diff -r b9efbbe0d829 -r 2dfc19a33bbc interfaces/ABX.js --- a/interfaces/ABX.js Thu Apr 13 11:36:24 2017 +0100 +++ b/interfaces/ABX.js Fri Apr 14 16:02:52 2017 +0100 @@ -4,6 +4,7 @@ */ // Once this is loaded and parsed, begin execution +/* globals interfaceContext, Interface, testState, audioEngineContext, console, document, window, feedbackHolder, $, specification, storage*/ loadInterface(); function loadInterface() { @@ -12,34 +13,6 @@ interfaceContext.insertPoint.innerHTML = ""; // Clear the current schema - Interface.prototype.checkScaleRange = function (min, max) { - var page = testState.getCurrentTestPage(); - var audioObjects = audioEngineContext.audioObjects; - var state = true; - var str = "Please keep listening. "; - var minRanking = Infinity; - var maxRanking = -Infinity; - for (var ao of audioObjects) { - var rank = ao.interfaceDOM.getValue(); - if (rank < minRanking) { - minRanking = rank; - } - if (rank > maxRanking) { - maxRanking = rank; - } - } - if (maxRanking * 100 < max) { - str += "At least one fragment must be selected." - state = false; - } - if (!state) { - console.log(str); - this.storeErrorNode(str); - interfaceContext.lightbox.post("Message", str); - } - return state; - } - // Custom comparator Object Interface.prototype.comparator = null; @@ -57,7 +30,7 @@ titleSpan.id = "test-title"; // Set title to that defined in XML, else set to default - if (titleAttr != undefined) { + if (titleAttr !== undefined) { titleSpan.textContent = titleAttr; } else { titleSpan.textContent = 'Listening test'; @@ -68,7 +41,8 @@ var pagetitle = document.createElement('div'); pagetitle.className = "pageTitle"; pagetitle.align = "center"; - var titleSpan = document.createElement('span'); + + titleSpan = document.createElement('span'); titleSpan.id = "pageTitle"; pagetitle.appendChild(titleSpan); @@ -131,7 +105,7 @@ // Load the full interface testState.initialise(); testState.advanceState(); -}; +} function loadTest(page) { // Called each time a new test page is to be build. The page specification node is the only item passed in @@ -148,10 +122,10 @@ // Set the page title if (typeof page.title == "string" && page.title.length > 0) { - document.getElementById("test-title").textContent = page.title + document.getElementById("test-title").textContent = page.title; } - if (interfaceObj.title != null) { + if (interfaceObj.title !== null) { document.getElementById("pageTitle").textContent = interfaceObj.title; } @@ -163,7 +137,7 @@ switch (option.name) { case "playhead": var playbackHolder = document.getElementById('playback-holder'); - if (playbackHolder == null) { + if (playbackHolder === null) { playbackHolder = document.createElement('div'); playbackHolder.style.width = "100%"; playbackHolder.style.float = "left"; @@ -174,7 +148,7 @@ break; case "page-count": var pagecountHolder = document.getElementById('page-count'); - if (pagecountHolder == null) { + if (pagecountHolder === null) { pagecountHolder = document.createElement('div'); pagecountHolder.id = 'page-count'; } @@ -183,7 +157,7 @@ inject.appendChild(pagecountHolder); break; case "volume": - if (document.getElementById('master-volume-holder') == null) { + if (document.getElementById('master-volume-holder') === null) { feedbackHolder.appendChild(interfaceContext.volume.object); } break; @@ -231,60 +205,54 @@ this.playback.textContent = "Listen"; this.box.appendChild(this.selector); this.box.appendChild(this.playback); - this.selector.onclick = function (event) { - var label = event.currentTarget.children[0].textContent; + this.selectorClicked = function (event) { if (label == "X" || label == "x") { return; } var time = audioEngineContext.timer.getTestTime(); - if ($(event.currentTarget).hasClass('disabled')) { + if (this.disabled) { + interfaceContext.lightbox.post("Message", "Please wait until sample has loaded"); console.log("Please wait until sample has loaded"); return; } - if (audioEngineContext.status == 0) { + if (audioEngineContext.status === 0) { interfaceContext.lightbox.post("Message", "Please listen to the samples before making a selection"); console.log("Please listen to the samples before making a selection"); return; } - var id = event.currentTarget.parentElement.getAttribute('track-id'); - interfaceContext.comparator.selected = id; - if ($(event.currentTarget).hasClass("selected")) { - $(".comparator-selector").removeClass('selected'); - for (var i = 0; i < interfaceContext.comparator.pair.length; i++) { - var obj = interfaceContext.comparator.pair[i]; - obj.parent.metric.moved(time, 0); - obj.value = 0; - } - } else { - $(".comparator-selector").removeClass('selected'); - $(event.currentTarget).addClass('selected'); - for (var i = 0; i < interfaceContext.comparator.pair.length; i++) { - var obj = interfaceContext.comparator.pair[i]; - if (i == id) { - obj.value = 1; - } else { - obj.value = 0; - } - obj.parent.metric.moved(time, obj.value); - } - console.log("Selected " + id + ' (' + time + ')'); - } + interfaceContext.comparator.selected = this.id; + $(".comparator-selector").removeClass('selected'); + $(this.selector).addClass('selected'); + interfaceContext.comparator.pair.forEach(function (obj) { + obj.value = 1.0 * obj === this; + obj.parent.metric.moved(time, obj.value); + }); + console.log("Selected " + this.id + ' (' + time + ')'); }; this.playback.setAttribute("playstate", "ready"); - this.playback.onclick = function (event) { - var id = event.currentTarget.parentElement.getAttribute('track-id'); - if (event.currentTarget.getAttribute("playstate") == "ready") { - audioEngineContext.play(id); + this.playbackClicked = function (event) { + if (this.playback.getAttribute("playstate") == "ready") { + audioEngineContext.play(this.id); } else if (event.currentTarget.getAttribute("playstate") == "playing") { audioEngineContext.stop(); } }; + this.handleEvent = function (event) { + if (event.currentTarget === this.playback) { + this.playbackClicked(event); + } else if (event.currentTarget === this.selector) { + this.selectorClicked(event); + } + }; + this.playback.addEventListener("click", this); + this.selector.addEventListener("click", this); this.enable = function () { // This is used to tell the interface object that playback of this node is ready if (this.parent.state == 1) { $(this.selector).removeClass('disabled'); this.playback.disabled = false; + this.disabled = false; } }; this.updateLoading = function (progress) { @@ -345,7 +313,7 @@ }; this.error = function () { // If there is an error with the audioObject, this will be called to indicate a failure - } + }; }; // Ensure there are only two comparisons per page if (page.audioElements.length != 2) { @@ -353,31 +321,42 @@ return; } // Build the three audio elements + + function buildElement(index, audioObject) { + var label; + switch (index) { + case 0: + label = "A"; + break; + case 1: + label = "B"; + break; + default: + label = "X"; + break; + } + var node = new this.interfaceObject(audioObject, label); + audioObject.bindInterface(node); + return node; + } + this.pair = []; this.X = null; this.boxHolders = document.getElementById('box-holders'); - for (var index = 0; index < page.audioElements.length; index++) { - var element = page.audioElements[index]; + var node; + page.audioElements.forEach(function (element, index) { if (element.type != 'normal') { console.log("WARNING - ABX can only have normal elements. Page " + page.id + ", Element " + element.id); element.type = "normal"; } - var audioObject = audioEngineContext.newTrack(element); - var label; - if (index == 0) { - label = "A"; - } else { - label = "B"; - } - var node = new this.interfaceObject(audioObject, label); - audioObject.bindInterface(node); + node = buildElement.call(this, index, audioEngineContext.newTrack(element)); this.pair.push(node); this.boxHolders.appendChild(node.box); - } + }, this); var elementId = Math.floor(Math.random() * 2); //Randomly pick A or B to be X var element = new page.audioElementNode(specification); for (var atr in page.audioElements[elementId]) { - eval("element." + atr + " = page.audioElements[elementId]." + atr); + element[atr] = page.audioElements[elementId][atr]; } element.id += "-X"; if (typeof element.name == "string") { @@ -397,17 +376,9 @@ aeNode.appendChild(storage.document.createElement('metric')); root.appendChild(aeNode); // Build the 'X' element + var label; var audioObject = audioEngineContext.newTrack(element); - var label; - switch (audioObject.specification.parent.label) { - case "letter": - label = "x"; - break; - default: - label = "X"; - break; - } - var node = new this.interfaceObject(audioObject, label); + node = buildElement.call(this, 3, audioObject); node.box.children[0].classList.add('inactive'); audioObject.bindInterface(node); this.X = node; @@ -434,42 +405,28 @@ canContinue = true; for (var i = 0; i < checks.length; i++) { + var checkState = true; if (checks[i].type == 'check') { switch (checks[i].name) { case 'fragmentPlayed': // Check if all fragments have been played - var checkState = interfaceContext.checkAllPlayed(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllPlayed(); + break; case 'fragmentFullPlayback': // Check all fragments have been played to their full length - var checkState = interfaceContext.checkFragmentsFullyPlayed(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkFragmentsFullyPlayed(); break; case 'fragmentMoved': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllMoved(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllMoved(); break; case 'fragmentComments': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllCommented(); - if (checkState == false) { - canContinue = false; - } break; case 'scalerange': // Check the scale has been used effectively - var checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max); - if (checkState == false) { - canContinue = false; - } + console.log("WARNING - Check 'scalerange' does not make sense in AB/ABX! Ignoring!"); break; default: console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); @@ -477,17 +434,19 @@ } } - if (!canContinue) { + if (checkState === false) { + canContinue = false; break; } } + if (canContinue) { if (audioEngineContext.status == 1) { var playback = document.getElementById('playback-button'); playback.click(); // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options } else { - if (audioEngineContext.timer.testStarted == false) { + if (audioEngineContext.timer.testStarted === false) { interfaceContext.lightbox.post("Warning", 'You have not started the test! Please listen to a sample to begin the test!'); return; } diff -r b9efbbe0d829 -r 2dfc19a33bbc interfaces/ape.js --- a/interfaces/ape.js Thu Apr 13 11:36:24 2017 +0100 +++ b/interfaces/ape.js Fri Apr 14 16:02:52 2017 +0100 @@ -3,7 +3,8 @@ * Create the APE interface */ - +/*globals window,interfaceContext, document, audioEngineContext, console, $, Interface, testState, storage, specification */ +/*globals metricTracker */ // Once this is loaded and parsed, begin execution loadInterface(); @@ -21,7 +22,7 @@ // Bindings for interfaceContext interfaceContext.checkAllPlayed = function () { - hasBeenPlayed = audioEngineContext.checkAllPlayed(); + var hasBeenPlayed = audioEngineContext.checkAllPlayed(); if (hasBeenPlayed.length > 0) // if a fragment has not been played yet { var str = ""; @@ -53,14 +54,14 @@ var interfaceTID = []; for (var j = 0; j < this.interfaceSliders[i].metrics.length; j++) { var ao_id = this.interfaceSliders[i].sliders[j].getAttribute("trackIndex"); - if (this.interfaceSliders[i].metrics[j].wasMoved == false && audioEngineContext.audioObjects[ao_id].interfaceDOM.canMove()) { + if (this.interfaceSliders[i].metrics[j].wasMoved === false && audioEngineContext.audioObjects[ao_id].interfaceDOM.canMove()) { state = false; interfaceTID.push(j); } } - if (interfaceTID.length != 0) { + if (interfaceTID.length !== 0) { var interfaceName = this.interfaceSliders[i].interfaceObject.title; - if (interfaceName == undefined) { + if (interfaceName === undefined) { str += 'On axis ' + String(i + 1) + ' you must move '; } else { str += 'On axis "' + interfaceName + '" you must move '; @@ -76,7 +77,7 @@ } } } - if (state != true) { + if (state !== true) { this.storeErrorNode(str); interfaceContext.lightbox.post("Message", str); console.log(str); @@ -84,75 +85,38 @@ return state; }; - Interface.prototype.checkAllCommented = function () { + interfaceContext.checkScaleRange = function () { var audioObjs = audioEngineContext.audioObjects; var audioHolder = testState.stateMap[testState.stateIndex]; - var state = true; - if (audioHolder.elementComments) { - var strNums = []; - for (var i = 0; i < audioObjs.length; i++) { - if (audioObjs[i].commentDOM.trackCommentBox.value.length == 0) { - state = false; - strNums.push(i); - } - } - if (state == false) { - var str = ""; - if (strNums.length > 1) { - - for (var i = 0; i < strNums.length; i++) { - var ao_id = audioEngineContext.audioObjects[strNums[i]].interfaceDOM.getPresentedId(); - str = str + (ao_id); // start from 1 - if (i < strNums.length - 2) { - str += ", "; - } else if (i == strNums.length - 2) { - str += " or "; - } - } - str = 'You have not commented on fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.'; - } else { - str = 'You have not commented on fragment ' + (audioEngineContext.audioObjects[strNums[0]].interfaceDOM.getPresentedId()) + ' yet. Please listen, rate and comment all samples before submitting.'; - } - this.storeErrorNode(str); - interfaceContext.lightbox.post("Message", str); - console.log(str); - } - } - return state; - }; - - Interface.prototype.checkScaleRange = function () { - var audioObjs = audioEngineContext.audioObjects; - var audioHolder = testState.stateMap[testState.stateIndex]; + var interfaceObject = this.interfaceSliders[0].interfaceObject; var state = true; var str = ''; - for (var i = 0; i < this.interfaceSliders.length; i++) { - var minScale; - var maxScale; - var interfaceObject = interfaceContext.interfaceSliders[0].interfaceObject; - for (var j = 0; j < interfaceObject.options.length; j++) { - if (interfaceObject.options[j].check == "scalerange") { - minScale = interfaceObject.options[j].min; - maxScale = interfaceObject.options[j].max; - break; + this.interfaceSliders.forEach(function (sliderHolder, i) { + var scales = (function () { + var scaleRange = interfaceObject.options.find(function (a) { + return a.name == "scalerange"; + }); + return { + min: scaleRange.min, + max: scaleRange.max + }; + })(); + var range = sliderHolder.sliders.reduce(function (a, b) { + var v = convSliderPosToRate(b) * 100.0; + return { + min: Math.min(a.min, v), + max: Math.max(a.max, v) } + }, { + min: 100, + max: 0 + }); + if (range.min >= scales.min || range.max <= scales.max) { + state = false; + str += 'On axis "' + sliderHolder.interfaceObject.title + '" you have not used the full width of the scale. '; } - var minRanking = convSliderPosToRate(this.interfaceSliders[i].sliders[0]); - var maxRanking = minRanking; - for (var j = 1; j < this.interfaceSliders[i].sliders.length; j++) { - var ranking = convSliderPosToRate(this.interfaceSliders[i].sliders[j]); - if (ranking < minRanking) { - minRanking = ranking; - } else if (ranking > maxRanking) { - maxRanking = ranking; - } - } - if (minRanking > minScale || maxRanking < maxScale) { - state = false; - str += 'On axis "' + this.interfaceSliders[i].interfaceObject.title + '" you have not used the full width of the scale. '; - } - } - if (state != true) { + }); + if (state !== true) { this.storeErrorNode(str); interfaceContext.lightbox.post("Message", str); console.log(str); @@ -163,13 +127,13 @@ Interface.prototype.objectSelected = null; Interface.prototype.objectMoved = false; Interface.prototype.selectObject = function (object) { - if (this.objectSelected == null) { + if (this.objectSelected === null) { this.objectSelected = object; this.objectMoved = false; } }; Interface.prototype.moveObject = function () { - if (this.objectMoved == false) { + if (this.objectMoved === false) { this.objectMoved = true; } }; @@ -198,7 +162,7 @@ titleSpan.id = "test-title"; // Set title to that defined in XML, else set to default - if (titleAttr != undefined) { + if (titleAttr !== undefined) { titleSpan.textContent = titleAttr; } else { titleSpan.textContent = 'Listening test'; @@ -274,12 +238,12 @@ sliderHolder.innerHTML = ""; // Set labelType if default to number - if (audioHolderObject.label == "default" || audioHolderObject.label == "") { + if (audioHolderObject.label === "default" || audioHolderObject.label === "") { audioHolderObject.label = "number"; } // Set the page title if (typeof audioHolderObject.title == "string" && audioHolderObject.title.length > 0) { - document.getElementById("test-title").textContent = audioHolderObject.title + document.getElementById("test-title").textContent = audioHolderObject.title; } @@ -287,17 +251,17 @@ document.getElementById("outside-reference-holder").innerHTML = ""; var interfaceObj = interfaceContext.getCombinedInterfaces(audioHolderObject); - for (var k = 0; k < interfaceObj.length; k++) { + interfaceObj.forEach(function (interfaceObjectInstance) { // Create the div box to center align - interfaceContext.interfaceSliders.push(new interfaceSliderHolder(interfaceObj[k])); - } + interfaceContext.interfaceSliders.push(new interfaceSliderHolder(interfaceObjectInstance)); + }); interfaceObj.forEach(function (interface) { - for (var option of interface.options) { + interface.options.forEach(function (option) { if (option.type == "show") { switch (option.name) { case "playhead": var playbackHolder = document.getElementById('playback-holder'); - if (playbackHolder == null) { + if (playbackHolder === null) { playbackHolder = document.createElement('div'); playbackHolder.style.width = "100%"; playbackHolder.align = 'center'; @@ -307,7 +271,7 @@ break; case "page-count": var pagecountHolder = document.getElementById('page-count'); - if (pagecountHolder == null) { + if (pagecountHolder === null) { pagecountHolder = document.createElement('div'); pagecountHolder.id = 'page-count'; } @@ -316,7 +280,7 @@ inject.appendChild(pagecountHolder); break; case "volume": - if (document.getElementById('master-volume-holder') == null) { + if (document.getElementById('master-volume-holder') === null) { feedbackHolder.appendChild(interfaceContext.volume.object); } break; @@ -325,7 +289,7 @@ break; } } - } + }); }); var commentBoxPrefix = "Comment on fragment"; @@ -334,7 +298,7 @@ var loopPlayback = audioHolderObject.loop; - currentTestHolder = document.createElement('audioHolder'); + var currentTestHolder = document.createElement('audioHolder'); currentTestHolder.id = audioHolderObject.id; currentTestHolder.repeatCount = audioHolderObject.repeatCount; @@ -372,7 +336,7 @@ $('.slider').mousemove(function (event) { event.preventDefault(); var obj = interfaceContext.getSelectedObject(); - if (obj == null) { + if (obj === null) { return; } var move = event.clientX - 6; @@ -386,7 +350,7 @@ $('.slider').on('touchmove', null, function (event) { event.preventDefault(); var obj = interfaceContext.getSelectedObject(); - if (obj == null) { + if (obj === null) { return; } var move = event.originalEvent.targetTouches[0].clientX - 6; @@ -400,14 +364,15 @@ $(document).mouseup(function (event) { event.preventDefault(); var obj = interfaceContext.getSelectedObject(); - if (obj == null) { + if (obj === null) { return; } var interfaceID = obj.parentElement.getAttribute("interfaceid"); var trackID = obj.getAttribute("trackindex"); - if (interfaceContext.hasSelectedObjectMoved() == true) { + var id; + if (interfaceContext.hasSelectedObjectMoved() === true) { var l = $(obj).css("left"); - var id = obj.getAttribute('trackIndex'); + id = obj.getAttribute('trackIndex'); var time = audioEngineContext.timer.getTestTime(); var rate = convSliderPosToRate(obj); audioEngineContext.audioObjects[id].metric.moved(time, rate); @@ -415,7 +380,7 @@ console.log("slider " + id + " moved to " + rate + ' (' + time + ')'); obj.setAttribute("slider-value", convSliderPosToRate(obj)); } else { - var id = Number(obj.attributes['trackIndex'].value); + id = Number(obj.attributes.trackIndex.value); //audioEngineContext.metric.sliderPlayed(id); audioEngineContext.play(id); } @@ -424,12 +389,12 @@ $('.slider').on('touchend', null, function (event) { var obj = interfaceContext.getSelectedObject(); - if (obj == null) { + if (obj === null) { return; } var interfaceID = obj.parentElement.getAttribute("interfaceid"); var trackID = obj.getAttribute("trackindex"); - if (interfaceContext.hasSelectedObjectMoved() == true) { + if (interfaceContext.hasSelectedObjectMoved() === true) { var l = $(obj).css("left"); var id = obj.getAttribute('trackIndex'); var time = audioEngineContext.timer.getTestTime(); @@ -446,7 +411,7 @@ for (var i = 0; i < interfaceList[k].options.length; i++) { if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'playhead') { var playbackHolder = document.getElementById('playback-holder'); - if (playbackHolder == null) { + if (playbackHolder === null) { playbackHolder = document.createElement('div'); playbackHolder.id = "playback-holder"; playbackHolder.style.width = "100%"; @@ -456,7 +421,7 @@ } } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'page-count') { var pagecountHolder = document.getElementById('page-count'); - if (pagecountHolder == null) { + if (pagecountHolder === null) { pagecountHolder = document.createElement('div'); pagecountHolder.id = 'page-count'; } @@ -464,7 +429,7 @@ var inject = document.getElementById('interface-buttons'); inject.appendChild(pagecountHolder); } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'volume') { - if (document.getElementById('master-volume-holder') == null) { + if (document.getElementById('master-volume-holder') === null) { feedbackHolder.appendChild(interfaceContext.volume.object); } } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'comments') { @@ -497,7 +462,7 @@ pagetitle.align = "center"; var titleSpan = document.createElement('span'); titleSpan.id = "pageTitle-" + this.id; - if (interfaceObject.title != undefined && typeof interfaceObject.title == "string") { + if (interfaceObject.title !== undefined && typeof interfaceObject.title == "string") { titleSpan.textContent = interfaceObject.title; } else { titleSpan.textContent = "Axis " + String(this.id + 1); @@ -507,7 +472,7 @@ // Create the slider box to hold the slider elements this.canvas = document.createElement('div'); - if (this.name != undefined) + if (this.name !== undefined) this.canvas.id = 'slider-' + this.name; else this.canvas.id = 'slider-' + this.id; @@ -531,16 +496,16 @@ var positionScale = this.canvas.style.width.substr(0, this.canvas.style.width.length - 2); var offset = 50; var dest = document.getElementById("slider-holder").appendChild(this.sliderDOM); - for (var scaleObj of interfaceObject.scales) { + interfaceObject.scales.forEach(function (scaleObj) { var position = Number(scaleObj.position) * 0.01; var pixelPosition = (position * $(this.canvas).width()) + offset; var scaleDOM = document.createElement('span'); scaleDOM.className = "ape-marker-text"; scaleDOM.textContent = scaleObj.text; - scaleDOM.setAttribute('value', position) + scaleDOM.setAttribute('value', position); this.scale.appendChild(scaleDOM); scaleDOM.style.left = Math.floor((pixelPosition - ($(scaleDOM).width() / 2))) + 'px'; - } + }, this); this.createSliderObject = function (audioObject, label) { var trackObj = document.createElement('div'); @@ -548,7 +513,7 @@ trackObj.className = 'track-slider track-slider-disabled track-slider-' + audioObject.id; trackObj.id = 'track-slider-' + this.id + '-' + audioObject.id; trackObj.setAttribute('trackIndex', audioObject.id); - if (this.name != undefined) { + if (this.name !== undefined) { trackObj.setAttribute('interface-name', this.name); } else { trackObj.setAttribute('interface-name', this.id); @@ -572,21 +537,20 @@ }; this.resize = function (event) { - var width = window.innerWidth; var sliderDiv = this.canvas; var sliderScaleDiv = this.scale; var width = $(sliderDiv).width(); var marginsize = 50; // Move sliders into new position - for (var index = 0; index < this.sliders.length; index++) { - var pix = Number(this.sliders[index].getAttribute("slider-value")) * width; - this.sliders[index].style.left = (pix + marginsize) + 'px'; - } + this.sliders.forEach(function (slider, index) { + var pix = Number(slider.getAttribute("slider-value")) * width; + slider.style.left = (pix + marginsize) + 'px'; + }); // Move scale labels for (var index = 0; index < this.scale.children.length; index++) { var scaleObj = this.scale.children[index]; - var position = Number(scaleObj.attributes['value'].value); + var position = Number(scaleObj.attributes.value.value); var pixelPosition = (position * width) + marginsize; scaleObj.style.left = Math.floor((pixelPosition - ($(scaleObj).width() / 2))) + 'px'; } @@ -671,7 +635,7 @@ // audioObject has an error!! this.playback.textContent = "Error"; $(this.playback).addClass("error-colour"); - } + }; } function outsideReferenceDOM(audioObject, index, inject) { @@ -684,16 +648,13 @@ this.outsideReferenceHolder.appendChild(outsideReferenceHolderspan); this.outsideReferenceHolder.setAttribute('track-id', index); - this.outsideReferenceHolder.onclick = function (event) { - audioEngineContext.play(event.currentTarget.getAttribute('track-id')); + this.handleEvent = function (event) { + audioEngineContext.play(audioObject.id); $('.track-slider').removeClass('track-slider-playing'); $('.comment-div').removeClass('comment-box-playing'); - if (event.currentTarget.nodeName == 'DIV') { - $(event.currentTarget).addClass('track-slider-playing'); - } else { - $(event.currentTarget.parentElement).addClass('track-slider-playing'); - } + $(this.outsideReferenceHolder).addClass('track-slider-playing'); }; + this.outsideReferenceHolder.addEventListener("click", this.handleEvent); inject.appendChild(this.outsideReferenceHolder); this.enable = function () { if (this.parent.state == 1) { @@ -733,7 +694,7 @@ // audioObject has an error!! this.outsideReferenceHolder.textContent = "Error"; $(this.outsideReferenceHolder).addClass("error-colour"); - } + }; } function buttonSubmitClick() { @@ -741,50 +702,36 @@ canContinue = true; // Check that the anchor and reference objects are correctly placed - if (interfaceContext.checkHiddenAnchor() == false) { + if (interfaceContext.checkHiddenAnchor() === false) { return; } - if (interfaceContext.checkHiddenReference() == false) { + if (interfaceContext.checkHiddenReference() === false) { return; } for (var i = 0; i < checks.length; i++) { if (checks[i].type == 'check') { + var checkState = true; switch (checks[i].name) { case 'fragmentPlayed': // Check if all fragments have been played - var checkState = interfaceContext.checkAllPlayed(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllPlayed(); break; case 'fragmentFullPlayback': // Check all fragments have been played to their full length - var checkState = interfaceContext.checkFragmentsFullyPlayed(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkFragmentsFullyPlayed(); break; case 'fragmentMoved': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllMoved(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllMoved(); break; case 'fragmentComments': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllCommented(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllCommented(); break; case 'scalerange': // Check the scale is used to its full width outlined by the node - var checkState = interfaceContext.checkScaleRange(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkScaleRange(); break; default: console.log("WARNING - Check option " + checks[i].name + " is not supported on this interface"); @@ -792,7 +739,8 @@ } } - if (!canContinue) { + if (checkState === false) { + canContinue = false; break; } } @@ -803,7 +751,7 @@ playback.click(); // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options } else { - if (audioEngineContext.timer.testStarted == false) { + if (audioEngineContext.timer.testStarted === false) { interfaceContext.lightbox.post("Warning", 'You have not started the test! Please click a fragment to begin the test!'); return; } @@ -847,9 +795,9 @@ var audioelements = store.getElementsByTagName("audioelement"); for (var i = 0; i < audioelements.length; i++) { // Have to append the metric specific nodes - if (pageSpecification.outsideReference == null || pageSpecification.outsideReference.id != audioelements[i].id) { + if (pageSpecification.outsideReference === undefined || pageSpecification.outsideReference.id != audioelements[i].id) { var inject = audioelements[i].getElementsByTagName("metric"); - if (inject.length == 0) { + if (inject.length === 0) { inject = storage.document.createElement("metric"); } else { inject = inject[0]; @@ -861,7 +809,6 @@ if (name == "elementTracker" || name == "elementTrackerFull" || name == "elementInitialPosition" || name == "elementFlagMoved") { mrnodes[j].setAttribute("interface-name", interfaceContext.interfaceSliders[k].name); mrnodes[j].setAttribute("interface-id", k); - inject.appendChild(mrnodes[j]); } } } diff -r b9efbbe0d829 -r 2dfc19a33bbc interfaces/discrete.js --- a/interfaces/discrete.js Thu Apr 13 11:36:24 2017 +0100 +++ b/interfaces/discrete.js Fri Apr 14 16:02:52 2017 +0100 @@ -1,3 +1,4 @@ +/* globals interfaceContext, document, window, $, specification, audioEngineContext, console, window, testState, storage */ // Once this is loaded and parsed, begin execution loadInterface(); @@ -19,7 +20,7 @@ titleSpan.id = "test-title"; // Set title to that defined in XML, else set to default - if (titleAttr != undefined) { + if (titleAttr !== undefined) { titleSpan.textContent = titleAttr; } else { titleSpan.textContent = 'Listening test'; @@ -30,7 +31,8 @@ var pagetitle = document.createElement('div'); pagetitle.className = "pageTitle"; pagetitle.align = "center"; - var titleSpan = document.createElement('span'); + + titleSpan = document.createElement('span'); titleSpan.id = "pageTitle"; pagetitle.appendChild(titleSpan); @@ -112,7 +114,7 @@ // Load the full interface testState.initialise(); testState.advanceState(); -}; +} function loadTest(page) { // Called each time a new test page is to be build. The page specification node is the only item passed in @@ -128,10 +130,10 @@ // Set the page title if (typeof page.title == "string" && page.title.length > 0) { - document.getElementById("test-title").textContent = page.title + document.getElementById("test-title").textContent = page.title; } - if (interfaceObj.title != null) { + if (interfaceObj.title !== null) { document.getElementById("pageTitle").textContent = interfaceObj.title; } @@ -142,17 +144,17 @@ sliderBox.innerHTML = ""; var commentBoxPrefix = "Comment on track"; - if (interfaceObj.commentBoxPrefix != undefined) { + if (interfaceObj.commentBoxPrefix !== undefined) { commentBoxPrefix = interfaceObj.commentBoxPrefix; } var loopPlayback = page.loop; - for (var option of interfaceObj.options) { + interfaceObj.options.forEach(function (option) { if (option.type == "show") { switch (option.name) { case "playhead": var playbackHolder = document.getElementById('playback-holder'); - if (playbackHolder == null) { + if (playbackHolder === null) { playbackHolder = document.createElement('div'); playbackHolder.style.width = "100%"; playbackHolder.align = 'center'; @@ -162,7 +164,7 @@ break; case "page-count": var pagecountHolder = document.getElementById('page-count'); - if (pagecountHolder == null) { + if (pagecountHolder === null) { pagecountHolder = document.createElement('div'); pagecountHolder.id = 'page-count'; } @@ -171,7 +173,7 @@ inject.appendChild(pagecountHolder); break; case "volume": - if (document.getElementById('master-volume-holder') == null) { + if (document.getElementById('master-volume-holder') === null) { feedbackHolder.appendChild(interfaceContext.volume.object); } break; @@ -180,7 +182,7 @@ break; } } - } + }); // Find all the audioElements from the audioHolder var index = 0; @@ -223,9 +225,9 @@ // An example node, you can make this however you want for each audioElement. // However, every audioObject (audioEngineContext.audioObject) MUST have an interface object with the following // You attach them by calling audioObject.bindInterface( ) - if (interfaceScales == null || interfaceScales.length == 0) { + if (interfaceScales === null || interfaceScales.length === 0) { console.log("WARNING: The discrete radio's are built depending on the number of scale points specified! Ensure you have some specified. Defaulting to 5 for now!"); - numOptions = 5; + var numOptions = 5; } this.parent = audioObject; @@ -246,6 +248,23 @@ this.discreteHolder.className = "track-slider-range"; this.discreteHolder.style.width = window.innerWidth - 500 + 'px'; + this.radioClicked = function (event) { + var time = audioEngineContext.timer.getTestTime(); + if (audioEngineContext.status === 0) { + event.currentTarget.checked = false; + return; + } + var id = this.parent.id; + var position = this.getValue(); + this.parent.metric.moved(time, position); + console.log('slider ' + id + ' moved to ' + position + ' (' + time + ')'); + + }; + this.handleEvent = function (event) { + if (event.currentTarget.getAttribute("name") === this.parent.specification.id) { + this.radioClicked(event); + } + }; for (var i = 0; i < interfaceScales.length; i++) { var node = document.createElement('input'); node.setAttribute('type', 'radio'); @@ -256,17 +275,7 @@ node.setAttribute('id', audioObject.specification.id + '-' + String(i)); this.discretes.push(node); this.discreteHolder.appendChild(node); - node.onclick = function (event) { - if (audioEngineContext.status == 0) { - event.currentTarget.checked = false; - return; - } - var time = audioEngineContext.timer.getTestTime(); - var id = Number(event.currentTarget.parentNode.parentNode.getAttribute('trackIndex')); - var value = event.currentTarget.getAttribute('position') / 100.0; - audioEngineContext.audioObjects[id].metric.moved(time, value); - console.log('slider ' + id + ' moved to ' + value + ' (' + time + ')'); - }; + node.addEventListener("click", this); } this.play.className = 'track-slider-button'; @@ -300,9 +309,9 @@ this.play.disabled = false; this.play.textContent = "Play"; $(this.slider).removeClass('track-slider-disabled'); - for (var radio of this.discretes) { - radio.disabled = false; - } + this.discretes.forEach(function (elem) { + elem.disabled = false; + }); }; this.updateLoading = function (progress) { // progress is a value from 0 to 100 indicating the current download state of media files @@ -322,14 +331,14 @@ $(this.holder).addClass('track-slider-playing'); var outsideReference = document.getElementById('outside-reference'); this.play.textContent = "Listening"; - if (outsideReference != null) { + if (outsideReference !== null) { $(outsideReference).removeClass('track-slider-playing'); } if (this.parent.specification.parent.playOne || specification.playOne) { $('.track-slider-button').text = "Wait"; $('.track-slider-button').attr("disabled", "true"); } - } + }; this.stopPlayback = function () { // Called by audioObject when playback stops if (this.play.getAttribute("playstate") == "playing") { @@ -339,18 +348,17 @@ this.play.textContent = "Play"; $('.track-slider-button').removeAttr("disabled"); } - } + }; this.getValue = function () { // Return the current value of the object. If there is no value, return -1 - var value = -1; - for (var i = 0; i < this.discretes.length; i++) { - if (this.discretes[i].checked == true) { - value = this.discretes[i].getAttribute('position') / 100.0; - break; - } + var checkedElement = this.discretes.find(function (elem) { + return elem.checked; + }); + if (checkedElement === undefined) { + return -1; } - return value; + return checkedElement.getAttribute("position") / 100.0; }; this.getPresentedId = function () { // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale @@ -374,8 +382,8 @@ // audioObject has an error!! this.playback.textContent = "Error"; $(this.playback).addClass("error-colour"); - } -}; + }; +} function resizeWindow(event) { // Called on every window resize event, use this to scale your page properly @@ -415,7 +423,7 @@ textHolder.innerHTML = ""; ctx.fillStyle = "#000000"; ctx.setLineDash([1, 4]); - for (var scale of scales) { + scales.forEach(function (scale) { var posPercent = scale.position / 100.0; var posPix = Math.round(width * posPercent); if (posPix <= 0) { @@ -437,7 +445,7 @@ textHolder.appendChild(text); text.style.width = $(text.children[0]).width() + 'px'; text.style.left = (posPix + 150 - ($(text).width() / 2)) + 'px'; - } + }); } function buttonSubmitClick() // TODO: Only when all songs have been played! @@ -446,57 +454,45 @@ canContinue = true; // Check that the anchor and reference objects are correctly placed - if (interfaceContext.checkHiddenAnchor() == false) { + if (interfaceContext.checkHiddenAnchor() === false) { return; } - if (interfaceContext.checkHiddenReference() == false) { + if (interfaceContext.checkHiddenReference() === false) { return; } for (var i = 0; i < checks.length; i++) { + var checkState; if (checks[i].type == 'check') { switch (checks[i].name) { case 'fragmentPlayed': // Check if all fragments have been played - var checkState = interfaceContext.checkAllPlayed(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllPlayed(); break; case 'fragmentFullPlayback': // Check all fragments have been played to their full length - var checkState = interfaceContext.checkAllPlayed(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllPlayed(); console.log('NOTE: fragmentFullPlayback not currently implemented, performing check fragmentPlayed instead'); break; case 'fragmentMoved': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllMoved(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllMoved(); break; case 'fragmentComments': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllCommented(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllCommented(); break; case 'scalerange': // Check the scale has been used effectively - var checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max); break; default: console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); break; } - + if (checkState === false) { + canContinue = false; + } } if (!canContinue) { break; @@ -509,7 +505,7 @@ playback.click(); // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options } else { - if (audioEngineContext.timer.testStarted == false) { + if (audioEngineContext.timer.testStarted === false) { interfaceContext.lightbox.post("Warning", 'You have not started the test! Please press start to begin the test!'); return; } diff -r b9efbbe0d829 -r 2dfc19a33bbc interfaces/horizontal-sliders.js --- a/interfaces/horizontal-sliders.js Thu Apr 13 11:36:24 2017 +0100 +++ b/interfaces/horizontal-sliders.js Fri Apr 14 16:02:52 2017 +0100 @@ -1,4 +1,5 @@ // Once this is loaded and parsed, begin execution +/*globals interfaceContext, window, document, specification, audioEngineContext, console, testState, $, storage */ loadInterface(); function loadInterface() { @@ -19,7 +20,7 @@ titleSpan.id = "test-title"; // Set title to that defined in XML, else set to default - if (titleAttr != undefined) { + if (titleAttr !== undefined) { titleSpan.textContent = titleAttr; } else { titleSpan.textContent = 'Listening test'; @@ -30,7 +31,8 @@ var pagetitle = document.createElement('div'); pagetitle.className = "pageTitle"; pagetitle.align = "center"; - var titleSpan = document.createElement('span'); + + titleSpan = document.createElement('span'); titleSpan.id = "pageTitle"; pagetitle.appendChild(titleSpan); @@ -111,7 +113,7 @@ // Load the full interface testState.initialise(); testState.advanceState(); -}; +} function loadTest(page) { // Called each time a new test page is to be build. The page specification node is the only item passed in @@ -128,10 +130,10 @@ // Set the page title if (typeof page.title == "string" && page.title.length > 0) { - document.getElementById("test-title").textContent = page.title + document.getElementById("test-title").textContent = page.title; } - if (interfaceObj.title != null) { + if (interfaceObj.title !== null) { document.getElementById("pageTitle").textContent = interfaceObj.title; } @@ -142,7 +144,7 @@ sliderBox.innerHTML = ""; var commentBoxPrefix = "Comment on track"; - if (interfaceObj.commentBoxPrefix != undefined) { + if (interfaceObj.commentBoxPrefix !== undefined) { commentBoxPrefix = interfaceObj.commentBoxPrefix; } var loopPlayback = page.loop; @@ -186,12 +188,12 @@ } }); - for (var option of interfaceObj.options) { + interfaceObj.options.forEach(function (option) { if (option.type == "show") { switch (option.name) { case "playhead": var playbackHolder = document.getElementById('playback-holder'); - if (playbackHolder == null) { + if (playbackHolder === null) { playbackHolder = document.createElement('div'); playbackHolder.style.width = "100%"; playbackHolder.align = 'center'; @@ -201,7 +203,7 @@ break; case "page-count": var pagecountHolder = document.getElementById('page-count'); - if (pagecountHolder == null) { + if (pagecountHolder === null) { pagecountHolder = document.createElement('div'); pagecountHolder.id = 'page-count'; } @@ -210,7 +212,7 @@ inject.appendChild(pagecountHolder); break; case "volume": - if (document.getElementById('master-volume-holder') == null) { + if (document.getElementById('master-volume-holder') === null) { feedbackHolder.appendChild(interfaceContext.volume.object); } break; @@ -219,7 +221,7 @@ break; } } - } + }); // Auto-align resizeWindow(null); } @@ -291,7 +293,7 @@ $(".track-slider").removeClass('track-slider-playing'); $(this.holder).addClass('track-slider-playing'); var outsideReference = document.getElementById('outside-reference'); - if (outsideReference != null) { + if (outsideReference !== null) { $(outsideReference).removeClass('track-slider-playing'); } }; @@ -326,8 +328,8 @@ // audioObject has an error!! this.playback.textContent = "Error"; $(this.playback).addClass("error-colour"); - } -}; + }; +} function resizeWindow(event) { // Called on every window resize event, use this to scale your page properly @@ -367,7 +369,7 @@ textHolder.innerHTML = ""; ctx.fillStyle = "#000000"; ctx.setLineDash([1, 4]); - for (var scale of scales) { + scales.forEach(function (scale) { var posPercent = scale.position / 100.0; var posPix = Math.round(width * posPercent); if (posPix <= 0) { @@ -389,7 +391,7 @@ textHolder.appendChild(text); text.style.width = Math.ceil($(text).width()) + 'px'; text.style.left = (posPix + 100 - ($(text).width() / 2)) + 'px'; - } + }); } function buttonSubmitClick() // TODO: Only when all songs have been played! @@ -398,59 +400,46 @@ canContinue = true; // Check that the anchor and reference objects are correctly placed - if (interfaceContext.checkHiddenAnchor() == false) { + if (interfaceContext.checkHiddenAnchor() === false) { return; } - if (interfaceContext.checkHiddenReference() == false) { + if (interfaceContext.checkHiddenReference() === false) { return; } for (var i = 0; i < checks.length; i++) { + var checkState = true; if (checks[i].type == 'check') { switch (checks[i].name) { case 'fragmentPlayed': // Check if all fragments have been played - var checkState = interfaceContext.checkAllPlayed(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllPlayed(); break; case 'fragmentFullPlayback': // Check all fragments have been played to their full length - var checkState = interfaceContext.checkAllPlayed(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllPlayed(); console.log('NOTE: fragmentFullPlayback not currently implemented, performing check fragmentPlayed instead'); break; case 'fragmentMoved': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllMoved(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllMoved(); break; case 'fragmentComments': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllCommented(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllCommented(); break; case 'scalerange': // Check the scale has been used effectively - var checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max); + break; default: console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); break; } - } - if (!canContinue) { + if (checkState === false) { + canContinue = false; break; } } @@ -461,7 +450,7 @@ playback.click(); // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options } else { - if (audioEngineContext.timer.testStarted == false) { + if (audioEngineContext.timer.testStarted === false) { interfaceContext.lightbox.post("Warning", 'You have not started the test! Please press start to begin the test!'); return; } diff -r b9efbbe0d829 -r 2dfc19a33bbc interfaces/mushra.js --- a/interfaces/mushra.js Thu Apr 13 11:36:24 2017 +0100 +++ b/interfaces/mushra.js Fri Apr 14 16:02:52 2017 +0100 @@ -2,7 +2,7 @@ * mushra.js * Create the MUSHRA interface */ - +/*globals window, interfaceContext, document, $, specification, audioEngineContext, console, testState, storage */ // Once this is loaded and parsed, begin execution loadInterface(); @@ -25,7 +25,7 @@ titleSpan.id = "test-title"; // Set title to that defined in XML, else set to default - if (titleAttr != undefined) { + if (titleAttr !== undefined) { titleSpan.textContent = titleAttr; } else { titleSpan.textContent = 'Listening test'; @@ -36,7 +36,8 @@ var pagetitle = document.createElement('div'); pagetitle.className = "pageTitle"; pagetitle.align = "center"; - var titleSpan = document.createElement('span'); + + titleSpan = document.createElement('span'); titleSpan.id = "pageTitle"; pagetitle.appendChild(titleSpan); @@ -129,10 +130,10 @@ // Set the page title if (typeof audioHolderObject.title == "string" && audioHolderObject.title.length > 0) { - document.getElementById("test-title").textContent = audioHolderObject.title + document.getElementById("test-title").textContent = audioHolderObject.title; } - if (interfaceObj.title != null) { + if (interfaceObj.title !== null) { document.getElementById("pageTitle").textContent = interfaceObj.title; } @@ -144,12 +145,12 @@ sliderBox.innerHTML = ""; var commentBoxPrefix = "Comment on track"; - if (interfaceObj.commentBoxPrefix != undefined) { + if (interfaceObj.commentBoxPrefix !== undefined) { commentBoxPrefix = interfaceObj.commentBoxPrefix; } var loopPlayback = audioHolderObject.loop; - currentTestHolder = document.createElement('audioHolder'); + var currentTestHolder = document.createElement('audioHolder'); currentTestHolder.id = audioHolderObject.id; currentTestHolder.repeatCount = audioHolderObject.repeatCount; @@ -192,18 +193,18 @@ if (testState.currentStateMap.restrictMovement) { $(".track-slider-range").addClass("track-slider-range-disabled"); $(".track-slider-range").each(function (i, e) { - e.disabled = true + e.disabled = true; }); } var interfaceOptions = interfaceObj.options; - for (var option of interfaceOptions) { + interfaceOptions.forEach(function (option) { if (option.type == "show") { switch (option.name) { case "playhead": var playbackHolder = document.getElementById('playback-holder'); - if (playbackHolder == null) { + if (playbackHolder === null) { playbackHolder = document.createElement('div'); playbackHolder.style.width = "100%"; playbackHolder.align = 'center'; @@ -213,7 +214,7 @@ break; case "page-count": var pagecountHolder = document.getElementById('page-count'); - if (pagecountHolder == null) { + if (pagecountHolder === null) { pagecountHolder = document.createElement('div'); pagecountHolder.id = 'page-count'; } @@ -222,7 +223,7 @@ inject.appendChild(pagecountHolder); break; case "volume": - if (document.getElementById('master-volume-holder') == null) { + if (document.getElementById('master-volume-holder') === null) { feedbackHolder.appendChild(interfaceContext.volume.object); } break; @@ -231,7 +232,7 @@ break; } } - } + }); $(audioHolderObject.commentQuestions).each(function (index, element) { var node = interfaceContext.createCommentQuestion(element); @@ -257,7 +258,7 @@ this.holder.appendChild(this.slider); this.holder.appendChild(this.play); this.holder.align = "center"; - if (label == 0) { + if (label === 0) { this.holder.style.marginLeft = '0px'; } this.holder.setAttribute('trackIndex', audioObject.id); @@ -316,7 +317,7 @@ $(".track-slider").removeClass('track-slider-playing'); $(this.holder).addClass('track-slider-playing'); var outsideReference = document.getElementById('outside-reference'); - if (outsideReference != null) { + if (outsideReference !== null) { $(outsideReference).removeClass('track-slider-playing'); } this.play.textContent = "Stop"; @@ -374,7 +375,7 @@ // audioObject has an error!! this.playback.textContent = "Error"; $(this.playback).addClass("error-colour"); - } + }; } function resizeWindow(event) { @@ -382,7 +383,7 @@ // MANDATORY FUNCTION var outsideRef = document.getElementById('outside-reference'); - if (outsideRef != null) { + if (outsideRef !== null) { outsideRef.style.left = (window.innerWidth - 120) / 2 + 'px'; } @@ -428,7 +429,7 @@ var textHolder = document.getElementById('scale-text-holder'); textHolder.innerHTML = ""; var lastHeight = 0; - for (var scale of scales) { + scales.forEach(function (scale) { var posPercent = scale.position / 100.0; var posPix = (1 - posPercent) * (draw_heights[1] - draw_heights[0]) + draw_heights[0]; ctx.fillStyle = "#000000"; @@ -446,7 +447,7 @@ text.style.top = (posPix - 9) + 'px'; text.style.left = 100 - ($(text).width() + 3) + 'px'; lastHeight = posPix; - } + }); } function buttonSubmitClick() // TODO: Only when all songs have been played! @@ -455,51 +456,37 @@ canContinue = true; // Check that the anchor and reference objects are correctly placed - if (interfaceContext.checkHiddenAnchor() == false) { + if (interfaceContext.checkHiddenAnchor() === false) { return; } - if (interfaceContext.checkHiddenReference() == false) { + if (interfaceContext.checkHiddenReference() === false) { return; } for (var i = 0; i < checks.length; i++) { + var checkState = true; if (checks[i].type == 'check') { switch (checks[i].name) { case 'fragmentPlayed': // Check if all fragments have been played - var checkState = interfaceContext.checkAllPlayed(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllPlayed(); break; case 'fragmentFullPlayback': // Check all fragments have been played to their full length - var checkState = interfaceContext.checkAllPlayed(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllPlayed(); console.log('NOTE: fragmentFullPlayback not currently implemented, performing check fragmentPlayed instead'); break; case 'fragmentMoved': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllMoved(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllMoved(); break; case 'fragmentComments': // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllCommented(); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkAllCommented(); break; case 'scalerange': // Check the scale has been used effectively - var checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max); - if (checkState == false) { - canContinue = false; - } + checkState = interfaceContext.checkScaleRange(checks[i].min, checks[i].max); break; default: console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); @@ -507,7 +494,8 @@ } } - if (!canContinue) { + if (checkState === false) { + canContinue = false; break; } } @@ -518,7 +506,7 @@ playback.click(); // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options } else { - if (audioEngineContext.timer.testStarted == false) { + if (audioEngineContext.timer.testStarted === false) { interfaceContext.lightbox.post("Message", 'You have not started the test! Please press start to begin the test!'); return; } diff -r b9efbbe0d829 -r 2dfc19a33bbc interfaces/timeline.js --- a/interfaces/timeline.js Thu Apr 13 11:36:24 2017 +0100 +++ b/interfaces/timeline.js Fri Apr 14 16:02:52 2017 +0100 @@ -2,7 +2,7 @@ * WAET Timeline * This interface plots a waveform timeline per audio fragment on a page. Clicking on the fragment will generate a comment box for processing. */ - +/*globals interfaceContext, window, document, console, audioEngineContext, testState, $, storage */ // Once this is loaded and parsed, begin execution loadInterface(); @@ -77,7 +77,7 @@ // Load the full interface testState.initialise(); testState.advanceState(); -}; +} function loadTest(page) { // Called each time a new test page is to be build. The page specification node is the only item passed in @@ -94,7 +94,7 @@ document.getElementById("test-title").textContent = page.title; } - if (interfaceObj.title != null) { + if (interfaceObj.title !== null) { document.getElementById("page-title").textContent = interfaceObj.title; } @@ -103,7 +103,7 @@ outsideReferenceHolder.innerHTML = ""; var commentBoxPrefix = "Comment on track"; - if (interfaceObj.commentBoxPrefix != undefined) { + if (interfaceObj.commentBoxPrefix !== undefined) { commentBoxPrefix = interfaceObj.commentBoxPrefix; } var index = 0; @@ -116,7 +116,7 @@ var audioObject = audioEngineContext.newTrack(element); if (page.audioElements.type == 'outside-reference') { var refNode = interfaceContext.outsideReferenceDOM(audioObject, index, outsideReferenceHolder); - audioObject.bindInterface(orNode); + audioObject.bindInterface(refNode); } else { var label = interfaceContext.getLabel(labelType, index, page.labelStart); var node = new interfaceObject(audioObject, label); @@ -169,7 +169,7 @@ var titleHolder = document.createElement("div"); titleHolder.className = "comment-entry-header"; this.title = document.createElement("span"); - if (str != undefined) { + if (str !== undefined) { this.title.textContent = str; } else { this.title.textContent = "Time: " + time.toFixed(2) + "s"; @@ -186,7 +186,7 @@ handleEvent: function () { this.parent.parent.deleteComment(this.parent); } - } + }; this.clear.DOM.textContent = "Delete"; this.clear.DOM.addEventListener("click", this.clear); titleHolder.appendChild(this.clear.DOM); @@ -199,7 +199,7 @@ elem_w = Math.max(elem_w, 190); this.DOM.style.width = elem_w + "px"; this.textarea.style.width = (elem_w - 5) + "px"; - } + }; this.buildXML = function (root) { //storage.document.createElement(); var node = storage.document.createElement("comment"); @@ -211,7 +211,7 @@ node.appendChild(question); node.appendChild(comment); root.appendChild(node); - } + }; this.resize(); }, newComment: function (time) { @@ -240,7 +240,7 @@ this.deleteComment(this.list[0]); } } - } + }; this.canvas = { parent: this, @@ -283,7 +283,7 @@ } }, drawWaveform: function () { - if (this.parent.parent == undefined || this.parent.parent.buffer == undefined) { + if (this.parent.parent === undefined || this.parent.parent.buffer === undefined) { return; } var buffer = this.parent.parent.buffer.buffer; @@ -342,7 +342,7 @@ context.stroke(); }, drawMarkers: function () { - if (this.parent.parent == undefined || this.parent.parent.buffer == undefined) { + if (this.parent.parent === undefined || this.parent.parent.buffer === undefined) { return; } var context = this.layer3.getContext("2d"); @@ -362,7 +362,7 @@ var context = canvas.getContext("2d"); context.clearRect(0, 0, canvas.width, canvas.height); } - } + }; this.canvas.layer1.className = "timeline-element-canvas canvas-layer1 canvas-disabled"; this.canvas.layer2.className = "timeline-element-canvas canvas-layer2"; this.canvas.layer3.className = "timeline-element-canvas canvas-layer3"; @@ -393,7 +393,7 @@ audioEngineContext.stop(); } } - } + }; this.playButton.DOM.addEventListener("click", this.playButton); this.playButton.DOM.className = "timeline-button timeline-button-disabled"; this.playButton.DOM.disabled = true; @@ -408,7 +408,7 @@ root.style.width = w + "px"; var c_w = w - 100; this.canvas.resize(c_w); - } + }; this.enable = function () { // This is used to tell the interface object that playback of this node is ready @@ -459,8 +459,8 @@ }; this.error = function () { // If there is an error with the audioObject, this will be called to indicate a failure - } -}; + }; +} function resizeWindow(event) { // Called on every window resize event, use this to scale your page properly @@ -470,7 +470,7 @@ } function buttonSubmitClick() { - if (audioEngineContext.timer.testStarted == false) { + if (audioEngineContext.timer.testStarted === false) { interfaceContext.lightbox.post("Warning", 'You have not started the test! Please click play on a sample to begin the test!'); return; } @@ -495,7 +495,7 @@ console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); break; } - if (checkState == false) { + if (checkState === false) { canContinue = false; } } diff -r b9efbbe0d829 -r 2dfc19a33bbc js/WAVE.js --- a/js/WAVE.js Thu Apr 13 11:36:24 2017 +0100 +++ b/js/WAVE.js Fri Apr 14 16:02:52 2017 +0100 @@ -1,6 +1,7 @@ // Decode and perform WAVE file byte level manipulation +/*globals console, Uint8Array, Float32Array, Float64Array */ -find_subarray = function (arr, subarr) { +function find_subarray(arr, subarr) { var arr_length = arr.length; var subarr_length = subarr.length; var last_check_index = arr_length - subarr_length; @@ -15,7 +16,7 @@ return i; } return -1; -}; +} function convertToInteger(arr) { var value = 0; @@ -35,24 +36,24 @@ function WAVE() { // The WAVE file object - this.status == 'WAVE_DECLARED' + this.status = 'WAVE_DECLARED'; this.decoded_data = null; this.RIFF = String(); //ChunkID - this.size; //ChunkSize - this.FT_Header; //Format - this.fmt_marker; //Subchunk1ID - this.formatDataLength; //Subchunk1Size - this.type; //AudioFormat - this.num_channels; //NumChannels - this.sample_rate; //SampleRate - this.byte_rate; //ByteRate - this.block_align; //BlockAlign - this.bits_per_sample; //BitsPerSample - this.data_header; //Subchunk2ID - this.data_size; //Subchunk2Size - this.num_samples; + this.size = undefined; //ChunkSize + this.FT_Header = undefined; //Format + this.fmt_marker = undefined; //Subchunk1ID + this.formatDataLength = undefined; //Subchunk1Size + this.type = undefined; //AudioFormat + this.num_channels = undefined; //NumChannels + this.sample_rate = undefined; //SampleRate + this.byte_rate = undefined; //ByteRate + this.block_align = undefined; //BlockAlign + this.bits_per_sample = undefined; //BitsPerSample + this.data_header = undefined; //Subchunk2ID + this.data_size = undefined; //Subchunk2Size + this.num_samples = undefined; this.open = function (IOArrayBuffer) { var IOView8 = new Uint8Array(IOArrayBuffer); diff -r b9efbbe0d829 -r 2dfc19a33bbc js/loader.js --- a/js/loader.js Thu Apr 13 11:36:24 2017 +0100 +++ b/js/loader.js Fri Apr 14 16:02:52 2017 +0100 @@ -1,8 +1,8 @@ // Script to load the relevant JS files if the system supports it - +/*globals window, document */ window.onload = function () { // First check if the Web Audio API is supported - if (window.AudioContext == undefined && window.webkitAudioContext == undefined) { + if (window.AudioContext === undefined && window.webkitAudioContext === undefined) { // Display unsuported error message var body = document.getElementsByTagName("body")[0]; body.innerHTML = "

Sorry! Your browser is not supported :(

Your browser does not support the HTML5 Web Audio API. Please use one of the following supported browsers instead.

"; @@ -26,4 +26,4 @@ head.appendChild(script); } } -} +}; diff -r b9efbbe0d829 -r 2dfc19a33bbc js/loudness.js --- a/js/loudness.js Thu Apr 13 11:36:24 2017 +0100 +++ b/js/loudness.js Fri Apr 14 16:02:52 2017 +0100 @@ -5,7 +5,7 @@ * return gain values to correct for a target loudness or match loudness between * multiple objects */ - +/* globals webkitOfflineAudioContext, navigator, audioContext, Float32Array */ var interval_cal_loudness_event = null; if (typeof OfflineAudioContext == "undefined") { @@ -21,16 +21,16 @@ if (navigator.platform == 'iPad' || navigator.platform == 'iPhone') { buffer.ready(); } - if (buffer == undefined) { + if (buffer === undefined) { return 0; } - if (timescale == undefined) { + if (timescale === undefined) { timescale = "I"; } - if (target == undefined) { + if (target === undefined) { target = -23; } - if (offlineContext == undefined) { + if (offlineContext === undefined) { offlineContext = new OfflineAudioContext(audioContext.destination.channelCount, buffer.buffer.duration * audioContext.sampleRate, audioContext.sampleRate); } // Create the required filters @@ -77,12 +77,12 @@ } function calculateMeanSquared(buffer, frame_dur, frame_overlap) { - frame_size = Math.floor(buffer.sampleRate * frame_dur); - step_size = Math.floor(frame_size * (1.0 - frame_overlap)); - num_frames = Math.floor((buffer.length - frame_size) / step_size); - num_frames = Math.max(num_frames, 1); + var frame_size = Math.floor(buffer.sampleRate * frame_dur); + var step_size = Math.floor(frame_size * (1.0 - frame_overlap)); + var num_frames = Math.floor((buffer.length - frame_size) / step_size); + num_frames = Math.max(num_frames, 0); - MS = Array(buffer.numberOfChannels); + var MS = Array(buffer.numberOfChannels); for (var c = 0; c < buffer.numberOfChannels; c++) { MS[c] = new Float32Array(num_frames); var data = buffer.getChannelData(c); @@ -124,13 +124,14 @@ var num_frames = source[0].length; var num_channels = source.length; var LK = Array(num_channels); - for (var c = 0; c < num_channels; c++) { + var n, c; + for (c = 0; c < num_channels; c++) { LK[c] = []; } - for (var n = 0; n < num_frames; n++) { + for (n = 0; n < num_frames; n++) { if (blocks[n] > threshold) { - for (var c = 0; c < num_channels; c++) { + for (c = 0; c < num_channels; c++) { LK[c].push(source[c][n]); } } diff -r b9efbbe0d829 -r 2dfc19a33bbc js/specification.js --- a/js/specification.js Thu Apr 13 11:36:24 2017 +0100 +++ b/js/specification.js Fri Apr 14 16:02:52 2017 +0100 @@ -1,38 +1,40 @@ +/* globals document, console, DOMParser */ function Specification() { + var schemaRoot; + var schemaString; // Handles the decoding of the project specification XML into a simple JavaScript Object. // attributes - this.interface = null; - this.projectReturn = null; - this.returnURL = null; - this.randomiseOrder = null; - this.poolSize = null; - this.loudness = null; - this.sampleRate = null; - this.calibration = null; - this.crossFade = null; - this.preSilence = null; - this.postSilence = null; - this.playOne = null; + this.interface = undefined; + this.projectReturn = undefined; + this.returnURL = undefined; + this.randomiseOrder = undefined; + this.poolSize = undefined; + this.loudness = undefined; + this.sampleRate = undefined; + this.calibration = undefined; + this.crossFade = undefined; + this.preSilence = undefined; + this.postSilence = undefined; + this.playOne = undefined; // nodes - this.metrics = null; + this.metrics = undefined; this.preTest = undefined; this.postTest = undefined; this.pages = []; - this.interfaces = null; + this.interfaces = undefined; this.errors = []; - this.schema = null; this.exitText = "Thank you."; - this.processAttribute = function (attribute, schema, schemaRoot) { + var processAttribute = function (attribute, schema) { // attribute is the string returned from getAttribute on the XML // schema is the node - if (schema.getAttribute('name') == undefined && schema.getAttribute('ref') != undefined) { + if (schema.getAttribute('name') === null && schema.getAttribute('ref') !== undefined) { schema = schemaRoot.getAllElementsByName(schema.getAttribute('ref'))[0]; } var defaultOpt = schema.getAttribute('default'); - if (attribute == null) { + if (attribute === null) { attribute = defaultOpt; } var dataType = schema.getAttribute('type'); @@ -51,7 +53,7 @@ dataType = "string"; } } - if (attribute == null) { + if (attribute === null) { return attribute; } switch (dataType) { @@ -71,7 +73,6 @@ case "short": attribute = Number(attribute); break; - case "string": default: attribute = String(attribute); break; @@ -79,26 +80,44 @@ return attribute; }; + this.processSchema = function (schemaXSD) { + if (schemaRoot === undefined) { + schemaString = schemaXSD; + var parse = new DOMParser(); + schemaRoot = parse.parseFromString(schemaString, 'text/xml'); + Object.defineProperties(this, { + 'schema': { + 'value': schemaRoot + }, + 'schemaString': { + 'value': schemaString + } + }); + } + }; + this.getSchema = function () { + return schemaRoot; + }; + this.getSchemaString = function () { + return schemaString; + }; + this.decode = function (projectXML) { + schemaRoot = this.schema; this.errors = []; // projectXML - DOM Parsed document this.projectXML = projectXML.childNodes[0]; var setupNode = projectXML.getElementsByTagName('setup')[0]; - var schemaSetup = this.schema.getAllElementsByName('setup')[0]; + var schemaSetup = schemaRoot.getAllElementsByName('setup')[0]; // First decode the attributes var attributes = schemaSetup.getAllElementsByTagName('xs:attribute'); - for (var i = 0; i < attributes.length; i++) { + var i; + for (i = 0; i < attributes.length; i++) { var attributeName = attributes[i].getAttribute('name') || attributes[i].getAttribute('ref'); var projectAttr = setupNode.getAttribute(attributeName); - projectAttr = this.processAttribute(projectAttr, attributes[i], this.schema); - switch (typeof projectAttr) { - case "number": - case "boolean": - eval('this.' + attributeName + ' = ' + projectAttr); - break; - case "string": - eval('this.' + attributeName + ' = "' + projectAttr + '"'); - break; + projectAttr = processAttribute(projectAttr, attributes[i]); + if (projectAttr !== null) { + this[attributeName] = projectAttr; } } @@ -114,7 +133,7 @@ // Now process the survey node options var survey = setupNode.getElementsByTagName('survey'); - for (var i = 0; i < survey.length; i++) { + for (i = 0; i < survey.length; i++) { var location = survey[i].getAttribute('location'); switch (location) { case 'pre': @@ -135,7 +154,7 @@ this.errors.push("Only one node in the node allowed! Others except first ingnored!"); } this.interfaces = new this.interfaceNode(this); - if (interfaceNode.length != 0) { + if (interfaceNode.length !== 0) { interfaceNode = interfaceNode[0]; this.interfaces.decode(this, interfaceNode, this.schema.getAllElementsByName('interface')[1]); } @@ -143,7 +162,7 @@ // Page tags var pageTags = projectXML.getElementsByTagName('page'); var pageSchema = this.schema.getAllElementsByName('page')[0]; - for (var i = 0; i < pageTags.length; i++) { + for (i = 0; i < pageTags.length; i++) { var node = new this.page(this); node.decode(this, pageTags[i], pageSchema); this.pages.push(node); @@ -157,21 +176,21 @@ root.setAttribute("xsi:noNamespaceSchemaLocation", "test-schema.xsd"); // Build setup node var setup = RootDocument.createElement("setup"); - var schemaSetup = this.schema.getAllElementsByName('setup')[0]; + var schemaSetup = schemaRoot.getAllElementsByName('setup')[0]; // First decode the attributes var attributes = schemaSetup.getAllElementsByTagName('xs:attribute'); for (var i = 0; i < attributes.length; i++) { var name = attributes[i].getAttribute("name"); - if (name == undefined) { + if (name === undefined) { name = attributes[i].getAttribute("ref"); } - if (eval("this." + name + " != undefined") || attributes[i].getAttribute("use") == "required") { - eval("setup.setAttribute('" + name + "',this." + name + ")"); + if (this[name] !== undefined || attributes[i].getAttribute("use") == "required") { + setup.setAttribute(name, this[name]); } } root.appendChild(setup); // Survey node - if (this.exitText != null) { + if (this.exitText !== null) { var exitTextNode = RootDocument.createElement('exitText'); exitTextNode.textContent = this.exitText; setup.appendChild(exitTextNode); @@ -180,17 +199,17 @@ setup.appendChild(this.postTest.encode(RootDocument)); setup.appendChild(this.metrics.encode(RootDocument)); setup.appendChild(this.interfaces.encode(RootDocument)); - for (var page of this.pages) { + this.pages.forEach(function (page) { root.appendChild(page.encode(RootDocument)); - } + }); return RootDocument; }; this.surveyNode = function (specification) { - this.location = null; + this.location = undefined; this.options = []; - this.parent = null; - this.schema = specification.schema.getAllElementsByName('survey')[0]; + this.parent = undefined; + this.schema = schemaRoot.getAllElementsByName('survey')[0]; this.specification = specification; this.OptionNode = function (specification) { @@ -208,23 +227,18 @@ this.conditions = []; this.decode = function (parent, child) { - this.schema = specification.schema.getAllElementsByName(child.nodeName)[0]; + this.schema = schemaRoot.getAllElementsByName(child.nodeName)[0]; var attributeMap = this.schema.getAllElementsByTagName('xs:attribute'); - for (var i in attributeMap) { - if (isNaN(Number(i)) == true) { + var i; + for (i in attributeMap) { + if (isNaN(Number(i)) === true) { break; } var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref'); var projectAttr = child.getAttribute(attributeName); - projectAttr = parent.processAttribute(projectAttr, attributeMap[i], parent.schema); - switch (typeof projectAttr) { - case "number": - case "boolean": - eval('this.' + attributeName + ' = ' + projectAttr); - break; - case "string": - eval('this.' + attributeName + ' = "' + projectAttr + '"'); - break; + projectAttr = processAttribute(projectAttr, attributeMap[i]); + if (projectAttr !== null) { + this[attributeName] = projectAttr; } } if (child.nodeName == 'surveyentry') { @@ -239,13 +253,13 @@ this.statement = child.getElementsByTagName('statement')[0].textContent; if (this.type == "checkbox" || this.type == "radio") { var children = child.getElementsByTagName('option'); - if (children.length == null) { + if (children.length === null) { console.log('Malformed' + child.nodeName + 'entry'); this.statement = 'Malformed' + child.nodeName + 'entry'; this.type = 'statement'; } else { this.options = []; - for (var i = 0; i < children.length; i++) { + for (i = 0; i < children.length; i++) { this.options.push({ name: children[i].getAttribute('name'), text: children[i].textContent @@ -265,14 +279,14 @@ } } var conditionElements = child.getElementsByTagName("conditional"); - for (var i = 0; i < conditionElements.length; i++) { + for (i = 0; i < conditionElements.length; i++) { var condition = conditionElements[i]; var obj = { check: condition.getAttribute("check"), value: condition.getAttribute("value"), jumpToOnPass: condition.getAttribute("jumpToOnPass"), jumpToOnFail: condition.getAttribute("jumpToOnFail") - } + }; this.conditions.push(obj); } }; @@ -283,28 +297,28 @@ statement.textContent = this.statement; node.appendChild(statement); node.id = this.id; - if (this.name != undefined) { + if (this.name !== undefined) { node.setAttribute("name", this.name); } - if (this.mandatory != undefined) { + if (this.mandatory !== undefined) { node.setAttribute("mandatory", this.mandatory); } node.id = this.id; - if (this.name != undefined) { + if (this.name !== undefined) { node.setAttribute("name", this.name); } switch (this.type) { case "checkbox": - if (this.min != undefined) { + if (this.min !== undefined) { node.setAttribute("min", this.min); } else { node.setAttribute("min", "0"); } - if (this.max != undefined) { + if (this.max !== undefined) { node.setAttribute("max", this.max); } else { node.setAttribute("max", "undefined"); - } + } /* falls through */ case "radio": for (var i = 0; i < this.options.length; i++) { var option = this.options[i]; @@ -315,27 +329,27 @@ } break; case "number": - if (this.min != undefined) { + if (this.min !== undefined) { node.setAttribute("min", this.min); } - if (this.max != undefined) { + if (this.max !== undefined) { node.setAttribute("max", this.max); } break; case "question": - if (this.boxsize != undefined) { + if (this.boxsize !== undefined) { node.setAttribute("boxsize", this.boxsize); } - if (this.mandatory != undefined) { + if (this.mandatory !== undefined) { node.setAttribute("mandatory", this.mandatory); } break; case "video": - if (this.mandatory != undefined) { + if (this.mandatory !== undefined) { node.setAttribute("mandatory", this.mandatory); - } + } /* falls through */ case "youtube": - if (this.url != undefined) { + if (this.url !== undefined) { node.setAttribute("url", this.url); } break; @@ -352,17 +366,18 @@ maxText.textContent = this.rightText; node.appendChild(maxText); } + break; default: break; } - for (var condition of this.conditions) { + this.conditions.forEach(function (condition) { var conditionDOM = doc.createElement("conditional"); conditionDOM.setAttribute("check", condition.check); conditionDOM.setAttribute("value", condition.value); conditionDOM.setAttribute("jumpToOnPass", condition.jumpToOnPass); conditionDOM.setAttribute("jumpToOnFail", condition.jumpToOnFail); node.appendChild(conditionDOM); - } + }); return node; }; }; @@ -374,14 +389,14 @@ } else if (this.location == 'after') { this.location = 'post'; } - var child = xml.firstElementChild + var child = xml.firstElementChild; while (child) { var node = new this.OptionNode(this.specification); node.decode(parent, child); this.options.push(node); child = child.nextElementSibling; } - if (this.options.length == 0) { + if (this.options.length === 0) { console.log("Empty survey node"); console.log(this); } @@ -397,11 +412,11 @@ }; this.interfaceNode = function (specification) { - this.title = null; - this.name = null; + this.title = undefined; + this.name = undefined; this.options = []; this.scales = []; - this.schema = specification.schema.getAllElementsByName('interface')[1]; + this.schema = schemaRoot.getAllElementsByName('interface')[1]; this.decode = function (parent, xml) { this.name = xml.getAttribute('name'); @@ -413,25 +428,16 @@ // Extract interfaceoption node schema var interfaceOptionNodeSchema = this.schema.getAllElementsByName('interfaceoption')[0]; var attributeMap = interfaceOptionNodeSchema.getAllElementsByTagName('xs:attribute'); - for (var i = 0; i < interfaceOptionNodes.length; i++) { + var i, j; + for (i = 0; i < interfaceOptionNodes.length; i++) { var ioNode = interfaceOptionNodes[i]; var option = {}; - for (var j = 0; j < attributeMap.length; j++) { + for (j = 0; j < attributeMap.length; j++) { var attributeName = attributeMap[j].getAttribute('name') || attributeMap[j].getAttribute('ref'); var projectAttr = ioNode.getAttribute(attributeName); - if (parent.processAttribute) { - parent.processAttribute(projectAttr, attributeMap[j], parent.schema) - } else { - parent.parent.processAttribute(projectAttr, attributeMap[j], parent.parent.schema) - } - switch (typeof projectAttr) { - case "number": - case "boolean": - eval('option.' + attributeName + ' = ' + projectAttr); - break; - case "string": - eval('option.' + attributeName + ' = "' + projectAttr + '"'); - break; + projectAttr = processAttribute(projectAttr, attributeMap[j]); + if (projectAttr !== null) { + option[attributeName] = projectAttr; } } this.options.push(option); @@ -442,7 +448,7 @@ if (scaleParent.length == 1) { scaleParent = scaleParent[0]; var scalelabels = scaleParent.getAllElementsByTagName('scalelabel'); - for (var i = 0; i < scalelabels.length; i++) { + for (i = 0; i < scalelabels.length; i++) { this.scales.push({ text: scalelabels[i].textContent, position: Number(scalelabels[i].getAttribute('position')) @@ -453,27 +459,27 @@ this.encode = function (doc) { var node = doc.createElement("interface"); - if (typeof name == "string" && name.length > 0) + if (typeof this.name == "string" && this.name.length > 0) node.setAttribute("name", this.name); if (typeof this.title == "string") { var titleNode = doc.createElement("title"); titleNode.textContent = this.title; node.appendChild(titleNode); } - for (var option of this.options) { + this.options.forEach(function (option) { var child = doc.createElement("interfaceoption"); child.setAttribute("type", option.type); child.setAttribute("name", option.name); node.appendChild(child); - } - if (this.scales.length != 0) { + }); + if (this.scales.length !== 0) { var scales = doc.createElement("scales"); - for (var scale of this.scales) { + this.scales.forEach(function (scale) { var child = doc.createElement("scalelabel"); child.setAttribute("position", scale.position); child.textContent = scale.text; scales.appendChild(child); - } + }); node.appendChild(scales); } return node; @@ -485,16 +491,16 @@ this.decode = function (parent, xml) { var children = xml.getElementsByTagName('metricenable'); for (var i in children) { - if (isNaN(Number(i)) == true) { + if (isNaN(Number(i)) === true) { break; } this.enabled.push(children[i].textContent); } - } + }; this.encode = function (doc) { var node = doc.createElement('metric'); for (var i in this.enabled) { - if (isNaN(Number(i)) == true) { + if (isNaN(Number(i)) === true) { break; } var child = doc.createElement('metricenable'); @@ -502,8 +508,8 @@ node.appendChild(child); } return node; - } - } + }; + }; this.page = function (specification) { this.presentedId = undefined; @@ -512,57 +518,52 @@ this.hostURL = undefined; this.randomiseOrder = undefined; this.loop = undefined; - this.outsideReference = null; - this.loudness = null; - this.label = null; - this.labelStart = ""; - this.preTest = null; - this.postTest = null; + this.outsideReference = undefined; + this.loudness = undefined; + this.label = undefined; + this.labelStart = undefined; + this.preTest = undefined; + this.postTest = undefined; this.interfaces = []; - this.playOne = null; - this.restrictMovement = null; - this.position = null; + this.playOne = undefined; + this.restrictMovement = undefined; + this.position = undefined; this.commentBoxPrefix = "Comment on track"; this.audioElements = []; this.commentQuestions = []; - this.schema = specification.schema.getAllElementsByName("page")[0]; + this.schema = schemaRoot.getAllElementsByName("page")[0]; this.specification = specification; - this.parent = null; + this.parent = undefined; this.decode = function (parent, xml) { this.parent = parent; var attributeMap = this.schema.getAllElementsByTagName('xs:attribute'); - for (var i = 0; i < attributeMap.length; i++) { + var i, node; + for (i = 0; i < attributeMap.length; i++) { var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref'); var projectAttr = xml.getAttribute(attributeName); - projectAttr = parent.processAttribute(projectAttr, attributeMap[i], parent.schema); - switch (typeof projectAttr) { - case "number": - case "boolean": - eval('this.' + attributeName + ' = ' + projectAttr); - break; - case "string": - eval('this.' + attributeName + ' = "' + projectAttr + '"'); - break; + projectAttr = processAttribute(projectAttr, attributeMap[i]); + if (projectAttr !== null) { + this[attributeName] = projectAttr; } } // Get the title var title = xml.getElementsByTagName('title'); - if (title.length != 0 && title[0].parentElement == xml) { + if (title.length !== 0 && title[0].parentElement == xml) { this.title = title[0].textContent; } // Get the Comment Box Prefix var CBP = xml.getElementsByTagName('commentboxprefix'); - if (CBP.length != 0 && CBP[0].parentElement == xml) { + if (CBP.length !== 0 && CBP[0].parentElement == xml) { this.commentBoxPrefix = CBP[0].textContent; } // Now decode the interfaces var interfaceNode = xml.getElementsByTagName('interface'); - for (var i = 0; i < interfaceNode.length; i++) { - var node = new parent.interfaceNode(this.specification); + for (i = 0; i < interfaceNode.length; i++) { + node = new parent.interfaceNode(this.specification); node.decode(this, interfaceNode[i], parent.schema.getAllElementsByName('interface')[1]); this.interfaces.push(node); } @@ -570,17 +571,17 @@ // Now process the survey node options var survey = xml.getElementsByTagName('survey'); var surveySchema = parent.schema.getAllElementsByName('survey')[0]; - for (var i = 0; i < survey.length; i++) { + for (i = 0; i < survey.length; i++) { var location = survey[i].getAttribute('location'); if (location == 'pre' || location == 'before') { - if (this.preTest != null) { + if (this.preTest !== undefined) { this.errors.push("Already a pre/before test survey defined! Ignoring second!!"); } else { this.preTest = new parent.surveyNode(this.specification); this.preTest.decode(parent, survey[i], surveySchema); } } else if (location == 'post' || location == 'after') { - if (this.postTest != null) { + if (this.postTest !== undefined) { this.errors.push("Already a post/after test survey defined! Ignoring second!!"); } else { this.postTest = new parent.surveyNode(this.specification); @@ -591,19 +592,19 @@ // Now process the audioelement tags var audioElements = xml.getElementsByTagName('audioelement'); - for (var i = 0; i < audioElements.length; i++) { - var node = new this.audioElementNode(this.specification); - node.decode(this, audioElements[i]); - this.audioElements.push(node); + for (i = 0; i < audioElements.length; i++) { + var audioNode = new this.audioElementNode(this.specification); + audioNode.decode(this, audioElements[i]); + this.audioElements.push(audioNode); } // Now decode the commentquestions var cqNode = xml.getElementsByTagName('commentquestions'); - if (cqNode.length != 0) { + if (cqNode.length !== 0) { cqNode = cqNode[0]; var commentQuestion = cqNode.firstElementChild; while (commentQuestion) { - var node = new this.commentQuestionNode(this.specification); + node = new this.commentQuestionNode(this.specification); node.decode(parent, commentQuestion); this.commentQuestions.push(node); commentQuestion = commentQuestion.nextElementSibling; @@ -615,32 +616,30 @@ var AHNode = root.createElement("page"); // First decode the attributes var attributes = this.schema.getAllElementsByTagName('xs:attribute'); - for (var i = 0; i < attributes.length; i++) { + var i; + for (i = 0; i < attributes.length; i++) { var name = attributes[i].getAttribute("name"); - if (name == undefined) { + if (name === null) { name = attributes[i].getAttribute("ref"); } - if (eval("this." + name + " != undefined") || attributes[i].getAttribute("use") == "required") { - eval("AHNode.setAttribute('" + name + "',this." + name + ")"); + if (this[name] !== undefined || attributes[i].getAttribute("use") == "required") { + AHNode.setAttribute(name, this[name]); } } - if (this.loudness != null) { - AHNode.setAttribute("loudness", this.loudness); - } // var commentboxprefix = root.createElement("commentboxprefix"); commentboxprefix.textContent = this.commentBoxPrefix; AHNode.appendChild(commentboxprefix); - for (var i = 0; i < this.interfaces.length; i++) { + for (i = 0; i < this.interfaces.length; i++) { AHNode.appendChild(this.interfaces[i].encode(root)); } - for (var i = 0; i < this.audioElements.length; i++) { + for (i = 0; i < this.audioElements.length; i++) { AHNode.appendChild(this.audioElements[i].encode(root)); } // Create - for (var i = 0; i < this.commentQuestions.length; i++) { + for (i = 0; i < this.commentQuestions.length; i++) { AHNode.appendChild(this.commentQuestions[i].encode(root)); } @@ -650,14 +649,17 @@ }; this.commentQuestionNode = function (specification) { - this.id = null; + this.id = undefined; this.name = undefined; this.type = undefined; this.statement = undefined; - this.schema = specification.schema.getAllElementsByName('commentquestion')[0]; + this.schema = schemaRoot.getAllElementsByName('commentquestion')[0]; this.decode = function (parent, xml) { this.id = xml.id; this.name = xml.getAttribute('name'); + if (this.name === null) { + this.name = undefined; + } switch (xml.nodeName) { case "commentradio": this.type = "radio"; @@ -674,9 +676,10 @@ this.step = undefined; break; case "commentquestion": - default: this.type = "question"; break; + default: + throw ("Unknown comment type " + xml.nodeName); } this.statement = xml.getElementsByTagName('statement')[0].textContent; if (this.type == "radio" || this.type == "checkbox") { @@ -693,12 +696,12 @@ this.min = Number(xml.getAttribute("min")); this.max = Number(xml.getAttribute("max")); this.step = Number(xml.getAttribute("step")); - if (this.step == undefined) { + if (this.step === undefined) { this.step = 1; } this.value = Number(xml.getAttribute("value")); - if (this.value == undefined) { - this.value = min; + if (this.value === undefined) { + this.value = this.min; } this.leftText = xml.getElementsByTagName("minText"); if (this.leftText && this.leftText.length > 0) { @@ -728,25 +731,26 @@ node = root.createElement("commentslider"); break; case "question": - default: node = root.createElement("commentquestion"); break; + default: + throw ("Unknown type " + this.type); } node.id = this.id; node.setAttribute("type", this.type); - if (this.name != undefined) { + if (this.name !== undefined) { node.setAttribute("name", this.name); } var statement = root.createElement("statement"); statement.textContent = this.statement; node.appendChild(statement); if (this.type == "radio" || this.type == "checkbox") { - for (var option of this.options) { + this.options.forEach(function (option) { var child = root.createElement("option"); child.setAttribute("name", option.name); child.textContent = option.text; node.appendChild(child); - } + }); } if (this.type == "slider") { node.setAttribute("min", this.min); @@ -773,36 +777,30 @@ }; this.audioElementNode = function (specification) { - this.url = null; - this.id = null; - this.name = null; - this.parent = null; - this.type = null; - this.marker = null; + this.url = undefined; + this.id = undefined; + this.name = undefined; + this.parent = undefined; + this.type = undefined; + this.marker = undefined; this.enforce = false; this.gain = 0.0; - this.label = null; + this.label = undefined; this.startTime = undefined; this.stopTime = undefined; this.sampleRate = undefined; this.alternatives = []; - this.schema = specification.schema.getAllElementsByName('audioelement')[0];; - this.parent = null; + this.schema = schemaRoot.getAllElementsByName('audioelement')[0]; + this.parent = undefined; this.decode = function (parent, xml) { this.parent = parent; var attributeMap = this.schema.getAllElementsByTagName('xs:attribute'); for (var i = 0; i < attributeMap.length; i++) { var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref'); var projectAttr = xml.getAttribute(attributeName); - projectAttr = parent.parent.processAttribute(projectAttr, attributeMap[i], parent.parent.schema); - switch (typeof projectAttr) { - case "number": - case "boolean": - eval('this.' + attributeName + ' = ' + projectAttr); - break; - case "string": - eval('this.' + attributeName + ' = "' + projectAttr + '"'); - break; + projectAttr = processAttribute(projectAttr, attributeMap[i]); + if (projectAttr !== null) { + this[attributeName] = projectAttr; } } // Get the alternative nodes @@ -823,11 +821,11 @@ var attributes = this.schema.getAllElementsByTagName('xs:attribute'); for (var i = 0; i < attributes.length; i++) { var name = attributes[i].getAttribute("name"); - if (name == undefined) { + if (name === null) { name = attributes[i].getAttribute("ref"); } - if (eval("this." + name + " != undefined") || attributes[i].getAttribute("use") == "required") { - eval("AENode.setAttribute('" + name + "',this." + name + ")"); + if (this[name] !== undefined || attributes[i].getAttribute("use") == "required") { + AENode.setAttribute(name, this[name]); } } this.alternatives.forEach(function (alt) {