# HG changeset patch # User Nicholas Jillings # Date 1452677686 0 # Node ID 1330c77d212c9fd9f96a2ba6e2c892b4d1f4a104 # Parent d39d243e66011748b1357616a3a65d6a647915c4 Moved interfaces into their own sub-directory diff -r d39d243e6601 -r 1330c77d212c AB.css --- a/AB.css Tue Jan 12 18:29:55 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -body { - /* Set the background colour (note US English spelling) to grey*/ - background-color: #fff -} - -div.pageTitle { - width: auto; - height: 20px; - margin-top: 20px; -} - -div.pageTitle span{ - font-size: 1.5em; -} - -div.testHalt { - /* Specify any colouring during the test halt for pre/post questions */ - background-color: rgba(0,0,0,0.5); - /* Don't mess with this bit */ - z-index: 2; - width: 100%; - height: 100%; - position: absolute; - left: 0px; - top: 0px; -} - -button { - /* Specify any button structure or style */ - min-width: 20px; - background-color: #ddd -} - -button.big-button { - width: 250px; - height: 40px; - font-size: 1.2em; -} - -div.comparitor-holder { - width: 260px; - height: 300px; - border: black 1px solid; - float: left; - padding-top: 5px; - margin: 25px; -} - -div.comparitor-selector { - width: 248px; - height: 250px; - border: black 1px solid; - position: relative; - background-color: #FF0000; -} - -div.disabled { - background-color: #AAA; -} - -div.selected { - background-color: #008000; -} - -div.comparitor-selector span { - font-size: 4em; -} - -button.comparitor-button { - width: 250px; - height: 38px; - position: relative; - margin-top: 5px; -} diff -r d39d243e6601 -r 1330c77d212c AB.js --- a/AB.js Tue Jan 12 18:29:55 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,320 +0,0 @@ -// Once this is loaded and parsed, begin execution -loadInterface(); - -function loadInterface() { - // Get the dimensions of the screen available to the page - var width = window.innerWidth; - var height = window.innerHeight; - interfaceContext.insertPoint.innerHTML = null; // Clear the current schema - - // Custom Comparitor Object - Interface.prototype.comparitor = null; - - // The injection point into the HTML page - interfaceContext.insertPoint = document.getElementById("topLevelBody"); - var testContent = document.createElement('div'); - testContent.id = 'testContent'; - - // Create the top div for the Title element - var titleAttr = specification.title; - var title = document.createElement('div'); - title.className = "title"; - title.align = "center"; - var titleSpan = document.createElement('span'); - - // Set title to that defined in XML, else set to default - if (titleAttr != undefined) { - titleSpan.textContent = titleAttr; - } else { - titleSpan.textContent = 'Listening test'; - } - // Insert the titleSpan element into the title div element. - title.appendChild(titleSpan); - - var pagetitle = document.createElement('div'); - pagetitle.className = "pageTitle"; - pagetitle.align = "center"; - var titleSpan = document.createElement('span'); - titleSpan.id = "pageTitle"; - pagetitle.appendChild(titleSpan); - - // Create Interface buttons! - var interfaceButtons = document.createElement('div'); - interfaceButtons.id = 'interface-buttons'; - interfaceButtons.style.height = '25px'; - - // Create playback start/stop points - var playback = document.createElement("button"); - playback.innerHTML = 'Stop'; - playback.id = 'playback-button'; - playback.style.float = 'left'; - // onclick function. Check if it is playing or not, call the correct function in the - // audioEngine, change the button text to reflect the next state. - playback.onclick = function() { - if (audioEngineContext.status == 1) { - audioEngineContext.stop(); - this.innerHTML = 'Stop'; - var time = audioEngineContext.timer.getTestTime(); - console.log('Stopped at ' + time); // DEBUG/SAFETY - } - }; - // Append the interface buttons into the interfaceButtons object. - interfaceButtons.appendChild(playback); - - // Global parent for the comment boxes on the page - var feedbackHolder = document.createElement('div'); - feedbackHolder.id = 'feedbackHolder'; - - // Construct the AB Boxes - var boxes = document.createElement('div'); - boxes.align = "center"; - boxes.id = "box-holders"; - boxes.style.float = "left"; - - var submit = document.createElement('button'); - submit.id = "submit"; - submit.onclick = buttonSubmitClick; - submit.className = "big-button"; - submit.textContent = "submit"; - submit.style.position = "relative"; - submit.style.left = (window.innerWidth-250)/2 + 'px'; - - feedbackHolder.appendChild(boxes); - - // Inject into HTML - testContent.appendChild(title); // Insert the title - testContent.appendChild(pagetitle); - testContent.appendChild(interfaceButtons); - testContent.appendChild(feedbackHolder); - testContent.appendChild(submit); - interfaceContext.insertPoint.appendChild(testContent); - - // Load the full interface - testState.initialise(); - testState.advanceState(); -} - -function loadTest(audioHolderObject) -{ - var feedbackHolder = document.getElementById('feedbackHolder'); - var interfaceObj = audioHolderObject.interfaces; - if (interfaceObj.length > 1) - { - console.log("WARNING - This interface only supports one node per page. Using first interface node"); - } - interfaceObj = interfaceObj[0]; - - if(interfaceObj.title != null) - { - document.getElementById("pageTitle").textContent = interfaceObj.title; - } - - // Populate the comparitor object - interfaceContext.comparitor = new Comparitor(audioHolderObject); - resizeWindow(null); -} - -function Comparitor(audioHolderObject) -{ - this.comparitorBox = function(audioElement,id,text) - { - this.parent = audioElement; - this.id = id; - this.value = 0; - this.disabled = true; - this.box = document.createElement('div'); - this.box.className = 'comparitor-holder'; - this.box.setAttribute('track-id',audioElement.id); - this.box.id = 'comparitor-'+text; - this.selector = document.createElement('div'); - this.selector.className = 'comparitor-selector disabled'; - var selectorText = document.createElement('span'); - selectorText.textContent = text; - this.selector.appendChild(selectorText); - this.playback = document.createElement('button'); - this.playback.className = 'comparitor-button'; - this.playback.disabled = true; - this.playback.textContent = "Listen"; - this.box.appendChild(this.selector); - this.box.appendChild(this.playback); - this.selector.onclick = function() - { - var time = audioEngineContext.timer.getTestTime(); - if ($(event.currentTarget).hasClass('disabled')) - { - console.log("Please wait until sample has loaded"); - return; - } - if (audioEngineContext.status == 0) - { - alert("Please listen to the samples before making a selection"); - console.log("Please listen to the samples before making a selection"); - return; - } - $(".comparitor-selector").removeClass('selected'); - var id = event.currentTarget.parentElement.getAttribute('track-id'); - interfaceContext.comparitor.selected = id; - $(event.currentTarget).addClass('selected'); - for (var i=0; i saves - // Get the current information in store (remember to appendChild your data to it) - // pageSpecification is the current page node configuration - // To create new XML nodes, use storage.document.createElement(); -} \ No newline at end of file diff -r d39d243e6601 -r 1330c77d212c ape.css --- a/ape.css Tue Jan 12 18:29:55 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * Hold any style information for APE interface. Customise if you like to make the interface your own! - * - */ -body { - /* Set the background colour (note US English spelling) to grey*/ - background-color: #ddd -} - -div.title { - /* Specify any colouring for the title */ -} - -div.pageTitle { - width: auto; - height: 20px; - margin-top: 5px; - margin-bottom: 10px; -} - -div.pageTitle span{ - font-size: 1.5em; -} - -button { - /* Specify any button structure or style */ - min-width: 20px; - background-color: #ddd -} - -div.slider { - /* Specify any structure for the slider holder interface */ - background-color: #eee; - height: 150px; - margin-bottom: 5px; - -moz-user-select: -moz-none; - -khtml-user-select: none; - -webkit-user-select: none; -} - -div.sliderScale { - width: 100%; - min-height: 30px; - -moz-user-select: -moz-none; - -khtml-user-select: none; - -webkit-user-select: none; -} - -div.sliderScale span { - /* Any formatting of text below scale */ - font-size: 1.2em; - min-width: 5px; - height: 20px; - position: absolute; -} - -div.track-slider { - /* Specify any structure for the slider objects */ - position: absolute; - height: inherit; - width: 12px; - float: left; - background-color: rgb(100,200,100); - -moz-user-select: -moz-none; - -khtml-user-select: none; - -webkit-user-select: none; -} - -div.outside-reference { - width:120px; - padding-left: 55px; - margin-left: 100px; - height:20px; - margin-bottom:5px; - background-color: rgb(100,200,100); -} - -div.track-slider-disabled { - background-color: rgb(100,100,100); -} - -div.track-slider-playing { - background-color: #FF0000; -} - -div.comment-box-playing { - background-color: #FFDDDD; -} diff -r d39d243e6601 -r 1330c77d212c ape.js --- a/ape.js Tue Jan 12 18:29:55 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,826 +0,0 @@ -/** - * ape.js - * Create the APE interface - */ - - -// Once this is loaded and parsed, begin execution -loadInterface(); - -function loadInterface() { - - // Get the dimensions of the screen available to the page - var width = window.innerWidth; - var height = window.innerHeight; - - // The injection point into the HTML page - interfaceContext.insertPoint = document.getElementById("topLevelBody"); - var testContent = document.createElement('div'); - - testContent.id = 'testContent'; - - // Bindings for interfaceContext - interfaceContext.checkAllPlayed = function() - { - hasBeenPlayed = audioEngineContext.checkAllPlayed(); - if (hasBeenPlayed.length > 0) // if a fragment has not been played yet - { - str = ""; - if (hasBeenPlayed.length > 1) { - for (var i=0; i 1) { - var str = ""; - for (var i=0; i 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) - { - alert(str); - console.log(str); - } - return state; - }; - - 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 - var titleAttr = specification.title; - var title = document.createElement('div'); - title.className = "title"; - title.align = "center"; - var titleSpan = document.createElement('span'); - - // Set title to that defined in XML, else set to default - if (titleAttr != undefined) { - titleSpan.textContent = titleAttr; - } else { - titleSpan.textContent = 'Listening test'; - } - // Insert the titleSpan element into the title div element. - title.appendChild(titleSpan); - - // Create Interface buttons! - var interfaceButtons = document.createElement('div'); - interfaceButtons.id = 'interface-buttons'; - - // Create playback start/stop points - var playback = document.createElement("button"); - playback.innerHTML = 'Stop'; - playback.id = 'playback-button'; - // onclick function. Check if it is playing or not, call the correct function in the - // audioEngine, change the button text to reflect the next state. - playback.onclick = function() { - if (audioEngineContext.status == 1) { - audioEngineContext.stop(); - this.innerHTML = 'Stop'; - var time = audioEngineContext.timer.getTestTime(); - console.log('Stopped at ' + time); // DEBUG/SAFETY - } - }; - // Create Submit (save) button - var submit = document.createElement("button"); - submit.innerHTML = 'Submit'; - submit.onclick = buttonSubmitClick; - submit.id = 'submit-button'; - // Append the interface buttons into the interfaceButtons object. - interfaceButtons.appendChild(playback); - interfaceButtons.appendChild(submit); - - var sliderHolder = document.createElement("div"); - sliderHolder.id = "slider-holder"; - - - // Global parent for the comment boxes on the page - var feedbackHolder = document.createElement('div'); - feedbackHolder.id = 'feedbackHolder'; - - testContent.style.zIndex = 1; - interfaceContext.insertPoint.innerHTML = null; // Clear the current schema - - // Inject into HTML - testContent.appendChild(title); // Insert the title - testContent.appendChild(interfaceButtons); - testContent.appendChild(sliderHolder); - testContent.appendChild(feedbackHolder); - interfaceContext.insertPoint.appendChild(testContent); - - // Load the full interface - testState.initialise(); - testState.advanceState(); - -} - -function loadTest(audioHolderObject) -{ - var width = window.innerWidth; - var height = window.innerHeight; - var id = audioHolderObject.id; - - interfaceContext.interfaceSliders = []; - - var feedbackHolder = document.getElementById('feedbackHolder'); - var sliderHolder = document.getElementById('slider-holder'); - feedbackHolder.innerHTML = null; - sliderHolder.innerHTML = null; - - // Delete outside reference - var outsideReferenceHolder = document.getElementById('outside-reference'); - if (outsideReferenceHolder != null) { - document.getElementById('interface-buttons').removeChild(outsideReferenceHolder); - } - - var interfaceObj = audioHolderObject.interfaces; - for (var k=0; k'; - var inject = document.getElementById('interface-buttons'); - inject.appendChild(pagecountHolder); - } - } - } - - var commentBoxPrefix = "Comment on fragment"; - - var commentShow = audioHolderObject.elementComments; - - var loopPlayback = audioHolderObject.loop; - - 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('interface-buttons')); - audioObject.bindInterface(orNode); - } else { - var node = interfaceContext.createCommentBox(audioObject); - // Create a slider per track - var sliderNode = new sliderObject(audioObject,interfaceObj); - audioObject.bindInterface(sliderNode); - } - }); - - // 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;} - $(obj).css("left",event.clientX + "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; - $(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"); - 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+')'); - } else { - var id = Number(obj.attributes['trackIndex'].value); - //audioEngineContext.metric.sliderPlayed(id); - audioEngineContext.play(id); - // Currently playing track red, rest green - - $('.track-slider').removeClass('track-slider-playing'); - var name = ".track-slider-"+obj.getAttribute("trackindex"); - $(name).addClass('track-slider-playing'); - $('.comment-div').removeClass('comment-box-playing'); - $('#comment-div-'+id).addClass('comment-box-playing'); - var outsideReference = document.getElementById('outside-reference'); - if (outsideReference != undefined) - $(outsideReference).removeClass('track-slider-playing'); - } - 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(); - }); - - - if (audioHolderObject.showElementComments) { - interfaceContext.showCommentBoxes(feedbackHolder,true); - } - - $(audioHolderObject.commentQuestions).each(function(index,element) { - var node = interfaceContext.createCommentQuestion(element); - feedbackHolder.appendChild(node.holder); - }); - - - //testWaitIndicator(); -} - -function interfaceSliderHolder(interfaceObject) -{ - 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; - - 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); - } - pagetitle.appendChild(titleSpan); - this.sliderDOM.appendChild(pagetitle); - - // 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); - var sliderMargin = document.createAttribute('marginsize'); - sliderMargin.nodeValue = 42; // Set default margins to 42px either side - // Must have a known EXACT width, as this is used later to determine the ratings - var w = (Number(sliderMargin.nodeValue)+8)*2; - this.canvas.style.width = window.innerWidth - w +"px"; - this.canvas.style.marginLeft = sliderMargin.nodeValue +'px'; - this.canvas.setAttributeNode(sliderMargin); - 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 = Number(this.canvas.attributes['marginsize'].value); - for (var scaleObj of interfaceObject.scales) - { - var value = document.createAttribute('value'); - var position = Number(scaleObj.position)*0.01; - value.nodeValue = position; - var pixelPosition = (position*positionScale)+offset; - var scaleDOM = document.createElement('span'); - scaleDOM.textContent = scaleObj.text; - this.scale.appendChild(scaleDOM); - scaleDOM.style.left = Math.floor((pixelPosition-($(scaleDOM).width()/2)))+'px'; - scaleDOM.setAttributeNode(value); - } - - var dest = document.getElementById("slider-holder"); - dest.appendChild(this.sliderDOM); - - this.createSliderObject = function(audioObject) - { - var trackObj = document.createElement('div'); - 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); - } - var offset = Number(this.canvas.attributes['marginsize'].value); - // 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)); - trackObj.innerHTML = ''+(this.metrics.length-1)+''; - this.metrics[this.metrics.length-1].initialise(convSliderPosToRate(trackObj)); - return trackObj; - }; - - this.resize = function(event) - { - var holdValues = []; - for (var index = 0; index < this.sliders.length; index++) - { - holdValues.push(convSliderPosToRate(this.sliders[index])); - } - var width = event.target.innerWidth; - var sliderDiv = this.canvas; - var sliderScaleDiv = this.scale; - var marginsize = Number(sliderDiv.attributes['marginsize'].value); - var w = (marginsize+8)*2; - sliderDiv.style.width = width - w + 'px'; - var width = width - w; - // Move sliders into new position - for (var index = 0; index < this.sliders.length; index++) - { - var pos = holdValues[index]; - var pix = pos * width; - this.sliders[index].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'; - } - }; -} - -function sliderObject(audioObject,interfaceObjects) { - // Create a new slider object; - this.parent = audioObject; - this.trackSliderObjects = []; - for (var i=0; i saves - // Get the current information in store (remember to appendChild your data to it) - // 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 1) + { + console.log("WARNING - This interface only supports one node per page. Using first interface node"); + } + interfaceObj = interfaceObj[0]; + + if(interfaceObj.title != null) + { + document.getElementById("pageTitle").textContent = interfaceObj.title; + } + + // Populate the comparitor object + interfaceContext.comparitor = new Comparitor(audioHolderObject); + resizeWindow(null); +} + +function Comparitor(audioHolderObject) +{ + this.comparitorBox = function(audioElement,id,text) + { + this.parent = audioElement; + this.id = id; + this.value = 0; + this.disabled = true; + this.box = document.createElement('div'); + this.box.className = 'comparitor-holder'; + this.box.setAttribute('track-id',audioElement.id); + this.box.id = 'comparitor-'+text; + this.selector = document.createElement('div'); + this.selector.className = 'comparitor-selector disabled'; + var selectorText = document.createElement('span'); + selectorText.textContent = text; + this.selector.appendChild(selectorText); + this.playback = document.createElement('button'); + this.playback.className = 'comparitor-button'; + this.playback.disabled = true; + this.playback.textContent = "Listen"; + this.box.appendChild(this.selector); + this.box.appendChild(this.playback); + this.selector.onclick = function() + { + var time = audioEngineContext.timer.getTestTime(); + if ($(event.currentTarget).hasClass('disabled')) + { + console.log("Please wait until sample has loaded"); + return; + } + if (audioEngineContext.status == 0) + { + alert("Please listen to the samples before making a selection"); + console.log("Please listen to the samples before making a selection"); + return; + } + $(".comparitor-selector").removeClass('selected'); + var id = event.currentTarget.parentElement.getAttribute('track-id'); + interfaceContext.comparitor.selected = id; + $(event.currentTarget).addClass('selected'); + for (var i=0; i saves + // Get the current information in store (remember to appendChild your data to it) + // pageSpecification is the current page node configuration + // To create new XML nodes, use storage.document.createElement(); +} \ No newline at end of file diff -r d39d243e6601 -r 1330c77d212c interfaces/ape.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interfaces/ape.css Wed Jan 13 09:34:46 2016 +0000 @@ -0,0 +1,88 @@ +/* + * Hold any style information for APE interface. Customise if you like to make the interface your own! + * + */ +body { + /* Set the background colour (note US English spelling) to grey*/ + background-color: #ddd +} + +div.title { + /* Specify any colouring for the title */ +} + +div.pageTitle { + width: auto; + height: 20px; + margin-top: 5px; + margin-bottom: 10px; +} + +div.pageTitle span{ + font-size: 1.5em; +} + +button { + /* Specify any button structure or style */ + min-width: 20px; + background-color: #ddd +} + +div.slider { + /* Specify any structure for the slider holder interface */ + background-color: #eee; + height: 150px; + margin-bottom: 5px; + -moz-user-select: -moz-none; + -khtml-user-select: none; + -webkit-user-select: none; +} + +div.sliderScale { + width: 100%; + min-height: 30px; + -moz-user-select: -moz-none; + -khtml-user-select: none; + -webkit-user-select: none; +} + +div.sliderScale span { + /* Any formatting of text below scale */ + font-size: 1.2em; + min-width: 5px; + height: 20px; + position: absolute; +} + +div.track-slider { + /* Specify any structure for the slider objects */ + position: absolute; + height: inherit; + width: 12px; + float: left; + background-color: rgb(100,200,100); + -moz-user-select: -moz-none; + -khtml-user-select: none; + -webkit-user-select: none; +} + +div.outside-reference { + width:120px; + padding-left: 55px; + margin-left: 100px; + height:20px; + margin-bottom:5px; + background-color: rgb(100,200,100); +} + +div.track-slider-disabled { + background-color: rgb(100,100,100); +} + +div.track-slider-playing { + background-color: #FF0000; +} + +div.comment-box-playing { + background-color: #FFDDDD; +} diff -r d39d243e6601 -r 1330c77d212c interfaces/ape.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interfaces/ape.js Wed Jan 13 09:34:46 2016 +0000 @@ -0,0 +1,826 @@ +/** + * ape.js + * Create the APE interface + */ + + +// Once this is loaded and parsed, begin execution +loadInterface(); + +function loadInterface() { + + // Get the dimensions of the screen available to the page + var width = window.innerWidth; + var height = window.innerHeight; + + // The injection point into the HTML page + interfaceContext.insertPoint = document.getElementById("topLevelBody"); + var testContent = document.createElement('div'); + + testContent.id = 'testContent'; + + // Bindings for interfaceContext + interfaceContext.checkAllPlayed = function() + { + hasBeenPlayed = audioEngineContext.checkAllPlayed(); + if (hasBeenPlayed.length > 0) // if a fragment has not been played yet + { + str = ""; + if (hasBeenPlayed.length > 1) { + for (var i=0; i 1) { + var str = ""; + for (var i=0; i 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) + { + alert(str); + console.log(str); + } + return state; + }; + + 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 + var titleAttr = specification.title; + var title = document.createElement('div'); + title.className = "title"; + title.align = "center"; + var titleSpan = document.createElement('span'); + + // Set title to that defined in XML, else set to default + if (titleAttr != undefined) { + titleSpan.textContent = titleAttr; + } else { + titleSpan.textContent = 'Listening test'; + } + // Insert the titleSpan element into the title div element. + title.appendChild(titleSpan); + + // Create Interface buttons! + var interfaceButtons = document.createElement('div'); + interfaceButtons.id = 'interface-buttons'; + + // Create playback start/stop points + var playback = document.createElement("button"); + playback.innerHTML = 'Stop'; + playback.id = 'playback-button'; + // onclick function. Check if it is playing or not, call the correct function in the + // audioEngine, change the button text to reflect the next state. + playback.onclick = function() { + if (audioEngineContext.status == 1) { + audioEngineContext.stop(); + this.innerHTML = 'Stop'; + var time = audioEngineContext.timer.getTestTime(); + console.log('Stopped at ' + time); // DEBUG/SAFETY + } + }; + // Create Submit (save) button + var submit = document.createElement("button"); + submit.innerHTML = 'Submit'; + submit.onclick = buttonSubmitClick; + submit.id = 'submit-button'; + // Append the interface buttons into the interfaceButtons object. + interfaceButtons.appendChild(playback); + interfaceButtons.appendChild(submit); + + var sliderHolder = document.createElement("div"); + sliderHolder.id = "slider-holder"; + + + // Global parent for the comment boxes on the page + var feedbackHolder = document.createElement('div'); + feedbackHolder.id = 'feedbackHolder'; + + testContent.style.zIndex = 1; + interfaceContext.insertPoint.innerHTML = null; // Clear the current schema + + // Inject into HTML + testContent.appendChild(title); // Insert the title + testContent.appendChild(interfaceButtons); + testContent.appendChild(sliderHolder); + testContent.appendChild(feedbackHolder); + interfaceContext.insertPoint.appendChild(testContent); + + // Load the full interface + testState.initialise(); + testState.advanceState(); + +} + +function loadTest(audioHolderObject) +{ + var width = window.innerWidth; + var height = window.innerHeight; + var id = audioHolderObject.id; + + interfaceContext.interfaceSliders = []; + + var feedbackHolder = document.getElementById('feedbackHolder'); + var sliderHolder = document.getElementById('slider-holder'); + feedbackHolder.innerHTML = null; + sliderHolder.innerHTML = null; + + // Delete outside reference + var outsideReferenceHolder = document.getElementById('outside-reference'); + if (outsideReferenceHolder != null) { + document.getElementById('interface-buttons').removeChild(outsideReferenceHolder); + } + + var interfaceObj = audioHolderObject.interfaces; + for (var k=0; k'; + var inject = document.getElementById('interface-buttons'); + inject.appendChild(pagecountHolder); + } + } + } + + var commentBoxPrefix = "Comment on fragment"; + + var commentShow = audioHolderObject.elementComments; + + var loopPlayback = audioHolderObject.loop; + + 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('interface-buttons')); + audioObject.bindInterface(orNode); + } else { + var node = interfaceContext.createCommentBox(audioObject); + // Create a slider per track + var sliderNode = new sliderObject(audioObject,interfaceObj); + audioObject.bindInterface(sliderNode); + } + }); + + // 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;} + $(obj).css("left",event.clientX + "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; + $(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"); + 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+')'); + } else { + var id = Number(obj.attributes['trackIndex'].value); + //audioEngineContext.metric.sliderPlayed(id); + audioEngineContext.play(id); + // Currently playing track red, rest green + + $('.track-slider').removeClass('track-slider-playing'); + var name = ".track-slider-"+obj.getAttribute("trackindex"); + $(name).addClass('track-slider-playing'); + $('.comment-div').removeClass('comment-box-playing'); + $('#comment-div-'+id).addClass('comment-box-playing'); + var outsideReference = document.getElementById('outside-reference'); + if (outsideReference != undefined) + $(outsideReference).removeClass('track-slider-playing'); + } + 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(); + }); + + + if (audioHolderObject.showElementComments) { + interfaceContext.showCommentBoxes(feedbackHolder,true); + } + + $(audioHolderObject.commentQuestions).each(function(index,element) { + var node = interfaceContext.createCommentQuestion(element); + feedbackHolder.appendChild(node.holder); + }); + + + //testWaitIndicator(); +} + +function interfaceSliderHolder(interfaceObject) +{ + 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; + + 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); + } + pagetitle.appendChild(titleSpan); + this.sliderDOM.appendChild(pagetitle); + + // 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); + var sliderMargin = document.createAttribute('marginsize'); + sliderMargin.nodeValue = 42; // Set default margins to 42px either side + // Must have a known EXACT width, as this is used later to determine the ratings + var w = (Number(sliderMargin.nodeValue)+8)*2; + this.canvas.style.width = window.innerWidth - w +"px"; + this.canvas.style.marginLeft = sliderMargin.nodeValue +'px'; + this.canvas.setAttributeNode(sliderMargin); + 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 = Number(this.canvas.attributes['marginsize'].value); + for (var scaleObj of interfaceObject.scales) + { + var value = document.createAttribute('value'); + var position = Number(scaleObj.position)*0.01; + value.nodeValue = position; + var pixelPosition = (position*positionScale)+offset; + var scaleDOM = document.createElement('span'); + scaleDOM.textContent = scaleObj.text; + this.scale.appendChild(scaleDOM); + scaleDOM.style.left = Math.floor((pixelPosition-($(scaleDOM).width()/2)))+'px'; + scaleDOM.setAttributeNode(value); + } + + var dest = document.getElementById("slider-holder"); + dest.appendChild(this.sliderDOM); + + this.createSliderObject = function(audioObject) + { + var trackObj = document.createElement('div'); + 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); + } + var offset = Number(this.canvas.attributes['marginsize'].value); + // 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)); + trackObj.innerHTML = ''+(this.metrics.length-1)+''; + this.metrics[this.metrics.length-1].initialise(convSliderPosToRate(trackObj)); + return trackObj; + }; + + this.resize = function(event) + { + var holdValues = []; + for (var index = 0; index < this.sliders.length; index++) + { + holdValues.push(convSliderPosToRate(this.sliders[index])); + } + var width = event.target.innerWidth; + var sliderDiv = this.canvas; + var sliderScaleDiv = this.scale; + var marginsize = Number(sliderDiv.attributes['marginsize'].value); + var w = (marginsize+8)*2; + sliderDiv.style.width = width - w + 'px'; + var width = width - w; + // Move sliders into new position + for (var index = 0; index < this.sliders.length; index++) + { + var pos = holdValues[index]; + var pix = pos * width; + this.sliders[index].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'; + } + }; +} + +function sliderObject(audioObject,interfaceObjects) { + // Create a new slider object; + this.parent = audioObject; + this.trackSliderObjects = []; + for (var i=0; i saves + // Get the current information in store (remember to appendChild your data to it) + // 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 1) + { + console.log("WARNING - This interface only supports one node per page. Using first interface node"); + } + interfaceObj = interfaceObj[0]; + if(interfaceObj.title != null) + { + document.getElementById("pageTitle").textContent = interfaceObj.title; + } + + // Delete outside reference + var outsideReferenceHolder = document.getElementById('outside-reference'); + if (outsideReferenceHolder != null) { + document.getElementById('interface-buttons').removeChild(outsideReferenceHolder); + } + + var sliderBox = document.getElementById('slider-holder'); + feedbackHolder.innerHTML = null; + sliderBox.innerHTML = null; + + var commentBoxPrefix = "Comment on track"; + if (interfaceObj.commentBoxPrefix != undefined) { + commentBoxPrefix = interfaceObj.commentBoxPrefix; + } + var loopPlayback = audioHolderObject.loop; + + currentTestHolder = document.createElement('audioHolder'); + currentTestHolder.id = audioHolderObject.id; + currentTestHolder.repeatCount = audioHolderObject.repeatCount; + + $(audioHolderObject.commentQuestions).each(function(index,element) { + var node = interfaceContext.createCommentQuestion(element); + feedbackHolder.appendChild(node.holder); + }); + + // Find all the audioElements from the audioHolder + var label = 0; + $(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); + if (element.type == 'outside-reference') + { + // Construct outside reference; + var orNode = new outsideReferenceDOM(audioObject,index,document.getElementById('interface-buttons')); + audioObject.bindInterface(orNode); + } else { + var node = interfaceContext.createCommentBox(audioObject); + + // Create a slider per track + audioObject.bindInterface(new sliderObject(audioObject,label)); + + if (typeof audioHolderObject.initialPosition === "number") + { + // Set the values + audioObject.interfaceDOM.slider.value = audioHolderObject.initalPosition; + } else { + // Distribute it randomnly + audioObject.interfaceDOM.slider.value = Math.random(); + } + sliderBox.appendChild(audioObject.interfaceDOM.holder); + audioObject.metric.initialise(audioObject.interfaceDOM.slider.value); + label += 1; + } + + }); + + // Auto-align + resizeWindow(null); +} + +function sliderObject(audioObject,label) +{ + // Constructs the slider object. We use the HTML5 slider object + this.parent = audioObject; + this.holder = document.createElement('div'); + this.title = document.createElement('span'); + this.slider = document.createElement('input'); + this.play = document.createElement('button'); + + this.holder.className = 'track-slider'; + this.holder.style.height = window.innerHeight-200 + 'px'; + this.holder.appendChild(this.title); + this.holder.appendChild(this.slider); + this.holder.appendChild(this.play); + this.holder.align = "center"; + if (audioObject.id == 0) + { + this.holder.style.marginLeft = '0px'; + } + this.holder.setAttribute('trackIndex',audioObject.id); + + this.title.textContent = label; + this.title.style.width = "100%"; + this.title.style.float = "left"; + + this.slider.type = "range"; + this.slider.className = "track-slider-range track-slider-not-moved"; + this.slider.min = "0"; + this.slider.max = "1"; + this.slider.step = "0.01"; + this.slider.setAttribute('orient','vertical'); + this.slider.style.height = window.innerHeight-250 + 'px'; + this.slider.onchange = function() + { + var time = audioEngineContext.timer.getTestTime(); + var id = Number(this.parentNode.getAttribute('trackIndex')); + audioEngineContext.audioObjects[id].metric.moved(time,this.value); + console.log('slider '+id+' moved to '+this.value+' ('+time+')'); + $(this).removeClass('track-slider-not-moved'); + }; + + this.play.textContent = "Loading..."; + this.play.value = audioObject.id; + this.play.style.float = "left"; + this.play.style.width = "100%"; + this.play.disabled = true; + this.play.onclick = function(event) + { + var id = Number(event.currentTarget.value); + //audioEngineContext.metric.sliderPlayed(id); + audioEngineContext.play(id); + $(".track-slider").removeClass('track-slider-playing'); + $(event.currentTarget.parentElement).addClass('track-slider-playing'); + var outsideReference = document.getElementById('outside-reference'); + if (outsideReference != null) { + $(outsideReference).removeClass('track-slider-playing'); + } + }; + + this.enable = function() { + this.play.disabled = false; + this.play.textContent = "Play"; + $(this.slider).removeClass('track-slider-disabled'); + }; + + this.exportXMLDOM = function(audioObject) { + // Called by the audioObject holding this element. Must be present + var node = storage.document.createElement('value'); + node.textContent = this.slider.value; + return node; + }; + this.getValue = function() { + return this.slider.value; + }; + + this.resize = function(event) + { + this.holder.style.height = window.innerHeight-200 + 'px'; + this.slider.style.height = window.innerHeight-250 + 'px'; + }; + this.updateLoading = function(progress) + { + progress = String(progress); + progress = progress.substr(0,5); + this.play.textContent = "Loading: "+progress+"%"; + }; + + if (this.parent.state == 1) + { + this.enable(); + } + this.getPresentedId = function() + { + return this.title.textContent; + }; + this.canMove = function() + { + return true; + }; +} + +function outsideReferenceDOM(audioObject,index,inject) +{ + this.parent = audioObject; + this.outsideReferenceHolder = document.createElement('button'); + this.outsideReferenceHolder.id = 'outside-reference'; + this.outsideReferenceHolder.className = 'outside-reference'; + this.outsideReferenceHolder.setAttribute('track-id',index); + this.outsideReferenceHolder.textContent = "Play Reference"; + this.outsideReferenceHolder.disabled = true; + + this.outsideReferenceHolder.onclick = function(event) + { + audioEngineContext.play(event.currentTarget.getAttribute('track-id')); + $('.track-slider').removeClass('track-slider-playing'); + $('.comment-div').removeClass('comment-box-playing'); + $(event.currentTarget).addClass('track-slider-playing'); + }; + inject.appendChild(this.outsideReferenceHolder); + this.enable = function() + { + if (this.parent.state == 1) + { + this.outsideReferenceHolder.disabled = false; + } + }; + this.updateLoading = function(progress) + { + if (progress != 100) + { + progress = String(progress); + progress = progress.split('.')[0]; + this.outsideReferenceHolder[0].children[0].textContent = progress+'%'; + } else { + this.outsideReferenceHolder[0].children[0].textContent = "Play Reference"; + } + }; + this.exportXMLDOM = function(audioObject) + { + return null; + }; + this.getValue = function() + { + return 0; + }; + this.getPresentedId = function() + { + return 'reference'; + }; + this.canMove = function() + { + return false; + }; +} + +function resizeWindow(event) +{ + // Function called when the window has been resized. + // MANDATORY FUNCTION + + var outsideRef = document.getElementById('outside-reference'); + if(outsideRef != null) + { + outsideRef.style.left = (window.innerWidth-120)/2 + 'px'; + } + + // Auto-align + var numObj = document.getElementsByClassName('track-slider').length; + var totalWidth = (numObj-1)*150+100; + var diff = (window.innerWidth - totalWidth)/2; + document.getElementById('slider').style.height = window.innerHeight - 180 + 'px'; + if (diff <= 0){diff = 0;} + document.getElementById('slider-holder').style.marginLeft = diff + 'px'; + for (var i in audioEngineContext.audioObjects) + { + if (audioEngineContext.audioObjects[i].specification.type != 'outside-reference'){ + audioEngineContext.audioObjects[i].interfaceDOM.resize(event); + } + } + document.getElementById('scale-holder').style.marginLeft = (diff-100) + 'px'; + document.getElementById('scale-text-holder').style.height = window.innerHeight-194 + 'px'; + var canvas = document.getElementById('scale-canvas'); + canvas.width = totalWidth; + canvas.height = window.innerHeight-194; + drawScale(); +} + +function drawScale() +{ + var interfaceObj = testState.currentStateMap.interfaces[0]; + var scales = testState.currentStateMap.interfaces[0].scales; + scales = scales.sort(function(a,b) { + return a.position - b.position; + }); + var canvas = document.getElementById('scale-canvas'); + var ctx = canvas.getContext("2d"); + var height = canvas.height; + var width = canvas.width; + var draw_heights = [24, height-34]; + var textHolder = document.getElementById('scale-text-holder'); + textHolder.innerHTML = null; + var lastHeight = 0; + for (var scale of scales) + { + var posPercent = scale.position / 100.0; + var posPix = (1-posPercent)*(draw_heights[1]-draw_heights[0])+draw_heights[0]; + ctx.fillStyle = "#000000"; + ctx.setLineDash([1,2]); + ctx.moveTo(0,posPix); + ctx.lineTo(width,posPix); + ctx.stroke(); + var text = document.createElement('div'); + text.align = "right"; + var textC = document.createElement('span'); + textC.textContent = scale.text; + text.appendChild(textC); + text.className = "scale-text"; + textHolder.appendChild(text); + 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! +{ + var checks = []; + checks = checks.concat(testState.currentStateMap.interfaces[0].options); + checks = checks.concat(specification.interfaces.options); + var canContinue = true; + + // Check that the anchor and reference objects are correctly placed + if (interfaceContext.checkHiddenAnchor() == false) {return;} + if (interfaceContext.checkHiddenReference() == false) {return;} + + for (var i=0; i saves + // Get the current information in store (remember to appendChild your data to it) + // pageSpecification is the current page node configuration + // To create new XML nodes, use storage.document.createElement(); +} diff -r d39d243e6601 -r 1330c77d212c mushra.css --- a/mushra.css Tue Jan 12 18:29:55 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* - * Hold any style information for MUSHRA interface. Customise if you like to make the interface your own! - * - */ -body { - /* Set the background colour (note US English spelling) to grey*/ - background-color: #ddd -} - -div.pageTitle { - width: auto; - height: 20px; - margin: 10px 0px; -} - -div.pageTitle span{ - font-size: 1.5em; -} - -div.testHalt { - /* Specify any colouring during the test halt for pre/post questions */ - background-color: rgba(0,0,0,0.5); - /* Don't mess with this bit */ - z-index: 2; - width: 100%; - height: 100%; - position: absolute; - left: 0px; - top: 0px; -} - -button { - /* Specify any button structure or style */ - min-width: 20px; - background-color: #ddd -} - -div#slider-holder { - height: inherit; - position: absolute; - left: 0px; - z-index: 3; -} - -div#scale-holder { - height: inherit; - position: absolute; - left: 0px; - z-index: 2; -} - -div#scale-text-holder { - position:relative; - width: 100px; - float: left; -} -div.scale-text { - position: absolute; -} - -canvas#scale-canvas { - position: relative; - float: left; -} - -div.track-slider { - float: left; - width: 94px; - border: solid; - border-width: 1px; - border-color: black; - padding:2px; - margin-left: 50px; -} - -button.outside-reference { - width:120px; - height:20px; - margin-bottom:5px; - position: absolute; -} - -div.track-slider-playing { - background-color: #FFDDDD; -} - -input.track-slider-range { - margin: 2px 0px; -} - -input[type=range][orient=vertical] -{ - writing-mode: bt-lr; /* IE */ - -webkit-appearance: slider-vertical; /* WebKit */ - width: 8px; - padding: 0 5px; - color: rgb(255, 144, 144); -} - -input[type=range]::-webkit-slider-runnable-track { - width: 8px; - cursor: pointer; - background: #fff; - border-radius: 4px; - border: 1px solid #000; -} - -input[type=range]::-moz-range-track { - width: 8px; - cursor: pointer; - background: #fff; - border-radius: 4px; - border: 1px solid #000; -} - -input.track-slider-not-moved[type=range]::-webkit-slider-runnable-track { - background: #aaa; -} - -input.track-slider-not-moved[type=range]::-moz-range-track { - background: #aaa; -} - - -input[type=range]::-moz-range-thumb { - margin-left: -7px; - cursor: pointer; - margin-top: -1px; - box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; -} - -input[type=range]::-webkit-slider-thumb { - cursor: pointer; - margin-top: -1px; - margin-left: -4px; -} diff -r d39d243e6601 -r 1330c77d212c mushra.js --- a/mushra.js Tue Jan 12 18:29:55 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,489 +0,0 @@ -/** - * mushra.js - * Create the MUSHRA interface - */ - -// Once this is loaded and parsed, begin execution -loadInterface(); - -function loadInterface() { - // Get the dimensions of the screen available to the page - var width = window.innerWidth; - var height = window.innerHeight; - - // The injection point into the HTML page - interfaceContext.insertPoint = document.getElementById("topLevelBody"); - var testContent = document.createElement('div'); - testContent.id = 'testContent'; - - // Create the top div for the Title element - var titleAttr = specification.title; - var title = document.createElement('div'); - title.className = "title"; - title.align = "center"; - var titleSpan = document.createElement('span'); - - // Set title to that defined in XML, else set to default - if (titleAttr != undefined) { - titleSpan.textContent = titleAttr; - } else { - titleSpan.textContent = 'Listening test'; - } - // Insert the titleSpan element into the title div element. - title.appendChild(titleSpan); - - var pagetitle = document.createElement('div'); - pagetitle.className = "pageTitle"; - pagetitle.align = "center"; - var titleSpan = document.createElement('span'); - titleSpan.id = "pageTitle"; - pagetitle.appendChild(titleSpan); - - // Create Interface buttons! - var interfaceButtons = document.createElement('div'); - interfaceButtons.id = 'interface-buttons'; - interfaceButtons.style.height = '25px'; - - // Create playback start/stop points - var playback = document.createElement("button"); - playback.innerHTML = 'Stop'; - playback.id = 'playback-button'; - playback.style.float = 'left'; - // onclick function. Check if it is playing or not, call the correct function in the - // audioEngine, change the button text to reflect the next state. - playback.onclick = function() { - if (audioEngineContext.status == 1) { - audioEngineContext.stop(); - this.innerHTML = 'Stop'; - var time = audioEngineContext.timer.getTestTime(); - console.log('Stopped at ' + time); // DEBUG/SAFETY - } - }; - // Create Submit (save) button - var submit = document.createElement("button"); - submit.innerHTML = 'Submit'; - submit.onclick = buttonSubmitClick; - submit.id = 'submit-button'; - submit.style.float = 'left'; - // Append the interface buttons into the interfaceButtons object. - interfaceButtons.appendChild(playback); - interfaceButtons.appendChild(submit); - - // Create a slider box - var sliderBox = document.createElement('div'); - sliderBox.style.width = "100%"; - sliderBox.style.height = window.innerHeight - 200+12 + 'px'; - sliderBox.style.marginBottom = '10px'; - sliderBox.id = 'slider'; - var scaleHolder = document.createElement('div'); - scaleHolder.id = "scale-holder"; - sliderBox.appendChild(scaleHolder); - var scaleText = document.createElement('div'); - scaleText.id = "scale-text-holder"; - scaleHolder.appendChild(scaleText); - var scaleCanvas = document.createElement('canvas'); - scaleCanvas.id = "scale-canvas"; - scaleHolder.appendChild(scaleCanvas); - var sliderObjectHolder = document.createElement('div'); - sliderObjectHolder.id = 'slider-holder'; - sliderObjectHolder.align = "center"; - sliderBox.appendChild(sliderObjectHolder); - - // Global parent for the comment boxes on the page - var feedbackHolder = document.createElement('div'); - feedbackHolder.id = 'feedbackHolder'; - - testContent.style.zIndex = 1; - interfaceContext.insertPoint.innerHTML = null; // Clear the current schema - - // Inject into HTML - testContent.appendChild(title); // Insert the title - testContent.appendChild(pagetitle); - testContent.appendChild(interfaceButtons); - testContent.appendChild(sliderBox); - testContent.appendChild(feedbackHolder); - interfaceContext.insertPoint.appendChild(testContent); - - // Load the full interface - testState.initialise(); - testState.advanceState(); -} - -function loadTest(audioHolderObject) -{ - var id = audioHolderObject.id; - - var feedbackHolder = document.getElementById('feedbackHolder'); - var interfaceObj = audioHolderObject.interfaces; - if (interfaceObj.length > 1) - { - console.log("WARNING - This interface only supports one node per page. Using first interface node"); - } - interfaceObj = interfaceObj[0]; - if(interfaceObj.title != null) - { - document.getElementById("pageTitle").textContent = interfaceObj.title; - } - - // Delete outside reference - var outsideReferenceHolder = document.getElementById('outside-reference'); - if (outsideReferenceHolder != null) { - document.getElementById('interface-buttons').removeChild(outsideReferenceHolder); - } - - var sliderBox = document.getElementById('slider-holder'); - feedbackHolder.innerHTML = null; - sliderBox.innerHTML = null; - - var commentBoxPrefix = "Comment on track"; - if (interfaceObj.commentBoxPrefix != undefined) { - commentBoxPrefix = interfaceObj.commentBoxPrefix; - } - var loopPlayback = audioHolderObject.loop; - - currentTestHolder = document.createElement('audioHolder'); - currentTestHolder.id = audioHolderObject.id; - currentTestHolder.repeatCount = audioHolderObject.repeatCount; - - $(audioHolderObject.commentQuestions).each(function(index,element) { - var node = interfaceContext.createCommentQuestion(element); - feedbackHolder.appendChild(node.holder); - }); - - // Find all the audioElements from the audioHolder - var label = 0; - $(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); - if (element.type == 'outside-reference') - { - // Construct outside reference; - var orNode = new outsideReferenceDOM(audioObject,index,document.getElementById('interface-buttons')); - audioObject.bindInterface(orNode); - } else { - var node = interfaceContext.createCommentBox(audioObject); - - // Create a slider per track - audioObject.bindInterface(new sliderObject(audioObject,label)); - - if (typeof audioHolderObject.initialPosition === "number") - { - // Set the values - audioObject.interfaceDOM.slider.value = audioHolderObject.initalPosition; - } else { - // Distribute it randomnly - audioObject.interfaceDOM.slider.value = Math.random(); - } - sliderBox.appendChild(audioObject.interfaceDOM.holder); - audioObject.metric.initialise(audioObject.interfaceDOM.slider.value); - label += 1; - } - - }); - - // Auto-align - resizeWindow(null); -} - -function sliderObject(audioObject,label) -{ - // Constructs the slider object. We use the HTML5 slider object - this.parent = audioObject; - this.holder = document.createElement('div'); - this.title = document.createElement('span'); - this.slider = document.createElement('input'); - this.play = document.createElement('button'); - - this.holder.className = 'track-slider'; - this.holder.style.height = window.innerHeight-200 + 'px'; - this.holder.appendChild(this.title); - this.holder.appendChild(this.slider); - this.holder.appendChild(this.play); - this.holder.align = "center"; - if (audioObject.id == 0) - { - this.holder.style.marginLeft = '0px'; - } - this.holder.setAttribute('trackIndex',audioObject.id); - - this.title.textContent = label; - this.title.style.width = "100%"; - this.title.style.float = "left"; - - this.slider.type = "range"; - this.slider.className = "track-slider-range track-slider-not-moved"; - this.slider.min = "0"; - this.slider.max = "1"; - this.slider.step = "0.01"; - this.slider.setAttribute('orient','vertical'); - this.slider.style.height = window.innerHeight-250 + 'px'; - this.slider.onchange = function() - { - var time = audioEngineContext.timer.getTestTime(); - var id = Number(this.parentNode.getAttribute('trackIndex')); - audioEngineContext.audioObjects[id].metric.moved(time,this.value); - console.log('slider '+id+' moved to '+this.value+' ('+time+')'); - $(this).removeClass('track-slider-not-moved'); - }; - - this.play.textContent = "Loading..."; - this.play.value = audioObject.id; - this.play.style.float = "left"; - this.play.style.width = "100%"; - this.play.disabled = true; - this.play.onclick = function(event) - { - var id = Number(event.currentTarget.value); - //audioEngineContext.metric.sliderPlayed(id); - audioEngineContext.play(id); - $(".track-slider").removeClass('track-slider-playing'); - $(event.currentTarget.parentElement).addClass('track-slider-playing'); - var outsideReference = document.getElementById('outside-reference'); - if (outsideReference != null) { - $(outsideReference).removeClass('track-slider-playing'); - } - }; - - this.enable = function() { - this.play.disabled = false; - this.play.textContent = "Play"; - $(this.slider).removeClass('track-slider-disabled'); - }; - - this.exportXMLDOM = function(audioObject) { - // Called by the audioObject holding this element. Must be present - var node = storage.document.createElement('value'); - node.textContent = this.slider.value; - return node; - }; - this.getValue = function() { - return this.slider.value; - }; - - this.resize = function(event) - { - this.holder.style.height = window.innerHeight-200 + 'px'; - this.slider.style.height = window.innerHeight-250 + 'px'; - }; - this.updateLoading = function(progress) - { - progress = String(progress); - progress = progress.substr(0,5); - this.play.textContent = "Loading: "+progress+"%"; - }; - - if (this.parent.state == 1) - { - this.enable(); - } - this.getPresentedId = function() - { - return this.title.textContent; - }; - this.canMove = function() - { - return true; - }; -} - -function outsideReferenceDOM(audioObject,index,inject) -{ - this.parent = audioObject; - this.outsideReferenceHolder = document.createElement('button'); - this.outsideReferenceHolder.id = 'outside-reference'; - this.outsideReferenceHolder.className = 'outside-reference'; - this.outsideReferenceHolder.setAttribute('track-id',index); - this.outsideReferenceHolder.textContent = "Play Reference"; - this.outsideReferenceHolder.disabled = true; - - this.outsideReferenceHolder.onclick = function(event) - { - audioEngineContext.play(event.currentTarget.getAttribute('track-id')); - $('.track-slider').removeClass('track-slider-playing'); - $('.comment-div').removeClass('comment-box-playing'); - $(event.currentTarget).addClass('track-slider-playing'); - }; - inject.appendChild(this.outsideReferenceHolder); - this.enable = function() - { - if (this.parent.state == 1) - { - this.outsideReferenceHolder.disabled = false; - } - }; - this.updateLoading = function(progress) - { - if (progress != 100) - { - progress = String(progress); - progress = progress.split('.')[0]; - this.outsideReferenceHolder[0].children[0].textContent = progress+'%'; - } else { - this.outsideReferenceHolder[0].children[0].textContent = "Play Reference"; - } - }; - this.exportXMLDOM = function(audioObject) - { - return null; - }; - this.getValue = function() - { - return 0; - }; - this.getPresentedId = function() - { - return 'reference'; - }; - this.canMove = function() - { - return false; - }; -} - -function resizeWindow(event) -{ - // Function called when the window has been resized. - // MANDATORY FUNCTION - - var outsideRef = document.getElementById('outside-reference'); - if(outsideRef != null) - { - outsideRef.style.left = (window.innerWidth-120)/2 + 'px'; - } - - // Auto-align - var numObj = document.getElementsByClassName('track-slider').length; - var totalWidth = (numObj-1)*150+100; - var diff = (window.innerWidth - totalWidth)/2; - document.getElementById('slider').style.height = window.innerHeight - 180 + 'px'; - if (diff <= 0){diff = 0;} - document.getElementById('slider-holder').style.marginLeft = diff + 'px'; - for (var i in audioEngineContext.audioObjects) - { - if (audioEngineContext.audioObjects[i].specification.type != 'outside-reference'){ - audioEngineContext.audioObjects[i].interfaceDOM.resize(event); - } - } - document.getElementById('scale-holder').style.marginLeft = (diff-100) + 'px'; - document.getElementById('scale-text-holder').style.height = window.innerHeight-194 + 'px'; - var canvas = document.getElementById('scale-canvas'); - canvas.width = totalWidth; - canvas.height = window.innerHeight-194; - drawScale(); -} - -function drawScale() -{ - var interfaceObj = testState.currentStateMap.interfaces[0]; - var scales = testState.currentStateMap.interfaces[0].scales; - scales = scales.sort(function(a,b) { - return a.position - b.position; - }); - var canvas = document.getElementById('scale-canvas'); - var ctx = canvas.getContext("2d"); - var height = canvas.height; - var width = canvas.width; - var draw_heights = [24, height-34]; - var textHolder = document.getElementById('scale-text-holder'); - textHolder.innerHTML = null; - var lastHeight = 0; - for (var scale of scales) - { - var posPercent = scale.position / 100.0; - var posPix = (1-posPercent)*(draw_heights[1]-draw_heights[0])+draw_heights[0]; - ctx.fillStyle = "#000000"; - ctx.setLineDash([1,2]); - ctx.moveTo(0,posPix); - ctx.lineTo(width,posPix); - ctx.stroke(); - var text = document.createElement('div'); - text.align = "right"; - var textC = document.createElement('span'); - textC.textContent = scale.text; - text.appendChild(textC); - text.className = "scale-text"; - textHolder.appendChild(text); - 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! -{ - var checks = []; - checks = checks.concat(testState.currentStateMap.interfaces[0].options); - checks = checks.concat(specification.interfaces.options); - var canContinue = true; - - // Check that the anchor and reference objects are correctly placed - if (interfaceContext.checkHiddenAnchor() == false) {return;} - if (interfaceContext.checkHiddenReference() == false) {return;} - - for (var i=0; i saves - // Get the current information in store (remember to appendChild your data to it) - // pageSpecification is the current page node configuration - // To create new XML nodes, use storage.document.createElement(); -}