Mercurial > hg > webaudioevaluationtool
changeset 2916:300bb2bbba4a
Merge branch 'master' of https://github.com/BrechtDeMan/WebAudioEvaluationTool
author | www-data <www-data@sucuk.dcs.qmul.ac.uk> |
---|---|
date | Tue, 01 Aug 2017 15:23:47 +0100 |
parents | 0e4b84497040 (current diff) 03a66e54cdff (diff) |
children | db5e601861e6 |
files | |
diffstat | 9 files changed, 314 insertions(+), 214 deletions(-) [+] |
line wrap: on
line diff
--- a/interfaces/mushra.js Thu Jul 27 21:00:36 2017 +0100 +++ b/interfaces/mushra.js Tue Aug 01 15:23:47 2017 +0100 @@ -179,7 +179,7 @@ audioObject.bindInterface(orNode); } else { // Create a slider per track - var label = interfaceContext.getLabel(labelType, index, audioHolderObject.labelStart); + var label = element.label || interfaceContext.getLabel(labelType, index, audioHolderObject.labelStart); var sliderObj = new sliderObject(audioObject, label); if (typeof audioHolderObject.initialPosition === "number") {
--- a/js/core.js Thu Jul 27 21:00:36 2017 +0100 +++ b/js/core.js Tue Aug 01 15:23:47 2017 +0100 @@ -555,7 +555,7 @@ this.store = null; var lastNodeStart; $(window).keypress(function (e) { - if (e.keyCode == 13 && popup.popup.style.visibility == 'visible') { + if (e.keyCode == 13 && popup.popup.style.visibility == 'visible' && interfaceContext.lightbox.isVisible() === false) { console.log(e); popup.buttonProceed.onclick(); e.preventDefault(); @@ -1216,6 +1216,39 @@ this.currentStore = null; this.initialise = function () { + function randomiseElements(page) { + // Get the elements which are fixed / labelled + var fixed = [], + or = [], + remainder = []; + page.audioElements.forEach(function (a) { + if (a.label.length > 0 || a.postion !== undefined) { + fixed.push(a); + } else if (a.type === "outside-reference") { + or.push(a); + } else { + remainder.push(a); + } + }) + if (page.poolSize > 0 || page.randomiseOrder) { + page.randomiseOrder = true; + if (page.poolSize === 0) { + page.poolSize = page.audioElements.length; + } + page.poolSize -= fixed.length; + remainder = pickSubPool(remainder, page.poolSize); + } + // Randomise the remainders + if (page.randomiseOrder) { + remainder = randomiseOrder(remainder); + } + fixed = fixed.concat(remainder); + page.audioElements = fixed.concat(or); + page.audioElements.forEach(function (a, i) { + a.position = i; + }); + } + // Get the data from Specification var pagePool = []; specification.pages.forEach(function (page) { @@ -1253,17 +1286,7 @@ page.presentedId = i; this.stateMap.push(page); var elements = page.audioElements; - if (page.poolSize > 0 || page.randomiseOrder) { - page.randomiseOrder = true; - if (page.poolSize === 0) { - page.poolSize = elements.length; - } - elements = pickSubPool(elements, page.poolSize); - } - if (page.randomiseOrder) { - elements = randomiseOrder(elements); - } - page.audioElements = elements; + randomiseElements(page); storage.createTestPageStore(page); audioEngineContext.loadPageData(page); }, this); @@ -1325,23 +1348,6 @@ popup.hidePopup(); if (this.currentStateMap === null) { this.currentStateMap = this.stateMap[this.stateIndex]; - // Find and extract the outside reference - var elements = [], - ref = []; - var elem = this.currentStateMap.audioElements.pop(); - while (elem) { - if (elem.type == "outside-reference") { - ref.push(elem); - } else { - elements.push(elem); - } - elem = this.currentStateMap.audioElements.pop(); - } - elements = elements.reverse(); - if (this.currentStateMap.randomiseOrder) { - elements = randomiseOrder(elements); - } - this.currentStateMap.audioElements = elements.concat(ref); this.currentStore = storage.testPages[this.stateIndex]; if (this.currentStateMap.preTest !== undefined) { @@ -2401,6 +2407,7 @@ show: function () { this.root.style.visibility = "visible"; this.blanker.style.visibility = "visible"; + this.accept.focus(); }, clear: function () { this.root.style.visibility = ""; @@ -2414,6 +2421,9 @@ }, resize: function (event) { this.root.style.left = (window.innerWidth / 2) - 250 + 'px'; + }, + isVisible: function () { + return this.root.style.visibility == "visible"; } };
--- a/test_create.html Thu Jul 27 21:00:36 2017 +0100 +++ b/test_create.html Tue Aug 01 15:23:47 2017 +0100 @@ -12,13 +12,14 @@ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> <script type="text/javascript" src="js/xmllint.js"></script> - <title>WAET 1.2.1 Test Creator</title> + <title>WAET 1.2.2 Test Creator</title> </head> <body ng-app="creator" ng-controller="view"> <div class="container"> <div id="pageRoot"> - <h1>Web Audio Evaluation Tool - Test Creator</h1> + <h1>Web Audio Evaluation Tool</h1> + <h3>Test Creator <span class="label label-primary">v1.2.2</span></h3> </div> <button type="button" class="btn btn-info" ng-click="validate()">Validate</button> <button type="button" class="btn btn-success" ng-click="exportXML()" ng-disabled="validated == false">Export XML</button> @@ -45,7 +46,9 @@ <div class="attributes"> <div class="attribute"> <span>Interface: </span> - <input type="text" ng-model="specification.interface" required/> + <select type="text" ng-model="specification.interface" required> + <option value="{{i.name}}" ng-repeat="i in availableInterfaceModules">{{i.name}}</option> + </select> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="If you would like to save to a server other than your hosting server, you can place the full WAET URL here"> <span>Save URL: </span> @@ -53,7 +56,7 @@ </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Once the test is completed and save confirmed, the browser will redirect to this page, if not defined."> <span>Exit URL: </span> - <input type="text" ng-model="specification.returnURL" /> + <input type="text" ng-model="specification.returnURL" placeholder="{{placeholder('returnURL')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Randomise the page order"> <span>Randomise Page Order: </span> @@ -61,15 +64,15 @@ </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Set the number of pages to present to the user. This includes repeated pages. Set to '0' or blank to ignore. Randomise page order must be selected."> <span>Page Pool Size: </span> - <input type="number" ng-model="specification.poolSize" min="0" /> + <input type="number" ng-model="specification.poolSize" min="0" placeholder="{{placeholder('poolSize')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Automatically analyse and normalsie audio to this target LUFS. If unsure, use -25LUFS. 0 or blank disables normalisation"> <span>Loudness Normalisation (LUFS): </span> - <input type="number" ng-model="specification.loudness" max="0" /> + <input type="number" ng-model="specification.loudness" max="0" placeholder="{{placeholder('loudness')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Only perform the test if the browser reported sampling rate matches this."> <span>Fixed Sampling Rate: </span> - <input type="number" ng-model="specification.sampleRate" min="0" /> + <input type="number" ng-model="specification.sampleRate" min="0" placeholder="{{placeholder('sampleRate')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Show a 'method of adjustment' audio calibration before testing."> <span>Pre-Test audio calibration: </span> @@ -77,15 +80,15 @@ </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Default cross-fade time when switching between elements. Can be over-ridden on each page"> <span>Global Cross-fade time: </span> - <input type="number" ng-model="specification.crossFade" min="0" step="0.1" /> + <input type="number" ng-model="specification.crossFade" min="0" step="0.1" placeholder="{{placeholder('crossFade')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Default pre-play element silence. Can be over-ridden on each page and element"> <span>Global Fragment Pre-Silence: </span> - <input type="number" ng-model="specification.preSilence" min="0" step="0.1" /> + <input type="number" ng-model="specification.preSilence" min="0" step="0.1" placeholder="{{placeholder('preSilence')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Default post-play element silence. Can be over-ridden on each page and element"> <span>Global Fragment Post-Silence: </span> - <input type="number" ng-model="specification.preSilence" min="0" step="0.1" /> + <input type="number" ng-model="specification.postSilence" min="0" step="0.1" placeholder="{{placeholder('postSilence')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Disable switching of audio elements"> <span>Play audio one-at-a-time: </span> @@ -93,11 +96,11 @@ </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Minimum number of times an audio fragment must be played"> <span>Minimum number of fragment plays</span> - <input type="number" ng-model="specification.minNumberPlays" min="0" max="{{specification.maxNumberPlays}}" /> + <input type="number" ng-model="specification.minNumberPlays" min="0" max="{{specification.maxNumberPlays}}" placeholder="{{placeholder('minNumberPlays')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Maximum number of times an audio fragment can be played"> <span>Maximum number of fragment plays</span> - <input type="number" ng-model="specification.maxNumberPlays" min="{{specification.minNumberPlays || 0}}" /> + <input type="number" ng-model="specification.maxNumberPlays" min="{{specification.minNumberPlays || 0}}" placeholder="{{placeholder('maxNumberPlays')}}" /> </div> </div> <div class="node"> @@ -140,11 +143,11 @@ <div id="globalpresurvey" class="node" ng-controller="survey" ng-init="survey = specification.preTest"> <h2>Pre Test Survey</h2> <button type="button" class="btn btn-success" ng-click="addSurveyEntry()">Add Entry</button> - <div class="node" ng-repeat="opt in survey.options" ng-controller="surveyOption"> + <div class="node surveyentry" ng-repeat="opt in survey.options" ng-controller="surveyOption"> <h3>Survey Entry</h3> <button type="button" class="btn btn-danger" ng-click="removeSurveyEntry(opt);">Delete Entry</button> <div class="attributes"> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Type of survey entry."> <span>Survey Type: </span> <select ng-model="opt.type"> <option value="question">Question</option> @@ -157,23 +160,23 @@ <option value="youtube">YouTube</option> </select> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Unique across the entire session of all ID entries. "> <span>Unique Survey Entry ID:</span> <input type="text" ng-model="opt.id" required/> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Friendly name. Will be used in test results parsers instead of the ID, if defined."> <span>Entry Name:</span> <input type="text" ng-model="opt.name" /> </div> - <div class="attribute" ng-show="['question', 'checkbox', 'radio', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['question', 'checkbox', 'radio', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="An answer must be given to continue with the test."> <span>Mandatory:</span> <input type="checkbox" ng-model="opt.mandatory" /> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Minimum time in seconds before continuing."> <span>Minimum Wait Time (s):</span> <input type="number" ng-model="opt.minWait" min="0" /> </div> - <div class="attribute" ng-show="opt.type == 'question'"> + <div class="attribute" ng-show="opt.type == 'question'" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Size of the displayed text box. Does not limit entry but may discourage (or encourage) longer ansewrs if bigger."> <span>Box Size:</span> <select ng-model="opt.boxsize"> <option value="small">Small</option> @@ -182,28 +185,28 @@ <option value="huge">Huge</option> </select> </div> - <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="The minimum number of options that must be selected before continuing"> <span>Minimum Selected:</span> <input type="number" ng-model="opt.min" min="0" /> </div> - <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Maximum number of options that can be selected to continue."> <span>Maximum Selected:</span> <input type="number" ng-model="opt.max" max="{{opt.options.length}}" /> </div> - <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Minimum numerical value"> <span>Minimum Value:</span> <input type="number" ng-model="opt.min" /> </div> - <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Maximum numerical value"> <span>Maximum Value:</span> <input type="number" ng-model="opt.max" /> </div> - <div class="attribute" ng-show="['video', 'youtube'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['video', 'youtube'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="URL of the video to embed."> <span>Video URL:</span> <input type="text" ng-model="opt.url" /> </div> </div> - <div class="node"> + <div class="node" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Statement / Question to pose to the subject."> <h4>Statement</h4> <textarea ng-model="opt.statement"></textarea> </div> @@ -271,11 +274,11 @@ <div id="globalpostsurvey" class="node" ng-controller="survey" ng-init="survey = specification.postTest"> <h2>Post Test Survey</h2> <button type="button" class="btn btn-success" ng-click="addSurveyEntry()">Add Entry</button> - <div class="node" ng-repeat="opt in survey.options" ng-controller="surveyOption"> + <div class="node surveyentry" ng-repeat="opt in survey.options" ng-controller="surveyOption"> <h3>Survey Entry</h3> <button type="button" class="btn btn-danger" ng-click="removeSurveyEntry(opt);">Delete Entry</button> <div class="attributes"> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Type of survey entry."> <span>Survey Type: </span> <select ng-model="opt.type"> <option value="question">Question</option> @@ -288,23 +291,23 @@ <option value="youtube">YouTube</option> </select> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Unique across the entire session of all ID entries. "> <span>Unique Survey Entry ID:</span> <input type="text" ng-model="opt.id" required/> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Friendly name. Will be used in test results parsers instead of the ID, if defined."> <span>Entry Name:</span> <input type="text" ng-model="opt.name" /> </div> - <div class="attribute" ng-show="['question', 'checkbox', 'radio', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['question', 'checkbox', 'radio', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="An answer must be given to continue with the test."> <span>Mandatory:</span> <input type="checkbox" ng-model="opt.mandatory" /> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Minimum time in seconds before continuing."> <span>Minimum Wait Time (s):</span> <input type="number" ng-model="opt.minWait" min="0" /> </div> - <div class="attribute" ng-show="opt.type == 'question'"> + <div class="attribute" ng-show="opt.type == 'question'" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Size of the displayed text box. Does not limit entry but may discourage (or encourage) longer ansewrs if bigger."> <span>Box Size:</span> <select ng-model="opt.boxsize"> <option value="small">Small</option> @@ -313,28 +316,28 @@ <option value="huge">Huge</option> </select> </div> - <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="The minimum number of options that must be selected before continuing"> <span>Minimum Selected:</span> <input type="number" ng-model="opt.min" min="0" /> </div> - <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Maximum number of options that can be selected to continue."> <span>Maximum Selected:</span> <input type="number" ng-model="opt.max" max="{{opt.options.length}}" /> </div> - <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Minimum numerical value"> <span>Minimum Value:</span> <input type="number" ng-model="opt.min" /> </div> - <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Maximum numerical value"> <span>Maximum Value:</span> <input type="number" ng-model="opt.max" /> </div> - <div class="attribute" ng-show="['video', 'youtube'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['video', 'youtube'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="URL of the video to embed."> <span>Video URL:</span> <input type="text" ng-model="opt.url" /> </div> </div> - <div class="node"> + <div class="node" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Statement / Question to pose to the subject."> <h4>Statement</h4> <textarea ng-model="opt.statement"></textarea> </div> @@ -403,23 +406,23 @@ <h2>Interface (Globals)</h2> <div class="node interfaceOptions"> <div class="attributes"> - <div class="attribute" name="fragmentPlayed" type="check"> + <div class="attribute" name="fragmentPlayed" type="check" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="A page can only be submitted if all fragments have been played"> <span>Check all fragments played: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> </div> - <div class="attribute" name="fragmentFullPlayback" type="check"> + <div class="attribute" name="fragmentFullPlayback" type="check" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="A page can only be submitted if all fragments have been played completely."> <span>Check all fragments fully played: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> </div> - <div class="attribute" name="fragmentMoved" type="check"> + <div class="attribute" name="fragmentMoved" type="check" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="A page can only be submitted if all fragments have been moved"> <span>Check all fragments have been moved: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> </div> - <div class="attribute" name="fragmentComments" type="check"> + <div class="attribute" name="fragmentComments" type="check" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="A page can only be submitted if all fragments have their comment boxes completed."> <span>Check all fragments have comments: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> </div> - <div class="attribute" name="scalerange" type="check"> + <div class="attribute" name="scalerange" type="check" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="A page can only be submitted if there are fragments above and below the maximum and minimum ranges."> <span>Enforce a scale usage: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> <span>Minimum:</span> @@ -427,19 +430,19 @@ <span>Maximum:</span> <input type="number" min="0" max="100" name="max" /> </div> - <div class="attribute" name="volume" type="show"> + <div class="attribute" name="volume" type="show" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Show the master volume control on each page."> <span>Show master volume control: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> </div> - <div class="attribute" name="playhead" type="show"> + <div class="attribute" name="playhead" type="show" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Show the playhead for the fragments."> <span>Show playhead: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> </div> - <div class="attribute" name="page-count" type="show"> + <div class="attribute" name="page-count" type="show" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Show number of completed and remaining pages."> <span>Show Page Count: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> </div> - <div class="attribute" name="comments" type="show"> + <div class="attribute" name="comments" type="show" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Show comment boxes for each fragment."> <span>Show Fragment Comments: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> </div> @@ -467,8 +470,8 @@ <input type="checkbox" ng-model="page.randomiseOrder" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Specify if this page should be repeated and how many times. Please note, that if page-pooling is also selected then it 'may' not repeat as many times."> - <span>Repeat Page N-times: </span> - <input type="number" ng-model="page.repeatCount" value="0" step="1" /> + <span>Numer of repetitions: </span> + <input type="number" ng-model="page.repeatCount" value="0" step="1" placeholder="{{placeholder('repeatCount')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Loop audio playback until manually stopped or the page submit button is pressed"> <span>Loop audio: </span> @@ -480,7 +483,7 @@ </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Over-ride global loudness normalisation"> <span>Loudness (page): </span> - <input type="number" ng-model="page.loudness" max="0" /> + <input type="number" ng-model="page.loudness" max="0" placeholder="{{specification.loudness || placeholder('loudness')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Label type to display on the fragments."> <span>Label type: </span> @@ -499,7 +502,7 @@ </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Select a subgroup of the given audio fragments to display. 0 or blank means all fragments will be displayed."> <span>Fragment pool size: </span> - <input type="number" ng-model="page.poolSize" min="0" max="page.audioElements.length" /> + <input type="number" ng-model="page.poolSize" min="0" max="page.audioElements.length" placeholder="{{placeholder('poolSize')}}" /> </div> <div class="attribute" ng-show="specification.poolSize > 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Always display this page, even after sub-pooling of pages"> <span>Always include page: </span> @@ -511,11 +514,11 @@ </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Over-ride global pre-silence"> <span>Fragment pre-silence: </span> - <input type="number" ng-model="page.preSilence" min="0" step="0.1" /> + <input type="number" ng-model="page.preSilence" min="0" step="0.1" placeholder="{{specification.preSilence || placeholder('preSilence')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Over-ride global post-silence"> <span>Fragment post-silence: </span> - <input type="number" ng-model="page.postSilence" min="0" step="0.1" /> + <input type="number" ng-model="page.postSilence" min="0" step="0.1" placeholder="{{specification.postSilence || placeholder('postSilence')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Disable switching of audio"> <span>Cannot interupt audio: </span> @@ -527,11 +530,11 @@ </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Over-ride global minimum number of fragment plays"> <span>Minimum number of fragment plays</span> - <input type="number" ng-model="page.minNumberPlays" min="0" max="{{page.maxNumberPlays || specification.maxNumberPlays}}" /> + <input type="number" ng-model="page.minNumberPlays" min="0" max="{{page.maxNumberPlays || specification.maxNumberPlays}}" placeholder="{{specification.minNumberPlays || placeholder('minNumberPlays')}}" /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Over-ride global maximum number of fragment plays"> <span>Maximum number of fragment plays</span> - <input type="number" ng-model="page.maxNumberPlays" min="{{page.minNumberPlays || specification.minNumberPlays || 0}}" /> + <input type="number" ng-model="page.maxNumberPlays" min="{{page.minNumberPlays || specification.minNumberPlays || 0}}" placeholder="{{specification.maxNumberPlays || placeholder('maxNumberPlays')}}" /> </div> </div> <div class="node" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Set the title of the page"> @@ -548,11 +551,11 @@ <div class="node" ng-controller="survey" ng-init="survey = page.preTest"> <h2>Pre Page Survey</h2> <button type="button" class="btn btn-success" ng-click="addSurveyEntry()">Add Entry</button> - <div class="node" ng-repeat="opt in survey.options" ng-controller="surveyOption"> + <div class="node surveyentry" ng-repeat="opt in survey.options" ng-controller="surveyOption"> <h3>Survey Entry</h3> <button type="button" class="btn btn-danger" ng-click="removeSurveyEntry(opt);">Delete Entry</button> <div class="attributes"> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Type of survey entry."> <span>Survey Type: </span> <select ng-model="opt.type"> <option value="question">Question</option> @@ -565,23 +568,23 @@ <option value="youtube">YouTube</option> </select> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Unique across the entire session of all ID entries. "> <span>Unique Survey Entry ID:</span> <input type="text" ng-model="opt.id" required/> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Friendly name. Will be used in test results parsers instead of the ID, if defined."> <span>Entry Name:</span> <input type="text" ng-model="opt.name" /> </div> - <div class="attribute" ng-show="['question', 'checkbox', 'radio', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['question', 'checkbox', 'radio', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="An answer must be given to continue with the test."> <span>Mandatory:</span> <input type="checkbox" ng-model="opt.mandatory" /> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Minimum time in seconds before continuing."> <span>Minimum Wait Time (s):</span> <input type="number" ng-model="opt.minWait" min="0" /> </div> - <div class="attribute" ng-show="opt.type == 'question'"> + <div class="attribute" ng-show="opt.type == 'question'" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Size of the displayed text box. Does not limit entry but may discourage (or encourage) longer ansewrs if bigger."> <span>Box Size:</span> <select ng-model="opt.boxsize"> <option value="small">Small</option> @@ -590,28 +593,28 @@ <option value="huge">Huge</option> </select> </div> - <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="The minimum number of options that must be selected before continuing"> <span>Minimum Selected:</span> <input type="number" ng-model="opt.min" min="0" /> </div> - <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Maximum number of options that can be selected to continue."> <span>Maximum Selected:</span> <input type="number" ng-model="opt.max" max="{{opt.options.length}}" /> </div> - <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Minimum numerical value"> <span>Minimum Value:</span> <input type="number" ng-model="opt.min" /> </div> - <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Maximum numerical value"> <span>Maximum Value:</span> <input type="number" ng-model="opt.max" /> </div> - <div class="attribute" ng-show="['video', 'youtube'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['video', 'youtube'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="URL of the video to embed."> <span>Video URL:</span> <input type="text" ng-model="opt.url" /> </div> </div> - <div class="node"> + <div class="node" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Statement / Question to pose to the subject."> <h4>Statement</h4> <textarea ng-model="opt.statement"></textarea> </div> @@ -679,11 +682,11 @@ <div class="node" ng-controller="survey" ng-init="survey = page.postTest"> <h2>Post Page Survey</h2> <button type="button" class="btn btn-success" ng-click="addSurveyEntry()">Add Entry</button> - <div class="node" ng-repeat="opt in survey.options" ng-controller="surveyOption"> + <div class="node surveyentry" ng-repeat="opt in survey.options" ng-controller="surveyOption"> <h3>Survey Entry</h3> <button type="button" class="btn btn-danger" ng-click="removeSurveyEntry(opt);">Delete Entry</button> <div class="attributes"> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Type of survey entry."> <span>Survey Type: </span> <select ng-model="opt.type"> <option value="question">Question</option> @@ -696,23 +699,23 @@ <option value="youtube">YouTube</option> </select> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Unique across the entire session of all ID entries. "> <span>Unique Survey Entry ID:</span> - <input type="text" ng-model="opt.id" required /> + <input type="text" ng-model="opt.id" required/> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Friendly name. Will be used in test results parsers instead of the ID, if defined."> <span>Entry Name:</span> <input type="text" ng-model="opt.name" /> </div> - <div class="attribute" ng-show="['question', 'checkbox', 'radio', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['question', 'checkbox', 'radio', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="An answer must be given to continue with the test."> <span>Mandatory:</span> <input type="checkbox" ng-model="opt.mandatory" /> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Minimum time in seconds before continuing."> <span>Minimum Wait Time (s):</span> <input type="number" ng-model="opt.minWait" min="0" /> </div> - <div class="attribute" ng-show="opt.type == 'question'"> + <div class="attribute" ng-show="opt.type == 'question'" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Size of the displayed text box. Does not limit entry but may discourage (or encourage) longer ansewrs if bigger."> <span>Box Size:</span> <select ng-model="opt.boxsize"> <option value="small">Small</option> @@ -721,28 +724,28 @@ <option value="huge">Huge</option> </select> </div> - <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="The minimum number of options that must be selected before continuing"> <span>Minimum Selected:</span> <input type="number" ng-model="opt.min" min="0" /> </div> - <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['checkbox', 'radio'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Maximum number of options that can be selected to continue."> <span>Maximum Selected:</span> <input type="number" ng-model="opt.max" max="{{opt.options.length}}" /> </div> - <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Minimum numerical value"> <span>Minimum Value:</span> <input type="number" ng-model="opt.min" /> </div> - <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['slider', 'number'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Maximum numerical value"> <span>Maximum Value:</span> <input type="number" ng-model="opt.max" /> </div> - <div class="attribute" ng-show="['video', 'youtube'].indexOf(opt.type) >= 0"> + <div class="attribute" ng-show="['video', 'youtube'].indexOf(opt.type) >= 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="URL of the video to embed."> <span>Video URL:</span> <input type="text" ng-model="opt.url" /> </div> </div> - <div class="node"> + <div class="node" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Statement / Question to pose to the subject."> <h4>Statement</h4> <textarea ng-model="opt.statement"></textarea> </div> @@ -808,7 +811,7 @@ </div> </div> <button type="button" class="btn btn-success" ng-show="specification.interface == 'APE' || page.interfaces.length == 0" ng-click="addInterface()">Add Interface/Axis</button> - <div class="node" ng-repeat="interface in page.interfaces" ng-controller="interfaceNode"> + <div class="node interface" ng-repeat="interface in page.interfaces" ng-controller="interfaceNode"> <h2>Interface</h2> <button type="button" class="btn btn-danger" ng-click="removeInterface(interface)">Remove Interface/Axis</button> <div class="node interfaceOptions"> @@ -955,15 +958,15 @@ </div> </div> <button type="button" class="btn btn-success" ng-click="addAudioElement()">Add Fragment</button> - <div class="node" ng-repeat="fragment in page.audioElements"> + <div class="node audioelement" ng-repeat="fragment in page.audioElements"> <h3>Audio Fragment</h3> <button type="button" class="btn btn-danger" ng-click="removeAudioElement(fragment)">Remove Fragment</button> <div class="attributes"> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="The unique ID of this fragment. Must be unique across the entire session"> <span>Unique ID: </span> <input type="text" ng-model="fragment.id" required/> </div> - <div class="attribute"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="URL of the fragment."> <span>URL: </span> <input type="text" ng-model="fragment.url" required/> <span>Full URL: </span><span style="font-weight=600">{{page.hostURL}}{{fragment.url}}</span> @@ -991,15 +994,15 @@ </div> <div class="attribute" ng-show="fragment.type == 'anchor'"> <span>Anchor must be below: </span> - <input type="number" ng-model="fragment.marker" min="0" max="100" /> + <input type="number" ng-model="fragment.marker" min="0" max="100" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="If this is set, the page cannot be submitted if this fragment is above this point." /> </div> <div class="attribute" ng-show="fragment.type == 'reference'"> <span>Reference must be above: </span> - <input type="number" ng-model="fragment.marker" min="0" max="100" /> + <input type="number" ng-model="fragment.marker" min="0" max="100" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="If this is set, the page cannot be submitted if this fragment is below this point." /> </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Over-ride global and page loudness"> <span>Loudness: </span> - <input type="number" ng-model="fragment.loudness" max="0" /> + <input type="number" ng-model="fragment.loudness" max="0" placeholder="{{page.loudness || specification.loudness || ''}}" /> </div> <div class="attribute" ng-show="page.poolSize > 0" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Always include this fragment after any sub-pooling"> <span>Always include fragment: </span> @@ -1044,13 +1047,13 @@ <div id="popupHolder" ng-show="popupVisible"> <div ng-controller="introduction" class="popup" ng-show="popupVisible"> <div class="popupTitle" ng-switch="state"> - <span ng-switch-when="0">Test Creator</span> + <span ng-switch-when="0">Test Creator <span class="label label-primary">v1.2.2</span></span> <span ng-switch-when="1">Create New Test</span> </div> <div class="popupContent container-fluid" ng-switch="state"> <div ng-switch-when="0"> <div> - <span>Welcome to the WAET test creator tool. This will allow you to create a new test from scratch to suit your testing needs. If you wish to update a test file, please drag and drop the XML document into the area below for processing, otherwise press 'Next' to start a new test. This tool generates files for the WAET 1.2.1 version.</span> + <span>Welcome to the WAET test creator tool. This will allow you to create a new test from scratch to suit your testing needs. If you wish to update a test file, please drag and drop the XML document into the area below for processing, otherwise press 'Next' to start a new test. This tool generates files for the WAET 1.2.2 version.</span> </div> <div> <input type="file" id="files" ng-model="files" onchange="handleFiles(event)" /> @@ -1062,7 +1065,7 @@ </div> <div class="row"> <div class="col-md-6" style="overflow-y: scroll;height: 333px;"> - <div class="new-test" ng-repeat="i in testSpecifications.interfaces" ng-mouseover="mouseover(i.name)" ng-click="initialise(i.name)"> + <div class="new-test" ng-repeat="i in testSpecifications.interfaces" ng-mouseover="mouseover(i.name)" ng-click="select(i.name)"> <label style="cursor:pointer"> <input type="radio" name="new-test" value="{{i.name}}" id="i.name" style="cursor:pointer" /> {{i.name}} </label>
--- a/test_create/interfaces/specifications.json Thu Jul 27 21:00:36 2017 +0100 +++ b/test_create/interfaces/specifications.json Tue Aug 01 15:23:47 2017 +0100 @@ -10,56 +10,6 @@ "show": [], "elements": [] }, { - "name": "MUSHRA", - "interface": "MUSHRA", - "description": { - "en": "Multi-stimulus with hidden reference and anchor. Each fragment is shown on its own vertical slider. One fragment must be labelled as a reference and another labelled as an anchor. One external reference must also be shown." - }, - "scales": ["ACR"], - "checks": [{ - "name": "fragmentMoved", - "support": "none" - }, { - "name": "fragmentPlayed", - "support": "none" - }, { - "name": "fragmentFullPlayback", - "support": "none" - }, { - "name": "fragmentComments", - "support": "none" - }, { - "name": "scalerange", - "support": "none" - }], - "show": [{ - "name": "volume", - "support": "none" - }, { - "name": "page-count", - "support": "none" - }, { - "name": "playhead", - "support": "none" - }, { - "name": "comments", - "support": "none" - }], - "elements": [{ - "anchor": { - "min": 1, - "max": "undefined" - }, - "reference": { - "min": 1, - "max": "undefined" - }, - "outsidereference": { - "min": 1, - "max": "undefined" - } - }] - }, { "name": "Vertical Sliders", "interface": "MUSHRA", "description": { @@ -78,7 +28,7 @@ "en": "Each element is given a horizontal scale broken into a number of discrete choices. The number of choices is defined by the scale markers." } }, { - "name": "Rank", + "name": "Rank/Ordinal", "interface": "ordinal", "description": { "en": "Each stimulus is placed on a discrete scale equalling the number of fragments. The fragments are then ranked based on the question posed. Only one element can occupy a rank position" @@ -114,38 +64,19 @@ "support": "none" }] }, { - "name": "ABC/HR", + "name": "ABC/HR (ITU-R BS.1116)", "interface": "MUSHRA", "description": { - "en": "Each stimulus is placed on a vertical slider. The scale is fixed with the labels 'Imperceptible' to 'Very Annoying'" + "en": "Double-blind triple-stimulus with hidden reference. Each fragment is shown on its own vertical slider. One fragment must be labelled as a reference and placed as fragment A. This must be copied again and then the tested difference as the third fragment. ITU-R BS.1116-3" }, - "scales": ["ABC"], - "checks": [{ - "name": "fragmentMoved", - "support": "none" - }, { - "name": "fragmentPlayed", - "support": "none" - }, { - "name": "fragmentFullPlayback", - "support": "none" - }, { - "name": "fragmentComments", - "support": "none" - }], - "show": [{ - "name": "volume", - "support": "none" - }, { - "name": "page-count", - "support": "none" - }, { - "name": "playhead", - "support": "none" - }, { - "name": "comments", - "support": "none" - }] + "template": "./tests/templates/itur1116.xml" + }, { + "name": "MUSHRA (ITU-R BS.1534)", + "interface": "MUSHRA", + "description": { + "en": "Multiple Stimulus with hiddren reference and anchor. At least four fragments must be shown, an outside reference, hidden reference, hidden anchor and the test candidate. ITU-R BS.1534-3" + }, + "template": "./tests/templates/itur1534.xml" }, { "name": "Bipolar", "interface": "horizontal",
--- a/test_create/style.css Thu Jul 27 21:00:36 2017 +0100 +++ b/test_create/style.css Tue Aug 01 15:23:47 2017 +0100 @@ -74,10 +74,10 @@ width: 80%; } .node > h1, -h2, -h3, -h4, -h5 { +.node > h2, +.node > h3, +.node > h4, +.node > h5 { text-align: center; } .attribute {
--- a/test_create/test_core.js Thu Jul 27 21:00:36 2017 +0100 +++ b/test_create/test_core.js Tue Aug 01 15:23:47 2017 +0100 @@ -35,10 +35,14 @@ window.onload = function () { // Get the test interface specifications + toggleDropdowns(); +}; + +function toggleDropdowns() { $(function () { $('[data-toggle="popover"]').popover(); }); -}; +} function handleFiles(event) { var s = angular.element(event.currentTarget).scope(); @@ -82,6 +86,11 @@ specification.processSchema(text); $s.globalSchema = specification.getSchema(); }); + $s.availableInterfaceModules = []; + get("interfaces/interfaces.json").then(JSON.parse).then(function (d) { + $s.availableInterfaceModules = d.interfaces; + $s.$apply(); + }); $s.specification = specification; $s.selectedTestPrototype = undefined; $s.setTestPrototype = function (obj) { @@ -112,10 +121,12 @@ }); var dnlk = window.URL.createObjectURL(bb); var a = document.createElement("a"); + document.body.appendChild(a) a.href = dnlk; a.download = "test.xml"; a.click(); window.URL.revokeObjectURL(dnlk); + document.body.removeChild(a); }; $s.validated = false; $s.showValidationMessages = false; @@ -149,14 +160,28 @@ $s.hideValidationMessages = function () { $s.showValidationMessages = false; } + $s.$watch(function () { + return document.querySelectorAll("div.pageNode").length; + }, $w.toggleDropdowns); + $s.$watch(function () { + return document.querySelectorAll("div.surveyentry").length; + }, $w.toggleDropdowns); + $s.$watch(function () { + return document.querySelectorAll("div.interface").length; + }, $w.toggleDropdowns); + $s.$watch(function () { + return document.querySelectorAll("div.audioelement").length; + }, $w.toggleDropdowns); }]); AngularInterface.controller("introduction", ['$scope', '$element', '$window', function ($s, $e, $w) { $s.state = 0; + $s.selected = undefined; $s.next = function () { $s.state++; if ($s.state > 1 || $s.file) { $s.hidePopup(); + $s.initialise($s.selected); } }; $s.back = function () { @@ -177,19 +202,32 @@ if (obj === undefined) { throw ("Cannot find specification"); } - $s.setTestPrototype(obj); + if (typeof obj.template === "string") { + get(obj.template).then(function (data) { + $s.parseFile(data); + }, function (err) {}) + } else { + $s.setTestPrototype(obj); + } }; - // Get the test interface specifications + $s.select = function (name) { + $s.selected = name; + } + // Get the test interface specifications $s.file = undefined; $s.description = ""; + $s.parseFile = function (f) { + var p = new DOMParser(); + specification.decode(p.parseFromString(f, "text/xml")); + $s.$apply(); + } + $s.handleFiles = function ($event) { $s.file = $event.currentTarget.files[0]; var r = new FileReader(); r.onload = function () { - var p = new DOMParser(); - specification.decode(p.parseFromString(r.result, "text/xml")); - $s.$apply(); + $s.parseFile(r.result); }; r.readAsText($s.file); }; @@ -240,6 +278,17 @@ $s.configure = function () {} $s.$watch("selectedTestPrototype", $s.configure); + + $s.placeholder = function (name) { + if ($s.schema) { + var spec = $s.schema.querySelector("attribute[name=\"" + name + "\"]") || $w.specification.schema.querySelector("attribute[name=\"" + name + "\"]"); + var attr = spec.getAttribute("default"); + if (attr === null) { + return "Not set"; + } + return attr; + } + } }]); AngularInterface.controller("survey", ['$scope', '$element', '$window', function ($s, $e, $w) { @@ -413,6 +462,8 @@ $s.configure(); }]); AngularInterface.controller("page", ['$scope', '$element', '$window', function ($s, $e, $w) { + $s.schema = $w.specification.schema.querySelector("element[name=\"page\"]"); + $s.page.label = $s.page.label || "default"; $s.addInterface = function () { $s.page.addInterface(); }; @@ -450,4 +501,13 @@ } $s.page.audioElements.splice(index, 1); }; + + $s.placeholder = function (name) { + var spec = $s.schema.querySelector("attribute[name=\"" + name + "\"]") || $w.specification.schema.querySelector("attribute[name=\"" + name + "\"]"); + var attr = spec.getAttribute("default"); + if (attr === null) { + return "Not set"; + } + return attr; + } }]);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/templates/itur1116.xml Tue Aug 01 15:23:47 2017 +0100 @@ -0,0 +1,48 @@ +<?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" loudness="-23"> + <exitText>Thank you for participating in this listening test. You may now exit the test environment</exitText> + <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" /> + </interface> + </setup> + <page id="training" randomiseOrder="true" repeatCount="0" loop="true" synchronous="true" position="0" label="capital"> + <interface> + <title>Quality</title> + <scales> + <scalelabel position="100">Imperceptible</scalelabel> + <scalelabel position="75">Perceptible but not annoying</scalelabel> + <scalelabel position="50">Slightly annoying</scalelabel> + <scalelabel position="25">Annoying</scalelabel> + <scalelabel position="0">Very annoying</scalelabel> + </scales> + </interface> + <audioelement url="0.wav" id="training-A" type="reference" label="A" position="0" /> + <audioelement url="1.wav" id="training-1" /> + <audioelement url="0.wav" id="training-2" /> + </page> + <page id="test-0" randomiseOrder="true" repeatCount="0" loop="true" synchronous="true" position="0" label="capital"> + <interface> + <title>Quality</title> + <scales> + <scalelabel position="100">Imperceptible</scalelabel> + <scalelabel position="75">Perceptible but not annoying</scalelabel> + <scalelabel position="50">Slightly annoying</scalelabel> + <scalelabel position="25">Annoying</scalelabel> + <scalelabel position="0">Very annoying</scalelabel> + </scales> + </interface> + <audioelement url="0.wav" id="test-0-A" type="reference" label="A" position="0" /> + <audioelement url="1.wav" id="test-0-1" /> + <audioelement url="0.wav" id="test-0-2" /> + </page> + </waet>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/templates/itur1534.xml Tue Aug 01 15:23:47 2017 +0100 @@ -0,0 +1,48 @@ +<?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" loudness="-23"> + <exitText>Thank you for participating in this listening test. You may now exit the test environment</exitText> + <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" /> + </interface> + </setup> + <page id="training" randomiseOrder="true" repeatCount="0" loop="true" synchronous="true" position="0" label="capital"> + <interface> + <title>Quality</title> + <scales> + <scalelabel position="100">Imperceptible</scalelabel> + <scalelabel position="75">Perceptible but not annoying</scalelabel> + <scalelabel position="50">Slightly annoying</scalelabel> + <scalelabel position="25">Annoying</scalelabel> + <scalelabel position="0">Very annoying</scalelabel> + </scales> + </interface> + <audioelement url="0.wav" id="training-0" type="reference" /> + <audioelement url="1.wav" id="training-1" type="anchor" /> + <audioelement url="0.wav" id="training-2" /> + </page> + <page id="test-0" randomiseOrder="true" repeatCount="0" loop="true" synchronous="true" position="0" label="capital"> + <interface> + <title>Quality</title> + <scales> + <scalelabel position="100">Imperceptible</scalelabel> + <scalelabel position="75">Perceptible but not annoying</scalelabel> + <scalelabel position="50">Slightly annoying</scalelabel> + <scalelabel position="25">Annoying</scalelabel> + <scalelabel position="0">Very annoying</scalelabel> + </scales> + </interface> + <audioelement url="0.wav" id="test-0-0" type="reference" /> + <audioelement url="1.wav" id="test-0-1" type="anchor" /> + <audioelement url="0.wav" id="test-0-2" /> + </page> + </waet>
--- a/xml/test-schema.xsd Thu Jul 27 21:00:36 2017 +0100 +++ b/xml/test-schema.xsd Tue Aug 01 15:23:47 2017 +0100 @@ -12,14 +12,14 @@ <xs:attribute name="poolSize" type="xs:nonNegativeInteger" default="0" /> <xs:attribute name="alwaysInclude" type="xs:boolean" default="false" /> - <xs:attribute name="preSilence"> + <xs:attribute name="preSilence" default="0.0"> <xs:simpleType> <xs:restriction base="xs:decimal"> <xs:minInclusive value="0.0" /> </xs:restriction> </xs:simpleType> </xs:attribute> - <xs:attribute name="postSilence"> + <xs:attribute name="postSilence" default="0.0"> <xs:simpleType> <xs:restriction base="xs:decimal"> <xs:minInclusive value="0.0" />