# HG changeset patch # User Nicholas Jillings # Date 1505240643 -3600 # Node ID c93687862a79c99047684248d9218149dee1b4e5 # Parent c29ef0cc741f030d39639fc1b0242f512f8bab3e# Parent 9cdcde1dafd8b10b55ea132857bf3a90bc1f70d7 Merge branch 'vnext' into Dev_main diff -r 9cdcde1dafd8 -r c93687862a79 .gitignore --- a/.gitignore Tue Sep 12 19:23:56 2017 +0100 +++ b/.gitignore Tue Sep 12 19:24:03 2017 +0100 @@ -11,3 +11,6 @@ *.DS_STORE *.swp *.swo +saves/ratings/* +saves/timelines/* +saves/timelines_movement/* diff -r 9cdcde1dafd8 -r c93687862a79 interfaces/ape.js --- a/interfaces/ape.js Tue Sep 12 19:23:56 2017 +0100 +++ b/interfaces/ape.js Tue Sep 12 19:24:03 2017 +0100 @@ -21,136 +21,15 @@ testContent.id = 'testContent'; // Bindings for interfaceContext - interfaceContext.checkAllPlayed = function () { - var hasBeenPlayed = audioEngineContext.checkAllPlayed(); - if (hasBeenPlayed.length > 0) // if a fragment has not been played yet - { - var str = ""; - if (hasBeenPlayed.length > 1) { - for (var i = 0; i < hasBeenPlayed.length; i++) { - var ao_id = audioEngineContext.audioObjects[hasBeenPlayed[i]].interfaceDOM.getPresentedId(); - str = str + ao_id; // start from 1 - if (i < hasBeenPlayed.length - 2) { - str += ", "; - } else if (i == hasBeenPlayed.length - 2) { - str += " or "; - } - } - str = 'You have not played fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.'; - } else { - str = 'You have not played fragment ' + (audioEngineContext.audioObjects[hasBeenPlayed[0]].interfaceDOM.getPresentedId()) + ' yet. Please listen, rate and comment all samples before submitting.'; - } - this.storeErrorNode(str); - interfaceContext.lightbox.post("Message", str); - return false; - } - return true; - }; interfaceContext.checkAllMoved = function () { - var state = true; - var str = 'You have not moved the following sliders. '; - for (var i = 0; i < this.interfaceSliders.length; i++) { - 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()) { - state = false; - interfaceTID.push(j); - } - } - if (interfaceTID.length !== 0) { - var interfaceName = this.interfaceSliders[i].interfaceObject.title; - if (interfaceName === undefined) { - str += 'On axis ' + String(i + 1) + ' you must move '; - } else { - str += 'On axis "' + interfaceName + '" you must move '; - } - if (interfaceTID.length == 1) { - str += 'slider ' + (audioEngineContext.audioObjects[interfaceTID[0]].interfaceDOM.getPresentedId()) + '. '; // start from 1 - } else { - str += 'sliders '; - for (var k = 0; k < interfaceTID.length - 1; k++) { - str += (audioEngineContext.audioObjects[interfaceTID[k]].interfaceDOM.getPresentedId()) + ', '; // start from 1 - } - str += (audioEngineContext.audioObjects[interfaceTID[interfaceTID.length - 1]].interfaceDOM.getPresentedId()) + '. '; - } - } - } - if (state !== true) { - this.storeErrorNode(str); - interfaceContext.lightbox.post("Message", str); - console.log(str); - } - return state; + return module.checkAllMoved(); }; interfaceContext.checkScaleRange = function () { - var audioObjs = audioEngineContext.audioObjects; - var audioHolder = testState.stateMap[testState.stateIndex]; - var interfaceObject = this.interfaceSliders[0].interfaceObject; - var state = true; - var str = ''; - 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. '; - } - }); - if (state !== true) { - this.storeErrorNode(str); - interfaceContext.lightbox.post("Message", str); - console.log(str); - } - return state; + return module.checkScaleRange(); }; - Interface.prototype.objectSelected = null; - Interface.prototype.objectMoved = false; - Interface.prototype.selectObject = function (object) { - if (this.objectSelected === null) { - this.objectSelected = object; - this.objectMoved = false; - } - }; - Interface.prototype.moveObject = function () { - if (this.objectMoved === false) { - this.objectMoved = true; - } - }; - Interface.prototype.releaseObject = function () { - this.objectSelected = null; - this.objectMoved = false; - }; - Interface.prototype.getSelectedObject = function () { - return this.objectSelected; - }; - Interface.prototype.hasSelectedObjectMoved = function () { - return this.objectMoved; - }; - - // Bindings for slider interfaces - Interface.prototype.interfaceSliders = []; - // Bindings for audioObjects // Create the top div for the Title element @@ -220,12 +99,13 @@ interfaceContext.insertPoint.appendChild(testContent); // Load the full interface + window.module = new ape(); testState.initialise(); testState.advanceState(); - } function loadTest(audioHolderObject) { + module.clear(); var width = window.innerWidth; var height = window.innerHeight; var id = audioHolderObject.id; @@ -246,15 +126,10 @@ document.getElementById("test-title").textContent = audioHolderObject.title; } - // Delete outside reference document.getElementById("outside-reference-holder").innerHTML = ""; var interfaceObj = interfaceContext.getCombinedInterfaces(audioHolderObject); - interfaceObj.forEach(function (interfaceObjectInstance) { - // Create the div box to center align - interfaceContext.interfaceSliders.push(new interfaceSliderHolder(interfaceObjectInstance, audioHolderObject)); - }); interfaceObj.forEach(function (interface) { interface.options.forEach(function (option) { if (option.type == "show") { @@ -298,113 +173,7 @@ var loopPlayback = audioHolderObject.loop; - var currentTestHolder = document.createElement('audioHolder'); - currentTestHolder.id = audioHolderObject.id; - currentTestHolder.repeatCount = audioHolderObject.repeatCount; - - // Find all the audioElements from the audioHolder - $(audioHolderObject.audioElements).each(function (index, element) { - // Find URL of track - // In this jQuery loop, variable 'this' holds the current audioElement. - var audioObject = audioEngineContext.newTrack(element); - // Check if an outside reference - if (element.type == 'outside-reference') { - // Construct outside reference; - var orNode = new outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder")); - audioObject.bindInterface(orNode); - } else { - // Create a slider per track - var sliderNode = new sliderObject(audioObject, interfaceObj, index); - audioObject.bindInterface(sliderNode); - interfaceContext.commentBoxes.createCommentBox(audioObject); - } - }); - - // Initialse the interfaceSlider object metrics - - $('.track-slider').mousedown(function (event) { - interfaceContext.selectObject($(this)[0]); - }); - $('.track-slider').on('touchstart', null, function (event) { - interfaceContext.selectObject($(this)[0]); - }); - - $('.track-slider').mousemove(function (event) { - event.preventDefault(); - }); - - $('.slider').mousemove(function (event) { - event.preventDefault(); - var obj = interfaceContext.getSelectedObject(); - if (obj === null) { - return; - } - var move = event.clientX - 6; - var w = $(event.currentTarget).width(); - move = Math.max(50, move); - move = Math.min(w + 50, move); - $(obj).css("left", move + "px"); - interfaceContext.moveObject(); - }); - - $('.slider').on('touchmove', null, function (event) { - event.preventDefault(); - var obj = interfaceContext.getSelectedObject(); - if (obj === null) { - return; - } - var move = event.originalEvent.targetTouches[0].clientX - 6; - var w = $(event.currentTarget).width(); - move = Math.max(50, move); - move = Math.min(w + 50, move); - $(obj).css("left", move + "px"); - interfaceContext.moveObject(); - }); - - $(document).mouseup(function (event) { - event.preventDefault(); - var obj = interfaceContext.getSelectedObject(); - if (obj === null) { - return; - } - var interfaceID = obj.parentElement.getAttribute("interfaceid"); - var trackID = obj.getAttribute("trackindex"); - var id; - if (interfaceContext.hasSelectedObjectMoved() === true) { - var l = $(obj).css("left"); - id = obj.getAttribute('trackIndex'); - var time = audioEngineContext.timer.getTestTime(); - var rate = convSliderPosToRate(obj); - audioEngineContext.audioObjects[id].metric.moved(time, rate); - interfaceContext.interfaceSliders[interfaceID].metrics[trackID].moved(time, rate); - console.log("slider " + id + " moved to " + rate + ' (' + time + ')'); - obj.setAttribute("slider-value", convSliderPosToRate(obj)); - } else { - id = Number(obj.attributes.trackIndex.value); - //audioEngineContext.metric.sliderPlayed(id); - audioEngineContext.play(id); - } - interfaceContext.releaseObject(); - }); - - $('.slider').on('touchend', null, function (event) { - var obj = interfaceContext.getSelectedObject(); - if (obj === null) { - return; - } - var interfaceID = obj.parentElement.getAttribute("interfaceid"); - var trackID = obj.getAttribute("trackindex"); - if (interfaceContext.hasSelectedObjectMoved() === true) { - var l = $(obj).css("left"); - var id = obj.getAttribute('trackIndex'); - var time = audioEngineContext.timer.getTestTime(); - var rate = convSliderPosToRate(obj); - audioEngineContext.audioObjects[id].metric.moved(time, rate); - interfaceContext.interfaceSliders[interfaceID].metrics[trackID].moved(time, rate); - console.log("slider " + id + " moved to " + rate + ' (' + time + ')'); - } - interfaceContext.releaseObject(); - }); + module.initialisePage(audioHolderObject); var interfaceList = audioHolderObject.interfaces.concat(specification.interfaces); for (var k = 0; k < interfaceList.length; k++) { @@ -447,237 +216,474 @@ //testWaitIndicator(); } -function interfaceSliderHolder(interfaceObject, page) { - this.sliders = []; - this.metrics = []; - this.id = document.getElementsByClassName("sliderCanvasDiv").length; - this.name = interfaceObject.name; - this.interfaceObject = interfaceObject; - this.sliderDOM = document.createElement('div'); - this.sliderDOM.className = 'sliderCanvasDiv'; - this.sliderDOM.id = 'sliderCanvasHolder-' + this.id; - this.imageHolder = (function () { - var imageController = {}; - imageController.root = document.createElement("div"); - imageController.root.className = "imageController"; - imageController.img = document.createElement("img"); - imageController.root.appendChild(imageController.img); - imageController.setImage = function (src) { - imageController.img.src = ""; - if (typeof src !== "string" || src.length === undefined) { +function ape() { + var axis = [] + var DOMRoot = document.getElementById("slider-holder"); + var AOIs = []; + var page = undefined; + + function audioObjectInterface(audioObject, parent) { + // The audioObject communicates with this object + var playing = false; + var sliders = []; + this.enable = function () { + sliders.forEach(function (s) { + s.enable(); + }); + } + + this.updateLoading = function (p) { + sliders.forEach(function (s) { + s.updateLoading(p); + }); + } + + this.startPlayback = function () { + playing = true; + sliders.forEach(function (s) { + s.playing(); + }); + } + + this.stopPlayback = function () { + playing = false; + sliders.forEach(function (s) { + s.stopped(); + }); + } + + this.getValue = function () { + return sliders[0].value(); + } + + this.getPresentedId = function () { + return sliders[0].label; + } + + this.canMove = function () { + return true; + } + + this.exportXMLDOM = function (audioObject) { + var elements = []; + sliders.forEach(function (s) { + elements.push(s.exportXMLDOM()); + }); + return elements; + } + + this.error = function () { + sliders.forEach(function (s) { + s.error(); + }); + } + + this.addSlider = function (s) { + sliders.push(s); + } + + this.clicked = function (event) { + if (!playing) { + audioEngineContext.play(audioObject.id); + } else { + audioEngineContext.stop(); + } + playing = !playing; + } + + this.pageXMLSave = function (store) { + var inject = audioObject.storeDOM.getElementsByTagName("metric")[0]; + sliders.forEach(function (s) { + s.pageXMLSave(inject); + }); + } + + } + + function axisObject(interfaceObject, parent) { + + function sliderInterface(AOI, axisInterface) { + var trackObj = document.createElement('div'); + var labelHolder = document.createElement("span"); + var label = ""; + var metric = new metricTracker(this); + trackObj.align = "center"; + trackObj.className = 'track-slider track-slider-disabled'; + trackObj.appendChild(labelHolder); + trackObj.style.left = (Math.random() * $(sliderRail).width()) + 50 + "px"; + axisInterface.sliderRail.appendChild(trackObj); + metric.initialise(this.value); + this.setLabel = function (s) { + label = s; + } + this.resize = function (event) { + var width = $(axisInterface.sliderRail).width(); + var w = Number(value * width + 50); + trackObj.style.left = String(w) + "px"; + } + this.playing = function () { + trackObj.classList.add("track-slider-playing"); + } + this.stopped = function () { + trackObj.classList.remove("track-slider-playing"); + } + this.enable = function () { + trackObj.addEventListener("mousedown", this); + trackObj.addEventListener("mouseup", this); + trackObj.addEventListener("touchstart", this); + trackObj.classList.remove("track-slider-disabled"); + labelHolder.textContent = label; + } + this.updateLoading = function (progress) { + labelHolder.textContent = progress + "%"; + } + this.exportXMLDOM = function () { + var node = storage.document.createElement('value'); + node.setAttribute("interface-name", axisInterface.name) + node.textContent = this.value(); + return node; + } + this.error = function () { + trackObj.classList.add("error-colour"); + trackObj.removeEventListener("mousedown"); + trackObj.removeEventListener("mouseup"); + trackObj.removeEventListener("touchstart"); + } + var timing = undefined; + this.handleEvent = function (e) { + // This is only for the mousedown / touchdown + if (e.preventDefault) { + e.preventDefault(); + } + if (e.type == "mousedown" || e.type == "touchstart") { + axisInterface.mousedown(this); + } else if (e.type == "mouseup") { + axisInterface.mouseup(this); + } + } + this.clicked = function (e) { + AOI.clicked(); + } + this.pageXMLSave = function (inject) { + var nodes = metric.exportXMLDOM(inject); + nodes.forEach(function (elem) { + var name = elem.getAttribute("name"); + if (name == "elementTracker" || name == "elementTrackerFull" || name == "elementInitialPosition" || name == "elementFlagMoved") { + elem.setAttribute("interface-name", axisInterface.name); + } else { + inject.removeChild(elem); + } + }); + } + this.hasMoved = function () { + return metric.wasMoved; + } + Object.defineProperties(this, { + "DOM": { + "value": trackObj + }, + "value": { + "value": function () { + var maxPix = $(axisInterface.sliderRail).width(); + var pix = trackObj.style.left.substr(0, trackObj.style.left.length - 2); + return (pix - 50) / maxPix; + } + }, + "moveToPixel": { + "value": function (pix) { + var t = audioEngineContext.timer.getTestTime(); + trackObj.style.left = String(pix) + "px"; + metric.moved(t, this.value); + } + }, + "label": { + "get": function () { + return label; + }, + "set": function () {} + } + }); + } + + function createScaleMarkers(interfaceObject, root, w) { + interfaceObject.scales.forEach(function (scaleObj) { + var position = Number(scaleObj.position) * 0.01; + var pixelPosition = (position * w) + 50; + var scaleDOM = document.createElement('span'); + scaleDOM.className = "ape-marker-text"; + scaleDOM.textContent = scaleObj.text; + scaleDOM.setAttribute('value', position); + root.appendChild(scaleDOM); + scaleDOM.style.left = Math.floor((pixelPosition - ($(scaleDOM).width() / 2))) + 'px'; + }, this); + } + var sliders = []; + var UI = { + selected: undefined, + startTime: undefined + } + this.name = interfaceObject.name; + var DOMRoot = document.createElement("div"); + parent.getDOMRoot().appendChild(DOMRoot); + DOMRoot.className = "sliderCanvasDiv"; + DOMRoot.id = "sliderCanvasHolder-" + this.name; + var sliders = []; + + var axisTitle = document.createElement("div"); + axisTitle.className = "pageTitle"; + axisTitle.align = "center"; + var titleSpan = document.createElement('span'); + titleSpan.id = "pageTitle-" + this.name; + if (interfaceObject.title !== undefined && typeof interfaceObject.title == "string") { + titleSpan.textContent = interfaceObject.title; + } else { + titleSpan.textContent = "Axis " + String(this.id + 1); + } + axisTitle.appendChild(titleSpan); + DOMRoot.appendChild(axisTitle); + + var imageHolder = (function () { + var imageController = {}; + imageController.root = document.createElement("div"); + imageController.root.className = "imageController"; + imageController.img = document.createElement("img"); + imageController.root.appendChild(imageController.img); + imageController.setImage = function (src) { + imageController.img.src = ""; + if (typeof src !== "string" || src.length === undefined) { + return; + } + imageController.img.src = src; + }; + return imageController; + })(); + if (interfaceObject.image !== undefined || page.audioElements.some(function (a) { + return a.image !== undefined; + })) { + DOMRoot.appendChild(imageHolder.root); + imageHolder.setImage(interfaceObject.image); + } + + // Now create the slider box to hold the fragment sliders + var sliderRail = document.createElement("div"); + sliderRail.id = "sliderrail-" + this.name; + sliderRail.className = "slider"; + sliderRail.align = "left"; + DOMRoot.appendChild(sliderRail); + + // Create the div to hold any scale objects + var scale = document.createElement("div"); + scale.className = "sliderScale"; + scale.id = "slider-scale-holder-" + this.name; + scale.slign = "left"; + DOMRoot.appendChild(scale); + createScaleMarkers(interfaceObject, scale, $(sliderRail).width()); + + this.resize = function (event) { + var w = $(sliderRail).width(); + var marginsize = 50; + sliders.forEach(function (s) { + s.resize(); + }); + scale.innerHTML = ""; + createScaleMarkers(interfaceObject, scale, $(sliderRail).width()); + } + this.playing = function (id) { + var node = audioEngineContext.audioObjects.find(function (a) { + return a.id == id; + }); + if (node === undefined) { + this.imageHolder.setImage(interfaceObject.image || ""); return; } - imageController.img.src = src; - }; - return imageController; - })(); + var imgurl = node.specification.image || interfaceObject.image || ""; + this.imageHolder.setImage(imgurl); + } + this.stopped = function () { + var imgurl = interfaceObject.image || ""; + this.imageHolder.setImage(imgurl); + } + this.addSlider = function (aoi) { + var node = new sliderInterface(aoi, this); + sliders.push(node); + return node; + } + this.mousedown = function (sliderUI) { + UI.selected = sliderUI; + UI.startTime = new Date(); + } + this.mouseup = function (sliderUI) { + var delta = new Date() - UI.startTime; + if (delta < 200) { + UI.selected.clicked(); + } + UI.selected = undefined; + UI.startTime = undefined; + } + this.handleEvent = function (event) { + if (event.preventDefault) { + event.preventDefault(); + } + if (UI.selected === undefined) { + return; + } + if (event.type == "mousemove") { + var move = event.clientX - 6; + var w = $(sliderRail).width(); + move = Math.max(50, move); + move = Math.min(w + 50, move); + UI.selected.moveToPixel(move); + } else if (event.type == "touchmove") { + var move = event.originalEvent.targetTouches[0].clientX - 6; + var w = $(event.currentTarget).width(); + move = Math.max(50, move); + move = Math.min(w + 50, move); + UI.selected.moveToPixel(move); + } + } + this.checkAllMoved = function () { + var notMoved = sliders.filter(function (s) { + return !s.hasMoved(); + }); + if (notMoved.length !== 0) { + var ls = []; + notMoved.forEach(function (s) { + ls.push(s.label); + }) + var str = "On axis \"" + interfaceObject.title + "\", "; + if (ls.length == 1) { + str += "slider " + ls[0]; + } else { + str += "sliders " + [ls.slice(0, ls.length - 1).join(", ")].concat(ls[ls.length - 1]).join(" and "); + } + str += "."; + return str; + } else { + return ""; + } + } + this.checkScaleRange = function () { + var scaleRange = interfaceObject.options.find(function (a) { + return a.name == "scalerange"; + }); + if (scaleRange === undefined) { + return ""; + } + var scales = { + min: scaleRange.min, + max: scaleRange.max + }; + var maxSlider = sliders.reduce(function (a, b) { + return Math.max(a, b.value); + }, 0); + var minSlider = sliders.reduce(function (a, b) { + return Math.min(a, b.value); + }, 100); + if (minSlider >= scales.min || maxSlider <= scales.max) { + return "On axis \"" + interfaceObject.title + "\", you have not used the required width of the scales"; + } + return ""; + } + sliderRail.addEventListener("mousemove", this); + sliderRail.addEventListener("touchmove", this); + Object.defineProperties(this, { + "sliderRail": { + "value": sliderRail + } + }); + } + this.getDOMRoot = function () { + return DOMRoot; + } + this.getPage = function () { + return page; + } + this.clear = function () { + page = undefined; + axis = []; + AOIs = []; + DOMRoot.innerHTML = ""; + } + this.initialisePage = function (page_init) { + this.clear(); + page = page_init; + var interfaceObj = interfaceContext.getCombinedInterfaces(page); + var commentBoxes = false; + // Create each of the interface axis + interfaceObj.forEach(function (i) { + var node = new axisObject(i, this); + axis.push(node); + i.options.forEach(function (o) { + if (o.type == "show" && o.name == "comments") { + commentBoxes = true; + } + }); + }, this); - var pagetitle = document.createElement('div'); - pagetitle.className = "pageTitle"; - pagetitle.align = "center"; - var titleSpan = document.createElement('span'); - titleSpan.id = "pageTitle-" + this.id; - if (interfaceObject.title !== undefined && typeof interfaceObject.title == "string") { - titleSpan.textContent = interfaceObject.title; - } else { - titleSpan.textContent = "Axis " + String(this.id + 1); + // Create the audioObject interface objects for each aO. + page.audioElements.forEach(function (element, index) { + var audioObject = audioEngineContext.newTrack(element); + if (element.type == 'outside-reference') { + // Construct outside reference; + var orNode = new outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder")); + audioObject.bindInterface(orNode); + } else { + var aoi = new audioObjectInterface(audioObject, this); + AOIs.push(aoi); + var label = interfaceContext.getLabel(page.label, index, page.labelStart); + axis.forEach(function (a) { + var node = a.addSlider(aoi); + node.setLabel(label); + aoi.addSlider(node); + audioObject.bindInterface(aoi); + if (commentBoxes) { + interfaceContext.commentBoxes.createCommentBox(audioObject); + } + }); + } + }); } - pagetitle.appendChild(titleSpan); - this.sliderDOM.appendChild(pagetitle); - - if (interfaceObject.image !== undefined || page.audioElements.some(function (a) { - return a.image !== undefined; - })) { - this.sliderDOM.appendChild(this.imageHolder.root); - this.imageHolder.setImage(interfaceObject.image); + this.checkAllMoved = function () { + var str = "You have not moved the following sliders. " + var cont = true; + axis.forEach(function (a) { + var msg = a.checkAllMoved(); + if (msg.length > 0) { + cont = false; + str += msg; + } + }); + if (!cont) { + interfaceContext.lightbox.post("Error", str); + interfaceContext.storeErrorNode(str); + console.log(str); + } + return cont; } - // Create the slider box to hold the slider elements - this.canvas = document.createElement('div'); - if (this.name !== undefined) - this.canvas.id = 'slider-' + this.name; - else - this.canvas.id = 'slider-' + this.id; - this.canvas.setAttribute("interfaceid", this.id); - this.canvas.className = 'slider'; - this.canvas.align = "left"; - this.canvas.addEventListener('dragover', function (event) { - event.preventDefault(); - event.dataTransfer.effectAllowed = 'none'; - event.dataTransfer.dropEffect = 'copy'; - return false; - }, false); - this.sliderDOM.appendChild(this.canvas); - - // Create the div to hold any scale objects - this.scale = document.createElement('div'); - this.scale.className = 'sliderScale'; - this.scale.id = 'sliderScaleHolder-' + this.id; - this.scale.align = 'left'; - this.sliderDOM.appendChild(this.scale); - 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); - 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); - 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'); - trackObj.align = "center"; - 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) { - trackObj.setAttribute('interface-name', this.name); - } else { - trackObj.setAttribute('interface-name', this.id); + this.checkScaleRange = function () { + var str = ""; + var cont = true; + axis.forEach(function (a) { + var msg = a.checkScaleRange(); + if (msg.length > 0) { + cont = false; + str += msg; + } + }); + if (!cont) { + interfaceContext.lightbox.post("Error", str); + interfaceContext.storeErrorNode(str); + console.log(str); } - var offset = 50; - // Distribute it randomnly - var w = window.innerWidth - (offset + 8) * 2; - w = Math.random() * w; - w = Math.floor(w + (offset + 8)); - trackObj.style.left = w + 'px'; - this.canvas.appendChild(trackObj); - this.sliders.push(trackObj); - this.metrics.push(new metricTracker(this)); - var labelHolder = document.createElement("span"); - labelHolder.textContent = label; - trackObj.appendChild(labelHolder); - var rate = convSliderPosToRate(trackObj); - this.metrics[this.metrics.length - 1].initialise(rate); - trackObj.setAttribute("slider-value", rate); - return trackObj; - }; - - this.resize = function (event) { - var sliderDiv = this.canvas; - var sliderScaleDiv = this.scale; - var width = $(sliderDiv).width(); - var marginsize = 50; - // Move sliders into new position - 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 pixelPosition = (position * width) + marginsize; - scaleObj.style.left = Math.floor((pixelPosition - ($(scaleObj).width() / 2))) + 'px'; - } - }; - - this.playing = function (id) { - var node = audioEngineContext.audioObjects.find(function (a) { - return a.id == id; - }); - if (node === undefined) { - this.imageHolder.setImage(interfaceObject.image || ""); - return; - } - var imgurl = node.specification.image || interfaceObject.image || ""; - this.imageHolder.setImage(imgurl); + return cont; } -} - -function sliderObject(audioObject, interfaceObjects, index) { - // Create a new slider object; - this.parent = audioObject; - this.trackSliderObjects = []; - this.label = interfaceContext.getLabel(audioObject.specification.parent.label, index, audioObject.specification.parent.labelStart); - this.playing = false; - for (var i = 0; i < interfaceContext.interfaceSliders.length; i++) { - var trackObj = interfaceContext.interfaceSliders[i].createSliderObject(audioObject, this.label); - this.trackSliderObjects.push(trackObj); - } - - // Onclick, switch playback to that track - - this.enable = function () { - if (this.parent.state == 1) { - $(this.trackSliderObjects).each(function (i, trackObj) { - $(trackObj).removeClass('track-slider-disabled'); + this.pageXMLSave = function (store, pageSpecification) { + if (axis.length > 1) { + AOIs.forEach(function (ao) { + ao.pageXMLSave(store); }); } - }; - this.updateLoading = function (progress) { - if (progress != 100) { - progress = String(progress); - progress = progress.split('.')[0]; - this.trackSliderObjects[0].children[0].textContent = progress + '%'; - } else { - this.trackSliderObjects[0].children[0].textContent = this.label; - } - }; - this.startPlayback = function () { - $('.track-slider').removeClass('track-slider-playing'); - var name = ".track-slider-" + this.parent.id; - $(name).addClass('track-slider-playing'); - interfaceContext.commentBoxes.highlightById(audioObject.id); - $('.outside-reference').removeClass('track-slider-playing'); - this.playing = true; - - if (this.parent.specification.parent.playOne || specification.playOne) { - $('.track-slider').addClass('track-slider-disabled'); - $('.outside-reference').addClass('track-slider-disabled'); - } - interfaceContext.interfaceSliders.forEach(function (ts) { - ts.playing(this.parent.id); - }, this); - }; - this.stopPlayback = function () { - if (this.playing) { - this.playing = false; - var name = ".track-slider-" + this.parent.id; - $(name).removeClass('track-slider-playing'); - $('.track-slider').removeClass('track-slider-disabled'); - $('.outside-reference').removeClass('track-slider-disabled'); - var box = interfaceContext.commentBoxes.boxes.find(function (a) { - return a.id === audioObject.id; - }); - if (box) { - box.highlight(false); - } - } - }; - this.exportXMLDOM = function (audioObject) { - // Called by the audioObject holding this element. Must be present - var obj = []; - $(this.trackSliderObjects).each(function (i, trackObj) { - var node = storage.document.createElement('value'); - if (trackObj.getAttribute("interface-name") !== "null") { - node.setAttribute("interface-name", trackObj.getAttribute("interface-name")); - } - node.textContent = convSliderPosToRate(trackObj); - obj.push(node); - }); - - return obj; - }; - this.getValue = function () { - return convSliderPosToRate(this.trackSliderObjects[0]); - }; - this.getPresentedId = function () { - return this.label; - }; - this.canMove = function () { - return true; - }; - this.error = function () { - // audioObject has an error!! - this.playback.textContent = "Error"; - $(this.playback).addClass("error-colour"); - }; + } } function outsideReferenceDOM(audioObject, index, inject) { @@ -833,32 +839,5 @@ // pageSpecification is the current page node configuration // To create new XML nodes, use storage.document.createElement(); - if (interfaceContext.interfaceSliders.length == 1) { - // If there is only one axis, there only needs to be one metric return - return; - } - var audioelements = store.getElementsByTagName("audioelement"); - for (var i = 0; i < audioelements.length; i++) { - // Have to append the metric specific nodes - if (pageSpecification.outsideReference === undefined || pageSpecification.outsideReference.id != audioelements[i].id) { - var inject = audioelements[i].getElementsByTagName("metric"); - if (inject.length === 0) { - inject = storage.document.createElement("metric"); - } else { - inject = inject[0]; - } - for (var k = 0; k < interfaceContext.interfaceSliders.length; k++) { - var mrnodes = interfaceContext.interfaceSliders[k].metrics[i].exportXMLDOM(inject); - for (var j = 0; j < mrnodes.length; j++) { - var name = mrnodes[j].getAttribute("name"); - if (name == "elementTracker" || name == "elementTrackerFull" || name == "elementInitialPosition" || name == "elementFlagMoved") { - if (interfaceContext.interfaceSliders[k].name !== null) { - mrnodes[j].setAttribute("interface-name", interfaceContext.interfaceSliders[k].name); - } - mrnodes[j].setAttribute("interface-id", k); - } - } - } - } - } + module.pageXMLSave(store, pageSpecification); } diff -r 9cdcde1dafd8 -r c93687862a79 interfaces/discrete.js --- a/interfaces/discrete.js Tue Sep 12 19:23:56 2017 +0100 +++ b/interfaces/discrete.js Tue Sep 12 19:24:03 2017 +0100 @@ -67,9 +67,19 @@ submit.onclick = buttonSubmitClick; submit.id = 'submit-button'; submit.style.float = 'left'; + + // Create the sort button + var sort = document.createElement("button"); + sort.id = "sort-fragments"; + sort.textContent = "Sort"; + sort.style.display = "inline-block"; + sort.style.visibility = "hidden"; + sort.onclick = buttonSortFragmentClick; + // Append the interface buttons into the interfaceButtons object. interfaceButtons.appendChild(playback); interfaceButtons.appendChild(submit); + interfaceButtons.appendChild(sort); // Create a slider box var sliderBox = document.createElement('div'); @@ -187,6 +197,10 @@ case "comments": interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder, true); break; + case "fragmentSort": + var button = document.getElementById('sort-fragments'); + button.style.visibility = "visible"; + break; } } }); @@ -539,6 +553,22 @@ } } +function buttonSortFragmentClick() { + var sortIndex = interfaceContext.sortFragmentsByScore(); + var sliderBox = document.getElementById("slider-holder"); + var nodes = audioEngineContext.audioObjects.filter(function (ao) { + return ao.specification.type !== "outside-reference"; + }); + var i; + nodes.forEach(function (ao) { + sliderBox.removeChild(ao.interfaceDOM.holder); + }); + for (i = 0; i < nodes.length; i++) { + var j = sortIndex[i]; + sliderBox.appendChild(nodes[j].interfaceDOM.holder); + } +} + function pageXMLSave(store, pageSpecification) { // MANDATORY // Saves a specific test page diff -r 9cdcde1dafd8 -r c93687862a79 interfaces/horizontal-sliders.js --- a/interfaces/horizontal-sliders.js Tue Sep 12 19:23:56 2017 +0100 +++ b/interfaces/horizontal-sliders.js Tue Sep 12 19:24:03 2017 +0100 @@ -62,9 +62,20 @@ submit.onclick = buttonSubmitClick; submit.id = 'submit-button'; submit.style.float = 'left'; + + // Create the sort button + var sort = document.createElement("button"); + sort.id = "sort-fragments"; + sort.textContent = "Sort"; + sort.style.display = "inline-block"; + sort.style.visibility = "hidden"; + sort.onclick = buttonSortFragmentClick; + // Append the interface buttons into the interfaceButtons object. interfaceButtons.appendChild(playback); interfaceButtons.appendChild(submit); + interfaceButtons.appendChild(sort); + // Create outside reference holder var outsideRef = document.createElement("div"); @@ -226,6 +237,10 @@ case "comments": interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder, true); break; + case "fragmentSort": + var button = document.getElementById('sort-fragments'); + button.style.visibility = "visible"; + break; } } }); @@ -419,6 +434,22 @@ }); } +function buttonSortFragmentClick() { + var sortIndex = interfaceContext.sortFragmentsByScore(); + var sliderBox = document.getElementById("slider-holder"); + var nodes = audioEngineContext.audioObjects.filter(function (ao) { + return ao.specification.type !== "outside-reference"; + }); + var i; + nodes.forEach(function (ao) { + sliderBox.removeChild(ao.interfaceDOM.holder); + }); + for (i = 0; i < nodes.length; i++) { + var j = sortIndex[i]; + sliderBox.appendChild(nodes[j].interfaceDOM.holder); + } +} + function buttonSubmitClick() // TODO: Only when all songs have been played! { var checks = testState.currentStateMap.interfaces[0].options, diff -r 9cdcde1dafd8 -r c93687862a79 interfaces/mushra.js --- a/interfaces/mushra.js Tue Sep 12 19:23:56 2017 +0100 +++ b/interfaces/mushra.js Tue Sep 12 19:24:03 2017 +0100 @@ -67,9 +67,20 @@ submit.onclick = buttonSubmitClick; submit.id = 'submit-button'; submit.style.display = 'inline-block'; + + // Create the sort button + var sort = document.createElement("button"); + sort.id = "sort-fragments"; + sort.textContent = "Sort"; + sort.style.display = "inline-block"; + sort.style.visibility = "hidden"; + sort.onclick = buttonSortFragmentClick; + // Append the interface buttons into the interfaceButtons object. interfaceButtons.appendChild(playback); interfaceButtons.appendChild(submit); + interfaceButtons.appendChild(sort); + // Create outside reference holder var outsideRef = document.createElement("div"); @@ -206,6 +217,8 @@ var interfaceOptions = interfaceObj.options; + var sortButton = document.getElementById("sort-fragments"); + sortButton.style.visibility = "hidden"; interfaceOptions.forEach(function (option) { if (option.type == "show") { switch (option.name) { @@ -239,31 +252,8 @@ interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder, true); break; case "fragmentSort": - var button = document.getElementById('sort'); - if (button === null) { - button = document.createElement("button"); - button.id = 'sort'; - button.textContent = "Sort"; - button.style.display = 'inline-block'; - var container = document.getElementById("interface-buttons"); - var neighbour = container.lastElementChild; - container.appendChild(button); - button.onclick = function () { - var sortIndex = interfaceContext.sortFragmentsByScore(); - var sliderBox = document.getElementById("slider-holder"); - var nodes = audioEngineContext.audioObjects.filter(function (ao) { - return ao.specification.type !== "outside-reference"; - }); - var i; - nodes.forEach(function (ao) { - sliderBox.removeChild(ao.interfaceDOM.holder); - }); - for (i = 0; i < nodes.length; i++) { - var j = sortIndex[i]; - sliderBox.appendChild(nodes[j].interfaceDOM.holder); - } - }; - } + var button = document.getElementById('sort-fragments'); + button.style.visibility = "visible"; break; } } @@ -513,6 +503,22 @@ }); } +function buttonSortFragmentClick() { + var sortIndex = interfaceContext.sortFragmentsByScore(); + var sliderBox = document.getElementById("slider-holder"); + var nodes = audioEngineContext.audioObjects.filter(function (ao) { + return ao.specification.type !== "outside-reference"; + }); + var i; + nodes.forEach(function (ao) { + sliderBox.removeChild(ao.interfaceDOM.holder); + }); + for (i = 0; i < nodes.length; i++) { + var j = sortIndex[i]; + sliderBox.appendChild(nodes[j].interfaceDOM.holder); + } +} + function buttonSubmitClick() // TODO: Only when all songs have been played! { var checks = testState.currentStateMap.interfaces[0].options, diff -r 9cdcde1dafd8 -r c93687862a79 interfaces/ordinal.js --- a/interfaces/ordinal.js Tue Sep 12 19:23:56 2017 +0100 +++ b/interfaces/ordinal.js Tue Sep 12 19:24:03 2017 +0100 @@ -222,6 +222,7 @@ root.addEventListener('dragleave', this, true); root.addEventListener('drop', this, true); root.addEventListener('dragend', this, true); + this.dragging = false; this.handleEvent = function (event) { if (event.type == "click") { if (playing === false) { @@ -252,6 +253,7 @@ e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/plain', audioObject.id); + this.dragging = "true"; } function dragEnter(e) { @@ -267,13 +269,10 @@ if (e.preventDefault) { e.preventDefault(); // Necessary. Allows us to drop. } - e.dataTransfer.dropEffect = 'move'; // See the section on the DataTransfer object. - - var srcid = Number(e.dataTransfer.getData("text/plain")); var elements = container.childNodes; var srcObject = audioEngineContext.audioObjects.find(function (ao) { - return ao.id === srcid; + return ao.interfaceDOM.dragging; }); var src = srcObject.interfaceDOM.root; if (src !== root) { @@ -293,8 +292,6 @@ } } - - return false; } function drop(e) { @@ -318,6 +315,7 @@ // this/e.target is the source node. $(".ordinal-element").removeClass("dragging"); $(".ordinal-element").removeClass("over"); + this.dragging = false; } this.getElementPosition = function () { diff -r 9cdcde1dafd8 -r c93687862a79 js/core.js --- a/js/core.js Tue Sep 12 19:23:56 2017 +0100 +++ b/js/core.js Tue Sep 12 19:24:03 2017 +0100 @@ -1107,7 +1107,7 @@ } else { this.buttonProceed.textContent = 'Next'; } - if (this.currentIndex > 0) + if (this.currentIndex > 0 && this.node.showBackButton) this.buttonPrevious.style.visibility = 'visible'; else this.buttonPrevious.style.visibility = 'hidden'; @@ -3608,7 +3608,7 @@ returnURL = specification.projectReturn; } } - xmlhttp.open("POST", returnURL + "php/save.php?key=" + this.key + "&saveFilenamePrefix=" + this.parent.filenamePrefix); + xmlhttp.open("POST", returnURL + "php/save.php?key=" + this.key + "&saveFilenamePrefix=" + this.parent.filenamePrefix + "&state=update"); xmlhttp.setRequestHeader('Content-Type', 'text/xml'); xmlhttp.onerror = function () { console.log('Error updating file to server!'); @@ -3646,6 +3646,7 @@ } else { saveURL += this.parent.filenamePrefix; } + saveURL += "&state=finish"; return new Promise(function (resolve, reject) { var xmlhttp = new XMLHttpRequest(); xmlhttp.open("POST", saveURL); diff -r 9cdcde1dafd8 -r c93687862a79 js/specification.js --- a/js/specification.js Tue Sep 12 19:23:56 2017 +0100 +++ b/js/specification.js Tue Sep 12 19:24:03 2017 +0100 @@ -216,6 +216,7 @@ this.location = undefined; this.options = []; this.parent = undefined; + this.showBackButton = true; this.specification = specification; this.addOption = function () { @@ -403,6 +404,12 @@ } else if (this.location == 'after') { this.location = 'post'; } + this.showBackButton = xml.getAttribute("showBackButton"); + if (this.showBackButton == "false") { + this.showBackButton = false; + } else { + this.showBackButton = true; + } var child = xml.firstElementChild; while (child) { var node = new this.OptionNode(this.specification); @@ -418,6 +425,7 @@ this.encode = function (doc) { var node = doc.createElement('survey'); node.setAttribute('location', this.location); + node.setAttribute('showBackButton', this.showBackButton); for (var i = 0; i < this.options.length; i++) { node.appendChild(this.options[i].exportXML(doc)); } diff -r 9cdcde1dafd8 -r c93687862a79 php/save.php --- a/php/save.php Tue Sep 12 19:23:56 2017 +0100 +++ b/php/save.php Tue Sep 12 19:24:03 2017 +0100 @@ -33,7 +33,17 @@ } $postText = file_get_contents('php://input'); $file_key = $_GET['key']; -$filename = '../saves/'.$saveFilenamePrefix.$file_key.".xml"; + +$update = false; +if (isset($_GET["update"])) { + $update = $_GET["update"] == "update"; +} + +if ($update) { + $filename = '../saves/update-'.$saveFilenamePrefix.$file_key.".xml"; +} else { + $filename = '../saves/'.$saveFilenamePrefix.$file_key.".xml"; +} if (!file_exists($filename)) { die('Could not find save'); @@ -132,4 +142,8 @@ // Return XML confirmation data $xml = 'OK"'.$filename.'"'; echo $xml; + +if (!$update) { + unlink('../saves/update-'.$saveFilenamePrefix.$file_key.".xml"); +} ?> diff -r 9cdcde1dafd8 -r c93687862a79 python/generate_report.py --- a/python/generate_report.py Tue Sep 12 19:23:56 2017 +0100 +++ b/python/generate_report.py Tue Sep 12 19:24:03 2017 +0100 @@ -227,17 +227,18 @@ # number of comments (interesting if comments not mandatory) for audioelement in audioelements: - response = audioelement.find("./comment/response") - was_played = audioelement.find("./metric/metricresult/[@name='elementFlagListenedTo']") - was_moved = audioelement.find("./metric/metricresult/[@name='elementFlagMoved']") - if response is not None and response.text is not None and len(response.text) > 1: - number_of_comments += 1 - else: - number_of_missing_comments += 1 - if was_played is not None and was_played.text == 'false': - not_played.append(audioelement.get('name')) - if was_moved is not None and was_moved.text == 'false': - not_moved.append(audioelement.get('name')) + if audioelement.get("type") != "outside-reference": + response = audioelement.find("./comment/response") + was_played = audioelement.find("./metric/metricresult/[@name='elementFlagListenedTo']") + was_moved = audioelement.find("./metric/metricresult/[@name='elementFlagMoved']") + if response is not None and response.text is not None and len(response.text) > 1: + number_of_comments += 1 + else: + number_of_missing_comments += 1 + if was_played is not None and was_played.text == 'false': + not_played.append(audioelement.get('name')) + if was_moved is not None and was_moved.text == 'false': + not_moved.append(audioelement.get('name')) # update global counters total_empty_comments += number_of_missing_comments diff -r 9cdcde1dafd8 -r c93687862a79 python/pythonServer.py --- a/python/pythonServer.py Tue Sep 12 19:23:56 2017 +0100 +++ b/python/pythonServer.py Tue Sep 12 19:24:03 2017 +0100 @@ -138,12 +138,15 @@ global curSaveIndex options = self.path.rsplit('?') options = options[1].rsplit('&') + update = False for option in options: optionPair = option.rsplit('=') if optionPair[0] == "key": key = optionPair[1] elif optionPair[0] == "saveFilenamePrefix": prefix = optionPair[1] + elif optionPair[0] == "state": + update = optionPair[1] == "update" if key == None: self.send_response(404) return @@ -153,6 +156,8 @@ postVars = self.rfile.read(varLen) print("Saving file key "+key) filename = prefix+'-'+key+'.xml' + if update: + filename = "update-"+filename file = open('../saves/'+filename,'wb') file.write(postVars) file.close() @@ -173,6 +178,8 @@ self.wfile.write(bytes(reply, "utf-8")) curSaveIndex += 1 curFileName = 'test-'+str(curSaveIndex)+'.xml' + if update == False: + os.remove("../saves/update-"+filename) def testSave(self): self.send_response(200) @@ -201,7 +208,6 @@ self.wfile.write(message) elif sys.version_info[0] == 3: self.wfile.write(bytes(message, "utf-8")) - def poolXML(s): pool = ET.parse('../tests/pool.xml') diff -r 9cdcde1dafd8 -r c93687862a79 python/score_parser.py --- a/python/score_parser.py Tue Sep 12 19:23:56 2017 +0100 +++ b/python/score_parser.py Tue Sep 12 19:24:03 2017 +0100 @@ -58,17 +58,16 @@ # Check if page in the store if storage.get(page_name) == None: - storage[page_name] = {'header':[], 'axis':{}} # add to the store + storage[page_name] = {'header':[], 'axis':{"default": {}}} # add to the store # Get the axis names pageConfig = root.find('./waet/page/[@id="'+page_name+'"]') for interface in pageConfig.findall('./interface'): # Get the noeds interfaceName = interface.get("name"); # Get the axis name - if interfaceName == None: + if interfaceName == None or interfaceName == "null": interfaceName = "default" # If name not set, make name 'default' - if storage[page_name]['axis'].get(interfaceName) == None: + if interfaceName not in storage[page_name]['axis'].keys(): storage[page_name]['axis'][interfaceName] = {} # If not in store for page, add empty dict - storage[page_name]['axis'][interfaceName][subject_id] = [] # Add the store for the session # header: fragment IDs in 'alphabetical' order # go to fragment column, or create new column if it doesn't exist yet @@ -76,7 +75,8 @@ # get alphabetical array of fragment IDs from this subject's XML fragmentnamelist = [] # make empty list for audioelement in page.findall("./audioelement"): # iterate over all audioelements - fragmentnamelist.append(audioelement.get('ref')) # add to list + if audioelement.get("type") != "outside-reference": + fragmentnamelist.append(audioelement.get('ref')) # add to list fragmentnamelist = sorted(fragmentnamelist); # Sort the list storage[page_name]['header'] = fragmentnamelist; @@ -87,11 +87,17 @@ axisName = value.get('interface-name') if axisName == None or axisName == "null": axisName = 'default' + print(storage[page_name]['axis']) axisStore = storage[page_name]['axis'][axisName] + try: + subjectStore = axisStore[subject_id] + except KeyError: + axisStore[subject_id] = [] + subjectStore = axisStore[subject_id] if hasattr(value, 'text'): - axisStore[subject_id].append(value.text) + subjectStore.append(value.text) else: - axisStore[subject_id].append('') + subjectStore.append('') # Now create the individual files for page_name in storage: diff -r 9cdcde1dafd8 -r c93687862a79 python/timeline_view_movement.py --- a/python/timeline_view_movement.py Tue Sep 12 19:23:56 2017 +0100 +++ b/python/timeline_view_movement.py Tue Sep 12 19:24:03 2017 +0100 @@ -74,6 +74,10 @@ if page_name is None: # ignore 'empty' audio_holders print("Skipping empty page name from "+subject_id+".") break + + if page.get("state") != "complete": + print("Skipping non-completed page "+page_name+" from "+subject_id+".") + break # subtract total page length from subsequent page event times page_time_temp = page.find("./metric/metricresult/[@id='testTime']") @@ -108,11 +112,20 @@ if audioelement is not None: # Check it exists audio_id = str(audioelement.get('ref')) - # break if no initial position or move events registered + # break if outside-reference + if audioelement.get("type") == "outside-reference": + break; + + # break if no initial position.... initial_position_temp = audioelement.find("./metric/metricresult/[@name='elementInitialPosition']") if initial_position_temp is None: print("Skipping "+page_name+" from "+subject_id+": does not have initial positions specified.") break + # ... or move events registered + movements = audioelement.find("./metric/metricresult[@name='elementTrackerFull']") + if movements is None: + print("Skipping "+page_name+" from "+subject_id+": does not have trackers.") + break # get move events, initial and eventual position initial_position = float(initial_position_temp.text) @@ -299,13 +312,20 @@ interfaces = page_setup.findall("./interface") interface_title = interfaces[0].find("./title") scales = interfaces[0].findall("./scales") # get first interface by default - scalelabels = scales[0].findall("./scalelabel") # get first scale by default - + labelpos = [] # array of scalelabel positions labelstr = [] # array of strings at labels - for scalelabel in scalelabels: - labelpos.append(float(scalelabel.get('position'))/100.0) - labelstr.append(scalelabel.text) + + # No scales given. Use normal floats + if len(scales) is 0: + labelpos = [0.0, 1.0] + labelstr = ["0", "100"] + else: + scalelabels = scales[0].findall("./scalelabel") # get first scale by default + + for scalelabel in scalelabels: + labelpos.append(float(scalelabel.get('position'))/100.0) + labelstr.append(scalelabel.text) # use interface name as Y axis label if interface_title is not None: diff -r 9cdcde1dafd8 -r c93687862a79 test_create.html --- a/test_create.html Tue Sep 12 19:23:56 2017 +0100 +++ b/test_create.html Tue Sep 12 19:24:03 2017 +0100 @@ -142,6 +142,12 @@

Pre Test Survey

+
+
+ Show back button: + +
+

Survey Entry

@@ -273,6 +279,12 @@

Post Test Survey

+
+
+ Show back button: + +
+

Survey Entry

@@ -550,6 +562,12 @@

Pre Page Survey

+
+
+ Show back button: + +
+

Survey Entry

@@ -681,6 +699,12 @@

Post Page Survey

+
+
+ Show back button: + +
+

Survey Entry

diff -r 9cdcde1dafd8 -r c93687862a79 tests/examples/AB_example.xml --- a/tests/examples/AB_example.xml Tue Sep 12 19:23:56 2017 +0100 +++ b/tests/examples/AB_example.xml Tue Sep 12 19:24:03 2017 +0100 @@ -45,10 +45,6 @@ elementListenTracker - - - Test Error Message - diff -r 9cdcde1dafd8 -r c93687862a79 tests/examples/APE_example.xml --- a/tests/examples/APE_example.xml Tue Sep 12 19:23:56 2017 +0100 +++ b/tests/examples/APE_example.xml Tue Sep 12 19:24:03 2017 +0100 @@ -123,7 +123,7 @@ - + Please describe the overall character diff -r 9cdcde1dafd8 -r c93687862a79 tests/examples/mushra_example.xml --- a/tests/examples/mushra_example.xml Tue Sep 12 19:23:56 2017 +0100 +++ b/tests/examples/mushra_example.xml Tue Sep 12 19:24:03 2017 +0100 @@ -112,24 +112,24 @@ - + What is your general experience with numbers? - + Please enter your overall preference - - + + Please describe the overall character - + diff -r 9cdcde1dafd8 -r c93687862a79 tests/examples/radio_example.xml --- a/tests/examples/radio_example.xml Tue Sep 12 19:23:56 2017 +0100 +++ b/tests/examples/radio_example.xml Tue Sep 12 19:24:03 2017 +0100 @@ -29,9 +29,9 @@ (5) Inaudible - - - - + + + + diff -r 9cdcde1dafd8 -r c93687862a79 xml/test-schema.xsd --- a/xml/test-schema.xsd Tue Sep 12 19:23:56 2017 +0100 +++ b/xml/test-schema.xsd Tue Sep 12 19:24:03 2017 +0100 @@ -547,6 +547,7 @@ +