Mercurial > hg > webaudioevaluationtool
changeset 2600:cc2364d8bc17
Merge branch 'vnext' into Dev_main
author | Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk> |
---|---|
date | Mon, 14 Nov 2016 12:14:48 +0000 |
parents | bc5c449c97e1 (diff) fddfb7c0b4fa (current diff) |
children | 2577d983f291 |
files | |
diffstat | 7 files changed, 1592 insertions(+), 1188 deletions(-) [+] |
line wrap: on
line diff
--- a/css/core.css Mon Nov 14 12:14:38 2016 +0000 +++ b/css/core.css Mon Nov 14 12:14:48 2016 +0000 @@ -3,60 +3,53 @@ */ div.title { - width: 100%; - height: 50px; - margin-bottom: 10px; - font-size: 2em; + width: 100%; + height: 50px; + margin-bottom: 10px; + font-size: 2em; } - div.indicator-box { - position: absolute; - left: 150px; - top: 10px; - width: 300px; - height: 60px; - padding: 20px; - border-radius: 10px; - background-color: rgb(100,200,200); + position: absolute; + left: 150px; + top: 10px; + width: 300px; + height: 60px; + padding: 20px; + border-radius: 10px; + background-color: rgb(100, 200, 200); } - div.comment-div { - border:1px solid #444444; - max-width: 600px; - min-width: 400px; - float: left; - margin: 5px 10px 5px 5px; - height: 90px; + border: 1px solid #444444; + max-width: 600px; + min-width: 400px; + float: left; + margin: 5px 10px 5px 5px; + height: 90px; border-radius: 10px; } - div.comment-div span { - margin-left: 15px; + margin-left: 15px; } - div.popupHolder { - width: 500px; - min-height: 250px; - max-height: 400px; - background-color: #fff; - border-radius: 10px; - box-shadow: 0px 0px 50px #000; - z-index: 10; - position: fixed; + width: 500px; + min-height: 250px; + max-height: 400px; + background-color: #fff; + border-radius: 10px; + box-shadow: 0px 0px 50px #000; + z-index: 10; + position: fixed; } - div#popupContent { margin-top: 20px; margin-bottom: 35px; overflow: auto; } - div#popupContent iframe { width: 100%; border: 0px none; height: 290px; } - div#popupTitleHolder { width: inherit; min-height: 25px; @@ -66,11 +59,9 @@ padding: 8px; text-align: center; } - #popupTitle { white-space: pre-line; } - div#popupResponse { width: inherit; min-height: 50px; @@ -78,20 +69,18 @@ overflow: auto; position: relative; } - button.popupButton { - /* Button for popup window + /* Button for popup window */ - width: 50px; - height: 25px; - position: absolute; - border-radius: 5px; - border: #444; - border-width: 1px; - border-style: solid; - background-color: #fff; + width: 50px; + height: 25px; + position: absolute; + border-radius: 5px; + border: #444; + border-width: 1px; + border-style: solid; + background-color: #fff; } - div.popup-option-checbox { /* Popup window checkbox */ padding: 5px; @@ -99,46 +88,44 @@ width: -moz-fit-content; width: -webkit-fit-content; } - -div.popup-option-checbox input{ +div.popup-option-checbox input { /* Popup window checkbox */ margin-right: 15px; } - table.popup-option-list { margin: auto; } - table.popup-option-list tr { padding: 5px; } - table.popup-option-list tr td { padding: 5px; } - +div.survey-slider-text-holder { + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 0px 15px; +} button#popup-proceed { bottom: 10px; right: 10px; } - button#popup-previous { bottom: 10px; left: 10px; } - 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: 9; - width: 100%; - height: 100%; - position: fixed; - left: 0px; - top: 0px; + /* 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: 9; + width: 100%; + height: 100%; + position: fixed; + left: 0px; + top: 0px; } - div#lightbox-root { visibility: hidden; z-index: 20; @@ -146,80 +133,69 @@ min-height: 50px; max-height: 250px; } - div.lightbox-error { margin: 25px; margin-bottom: 50px; padding: 5px; border-radius: 5px; - background-color: rgb(255,220,220); - border: 2px rgb(200,0,0) solid; + background-color: rgb(255, 220, 220); + border: 2px rgb(200, 0, 0) solid; } - div.lightbox-warning { margin: 25px; margin-bottom: 50px; padding: 5px; border-radius: 5px; - background-color: rgb(255,255,220); - border: 2px rgb(255,250,0) solid; + background-color: rgb(255, 255, 220); + border: 2px rgb(255, 250, 0) solid; } - div.lightbox-message { margin: 25px; margin-bottom: 50px; padding: 5px; border-radius: 5px; - background-color: rgb(200,220,255); - border: 2px rgb(50,100,250) solid; + background-color: rgb(200, 220, 255); + border: 2px rgb(50, 100, 250) solid; } - div#lightbox-blanker { visibility: hidden; z-index: 19; } - button.outside-reference { - width:120px; - height:20px; - margin-bottom:5px; - position: absolute; + width: 120px; + height: 20px; + margin-bottom: 5px; + position: absolute; } - textarea.trackComment { - max-width: 594px; - min-width: 350px; - max-height: 60px; + max-width: 594px; + min-width: 350px; + max-height: 60px; resize: none; } - div.playhead { - width: 500px; - height: 50px; - background-color: #eee; - border-radius: 10px; - padding: 10px; + width: 500px; + height: 50px; + background-color: #eee; + border-radius: 10px; + padding: 10px; } - div.playhead-scrub-track { - width: 100%; - height: 10px; - border-style: solid; - border-width: 1px; + width: 100%; + height: 10px; + border-style: solid; + border-width: 1px; } - div#playhead-scrubber { - width: 10px; - height: 10px; - position: relative; - background-color: #000; + width: 10px; + height: 10px; + position: relative; + background-color: #000; } - div.master-volume-holder-inline { width: 100%; padding: 5px; } - div.master-volume-holder-float { position: absolute; top: 20px; @@ -227,15 +203,13 @@ width: 250px%; padding: 5px; } - div#master-volume-root { - margin:auto; + margin: auto; border: black 1px solid; border-radius: 5px; width: 250px; height: 40px; } - input#master-volume-control { width: 200px; height: 25px; @@ -243,14 +217,12 @@ margin: 0px; padding: 0px; } - span#master-volume-feedback { width: 45px; height: 25px; margin-left: 5px; float: left; } - div.error-colour { background-color: #FF8F8F; } @@ -258,13 +230,11 @@ background-color: #FF8F8F; color: black; } - div.calibration-holder { text-align: center; align-content: center; height: auto; } - div.calibration-slider { width: 50px; margin: 2px; @@ -272,12 +242,23 @@ align-content: center; float: left; } - -div.calibration-slider input[type=range][orient=vertical] -{ - writing-mode: bt-lr; /* IE */ - -webkit-appearance: slider-vertical; /* WebKit */ +div.calibration-slider input[type=range][orient=vertical] { + writing-mode: bt-lr; + /* IE */ + -webkit-appearance: slider-vertical; + /* WebKit */ width: 8px; padding: 0 5px; height: 290px; } + +/* Comment Boxes */ + +div.comment-slider-text-holder { + display: flex; + flex-direction: row; + justify-content: space-between; +} +div.comment-slider-text-holder span { + margin: 0px 5px; +}
--- a/interfaces/ape.js Mon Nov 14 12:14:38 2016 +0000 +++ b/interfaces/ape.js Mon Nov 14 12:14:48 2016 +0000 @@ -8,472 +8,445 @@ 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 - { - var str = ""; - if (hasBeenPlayed.length > 1) { - for (var i=0; i<hasBeenPlayed.length; i++) { + + // 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 + { + 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 = 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.'; - } + } 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++) - { + 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) - { + 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; - }; - - Interface.prototype.checkAllCommented = function() { - var audioObjs = audioEngineContext.audioObjects; - var audioHolder = testState.stateMap[testState.stateIndex]; - var state = true; - if (audioHolder.elementComments) { - var strNums = []; - for (var i=0; i<audioObjs.length; i++) - { - if (audioObjs[i].commentDOM.trackCommentBox.value.length == 0) { - state = false; - strNums.push(i); - } - } - if (state == false) { + interfaceContext.lightbox.post("Message", str); + console.log(str); + } + return state; + }; + + Interface.prototype.checkAllCommented = function () { + var audioObjs = audioEngineContext.audioObjects; + var audioHolder = testState.stateMap[testState.stateIndex]; + var state = true; + if (audioHolder.elementComments) { + var strNums = []; + for (var i = 0; i < audioObjs.length; i++) { + if (audioObjs[i].commentDOM.trackCommentBox.value.length == 0) { + state = false; + strNums.push(i); + } + } + if (state == false) { var str = ""; - if (strNums.length > 1) { - - for (var i=0; i<strNums.length; i++) { + if (strNums.length > 1) { + + for (var i = 0; i < strNums.length; i++) { var ao_id = audioEngineContext.audioObjects[strNums[i]].interfaceDOM.getPresentedId(); - str = str + (ao_id); // start from 1 - if (i < strNums.length-2){ - str += ", "; - } else if (i == strNums.length-2) { - str += " or "; - } - } + str = str + (ao_id); // start from 1 + if (i < strNums.length - 2) { + str += ", "; + } else if (i == strNums.length - 2) { + str += " or "; + } + } str = 'You have not commented on fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.'; - } else { - str = 'You have not commented on fragment ' + (audioEngineContext.audioObjects[strNums[0]].interfaceDOM.getPresentedId()) + ' yet. Please listen, rate and comment all samples before submitting.'; - } + } else { + str = 'You have not commented on fragment ' + (audioEngineContext.audioObjects[strNums[0]].interfaceDOM.getPresentedId()) + ' yet. Please listen, rate and comment all samples before submitting.'; + } this.storeErrorNode(str); - interfaceContext.lightbox.post("Message",str); + interfaceContext.lightbox.post("Message", str); console.log(str); - } - } - return state; - }; - - Interface.prototype.checkScaleRange = function() - { - var audioObjs = audioEngineContext.audioObjects; - var audioHolder = testState.stateMap[testState.stateIndex]; - var state = true; - var str = ''; - for (var i=0; i<this.interfaceSliders.length; i++) - { - var minScale; - var maxScale; - var interfaceObject = interfaceContext.interfaceSliders[0].interfaceObject; - for (var j=0; j<interfaceObject.options.length; j++) - { - if (interfaceObject.options[j].check == "scalerange") { - minScale = interfaceObject.options[j].min; - maxScale = interfaceObject.options[j].max; - break; - } - } - var minRanking = convSliderPosToRate(this.interfaceSliders[i].sliders[0]); - var maxRanking = minRanking; - for (var j=1; j<this.interfaceSliders[i].sliders.length; j++) - { - var ranking = convSliderPosToRate(this.interfaceSliders[i].sliders[j]); - if (ranking < minRanking) - { - minRanking = ranking; - } else if (ranking > maxRanking) - { - maxRanking = ranking; - } - } - if (minRanking > minScale || maxRanking < maxScale) - { - state = false; - str += 'On axis "'+this.interfaceSliders[i].interfaceObject.title+'" you have not used the full width of the scale. '; - } - } - if (state != true) - { + } + } + return state; + }; + + Interface.prototype.checkScaleRange = function () { + var audioObjs = audioEngineContext.audioObjects; + var audioHolder = testState.stateMap[testState.stateIndex]; + var state = true; + var str = ''; + for (var i = 0; i < this.interfaceSliders.length; i++) { + var minScale; + var maxScale; + var interfaceObject = interfaceContext.interfaceSliders[0].interfaceObject; + for (var j = 0; j < interfaceObject.options.length; j++) { + if (interfaceObject.options[j].check == "scalerange") { + minScale = interfaceObject.options[j].min; + maxScale = interfaceObject.options[j].max; + break; + } + } + var minRanking = convSliderPosToRate(this.interfaceSliders[i].sliders[0]); + var maxRanking = minRanking; + for (var j = 1; j < this.interfaceSliders[i].sliders.length; j++) { + var ranking = convSliderPosToRate(this.interfaceSliders[i].sliders[j]); + if (ranking < minRanking) { + minRanking = ranking; + } else if (ranking > maxRanking) { + maxRanking = ranking; + } + } + if (minRanking > minScale || maxRanking < maxScale) { + state = false; + str += 'On axis "' + this.interfaceSliders[i].interfaceObject.title + '" you have not used the full width of the scale. '; + } + } + if (state != true) { this.storeErrorNode(str); - interfaceContext.lightbox.post("Message",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'); + interfaceContext.lightbox.post("Message", 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'); titleSpan.id = "test-title"; - - // 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'; + + // 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 = 'Next'; - 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"; - + } + }; + // Create Submit (save) button + var submit = document.createElement("button"); + submit.innerHTML = 'Next'; + 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"; + // Create outside reference holder var outsideRef = document.createElement("div"); outsideRef.id = "outside-reference-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 = ""; // Clear the current schema - - // Inject into HTML - testContent.appendChild(title); // Insert the title - testContent.appendChild(interfaceButtons); + + // Global parent for the comment boxes on the page + var feedbackHolder = document.createElement('div'); + feedbackHolder.id = 'feedbackHolder'; + + testContent.style.zIndex = 1; + interfaceContext.insertPoint.innerHTML = ""; // Clear the current schema + + // Inject into HTML + testContent.appendChild(title); // Insert the title + testContent.appendChild(interfaceButtons); testContent.appendChild(outsideRef); - testContent.appendChild(sliderHolder); - testContent.appendChild(feedbackHolder); - interfaceContext.insertPoint.appendChild(testContent); + testContent.appendChild(sliderHolder); + testContent.appendChild(feedbackHolder); + interfaceContext.insertPoint.appendChild(testContent); - // Load the full interface - testState.initialise(); - testState.advanceState(); - + // 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 = ""; - sliderHolder.innerHTML = ""; - +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 = ""; + sliderHolder.innerHTML = ""; + + // Set labelType if default to number + if (audioHolderObject.label == "default" || audioHolderObject.label == "") { + audioHolderObject.label = "number"; + } + // Set the page title if (typeof audioHolderObject.title == "string" && audioHolderObject.title.length > 0) { document.getElementById("test-title").textContent = audioHolderObject.title } - - - // Delete outside reference - document.getElementById("outside-reference-holder").innerHTML = ""; - - var interfaceObj = audioHolderObject.interfaces; - for (var k=0; k<interfaceObj.length; k++) { - // Create the div box to center align - interfaceContext.interfaceSliders.push(new interfaceSliderHolder(interfaceObj[k])); - } - + + + // Delete outside reference + document.getElementById("outside-reference-holder").innerHTML = ""; + + var interfaceObj = audioHolderObject.interfaces; + for (var k = 0; k < interfaceObj.length; k++) { + // Create the div box to center align + interfaceContext.interfaceSliders.push(new interfaceSliderHolder(interfaceObj[k])); + } + var interfaceList = audioHolderObject.interfaces.concat(specification.interfaces); - for (var k=0; k<interfaceList.length; k++) - { - for (var i=0; i<interfaceList[k].options.length; i++) - { - if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'playhead') - { + for (var k = 0; k < interfaceList.length; k++) { + for (var i = 0; i < interfaceList[k].options.length; i++) { + if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'playhead') { var playbackHolder = document.getElementById('playback-holder'); - if (playbackHolder == null) - { + if (playbackHolder == null) { playbackHolder = document.createElement('div'); playbackHolder.style.width = "100%"; playbackHolder.align = 'center'; playbackHolder.appendChild(interfaceContext.playhead.object); feedbackHolder.appendChild(playbackHolder); } - } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'page-count') - { + } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'page-count') { var pagecountHolder = document.getElementById('page-count'); - if (pagecountHolder == null) - { + if (pagecountHolder == null) { pagecountHolder = document.createElement('div'); pagecountHolder.id = 'page-count'; } - pagecountHolder.innerHTML = '<span>Page '+(testState.stateIndex+1)+' of '+testState.stateMap.length+'</span>'; + pagecountHolder.innerHTML = '<span>Page ' + (testState.stateIndex + 1) + ' of ' + testState.stateMap.length + '</span>'; var inject = document.getElementById('interface-buttons'); inject.appendChild(pagecountHolder); } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'volume') { - if (document.getElementById('master-volume-holder') == null) - { + if (document.getElementById('master-volume-holder') == null) { feedbackHolder.appendChild(interfaceContext.volume.object); } } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'comments') { var commentHolder = document.createElement('div'); commentHolder.id = 'commentHolder'; document.getElementById('testContent').appendChild(commentHolder); - interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder,true); + interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder, true); break; } } } - - 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("outside-reference-holder")); - audioObject.bindInterface(orNode); - } else { - // Create a slider per track - var sliderNode = new sliderObject(audioObject,interfaceObj,index); - audioObject.bindInterface(sliderNode); + 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("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; + } + }); + + // 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; + 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(); - }); + 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"); - 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+')'); - obj.setAttribute("slider-value",convSliderPosToRate(obj)); - } else { - var 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(); - }); - + $(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 + ')'); + obj.setAttribute("slider-value", convSliderPosToRate(obj)); + } else { + var 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(); + }); + var interfaceList = audioHolderObject.interfaces.concat(specification.interfaces); - for (var k=0; k<interfaceList.length; k++) - { - for (var i=0; i<interfaceList[k].options.length; i++) - { - if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'playhead') - { + for (var k = 0; k < interfaceList.length; k++) { + for (var i = 0; i < interfaceList[k].options.length; i++) { + if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'playhead') { var playbackHolder = document.getElementById('playback-holder'); - if (playbackHolder == null) - { + if (playbackHolder == null) { playbackHolder = document.createElement('div'); playbackHolder.id = "playback-holder"; playbackHolder.style.width = "100%"; @@ -481,461 +454,419 @@ playbackHolder.appendChild(interfaceContext.playhead.object); feedbackHolder.appendChild(playbackHolder); } - } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'page-count') - { + } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'page-count') { var pagecountHolder = document.getElementById('page-count'); - if (pagecountHolder == null) - { + if (pagecountHolder == null) { pagecountHolder = document.createElement('div'); pagecountHolder.id = 'page-count'; } - pagecountHolder.innerHTML = '<span>Page '+(testState.stateIndex+1)+' of '+testState.stateMap.length+'</span>'; + pagecountHolder.innerHTML = '<span>Page ' + (testState.stateIndex + 1) + ' of ' + testState.stateMap.length + '</span>'; var inject = document.getElementById('interface-buttons'); inject.appendChild(pagecountHolder); } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'volume') { - if (document.getElementById('master-volume-holder') == null) - { + if (document.getElementById('master-volume-holder') == null) { feedbackHolder.appendChild(interfaceContext.volume.object); } } else if (interfaceList[k].options[i].type == 'show' && interfaceList[k].options[i].name == 'comments') { - interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder,true); + interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder, true); break; } } } - - $(audioHolderObject.commentQuestions).each(function(index,element) { - var node = interfaceContext.createCommentQuestion(element); - feedbackHolder.appendChild(node.holder); - }); - - //testWaitIndicator(); + + $(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); - 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; +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); + 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); - for (var scaleObj of interfaceObject.scales) - { - var position = Number(scaleObj.position)*0.01; - var pixelPosition = (position*$(this.canvas).width())+offset; - var scaleDOM = document.createElement('span'); + for (var scaleObj of interfaceObject.scales) { + 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.createSliderObject = function(audioObject,label) - { - var trackObj = document.createElement('div'); + scaleDOM.textContent = scaleObj.text; + scaleDOM.setAttribute('value', position) + this.scale.appendChild(scaleDOM); + scaleDOM.style.left = Math.floor((pixelPosition - ($(scaleDOM).width() / 2))) + 'px'; + } + + 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); - } - 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"); + 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 = 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 width = window.innerWidth; - var sliderDiv = this.canvas; - var sliderScaleDiv = this.scale; - var width = $(sliderDiv).width(); + this.metrics[this.metrics.length - 1].initialise(rate); + trackObj.setAttribute("slider-value", rate); + return trackObj; + }; + + this.resize = function (event) { + var width = window.innerWidth; + var sliderDiv = this.canvas; + var sliderScaleDiv = this.scale; + var width = $(sliderDiv).width(); var marginsize = 50; - // Move sliders into new position - for (var index = 0; index < this.sliders.length; index++) - { - var pix = Number(this.sliders[index].getAttribute("slider-value")) * width; - this.sliders[index].style.left = (pix+marginsize)+'px'; - } - - // 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'; - } - }; + // Move sliders into new position + for (var index = 0; index < this.sliders.length; index++) { + var pix = Number(this.sliders[index].getAttribute("slider-value")) * width; + this.sliders[index].style.left = (pix + marginsize) + 'px'; + } + + // 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,index) { - // Create a new slider object; - this.parent = audioObject; - this.trackSliderObjects = []; - this.label = null; +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; - switch(audioObject.specification.parent.label) { - case "letter": - this.label = String.fromCharCode(97 + index); - break; - case "capital": - this.label = String.fromCharCode(65 + index); - break; - case "none": - this.label = ""; - break; - default: - this.label = ""+(index+1); - break; + for (var i = 0; i < interfaceContext.interfaceSliders.length; i++) { + var trackObj = interfaceContext.interfaceSliders[i].createSliderObject(audioObject, this.label); + this.trackSliderObjects.push(trackObj); } - 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.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() - { + // 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.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; + var name = ".track-slider-" + this.parent.id; $(name).addClass('track-slider-playing'); $('.comment-div').removeClass('comment-box-playing'); - $('#comment-div-'+this.parent.id).addClass('comment-box-playing'); + $('#comment-div-' + this.parent.id).addClass('comment-box-playing'); $('.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'); } }; - this.stopPlayback = function() - { + this.stopPlayback = function () { if (this.playing) { this.playing = false; - var name = ".track-slider-"+this.parent.id; + var name = ".track-slider-" + this.parent.id; $(name).removeClass('track-slider-playing'); - $('#comment-div-'+this.parent.id).removeClass('comment-box-playing'); + $('#comment-div-' + this.parent.id).removeClass('comment-box-playing'); $('.track-slider').removeClass('track-slider-disabled'); $('.outside-reference').removeClass('track-slider-disabled'); } }; - 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'); - 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.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'); + 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) -{ - this.parent = audioObject; - this.outsideReferenceHolder = document.createElement('div'); - this.outsideReferenceHolder.id = 'outside-reference'; - this.outsideReferenceHolder.className = 'outside-reference track-slider-disabled'; - var outsideReferenceHolderspan = document.createElement('span'); - outsideReferenceHolderspan.textContent = 'Reference'; - this.outsideReferenceHolder.appendChild(outsideReferenceHolderspan); - this.outsideReferenceHolder.setAttribute('track-id',index); - - this.outsideReferenceHolder.onclick = function(event) - { - audioEngineContext.play(event.currentTarget.getAttribute('track-id')); - $('.track-slider').removeClass('track-slider-playing'); +function outsideReferenceDOM(audioObject, index, inject) { + this.parent = audioObject; + this.outsideReferenceHolder = document.createElement('div'); + this.outsideReferenceHolder.id = 'outside-reference'; + this.outsideReferenceHolder.className = 'outside-reference track-slider-disabled'; + var outsideReferenceHolderspan = document.createElement('span'); + outsideReferenceHolderspan.textContent = 'Reference'; + this.outsideReferenceHolder.appendChild(outsideReferenceHolderspan); + this.outsideReferenceHolder.setAttribute('track-id', index); + + this.outsideReferenceHolder.onclick = function (event) { + audioEngineContext.play(event.currentTarget.getAttribute('track-id')); + $('.track-slider').removeClass('track-slider-playing'); $('.comment-div').removeClass('comment-box-playing'); if (event.currentTarget.nodeName == 'DIV') { - $(event.currentTarget).addClass('track-slider-playing'); + $(event.currentTarget).addClass('track-slider-playing'); } else { - $(event.currentTarget.parentElement).addClass('track-slider-playing'); + $(event.currentTarget.parentElement).addClass('track-slider-playing'); } - }; - inject.appendChild(this.outsideReferenceHolder); - this.enable = function() - { - if (this.parent.state == 1) - { - $(this.outsideReferenceHolder).removeClass('track-slider-disabled'); - } - }; - this.updateLoading = function(progress) - { - if (progress != 100) - { - progress = String(progress); - progress = progress.split('.')[0]; - this.outsideReferenceHolder.firstChild.textContent = progress+'%'; - } else { - this.outsideReferenceHolder.firstChild.textContent = "Play Reference"; - } - }; - this.startPlayback = function() - { + }; + inject.appendChild(this.outsideReferenceHolder); + this.enable = function () { + if (this.parent.state == 1) { + $(this.outsideReferenceHolder).removeClass('track-slider-disabled'); + } + }; + this.updateLoading = function (progress) { + if (progress != 100) { + progress = String(progress); + progress = progress.split('.')[0]; + this.outsideReferenceHolder.firstChild.textContent = progress + '%'; + } else { + this.outsideReferenceHolder.firstChild.textContent = "Play Reference"; + } + }; + this.startPlayback = function () { $('.track-slider').removeClass('track-slider-playing'); $(this.outsideReferenceHolder).addClass('track-slider-playing'); $('.comment-div').removeClass('comment-box-playing'); }; - this.stopPlayback = function() - { + this.stopPlayback = function () { $(this.outsideReferenceHolder).removeClass('track-slider-playing'); }; - this.exportXMLDOM = function(audioObject) - { - return null; - }; - this.getValue = function() - { - return 0; - }; - this.getPresentedId = function() - { - return 'reference'; - }; - this.canMove = function() - { - return false; - }; - this.error = function() { - // audioObject has an error!! + this.exportXMLDOM = function (audioObject) { + return null; + }; + this.getValue = function () { + return 0; + }; + this.getPresentedId = function () { + return 'reference'; + }; + this.canMove = function () { + return false; + }; + this.error = function () { + // audioObject has an error!! this.outsideReferenceHolder.textContent = "Error"; $(this.outsideReferenceHolder).addClass("error-colour"); } } -function buttonSubmitClick() -{ - 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<checks.length; i++) { - if (checks[i].type == 'check') - { - switch(checks[i].name) { - case 'fragmentPlayed': - // Check if all fragments have been played - var checkState = interfaceContext.checkAllPlayed(); - if (checkState == false) {canContinue = false;} - break; - case 'fragmentFullPlayback': - // Check all fragments have been played to their full length - var checkState = interfaceContext.checkFragmentsFullyPlayed(); - if (checkState == false) {canContinue = false;} - break; - case 'fragmentMoved': - // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllMoved(); - if (checkState == false) {canContinue = false;} - break; - case 'fragmentComments': - // Check all fragment sliders have been moved. - var checkState = interfaceContext.checkAllCommented(); - if (checkState == false) {canContinue = false;} - break; - case 'scalerange': - // Check the scale is used to its full width outlined by the node - var checkState = interfaceContext.checkScaleRange(); - if (checkState == false) {canContinue = false;} - break; - default: - console.log("WARNING - Check option "+checks[i].name+" is not supported on this interface"); - break; - } +function buttonSubmitClick() { + var checks = []; + checks = checks.concat(testState.currentStateMap.interfaces[0].options); + checks = checks.concat(specification.interfaces.options); + var canContinue = true; - } - if (!canContinue) {break;} - } - + // 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 < checks.length; i++) { + if (checks[i].type == 'check') { + switch (checks[i].name) { + case 'fragmentPlayed': + // Check if all fragments have been played + var checkState = interfaceContext.checkAllPlayed(); + if (checkState == false) { + canContinue = false; + } + break; + case 'fragmentFullPlayback': + // Check all fragments have been played to their full length + var checkState = interfaceContext.checkFragmentsFullyPlayed(); + if (checkState == false) { + canContinue = false; + } + break; + case 'fragmentMoved': + // Check all fragment sliders have been moved. + var checkState = interfaceContext.checkAllMoved(); + if (checkState == false) { + canContinue = false; + } + break; + case 'fragmentComments': + // Check all fragment sliders have been moved. + var checkState = interfaceContext.checkAllCommented(); + if (checkState == false) { + canContinue = false; + } + break; + case 'scalerange': + // Check the scale is used to its full width outlined by the node + var checkState = interfaceContext.checkScaleRange(); + if (checkState == false) { + canContinue = false; + } + break; + default: + console.log("WARNING - Check option " + checks[i].name + " is not supported on this interface"); + break; + } + + } + if (!canContinue) { + break; + } + } + if (canContinue) { - if (audioEngineContext.status == 1) { - var playback = document.getElementById('playback-button'); - playback.click(); - // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options - } else - { - if (audioEngineContext.timer.testStarted == false) - { - interfaceContext.lightbox.post("Warning",'You have not started the test! Please click a fragment to begin the test!'); - return; - } - } - testState.advanceState(); - } + if (audioEngineContext.status == 1) { + var playback = document.getElementById('playback-button'); + playback.click(); + // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options + } else { + if (audioEngineContext.timer.testStarted == false) { + interfaceContext.lightbox.post("Warning", 'You have not started the test! Please click a fragment to begin the test!'); + return; + } + } + testState.advanceState(); + } } -function convSliderPosToRate(trackSlider) -{ - var slider = trackSlider.parentElement; - var maxPix = $(slider).width(); - var marginsize = 50; - var pix = trackSlider.style.left; - pix = pix.substr(0,pix.length-2); - var rate = (pix-marginsize)/maxPix; - return rate; +function convSliderPosToRate(trackSlider) { + var slider = trackSlider.parentElement; + var maxPix = $(slider).width(); + var marginsize = 50; + var pix = trackSlider.style.left; + pix = pix.substr(0, pix.length - 2); + var rate = (pix - marginsize) / maxPix; + return rate; } -function resizeWindow(event){ - // Function called when the window has been resized. - // MANDATORY FUNCTION - - // Resize the slider objects - for (var i=0; i<interfaceContext.interfaceSliders.length; i++) - { - interfaceContext.interfaceSliders[i].resize(event); - } +function resizeWindow(event) { + // Function called when the window has been resized. + // MANDATORY FUNCTION + + // Resize the slider objects + for (var i = 0; i < interfaceContext.interfaceSliders.length; i++) { + interfaceContext.interfaceSliders[i].resize(event); + } } -function pageXMLSave(store, pageSpecification) -{ - // MANDATORY - // Saves a specific test page - // You can use this space to add any extra nodes to your XML <audioHolder> saves - // Get the current <page> 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<audioelements.length; i++) - { - // Have to append the metric specific nodes - if (pageSpecification.outsideReference == null || 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") - { - mrnodes[j].setAttribute("interface-name",interfaceContext.interfaceSliders[k].name); - mrnodes[j].setAttribute("interface-id",k); - inject.appendChild(mrnodes[j]); - } - } - } - } - } -} \ No newline at end of file +function pageXMLSave(store, pageSpecification) { + // MANDATORY + // Saves a specific test page + // You can use this space to add any extra nodes to your XML <audioHolder> saves + // Get the current <page> 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 < audioelements.length; i++) { + // Have to append the metric specific nodes + if (pageSpecification.outsideReference == null || 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") { + mrnodes[j].setAttribute("interface-name", interfaceContext.interfaceSliders[k].name); + mrnodes[j].setAttribute("interface-id", k); + inject.appendChild(mrnodes[j]); + } + } + } + } + } +}
--- a/js/core.js Mon Nov 14 12:14:38 2016 +0000 +++ b/js/core.js Mon Nov 14 12:14:48 2016 +0000 @@ -799,13 +799,13 @@ } else if (node.specification.type == 'number') { var input = document.createElement('input'); input.type = 'textarea'; - if (node.min != null) { + if (node.specification.min != null) { input.min = node.specification.min; } - if (node.max != null) { + if (node.specification.max != null) { input.max = node.specification.max; } - if (node.step != null) { + if (node.specification.step != null) { input.step = node.specification.step; } if (node.response != undefined) { @@ -823,6 +823,30 @@ iframe.className = "youtube"; iframe.src = node.specification.url; this.popupResponse.appendChild(iframe); + } else if (node.specification.type == "slider") { + var hold = document.createElement('div'); + var input = document.createElement('input'); + input.type = 'range'; + input.style.width = "90%"; + if (node.specification.min != null) { + input.min = node.specification.min; + } + if (node.specification.max != null) { + input.max = node.specification.max; + } + if (node.response != undefined) { + input.value = node.response; + } + hold.className = "survey-slider-text-holder"; + var minText = document.createElement('span'); + var maxText = document.createElement('span'); + minText.textContent = node.specification.leftText; + maxText.textContent = node.specification.rightText; + hold.appendChild(minText); + hold.appendChild(maxText); + this.popupResponse.appendChild(input); + this.popupResponse.appendChild(hold); + this.popupResponse.style.textAlign = "center"; } if (this.currentIndex + 1 == this.popupOptions.length) { if (this.node.location == "pre") { @@ -1107,6 +1131,49 @@ break; } } + } else if (node.specification.type == 'slider') { + var input = this.popupContent.getElementsByTagName('input')[0]; + node.response = input.value; + for (var condition of node.specification.conditions) { + var pass = false; + switch (condition.check) { + case "contains": + console.log("Survey Element of type 'number' cannot interpret contains conditions. IGNORING"); + break; + case "greaterThan": + if (node.response > Number(condition.value)) { + pass = true; + } + break; + case "lessThan": + if (node.response < Number(condition.value)) { + pass = true; + } + break; + case "equals": + if (node.response == condition.value) { + pass = true; + } + break; + } + var jumpID; + if (pass) { + jumpID = condition.jumpToOnPass; + } else { + jumpID = condition.jumpToOnFail; + } + if (jumpID != undefined) { + var index = this.popupOptions.findIndex(function (item, index, element) { + if (item.specification.id == jumpID) { + return true; + } else { + return false; + } + }, this); + this.currentIndex = index - 1; + break; + } + } } this.currentIndex++; if (this.currentIndex < this.popupOptions.length) { @@ -2629,6 +2696,63 @@ this.resize(); }; + this.sliderBox = function (commentQuestion) { + this.specification = commentQuestion; + this.holder = document.createElement("div"); + this.holder.className = 'comment-div'; + this.string = document.createElement("span"); + this.string.innerHTML = commentQuestion.statement; + this.slider = document.createElement("input"); + this.slider.type = "range"; + this.slider.min = commentQuestion.min; + this.slider.max = commentQuestion.max; + this.slider.step = commentQuestion.step; + this.slider.value = commentQuestion.value; + var br = document.createElement('br'); + + var textHolder = document.createElement("div"); + textHolder.className = "comment-slider-text-holder"; + + this.leftText = document.createElement("span"); + this.leftText.textContent = commentQuestion.leftText; + this.rightText = document.createElement("span"); + this.rightText.textContent = commentQuestion.rightText; + textHolder.appendChild(this.leftText); + textHolder.appendChild(this.rightText); + + this.holder.appendChild(this.string); + this.holder.appendChild(br); + this.holder.appendChild(this.slider); + this.holder.appendChild(textHolder); + + this.exportXMLDOM = function (storePoint) { + var root = storePoint.parent.document.createElement('comment'); + root.id = this.specification.id; + root.setAttribute('type', this.specification.type); + console.log("Question: " + this.string.textContent); + console.log("Response: " + this.slider.value); + var question = storePoint.parent.document.createElement('question'); + question.textContent = this.string.textContent; + var response = storePoint.parent.document.createElement('response'); + response.textContent = this.slider.value; + root.appendChild(question); + root.appendChild(response); + storePoint.XMLDOM.appendChild(root); + return root; + }; + this.resize = function () { + var boxwidth = (window.innerWidth - 100) / 2; + if (boxwidth >= 600) { + boxwidth = 600; + } else if (boxwidth < 400) { + boxwidth = 400; + } + this.holder.style.width = boxwidth + "px"; + this.slider.style.width = boxwidth - 24 + "px"; + }; + this.resize(); + }; + this.createCommentQuestion = function (element) { var node; if (element.type == 'question') { @@ -2637,6 +2761,8 @@ node = new this.radioBox(element); } else if (element.type == 'checkbox') { node = new this.checkboxBox(element); + } else if (element.type == 'slider') { + node = new this.sliderBox(element); } this.commentQuestions.push(node); return node; @@ -2912,8 +3038,8 @@ obj.input.value = obj.gain.gain.value; obj.input.setAttribute('orient', 'vertical'); obj.input.type = "range"; - obj.input.min = -6; - obj.input.max = 6; + obj.input.min = -12; + obj.input.max = 0; obj.input.step = 0.25; if (f0 != 1000) { obj.input.value = (Math.random() * 12) - 6; @@ -3112,6 +3238,70 @@ node.textContent = errorMessage; testState.currentStore.XMLDOM.appendChild(node); }; + + this.getLabel = function (labelType, index, labelStart) { + /* + Get the correct label based on type, index and offset + */ + + function calculateLabel(labelType, index, offset) { + if (labelType == "none") { + return ""; + } + switch (labelType) { + case "letter": + return String.fromCharCode((index + offset) % 26 + 97); + case "capital": + return String.fromCharCode((index + offset) % 26 + 66); + case "number": + return String(index + offset); + default: + return ""; + } + } + + if (typeof labelStart !== "string" || labelStart.length == 0) { + labelStart = String.fromCharCode(0); + } + + switch (labelType) { + case "letter": + labelStart = labelStart.charCodeAt(0); + if (labelStart < 97 || labelStart > 122) { + labelStart = 97; + } + labelStart -= 97; + break; + case "capital": + labelStart = labelStart.charCodeAt(0); + if (labelStart < 65 || labelStart > 90) { + labelStart = 65; + } + labelStart -= 65; + break; + case "number": + if (!isFinite(Number(labelStart))) { + labelStart = 1; + } + break; + case "none": + default: + labelStart = 0; + } + if (typeof index == "number") { + return calculateLabel(labelType, index, labelStart); + } else if (index.length && index.length > 0) { + var a = [], + l = index.length, + i; + for (i = 0; i < l; i++) { + a[i] = calculateLabel(labelType, index[i], labelStart); + } + return a; + } else { + throw ("Invalid arguments"); + } + } } function Storage() { @@ -3267,6 +3457,7 @@ switch (node.specification.type) { case "number": case "question": + case "slider": var child = this.parent.document.createElement('response'); child.textContent = node.response; surveyresult.appendChild(child);
--- a/js/specification.js Mon Nov 14 12:14:38 2016 +0000 +++ b/js/specification.js Mon Nov 14 12:14:48 2016 +0000 @@ -195,7 +195,7 @@ this.OptionNode = function (specification) { this.type = undefined; - this.schema = specification.schema.getAllElementsByName('surveyentry')[0]; + this.schema = undefined; this.id = undefined; this.name = undefined; this.mandatory = undefined; @@ -208,6 +208,7 @@ this.conditions = []; this.decode = function (parent, child) { + this.schema = specification.schema.getAllElementsByName(child.nodeName)[0]; var attributeMap = this.schema.getAllElementsByTagName('xs:attribute'); for (var i in attributeMap) { if (isNaN(Number(i)) == true) { @@ -226,6 +227,15 @@ break; } } + if (child.nodeName == 'surveyentry') { + console.log("NOTE - Use of <surveyelement> is now deprecated. Whilst these will still work, newer nodes and tighter error checking will not be enforced"); + console.log("Please use the newer, type specifc nodes"); + if (!this.type) { + throw ("Type not specified"); + } + } else { + this.type = child.nodeName.split('survey')[1]; + } this.statement = child.getElementsByTagName('statement')[0].textContent; if (this.type == "checkbox" || this.type == "radio") { var children = child.getElementsByTagName('option'); @@ -242,6 +252,17 @@ }); } } + } else if (this.type == "slider") { + this.leftText = ""; + this.rightText = ""; + var minText = child.getElementsByTagName("minText"); + var maxText = child.getElementsByTagName("maxText"); + if (minText.length > 0) { + this.leftText = minText[0].textContent; + } + if (maxText.length > 0) { + this.rightText = maxText[0].textContent; + } } var conditionElements = child.getElementsByTagName("conditional"); for (var i = 0; i < conditionElements.length; i++) { @@ -257,8 +278,7 @@ }; this.exportXML = function (doc) { - var node = doc.createElement('surveyentry'); - node.setAttribute('type', this.type); + var node = doc.createElement('survey' + this.type); var statement = doc.createElement('statement'); statement.textContent = this.statement; node.appendChild(statement); @@ -319,6 +339,19 @@ node.setAttribute("url", this.url); } break; + case "slider": + node.setAttribute("min", this.min); + node.setAttribute("max", this.max); + if (this.leftText) { + var minText = doc.createElement("minText"); + minText.textContent = this.leftText; + node.appendChild(minText); + } + if (this.rightText) { + var maxText = doc.createElement("maxText"); + maxText.textContent = this.rightText; + node.appendChild(maxText); + } default: break; } @@ -341,11 +374,12 @@ } else if (this.location == 'after') { this.location = 'post'; } - var children = xml.getAllElementsByTagName('surveyentry'); - for (var i = 0; i < children.length; i++) { + var child = xml.firstElementChild + while (child) { var node = new this.OptionNode(this.specification); - node.decode(parent, children[i]); + node.decode(parent, child); this.options.push(node); + child = child.nextElementSibling; } if (this.options.length == 0) { console.log("Empty survey node"); @@ -495,88 +529,87 @@ this.decode = function (parent, xml) { this.parent = parent; - var attributeMap = this.schema.getAllElementsByTagName('xs:attribute'); - for (var i=0; i<attributeMap.length; i++) - { - var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref'); - var projectAttr = xml.getAttribute(attributeName); - projectAttr = parent.processAttribute(projectAttr,attributeMap[i],parent.schema); - switch(typeof projectAttr) - { - case "number": - case "boolean": - eval('this.'+attributeName+' = '+projectAttr); - break; - case "string": - eval('this.'+attributeName+' = "'+projectAttr+'"'); - break; - } - } - + var attributeMap = this.schema.getAllElementsByTagName('xs:attribute'); + for (var i = 0; i < attributeMap.length; i++) { + var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref'); + var projectAttr = xml.getAttribute(attributeName); + projectAttr = parent.processAttribute(projectAttr, attributeMap[i], parent.schema); + switch (typeof projectAttr) { + case "number": + case "boolean": + eval('this.' + attributeName + ' = ' + projectAttr); + break; + case "string": + eval('this.' + attributeName + ' = "' + projectAttr + '"'); + break; + } + } + // Get the title var title = xml.getElementsByTagName('title'); if (title.length != 0 && title[0].parentElement == xml) { this.title = title[0].textContent; } - - // Get the Comment Box Prefix - var CBP = xml.getElementsByTagName('commentboxprefix'); - if (CBP.length != 0 && CBP[0].parentElement == xml) { - this.commentBoxPrefix = CBP[0].textContent; - } - - // Now decode the interfaces - var interfaceNode = xml.getElementsByTagName('interface'); - for (var i=0; i<interfaceNode.length; i++) - { - var node = new parent.interfaceNode(this.specification); - node.decode(this,interfaceNode[i],parent.schema.getAllElementsByName('interface')[1]); - this.interfaces.push(node); - } - - // Now process the survey node options - var survey = xml.getElementsByTagName('survey'); - var surveySchema = parent.schema.getAllElementsByName('survey')[0]; - for (var i=0; i<survey.length; i++){ - var location = survey[i].getAttribute('location'); - if (location == 'pre' || location == 'before') - { - if (this.preTest != null){this.errors.push("Already a pre/before test survey defined! Ignoring second!!");} - else { - this.preTest = new parent.surveyNode(this.specification); - this.preTest.decode(parent,survey[i],surveySchema); - } - } else if (location == 'post' || location == 'after') { - if (this.postTest != null){this.errors.push("Already a post/after test survey defined! Ignoring second!!");} - else { - this.postTest = new parent.surveyNode(this.specification); - this.postTest.decode(parent,survey[i],surveySchema); - } - } - } - - // Now process the audioelement tags - var audioElements = xml.getElementsByTagName('audioelement'); - for (var i=0; i<audioElements.length; i++) - { - var node = new this.audioElementNode(this.specification); - node.decode(this,audioElements[i]); - this.audioElements.push(node); - } - - // Now decode the commentquestions - var commentQuestions = xml.getElementsByTagName('commentquestion'); - for (var i=0; i<commentQuestions.length; i++) - { - var node = new this.commentQuestionNode(this.specification); - node.decode(parent,commentQuestions[i]); - this.commentQuestions.push(node); - } - }; - - this.encode = function(root) - { - var AHNode = root.createElement("page"); + + // Get the Comment Box Prefix + var CBP = xml.getElementsByTagName('commentboxprefix'); + if (CBP.length != 0 && CBP[0].parentElement == xml) { + this.commentBoxPrefix = CBP[0].textContent; + } + + // Now decode the interfaces + var interfaceNode = xml.getElementsByTagName('interface'); + for (var i = 0; i < interfaceNode.length; i++) { + var node = new parent.interfaceNode(this.specification); + node.decode(this, interfaceNode[i], parent.schema.getAllElementsByName('interface')[1]); + this.interfaces.push(node); + } + + // Now process the survey node options + var survey = xml.getElementsByTagName('survey'); + var surveySchema = parent.schema.getAllElementsByName('survey')[0]; + for (var i = 0; i < survey.length; i++) { + var location = survey[i].getAttribute('location'); + if (location == 'pre' || location == 'before') { + if (this.preTest != null) { + this.errors.push("Already a pre/before test survey defined! Ignoring second!!"); + } else { + this.preTest = new parent.surveyNode(this.specification); + this.preTest.decode(parent, survey[i], surveySchema); + } + } else if (location == 'post' || location == 'after') { + if (this.postTest != null) { + this.errors.push("Already a post/after test survey defined! Ignoring second!!"); + } else { + this.postTest = new parent.surveyNode(this.specification); + this.postTest.decode(parent, survey[i], surveySchema); + } + } + } + + // Now process the audioelement tags + var audioElements = xml.getElementsByTagName('audioelement'); + for (var i = 0; i < audioElements.length; i++) { + var node = new this.audioElementNode(this.specification); + node.decode(this, audioElements[i]); + this.audioElements.push(node); + } + + // Now decode the commentquestions + var cqNode = xml.getElementsByTagName('commentquestions'); + if (cqNode.length != 0) { + cqNode = cqNode[0]; + var commentQuestions = cqNode.children; + for (var i = 0; i < commentQuestions.length; i++) { + var node = new this.commentQuestionNode(this.specification); + node.decode(parent, commentQuestions[i]); + this.commentQuestions.push(node); + } + } + }; + + this.encode = function (root) { + var AHNode = root.createElement("page"); // First decode the attributes var attributes = this.schema.getAllElementsByTagName('xs:attribute'); for (var i = 0; i < attributes.length; i++) { @@ -617,26 +650,85 @@ this.id = null; this.name = undefined; this.type = undefined; - this.options = []; this.statement = undefined; this.schema = specification.schema.getAllElementsByName('commentquestion')[0]; this.decode = function (parent, xml) { this.id = xml.id; this.name = xml.getAttribute('name'); - this.type = xml.getAttribute('type'); + switch (xml.nodeName) { + case "commentradio": + this.type = "radio"; + this.options = []; + break; + case "commentcheckbox": + this.type = "checkbox"; + this.options = []; + break; + case "commentslider": + this.type = "slider"; + this.min = undefined; + this.max = undefined; + this.step = undefined; + break; + case "commentquestion": + default: + this.type = "question"; + break; + } this.statement = xml.getElementsByTagName('statement')[0].textContent; - var optNodes = xml.getElementsByTagName('option'); - for (var i = 0; i < optNodes.length; i++) { - var optNode = optNodes[i]; - this.options.push({ - name: optNode.getAttribute('name'), - text: optNode.textContent - }); + if (this.type == "radio" || this.type == "checkbox") { + var optNodes = xml.getElementsByTagName('option'); + for (var i = 0; i < optNodes.length; i++) { + var optNode = optNodes[i]; + this.options.push({ + name: optNode.getAttribute('name'), + text: optNode.textContent + }); + } + } + if (this.type == "slider") { + this.min = Number(xml.getAttribute("min")); + this.max = Number(xml.getAttribute("max")); + this.step = Number(xml.getAttribute("step")); + if (this.step == undefined) { + this.step = 1; + } + this.value = Number(xml.getAttribute("value")); + if (this.value == undefined) { + this.value = min; + } + this.leftText = xml.getElementsByTagName("minText"); + if (this.leftText && this.leftText.length > 0) { + this.leftText = this.leftText[0].textContent; + } else { + this.leftText = ""; + } + this.rightText = xml.getElementsByTagName("maxText"); + if (this.rightText && this.rightText.length > 0) { + this.rightText = this.rightText[0].textContent; + } else { + this.rightText = ""; + } } }; this.encode = function (root) { - var node = root.createElement("commentquestion"); + var node; + switch (this.type) { + case "radio": + node = root.createElement("commentradio"); + break; + case "checkbox": + node = root.createElement("commentcheckbox"); + break; + case "slider": + node = root.createElement("commentslider"); + break; + case "question": + default: + node = root.createElement("commentquestion"); + break; + } node.id = this.id; node.setAttribute("type", this.type); if (this.name != undefined) { @@ -645,11 +737,33 @@ var statement = root.createElement("statement"); statement.textContent = this.statement; node.appendChild(statement); - for (var option of this.options) { - var child = root.createElement("option"); - child.setAttribute("name", option.name); - child.textContent = option.text; - node.appendChild(child); + if (this.type == "radio" || this.type == "checkbox") { + for (var option of this.options) { + var child = root.createElement("option"); + child.setAttribute("name", option.name); + child.textContent = option.text; + node.appendChild(child); + } + } + if (this.type == "slider") { + node.setAttribute("min", this.min); + node.setAttribute("max", this.max); + if (this.step !== 1) { + node.setAttribute("step", this.step); + } + if (this.value !== this.min) { + node.setAttribute("value", this.value); + } + if (this.leftText.length > 0) { + var leftText = root.createElement("minText"); + leftText.textContent = this.leftText; + node.appendChild(leftText); + } + if (this.rightText.length > 0) { + var rightText = root.createElement("maxText"); + rightText.textContent = this.rightText; + node.appendChild(rightText); + } } return node; };
--- a/tests/examples/APE_example.xml Mon Nov 14 12:14:38 2016 +0000 +++ b/tests/examples/APE_example.xml Mon Nov 14 12:14:48 2016 +0000 @@ -111,24 +111,26 @@ <audioelement url="4.wav" gain="0.0" id="track-9"/> <audioelement url="5.wav" gain="0.0" id="track-10"/> <audioelement url="6.wav" gain="0.0" id="track-11" type="outside-reference"/> - <commentquestion id='mixingExperience' type="question"> - <statement>What is your general experience with numbers?</statement> - </commentquestion> - <commentquestion id="preference" type="radio"> - <statement>Please enter your overall preference</statement> - <option name="worst">Very Bad</option> - <option name="bad"></option> - <option name="OK">OK</option> - <option name="Good"></option> - <option name="Great">Great</option> - </commentquestion> - <commentquestion id="character" type="checkbox"> - <statement>Please describe the overall character</statement> - <option name="funky">Funky</option> - <option name="mellow">Mellow</option> - <option name="laidback">Laid back</option> - <option name="heavy">Heavy</option> - </commentquestion> + <commentquestions> + <commentquestion id='mixingExperience'> + <statement>What is your general experience with numbers?</statement> + </commentquestion> + <commentradio id="preference"> + <statement>Please enter your overall preference</statement> + <option name="worst">Very Bad</option> + <option name="bad"></option> + <option name="OK">OK</option> + <option name="Good"></option> + <option name="Great">Great</option> + </commentradio> + <commentcheckbox id="character" type="checkbox"> + <statement>Please describe the overall character</statement> + <option name="funky">Funky</option> + <option name="mellow">Mellow</option> + <option name="laidback">Laid back</option> + <option name="heavy">Heavy</option> + </commentcheckbox> + </commentquestions> <survey location="before"> <surveyentry type="statement" id="test-1-intro"> <statement>Example of an 'APE' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement>
--- a/tests/examples/mushra_example.xml Mon Nov 14 12:14:38 2016 +0000 +++ b/tests/examples/mushra_example.xml Mon Nov 14 12:14:48 2016 +0000 @@ -1,133 +1,135 @@ <?xml version="1.0" encoding="utf-8"?> -<waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="MUSHRA" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23"> - <exitText>Thank you for looking at WAET. You can modify the successful completion text as well!</exitText> - <survey location="before"> - <surveyentry type="question" id="sessionId" mandatory="true"> - <statement>Please enter your name.</statement> - </surveyentry> - <surveyentry type="checkbox" id="checkboxtest" mandatory="true"> - <statement>Please select with which activities you have any experience (example checkbox question)</statement> - <option name="musician">Playing a musical instrument</option> - <option name="soundengineer">Recording or mixing audio</option> - <option name="developer">Developing audio software</option> - <option name="hwdesigner">Designing or building audio hardware</option> - <option name="researcher">Research in the field of audio</option> - </surveyentry> - <surveyentry type="statement" id="test-intro"> - <statement>This is an example of an 'MUSHRA'-style test, with two pages, using the test stimuli in 'example_eval/'.</statement> - </surveyentry> - </survey> - <survey location="after"> - <surveyentry type="question" id="location" mandatory="true" boxsize="large"> - <statement>Please enter your location. (example mandatory text question)</statement> - </surveyentry> - <surveyentry type="number" id="age" min="0"> - <statement>Please enter your age (example non-mandatory number question)</statement> - </surveyentry> - <surveyentry type="radio" id="rating"> - <statement>Please rate this interface (example radio button question)</statement> - <option name="bad">Bad</option> - <option name="poor">Poor</option> - <option name="good">Good</option> - <option name="great">Great</option> - </surveyentry> - <surveyentry type="statement" id="thankyou"> - <statement>Thank you for taking this listening test. Please click 'submit' and your results will appear in the 'saves/' folder.</statement> - </surveyentry> - </survey> - <metric> - <metricenable>testTimer</metricenable> - <metricenable>elementTimer</metricenable> - <metricenable>elementInitialPosition</metricenable> - <metricenable>elementTracker</metricenable> - <metricenable>elementFlagListenedTo</metricenable> - <metricenable>elementFlagMoved</metricenable> - <metricenable>elementListenTracker</metricenable> - </metric> - <interface> - <interfaceoption type="check" name="fragmentMoved"/> - <interfaceoption type="check" name="scalerange" min="25" max="75"/> - <interfaceoption type="show" name='playhead'/> - <interfaceoption type="show" name="page-count"/> - <interfaceoption type="show" name="volume"/> - </interface> - </setup> - <page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='true' loudness="-12"> - <commentboxprefix>Comment on fragment</commentboxprefix> - <interface> - <scales> - <scalelabel position="12">Much Worse</scalelabel> - <scalelabel position="25">Worse</scalelabel> - <scalelabel position="38">Slightly Worse</scalelabel> - <scalelabel position="50">About the same</scalelabel> - <scalelabel position="62">Slightly Better</scalelabel> - <scalelabel position="75">Better</scalelabel> - <scalelabel position="88">Much Better</scalelabel> - </scales> - </interface> - <audioelement url="0.wav" id="track-0" type="anchor"/> - <audioelement url="1.wav" id="track-1"/> - <audioelement url="2.wav" id="track-2"/> - <audioelement url="3.wav" id="track-3"/> - <audioelement url="4.wav" id="track-4"/> - <survey location="before"> - <surveyentry type="statement" id="test-0-intro"> - <statement>Example of a 'MUSHRA' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75% using a Comparison Category Rating Scale.</statement> - </surveyentry> - </survey> - <survey location="after"> - <surveyentry type="question" id="genre-0" mandatory="true"> - <statement>Please enter the genre.</statement> - </surveyentry> - </survey> - </page> - <page id='test-1' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='false'> - <commentboxprefix>Comment on fragment</commentboxprefix> - <interface name="preference"> - <title>Example Test Question</title> - <interfaceoption type="show" name="comments"/> - <scales> - <scalelabel position="0">Min</scalelabel> - <scalelabel position="100">Max</scalelabel> - <scalelabel position="50">Middle</scalelabel> - <scalelabel position="20">20</scalelabel> - </scales> - </interface> - <audioelement url="0.wav" gain="-6.0" id="track-5" type="anchor" marker="20"/> - <audioelement url="1.wav" gain="0.0" id="track-6" type="reference" marker="80"/> - <audioelement url="2.wav" gain="0.0" id="track-7"/> - <audioelement url="3.wav" gain="0.0" id="track-8"/> - <audioelement url="4.wav" gain="0.0" id="track-9"/> - <audioelement url="5.wav" gain="0.0" id="track-10"/> - <audioelement url="1.wav" gain="0.0" id="track-11" type="outside-reference"/> - <commentquestion id='mixingExperience' type="question"> - <statement>What is your general experience with numbers?</statement> - </commentquestion> - <commentquestion id="preference" type="radio"> - <statement>Please enter your overall preference</statement> - <option name="worst">Very Bad</option> - <option name="bad"></option> - <option name="OK">OK</option> - <option name="Good"></option> - <option name="Great">Great</option> - </commentquestion> - <commentquestion id="character" type="checkbox"> - <statement>Please describe the overall character</statement> - <option name="funky">Funky</option> - <option name="mellow">Mellow</option> - <option name="laidback">Laid back</option> - <option name="heavy">Heavy</option> - </commentquestion> - <survey location="before"> - <surveyentry type="statement" id="test-1-intro"> - <statement>Example of a 'MUSHRA' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement> - </surveyentry> - </survey> - <survey location="after"> - <surveyentry type="question" id="genre-1" mandatory="true"> - <statement>Please enter the genre.</statement> - </surveyentry> - </survey> - </page> -</waet> \ No newline at end of file + <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> + <setup interface="MUSHRA" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23"> + <exitText>Thank you for looking at WAET. You can modify the successful completion text as well!</exitText> + <survey location="before"> + <surveyentry type="question" id="sessionId" mandatory="true"> + <statement>Please enter your name.</statement> + </surveyentry> + <surveyentry type="checkbox" id="checkboxtest" mandatory="true"> + <statement>Please select with which activities you have any experience (example checkbox question)</statement> + <option name="musician">Playing a musical instrument</option> + <option name="soundengineer">Recording or mixing audio</option> + <option name="developer">Developing audio software</option> + <option name="hwdesigner">Designing or building audio hardware</option> + <option name="researcher">Research in the field of audio</option> + </surveyentry> + <surveyentry type="statement" id="test-intro"> + <statement>This is an example of an 'MUSHRA'-style test, with two pages, using the test stimuli in 'example_eval/'.</statement> + </surveyentry> + </survey> + <survey location="after"> + <surveyentry type="question" id="location" mandatory="true" boxsize="large"> + <statement>Please enter your location. (example mandatory text question)</statement> + </surveyentry> + <surveyentry type="number" id="age" min="0"> + <statement>Please enter your age (example non-mandatory number question)</statement> + </surveyentry> + <surveyentry type="radio" id="rating"> + <statement>Please rate this interface (example radio button question)</statement> + <option name="bad">Bad</option> + <option name="poor">Poor</option> + <option name="good">Good</option> + <option name="great">Great</option> + </surveyentry> + <surveyentry type="statement" id="thankyou"> + <statement>Thank you for taking this listening test. Please click 'submit' and your results will appear in the 'saves/' folder.</statement> + </surveyentry> + </survey> + <metric> + <metricenable>testTimer</metricenable> + <metricenable>elementTimer</metricenable> + <metricenable>elementInitialPosition</metricenable> + <metricenable>elementTracker</metricenable> + <metricenable>elementFlagListenedTo</metricenable> + <metricenable>elementFlagMoved</metricenable> + <metricenable>elementListenTracker</metricenable> + </metric> + <interface> + <interfaceoption type="check" name="fragmentMoved" /> + <interfaceoption type="check" name="scalerange" min="25" max="75" /> + <interfaceoption type="show" name='playhead' /> + <interfaceoption type="show" name="page-count" /> + <interfaceoption type="show" name="volume" /> + </interface> + </setup> + <page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='true' loudness="-12"> + <commentboxprefix>Comment on fragment</commentboxprefix> + <interface> + <scales> + <scalelabel position="12">Much Worse</scalelabel> + <scalelabel position="25">Worse</scalelabel> + <scalelabel position="38">Slightly Worse</scalelabel> + <scalelabel position="50">About the same</scalelabel> + <scalelabel position="62">Slightly Better</scalelabel> + <scalelabel position="75">Better</scalelabel> + <scalelabel position="88">Much Better</scalelabel> + </scales> + </interface> + <audioelement url="0.wav" id="track-0" type="anchor" /> + <audioelement url="1.wav" id="track-1" /> + <audioelement url="2.wav" id="track-2" /> + <audioelement url="3.wav" id="track-3" /> + <audioelement url="4.wav" id="track-4" /> + <survey location="before"> + <surveyentry type="statement" id="test-0-intro"> + <statement>Example of a 'MUSHRA' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75% using a Comparison Category Rating Scale.</statement> + </surveyentry> + </survey> + <survey location="after"> + <surveyentry type="question" id="genre-0" mandatory="true"> + <statement>Please enter the genre.</statement> + </surveyentry> + </survey> + </page> + <page id='test-1' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='false'> + <commentboxprefix>Comment on fragment</commentboxprefix> + <interface name="preference"> + <title>Example Test Question</title> + <interfaceoption type="show" name="comments" /> + <scales> + <scalelabel position="0">Min</scalelabel> + <scalelabel position="100">Max</scalelabel> + <scalelabel position="50">Middle</scalelabel> + <scalelabel position="20">20</scalelabel> + </scales> + </interface> + <audioelement url="0.wav" gain="-6.0" id="track-5" type="anchor" marker="20" /> + <audioelement url="1.wav" gain="0.0" id="track-6" type="reference" marker="80" /> + <audioelement url="2.wav" gain="0.0" id="track-7" /> + <audioelement url="3.wav" gain="0.0" id="track-8" /> + <audioelement url="4.wav" gain="0.0" id="track-9" /> + <audioelement url="5.wav" gain="0.0" id="track-10" /> + <audioelement url="1.wav" gain="0.0" id="track-11" type="outside-reference" /> + <commentquestions> + <commentquestion id='mixingExperience' type="question"> + <statement>What is your general experience with numbers?</statement> + </commentquestion> + <commentquestion id="preference" type="radio"> + <statement>Please enter your overall preference</statement> + <option name="worst">Very Bad</option> + <option name="bad"></option> + <option name="OK">OK</option> + <option name="Good"></option> + <option name="Great">Great</option> + </commentquestion> + <commentquestion id="character" type="checkbox"> + <statement>Please describe the overall character</statement> + <option name="funky">Funky</option> + <option name="mellow">Mellow</option> + <option name="laidback">Laid back</option> + <option name="heavy">Heavy</option> + </commentquestion> + </commentquestions> + <survey location="before"> + <surveyentry type="statement" id="test-1-intro"> + <statement>Example of a 'MUSHRA' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement> + </surveyentry> + </survey> + <survey location="after"> + <surveyentry type="question" id="genre-1" mandatory="true"> + <statement>Please enter the genre.</statement> + </surveyentry> + </survey> + </page> + </waet>
--- a/xml/test-schema.xsd Mon Nov 14 12:14:38 2016 +0000 +++ b/xml/test-schema.xsd Mon Nov 14 12:14:48 2016 +0000 @@ -75,7 +75,7 @@ <xs:element name="commentboxprefix" type="xs:string" minOccurs="0" maxOccurs="1" /> <xs:element ref="interface" minOccurs="1" maxOccurs="unbounded" /> <xs:element ref="audioelement" minOccurs="1" maxOccurs="unbounded" /> - <xs:element ref="commentquestion" minOccurs="0" maxOccurs="unbounded" /> + <xs:element ref="commentquestions" minOccurs="0" maxOccurs="1" /> <xs:element ref="survey" minOccurs="0" maxOccurs="2" /> </xs:sequence> <xs:attribute ref="id" use="required" /> @@ -206,10 +206,21 @@ </xs:complexType> </xs:element> - <xs:element name="commentquestion"> + <xs:element name="commentquestions"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <xs:element name="commentquestion" maxOccurs="unbounded" /> + <xs:element name="commentradio" maxOccurs="unbounded" /> + <xs:element name="commentcheckbox" maxOccurs="unbounded" /> + <xs:element name="commentslider" maxOccurs="unbounded" /> + </xs:choice> + </xs:complexType> + </xs:element> + + <xs:element name="commentradio"> <xs:complexType> <xs:sequence> - <xs:element ref="statement" minOccurs="0" maxOccurs="1" /> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> <xs:element name="option" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:simpleContent> @@ -222,22 +233,202 @@ </xs:sequence> <xs:attribute ref="id" use="optional" /> <xs:attribute ref="name" use="optional" /> - <xs:attribute name="type" default="question"> + </xs:complexType> + </xs:element> + + <xs:element name="commentcheckbox"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + <xs:element name="option" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute ref="name" /> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute ref="id" use="optional" /> + <xs:attribute ref="name" use="optional" /> + </xs:complexType> + </xs:element> + + <xs:element name="commentquestion"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + </xs:sequence> + <xs:attribute ref="id" use="optional" /> + <xs:attribute ref="name" use="optional" /> + </xs:complexType> + </xs:element> + + <xs:element name="commentslider"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + <xs:element name="minText" minOccurs="0" maxOccurs="1" type="xs:string" /> + <xs:element name="maxText" minOccurs="0" maxOccurs="1" type="xs:string" /> + </xs:sequence> + <xs:attribute ref="id" use="optional" /> + <xs:attribute ref="name" use="optional" /> + <xs:attribute name="min" type="xs:decimal" use="required" /> + <xs:attribute name="max" type="xs:decimal" use="required" /> + <xs:attribute name="step" type="xs:decimal" use="optional" default="1" /> + <xs:attribute name="value" type="xs:decimal" use="optional" /> + </xs:complexType> + </xs:element> + + <xs:element name="conditional"> + <xs:complexType> + <xs:attribute name="check" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> - <xs:enumeration value="question" /> - <xs:enumeration value="radio" /> - <xs:enumeration value="checkbox" /> + <xs:enumeration value="equals" /> + <xs:enumeration value="lessThan" /> + <xs:enumeration value="greaterThan" /> + <xs:enumeration value="stringContains" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="value" type="xs:string" use="optional" /> + <xs:attribute name="jumpToOnPass" type="xs:string" use="optional" /> + <xs:attribute name="jumpToOnFail" type="xs:string" use="optional" /> + </xs:complexType> + </xs:element> + + <xs:element name="surveyquestion"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + <xs:element ref="conditional" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + <xs:attribute ref="name" /> + <xs:attribute ref="mandatory" /> + <xs:attribute name="boxsize" default="normal"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="normal" /> + <xs:enumeration value="large" /> + <xs:enumeration value="small" /> + <xs:enumeration value="huge" /> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element> + <xs:element name="surveyradio"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + <xs:element name="option" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute ref="name" /> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + <xs:element ref="conditional" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + <xs:attribute ref="name" /> + <xs:attribute ref="mandatory" /> + <xs:attribute name="min" type="xs:decimal" /> + <xs:attribute name="max" type="xs:decimal" /> + </xs:complexType> + </xs:element> + + <xs:element name="surveycheckbox"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + <xs:element name="option" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute ref="name" /> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + <xs:element ref="conditional" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + <xs:attribute ref="name" /> + <xs:attribute ref="mandatory" /> + <xs:attribute name="min" type="xs:decimal" /> + <xs:attribute name="max" type="xs:decimal" /> + </xs:complexType> + </xs:element> + + <xs:element name="surveystatement"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + </xs:complexType> + </xs:element> + + <xs:element name="surveynumber"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + <xs:element ref="conditional" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + <xs:attribute ref="name" /> + <xs:attribute ref="mandatory" /> + <xs:attribute name="min" type="xs:decimal" /> + <xs:attribute name="max" type="xs:decimal" /> + </xs:complexType> + </xs:element> + + <xs:element name="surveyslider"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + <xs:element name="minText" minOccurs="0" maxOccurs="1" type="xs:string" /> + <xs:element name="maxText" minOccurs="0" maxOccurs="1" type="xs:string" /> + <xs:element ref="conditional" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + <xs:attribute ref="name" /> + <xs:attribute name="min" use="required" type="xs:decimal" /> + <xs:attribute name="max" use="required" type="xs:decimal" /> + </xs:complexType> + </xs:element> + + <xs:element name="surveyvideo"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + <xs:attribute name="url" use="required" type="xs:string" /> + </xs:complexType> + </xs:element> + + <xs:element name="surveyyoutube"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + <xs:attribute name="url" use="required" type="xs:string" /> + </xs:complexType> + </xs:element> + <xs:element name="survey"> <xs:complexType> - <xs:sequence> - <xs:element name="surveyentry" minOccurs="0" maxOccurs="unbounded"> + <xs:choice maxOccurs="unbounded"> + <xs:element name="surveyentry" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> @@ -250,23 +441,7 @@ </xs:simpleContent> </xs:complexType> </xs:element> - <xs:element name="conditional" minOccurs="0" maxOccurs="unbounded"> - <xs:complexType> - <xs:attribute name="check" use="required"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="equals" /> - <xs:enumeration value="lessThan" /> - <xs:enumeration value="greaterThan" /> - <xs:enumeration value="stringContains" /> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="value" type="xs:string" use="optional" /> - <xs:attribute name="jumpToOnPass" type="xs:string" use="optional" /> - <xs:attribute name="jumpToOnFail" type="xs:string" use="optional" /> - </xs:complexType> - </xs:element> + <xs:element ref="conditional" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute ref="id" use="required" /> <xs:attribute ref="name" /> @@ -299,7 +474,15 @@ <xs:attribute name="url" type="xs:string" use="optional" default="" /> </xs:complexType> </xs:element> - </xs:sequence> + <xs:element name="surveyquestion" maxOccurs="unbounded" /> + <xs:element name="surveyradio" maxOccurs="unbounded" /> + <xs:element name="surveycheckbox" maxOccurs="unbounded" /> + <xs:element name="surveystatement" maxOccurs="unbounded" /> + <xs:element name="surveynumber" maxOccurs="unbounded" /> + <xs:element name="surveyslider" maxOccurs="unbounded" /> + <xs:element name="surveyvideo" maxOccurs="unbounded" /> + <xs:element name="surveyyoutube" maxOccurs="unbounded" /> + </xs:choice> <xs:attribute name="location"> <xs:simpleType> <xs:restriction base="xs:string">