# HG changeset patch # User Nicholas Jillings # Date 1458135102 0 # Node ID c99d334d85347e12b4f4cabcd5031ffd916b270f # Parent 4a221e7613840d90f256998ff65f886ab809bde9 WIP. ABX Framework. Minor core.js modifications. diff -r 4a221e761384 -r c99d334d8534 core.js --- a/core.js Tue Mar 15 15:33:29 2016 +0000 +++ b/core.js Wed Mar 16 13:31:42 2016 +0000 @@ -281,69 +281,82 @@ switch(specification.interface) { case "APE": - interfaceJS.setAttribute("src","interfaces/ape.js"); - - // APE comes with a css file - var css = document.createElement('link'); - css.rel = 'stylesheet'; - css.type = 'text/css'; - css.href = 'interfaces/ape.css'; - - document.getElementsByTagName("head")[0].appendChild(css); - break; - + interfaceJS.setAttribute("src","interfaces/ape.js"); + + // APE comes with a css file + var css = document.createElement('link'); + css.rel = 'stylesheet'; + css.type = 'text/css'; + css.href = 'interfaces/ape.css'; + + document.getElementsByTagName("head")[0].appendChild(css); + break; + case "MUSHRA": - interfaceJS.setAttribute("src","interfaces/mushra.js"); - - // MUSHRA comes with a css file - var css = document.createElement('link'); - css.rel = 'stylesheet'; - css.type = 'text/css'; - css.href = 'interfaces/mushra.css'; - - document.getElementsByTagName("head")[0].appendChild(css); - break; + interfaceJS.setAttribute("src","interfaces/mushra.js"); + + // MUSHRA comes with a css file + var css = document.createElement('link'); + css.rel = 'stylesheet'; + css.type = 'text/css'; + css.href = 'interfaces/mushra.css'; + + document.getElementsByTagName("head")[0].appendChild(css); + break; case "AB": - interfaceJS.setAttribute("src","interfaces/AB.js"); - - // AB comes with a css file - var css = document.createElement('link'); - css.rel = 'stylesheet'; - css.type = 'text/css'; - css.href = 'interfaces/AB.css'; - - document.getElementsByTagName("head")[0].appendChild(css); - break; + interfaceJS.setAttribute("src","interfaces/AB.js"); + + // AB comes with a css file + var css = document.createElement('link'); + css.rel = 'stylesheet'; + css.type = 'text/css'; + css.href = 'interfaces/AB.css'; + + document.getElementsByTagName("head")[0].appendChild(css); + break; + + case "ABX": + interfaceJS.setAttribute("src","interfaces/ABX.js"); + + // AB comes with a css file + var css = document.createElement('link'); + css.rel = 'stylesheet'; + css.type = 'text/css'; + css.href = 'interfaces/ABX.css'; + + document.getElementsByTagName("head")[0].appendChild(css); + break; + case "Bipolar": case "ACR": case "DCR": case "CCR": case "ABC": - // Above enumerate to horizontal sliders - interfaceJS.setAttribute("src","interfaces/horizontal-sliders.js"); - - // horizontal-sliders comes with a css file - var css = document.createElement('link'); - css.rel = 'stylesheet'; - css.type = 'text/css'; - css.href = 'interfaces/horizontal-sliders.css'; - - document.getElementsByTagName("head")[0].appendChild(css); - break; + // Above enumerate to horizontal sliders + interfaceJS.setAttribute("src","interfaces/horizontal-sliders.js"); + + // horizontal-sliders comes with a css file + var css = document.createElement('link'); + css.rel = 'stylesheet'; + css.type = 'text/css'; + css.href = 'interfaces/horizontal-sliders.css'; + + document.getElementsByTagName("head")[0].appendChild(css); + break; case "discrete": case "likert": - // Above enumerate to horizontal discrete radios - interfaceJS.setAttribute("src","interfaces/discrete.js"); - - // horizontal-sliders comes with a css file - var css = document.createElement('link'); - css.rel = 'stylesheet'; - css.type = 'text/css'; - css.href = 'interfaces/discrete.css'; - - document.getElementsByTagName("head")[0].appendChild(css); - break; + // Above enumerate to horizontal discrete radios + interfaceJS.setAttribute("src","interfaces/discrete.js"); + + // horizontal-sliders comes with a css file + var css = document.createElement('link'); + css.rel = 'stylesheet'; + css.type = 'text/css'; + css.href = 'interfaces/discrete.css'; + + document.getElementsByTagName("head")[0].appendChild(css); + break; } document.getElementsByTagName("head")[0].appendChild(interfaceJS); diff -r 4a221e761384 -r c99d334d8534 example_eval/ABX_example.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/example_eval/ABX_example.xml Wed Mar 16 13:31:42 2016 +0000 @@ -0,0 +1,87 @@ + + + + + + Please enter your name. + + + Please select with which activities you have any experience (example checkbox question) + + + + + + + + This is an example of an 'AB'-style test, with two pages, using the test stimuli in 'example_eval/'. + + + + + Please enter your location. (example mandatory text question) + + + Please enter your age (example non-mandatory number question) + + + Please rate this interface (example radio button question) + + + + + + + Thank you for taking this listening test. Please click 'submit' and your results will appear in the 'saves/' folder. + + + + testTimer + elementTimer + elementInitialPosition + elementTracker + elementFlagListenedTo + elementFlagMoved + elementListenTracker + + + + + + + + + + + Comment on fragment + + Depth + + + + + + A two way comparison using randomised element order, automatic loudness and synchronised looping. + + + + + Please enter the genre. + + + + + Comment on fragment + + Depth + + + + + + + Please enter the genre. + + + + \ No newline at end of file diff -r 4a221e761384 -r c99d334d8534 interfaces/ABX.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interfaces/ABX.css Wed Mar 16 13:31:42 2016 +0000 @@ -0,0 +1,90 @@ +body { + /* Set the background colour (note US English spelling) to grey*/ + background-color: #fff +} + +div.pageTitle { + width: auto; + height: 20px; + margin-top: 20px; +} + +div.pageTitle span{ + font-size: 1.5em; +} + +div.testHalt { + /* Specify any colouring during the test halt for pre/post questions */ + background-color: rgba(0,0,0,0.5); + /* Don't mess with this bit */ + z-index: 2; + width: 100%; + height: 100%; + position: absolute; + left: 0px; + top: 0px; +} + +button { + /* Specify any button structure or style */ + min-width: 20px; + background-color: #ddd +} + +button.big-button { + width: 250px; + height: 40px; + font-size: 1.2em; +} + +div.comparator-holder { + width: 260px; + height: 300px; + border: black 1px solid; + float: left; + padding-top: 5px; + margin: 25px; +} + +div.comparator-selector { + width: 248px; + height: 250px; + border: black 1px solid; + position: relative; + background-color: #FF0000; + border-radius: 20px; +} + +div.disabled { + background-color: #AAA; +} + +div.selected { + background-color: #008000; +} + +div.comparator-selector span { + font-size: 4em; +} + +button.comparator-button { + width: 250px; + height: 38px; + position: relative; + margin-top: 5px; +} + +div.playhead { + margin: 5px; +} + +div#page-count { + float: left; + margin: 0px 5px; +} + +div#master-volume-holder { + position: absolute; + top: 10px; + left: 120px; +} \ No newline at end of file diff -r 4a221e761384 -r c99d334d8534 interfaces/ABX.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interfaces/ABX.js Wed Mar 16 13:31:42 2016 +0000 @@ -0,0 +1,345 @@ +/** + * WAET Blank Template + * Use this to start building your custom interface + */ + +// Once this is loaded and parsed, begin execution +loadInterface(); + +function loadInterface() { + // Use this to do any one-time page / element construction. For instance, placing any stationary text objects, + // holding div's, or setting up any nodes which are present for the entire test sequence + + // Custom comparator Object + Interface.prototype.comparator = null; + + // The injection point into the HTML page + interfaceContext.insertPoint = document.getElementById("topLevelBody"); + var testContent = document.createElement('div'); + testContent.id = 'testContent'; + + // Create the top div for the Title element + var titleAttr = specification.title; + var title = document.createElement('div'); + title.className = "title"; + title.align = "center"; + var titleSpan = document.createElement('span'); + + // Set title to that defined in XML, else set to default + if (titleAttr != undefined) { + titleSpan.textContent = titleAttr; + } else { + titleSpan.textContent = 'Listening test'; + } + // Insert the titleSpan element into the title div element. + title.appendChild(titleSpan); + + var pagetitle = document.createElement('div'); + pagetitle.className = "pageTitle"; + pagetitle.align = "center"; + var titleSpan = document.createElement('span'); + titleSpan.id = "pageTitle"; + pagetitle.appendChild(titleSpan); + + // Create Interface buttons! + var interfaceButtons = document.createElement('div'); + interfaceButtons.id = 'interface-buttons'; + interfaceButtons.style.height = '25px'; + + // Create playback start/stop points + var playback = document.createElement("button"); + playback.innerHTML = 'Stop'; + playback.id = 'playback-button'; + playback.style.float = 'left'; + // onclick function. Check if it is playing or not, call the correct function in the + // audioEngine, change the button text to reflect the next state. + playback.onclick = function() { + if (audioEngineContext.status == 1) { + audioEngineContext.stop(); + this.innerHTML = 'Stop'; + var time = audioEngineContext.timer.getTestTime(); + console.log('Stopped at ' + time); // DEBUG/SAFETY + } + }; + // Append the interface buttons into the interfaceButtons object. + interfaceButtons.appendChild(playback); + + // Global parent for the comment boxes on the page + var feedbackHolder = document.createElement('div'); + feedbackHolder.id = 'feedbackHolder'; + + // Construct the AB Boxes + var boxes = document.createElement('div'); + boxes.align = "center"; + boxes.id = "box-holders"; + boxes.style.float = "left"; + + var submit = document.createElement('button'); + submit.id = "submit"; + submit.onclick = buttonSubmitClick; + submit.className = "big-button"; + submit.textContent = "submit"; + submit.style.position = "relative"; + submit.style.left = (window.innerWidth-250)/2 + 'px'; + + feedbackHolder.appendChild(boxes); + + // Inject into HTML + testContent.appendChild(title); // Insert the title + testContent.appendChild(pagetitle); + testContent.appendChild(interfaceButtons); + testContent.appendChild(feedbackHolder); + testContent.appendChild(submit); + interfaceContext.insertPoint.appendChild(testContent); + + // Load the full interface + testState.initialise(); + testState.advanceState(); +}; + +function loadTest(page) +{ + // Called each time a new test page is to be build. The page specification node is the only item passed in + interfaceContext.comparator = new comparator(page); +} + +function comparator(page) +{ + // Build prototype constructor + this.interfaceObject = function(element,label) + { + // An example node, you can make this however you want for each audioElement. + // However, every audioObject (audioEngineContext.audioObject) MUST have an interface object with the following + // You attach them by calling audioObject.bindInterface( ) + this.parent = element; + this.id = element.id; + this.value = 0; + this.disabled = true; + this.box = document.createElement('div'); + this.box.className = 'comparator-holder'; + this.box.setAttribute('track-id',element.id); + this.box.id = 'comparator-'+label; + this.selector = document.createElement('div'); + this.selector.className = 'comparator-selector disabled'; + var selectorText = document.createElement('span'); + selectorText.textContent = label; + this.selector.appendChild(selectorText); + this.playback = document.createElement('button'); + this.playback.className = 'comparator-button'; + this.playback.disabled = true; + this.playback.textContent = "Listen"; + this.box.appendChild(this.selector); + this.box.appendChild(this.playback); + this.selector.onclick = function(event) + { + var label = event.currentTarget.children[0].textContent; + if (label == "X" || label == "x") {return;} + var time = audioEngineContext.timer.getTestTime(); + if ($(event.currentTarget).hasClass('disabled')) + { + console.log("Please wait until sample has loaded"); + return; + } + if (audioEngineContext.status == 0) + { + alert("Please listen to the samples before making a selection"); + console.log("Please listen to the samples before making a selection"); + return; + } + var id = event.currentTarget.parentElement.getAttribute('track-id'); + interfaceContext.comparator.selected = id; + if ($(event.currentTarget).hasClass("selected")) { + $(".comparator-selector").removeClass('selected'); + for (var i=0; i node. + // If there is no value node (such as outside reference), return null + // If there are multiple value nodes (such as multiple scale / 2D scales), return an array of nodes with each value node having an 'interfaceName' attribute + // Use storage.document.createElement('value'); to generate the XML node. + var node = storage.document.createElement('value'); + node.textContent = this.value; + return node; + + }; + this.error = function() { + // If there is an error with the audioObject, this will be called to indicate a failure + } + }; + // Ensure there are only two comparisons per page + if (page.audioElements.length != 2) { + console.error('FATAL - There must be 2 nodes on each : '+page.id); + return; + } + // Build the three audio elements + this.pair = []; + this.X = null; + this.boxHolders = document.getElementById('box-holders'); + for (var index=0; index saves + // Get the current information in store (remember to appendChild your data to it) + // pageSpecification is the current page node configuration + // To create new XML nodes, use storage.document.createElement(); +} \ No newline at end of file