comparison js/core.js @ 2682:0a72855de078

Completing #180 up to the singletons
author Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk>
date Wed, 01 Mar 2017 16:30:59 +0000
parents 95f614a82762
children 66a24a6a0358
comparison
equal deleted inserted replaced
2681:95f614a82762 2682:0a72855de078
2 * core.js 2 * core.js
3 * 3 *
4 * Main script to run, calls all other core functions and manages loading/store to backend. 4 * Main script to run, calls all other core functions and manages loading/store to backend.
5 * Also contains all global variables. 5 * Also contains all global variables.
6 */ 6 */
7
8 /*globals window, document, XMLDocument, Element, XMLHttpRequest, DOMParser, console, Blob, $, Promise, navigator */
9 /*globals AudioBuffer, AudioBufferSourceNode */
10 /*globals Specification, calculateLoudness, WAVE, validateXML, showdown, pageXMLSave, loadTest, resizeWindow */
7 11
8 /* create the web audio API context and store in audioContext*/ 12 /* create the web audio API context and store in audioContext*/
9 var audioContext; // Hold the browser web audio API 13 var audioContext; // Hold the browser web audio API
10 var projectXML; // Hold the parsed setup XML 14 var projectXML; // Hold the parsed setup XML
11 var schemaXSD; // Hold the parsed schema XSD 15 var schemaXSD; // Hold the parsed schema XSD
154 158
155 if (window.location.search.length !== 0) { 159 if (window.location.search.length !== 0) {
156 var search = window.location.search.split('?')[1]; 160 var search = window.location.search.split('?')[1];
157 // Now split the requests into pairs 161 // Now split the requests into pairs
158 var searchQueries = search.split('&'); 162 var searchQueries = search.split('&');
159 163 var url;
160 for (var i in searchQueries) { 164 for (var i in searchQueries) {
161 // Split each key-value pair 165 // Split each key-value pair
162 searchQueries[i] = searchQueries[i].split('='); 166 searchQueries[i] = searchQueries[i].split('=');
163 var key = searchQueries[i][0]; 167 var key = searchQueries[i][0];
164 var value = decodeURIComponent(searchQueries[i][1]); 168 var value = decodeURIComponent(searchQueries[i][1]);
165 switch (key) { 169 switch (key) {
166 case "url": 170 case "url":
167 url = value; 171 url = value;
172 specification.url = url;
168 break; 173 break;
169 case "returnURL": 174 case "returnURL":
170 gReturnURL = value; 175 gReturnURL = value;
171 break; 176 break;
172 case "saveFilenamePrefix": 177 case "saveFilenamePrefix":
671 case "greaterThan": 676 case "greaterThan":
672 case "lessThan": 677 case "lessThan":
673 console.log("Survey Element of type 'question' cannot interpret greaterThan/lessThan conditions. IGNORING"); 678 console.log("Survey Element of type 'question' cannot interpret greaterThan/lessThan conditions. IGNORING");
674 break; 679 break;
675 case "contains": 680 case "contains":
676 if (textArea.value.includes(condition.value)) { 681 if (value.includes(condition.value)) {
677 return true; 682 return true;
678 } 683 }
679 break; 684 break;
680 } 685 }
681 return false; 686 return false;
862 } 867 }
863 868
864 function processRadioConditional(condition, response) { 869 function processRadioConditional(condition, response) {
865 switch (condition.check) { 870 switch (condition.check) {
866 case "equals": 871 case "equals":
867 if (node.response === condition.value) { 872 if (response === condition.value) {
868 return true; 873 return true;
869 } 874 }
870 break; 875 break;
871 case "contains": 876 case "contains":
872 case "greaterThan": 877 case "greaterThan":
923 processConditional.call(this, node, node.response); 928 processConditional.call(this, node, node.response);
924 return true; 929 return true;
925 } 930 }
926 931
927 function processNumberConditional(condtion, value) { 932 function processNumberConditional(condtion, value) {
933 var condition = condition;
928 switch (condition.check) { 934 switch (condition.check) {
929 case "greaterThan": 935 case "greaterThan":
930 if (node.response > Number(condition.value)) { 936 if (value > Number(condition.value)) {
931 return true; 937 return true;
932 } 938 }
933 break; 939 break;
934 case "lessThan": 940 case "lessThan":
935 if (node.response < Number(condition.value)) { 941 if (value < Number(condition.value)) {
936 return true; 942 return true;
937 } 943 }
938 break; 944 break;
939 case "equals": 945 case "equals":
940 if (node.response == condition.value) { 946 if (value == condition.value) {
941 return true; 947 return true;
942 } 948 }
943 break; 949 break;
944 case "contains": 950 case "contains":
945 console.log("Survey Element of type 'number' cannot interpret \"contains\" conditions. IGNORING"); 951 console.log("Survey Element of type 'number' cannot interpret \"contains\" conditions. IGNORING");
1001 switch (condition.check) { 1007 switch (condition.check) {
1002 case "contains": 1008 case "contains":
1003 console.log("Survey Element of type 'number' cannot interpret contains conditions. IGNORING"); 1009 console.log("Survey Element of type 'number' cannot interpret contains conditions. IGNORING");
1004 break; 1010 break;
1005 case "greaterThan": 1011 case "greaterThan":
1006 if (node.response > Number(condition.value)) { 1012 if (value > Number(condition.value)) {
1007 return true; 1013 return true;
1008 } 1014 }
1009 break; 1015 break;
1010 case "lessThan": 1016 case "lessThan":
1011 if (node.response < Number(condition.value)) { 1017 if (value < Number(condition.value)) {
1012 return true; 1018 return true;
1013 } 1019 }
1014 break; 1020 break;
1015 case "equals": 1021 case "equals":
1016 if (node.response == condition.value) { 1022 if (value == condition.value) {
1017 return true; 1023 return true;
1018 } 1024 }
1019 break; 1025 break;
1020 default: 1026 default:
1021 console.log("Unknown condition. IGNORING"); 1027 console.log("Unknown condition. IGNORING");
1609 1615
1610 this.registerAudioObject = function (audioObject) { 1616 this.registerAudioObject = function (audioObject) {
1611 // Called by an audioObject to register to the buffer for use 1617 // Called by an audioObject to register to the buffer for use
1612 // First check if already in the register pool 1618 // First check if already in the register pool
1613 this.users.forEach(function (object) { 1619 this.users.forEach(function (object) {
1614 if (audioObject.id == objects.id) { 1620 if (audioObject.id == object.id) {
1615 return 0; 1621 return 0;
1616 } 1622 }
1617 }); 1623 });
1618 this.users.push(audioObject); 1624 this.users.push(audioObject);
1619 if (this.status == 3 || this.status == -1) { 1625 if (this.status == 3 || this.status == -1) {
1764 this.newTrack = function (element) { 1770 this.newTrack = function (element) {
1765 // Pull data from given URL into new audio buffer 1771 // Pull data from given URL into new audio buffer
1766 // URLs must either be from the same source OR be setup to 'Access-Control-Allow-Origin' 1772 // URLs must either be from the same source OR be setup to 'Access-Control-Allow-Origin'
1767 1773
1768 // Create the audioObject with ID of the new track length; 1774 // Create the audioObject with ID of the new track length;
1769 audioObjectId = this.audioObjects.length; 1775 var audioObjectId = this.audioObjects.length;
1770 this.audioObjects[audioObjectId] = new audioObject(audioObjectId); 1776 this.audioObjects[audioObjectId] = new audioObject(audioObjectId);
1771 1777
1772 // Check if audioObject buffer is currently stored by full URL 1778 // Check if audioObject buffer is currently stored by full URL
1773 var URL = testState.currentStateMap.hostURL + element.url; 1779 var URL = testState.currentStateMap.hostURL + element.url;
1774 var buffer = this.buffers.find(function (buffObj) { 1780 var buffer = this.buffers.find(function (buffObj) {
1808 this.loopPlayback = audioHolderObject.loop; 1814 this.loopPlayback = audioHolderObject.loop;
1809 this.synchPlayback = audioHolderObject.synchronous; 1815 this.synchPlayback = audioHolderObject.synchronous;
1810 }; 1816 };
1811 1817
1812 this.checkAllPlayed = function () { 1818 this.checkAllPlayed = function () {
1813 arr = []; 1819 var arr = [];
1814 for (var id = 0; id < this.audioObjects.length; id++) { 1820 for (var id = 0; id < this.audioObjects.length; id++) {
1815 if (this.audioObjects[id].metric.wasListenedTo === false) { 1821 if (this.audioObjects[id].metric.wasListenedTo === false) {
1816 arr.push(this.audioObjects[id].id); 1822 arr.push(this.audioObjects[id].id);
1817 } 1823 }
1818 } 1824 }
2037 } 2043 }
2038 if (this.commentDOM !== null) { 2044 if (this.commentDOM !== null) {
2039 this.storeDOM.appendChild(this.commentDOM.exportXMLDOM(this)); 2045 this.storeDOM.appendChild(this.commentDOM.exportXMLDOM(this));
2040 } 2046 }
2041 } 2047 }
2042 var nodes = this.metric.exportXMLDOM(); 2048 this.metric.exportXMLDOM(this.storeDOM.getElementsByTagName('metric')[0]);
2043 var mroot = this.storeDOM.getElementsByTagName('metric')[0];
2044 for (var i = 0; i < nodes.length; i++) {
2045 mroot.appendChild(nodes[i]);
2046 }
2047 }; 2049 };
2048 } 2050 }
2049 2051
2050 function timer() { 2052 function timer() {
2051 /* Timer object used in audioEngine to keep track of session timings 2053 /* Timer object used in audioEngine to keep track of session timings
2200 } 2202 }
2201 console.log('slider ' + this.parent.id + ' played for (' + diff + ')'); // DEBUG/SAFETY: show played slider id 2203 console.log('slider ' + this.parent.id + ' played for (' + diff + ')'); // DEBUG/SAFETY: show played slider id
2202 } 2204 }
2203 }; 2205 };
2204 2206
2205 this.exportXMLDOM = function () { 2207 function exportElementTimer(parentElement) {
2206 var storeDOM = []; 2208 var mElementTimer = storage.document.createElement('metricresult');
2209 mElementTimer.setAttribute('name', 'enableElementTimer');
2210 mElementTimer.textContent = this.listenedTimer;
2211 parentElement.appendChild(mElementTimer);
2212 }
2213
2214 function exportElementTrack(parentElement) {
2215 var elementTrackerFull = storage.document.createElement('metricresult');
2216 elementTrackerFull.setAttribute('name', 'elementTrackerFull');
2217 for (var k = 0; k < this.movementTracker.length; k++) {
2218 var timePos = storage.document.createElement('movement');
2219 timePos.setAttribute("time", this.movementTracker[k][0]);
2220 timePos.setAttribute("value", this.movementTracker[k][1]);
2221 elementTrackerFull.appendChild(timePos);
2222 }
2223 parentElement.appendChild(elementTrackerFull);
2224 }
2225
2226 function exportElementListenTracker(parentElement) {
2227 var elementListenTracker = storage.document.createElement('metricresult');
2228 elementListenTracker.setAttribute('name', 'elementListenTracker');
2229 for (var k = 0; k < this.listenTracker.length; k++) {
2230 elementListenTracker.appendChild(this.listenTracker[k]);
2231 }
2232 parentElement.appendChild(elementListenTracker);
2233 }
2234
2235 function exportElementInitialPosition(parentElement) {
2236 var elementInitial = storage.document.createElement('metricresult');
2237 elementInitial.setAttribute('name', 'elementInitialPosition');
2238 elementInitial.textContent = this.initialPosition;
2239 parentElement.appendChild(elementInitial);
2240 }
2241
2242 function exportFlagListenedTo(parentElement) {
2243 var flagListenedTo = storage.document.createElement('metricresult');
2244 flagListenedTo.setAttribute('name', 'elementFlagListenedTo');
2245 flagListenedTo.textContent = this.wasListenedTo;
2246 parentElement.appendChild(flagListenedTo);
2247 }
2248
2249 function exportFlagMoved(parentElement) {
2250 var flagMoved = storage.document.createElement('metricresult');
2251 flagMoved.setAttribute('name', 'elementFlagMoved');
2252 flagMoved.textContent = this.wasMoved;
2253 parentElement.appendChild(flagMoved);
2254 }
2255
2256 function exportFlagComments(parentElement) {
2257 var flagComments = storage.document.createElement('metricresult');
2258 flagComments.setAttribute('name', 'elementFlagComments');
2259 if (this.parent.commentDOM === null) {
2260 flagComments.textContent = 'false';
2261 } else if (this.parent.commentDOM.textContent.length === 0) {
2262 flagComments.textContent = 'false';
2263 } else {
2264 flagComments.textContet = 'true';
2265 }
2266 parentElement.appendChild(flagComments);
2267 }
2268
2269 this.exportXMLDOM = function (parentElement) {
2207 if (audioEngineContext.metric.enableElementTimer) { 2270 if (audioEngineContext.metric.enableElementTimer) {
2208 var mElementTimer = storage.document.createElement('metricresult'); 2271 exportElementTimer.call(this, parentElement);
2209 mElementTimer.setAttribute('name', 'enableElementTimer');
2210 mElementTimer.textContent = this.listenedTimer;
2211 storeDOM.push(mElementTimer);
2212 } 2272 }
2213 if (audioEngineContext.metric.enableElementTracker) { 2273 if (audioEngineContext.metric.enableElementTracker) {
2214 var elementTrackerFull = storage.document.createElement('metricresult'); 2274 exportElementTrack.call(this, parentElement);
2215 elementTrackerFull.setAttribute('name', 'elementTrackerFull');
2216 for (var k = 0; k < this.movementTracker.length; k++) {
2217 var timePos = storage.document.createElement('movement');
2218 timePos.setAttribute("time", this.movementTracker[k][0]);
2219 timePos.setAttribute("value", this.movementTracker[k][1]);
2220 elementTrackerFull.appendChild(timePos);
2221 }
2222 storeDOM.push(elementTrackerFull);
2223 } 2275 }
2224 if (audioEngineContext.metric.enableElementListenTracker) { 2276 if (audioEngineContext.metric.enableElementListenTracker) {
2225 var elementListenTracker = storage.document.createElement('metricresult'); 2277 exportElementListenTracker.call(this, parentElement);
2226 elementListenTracker.setAttribute('name', 'elementListenTracker');
2227 for (var k = 0; k < this.listenTracker.length; k++) {
2228 elementListenTracker.appendChild(this.listenTracker[k]);
2229 }
2230 storeDOM.push(elementListenTracker);
2231 } 2278 }
2232 if (audioEngineContext.metric.enableElementInitialPosition) { 2279 if (audioEngineContext.metric.enableElementInitialPosition) {
2233 var elementInitial = storage.document.createElement('metricresult'); 2280 exportElementInitialPosition.call(this, parentElement);
2234 elementInitial.setAttribute('name', 'elementInitialPosition');
2235 elementInitial.textContent = this.initialPosition;
2236 storeDOM.push(elementInitial);
2237 } 2281 }
2238 if (audioEngineContext.metric.enableFlagListenedTo) { 2282 if (audioEngineContext.metric.enableFlagListenedTo) {
2239 var flagListenedTo = storage.document.createElement('metricresult'); 2283 exportFlagListenedTo.call(this, parentElement);
2240 flagListenedTo.setAttribute('name', 'elementFlagListenedTo');
2241 flagListenedTo.textContent = this.wasListenedTo;
2242 storeDOM.push(flagListenedTo);
2243 } 2284 }
2244 if (audioEngineContext.metric.enableFlagMoved) { 2285 if (audioEngineContext.metric.enableFlagMoved) {
2245 var flagMoved = storage.document.createElement('metricresult'); 2286 exportFlagMoved.call(this, parentElement);
2246 flagMoved.setAttribute('name', 'elementFlagMoved');
2247 flagMoved.textContent = this.wasMoved;
2248 storeDOM.push(flagMoved);
2249 } 2287 }
2250 if (audioEngineContext.metric.enableFlagComments) { 2288 if (audioEngineContext.metric.enableFlagComments) {
2251 var flagComments = storage.document.createElement('metricresult'); 2289 exportFlagComments.call(this, parentElement);
2252 flagComments.setAttribute('name', 'elementFlagComments'); 2290 }
2253 if (this.parent.commentDOM === null) {
2254 flag.textContent = 'false';
2255 } else if (this.parent.commentDOM.textContent.length === 0) {
2256 flag.textContent = 'false';
2257 } else {
2258 flag.textContet = 'true';
2259 }
2260 storeDOM.push(flagComments);
2261 }
2262 return storeDOM;
2263 }; 2291 };
2264 } 2292 }
2265 2293
2266 function Interface(specificationObject) { 2294 function Interface(specificationObject) {
2267 // This handles the bindings between the interface and the audioEngineContext; 2295 // This handles the bindings between the interface and the audioEngineContext;
2283 2311
2284 this.resizeWindow = function (event) { 2312 this.resizeWindow = function (event) {
2285 popup.resize(event); 2313 popup.resize(event);
2286 this.volume.resize(); 2314 this.volume.resize();
2287 this.lightbox.resize(); 2315 this.lightbox.resize();
2288 for (var i = 0; i < this.commentBoxes.length; i++) { 2316 this.commentBoxes.forEach(function (elem) {
2289 this.commentBoxes[i].resize(); 2317 elem.resize();
2290 } 2318 });
2291 for (var i = 0; i < this.commentQuestions.length; i++) { 2319 this.commentQuestions.forEach(function (elem) {
2292 this.commentQuestions[i].resize(); 2320 elem.resize();
2293 } 2321 });
2294 try { 2322 try {
2295 resizeWindow(event); 2323 resizeWindow(event);
2296 } catch (err) { 2324 } catch (err) {
2297 console.log("Warning - Interface does not have Resize option"); 2325 console.log("Warning - Interface does not have Resize option");
2298 console.log(err); 2326 console.log(err);
2462 this.showCommentBoxes = function (inject, sort) { 2490 this.showCommentBoxes = function (inject, sort) {
2463 this.injectPoint = inject; 2491 this.injectPoint = inject;
2464 if (sort) { 2492 if (sort) {
2465 this.sortCommentBoxes(); 2493 this.sortCommentBoxes();
2466 } 2494 }
2467 for (var box of this.boxes) { 2495 this.boxes.forEach(function (box) {
2468 inject.appendChild(box.trackComment); 2496 inject.appendChild(box.trackComment);
2469 } 2497 });
2470 }; 2498 };
2471 2499
2472 this.deleteCommentBoxes = function () { 2500 this.deleteCommentBoxes = function () {
2473 if (this.injectPoint !== null) { 2501 if (this.injectPoint !== null) {
2474 for (var box of this.boxes) { 2502 this.boxes.forEach(function (box) {
2475 this.injectPoint.removeChild(box.trackComment); 2503 this.injectPoint.removeChild(box.trackComment);
2476 } 2504 }, this);
2477 this.injectPoint = null; 2505 this.injectPoint = null;
2478 } 2506 }
2479 this.boxes = []; 2507 this.boxes = [];
2480 }; 2508 };
2481 }; 2509 };
2551 this.span.align = 'center'; 2579 this.span.align = 'center';
2552 this.span.style.marginTop = '15px'; 2580 this.span.style.marginTop = '15px';
2553 this.span.className = "comment-radio-span-holder"; 2581 this.span.className = "comment-radio-span-holder";
2554 2582
2555 var optCount = commentQuestion.options.length; 2583 var optCount = commentQuestion.options.length;
2556 for (var optNode of commentQuestion.options) { 2584 commentQuestion.options.forEach(function (optNode) {
2557 var div = document.createElement('div'); 2585 var div = document.createElement('div');
2558 div.style.width = '80px'; 2586 div.style.width = '80px';
2559 div.style.float = 'left'; 2587 div.style.float = 'left';
2560 var input = document.createElement('input'); 2588 var input = document.createElement('input');
2561 input.type = 'radio'; 2589 input.type = 'radio';
2574 span.textContent = optNode.text; 2602 span.textContent = optNode.text;
2575 span.className = 'comment-radio-span'; 2603 span.className = 'comment-radio-span';
2576 div.appendChild(span); 2604 div.appendChild(span);
2577 this.span.appendChild(div); 2605 this.span.appendChild(div);
2578 this.options.push(input); 2606 this.options.push(input);
2579 } 2607 }, this);
2580 this.holder.appendChild(this.span); 2608 this.holder.appendChild(this.span);
2581 this.holder.appendChild(this.inputs); 2609 this.holder.appendChild(this.inputs);
2582 2610
2583 this.exportXMLDOM = function (storePoint) { 2611 this.exportXMLDOM = function (storePoint) {
2584 var root = storePoint.parent.document.createElement('comment'); 2612 var root = storePoint.parent.document.createElement('comment');
2617 this.holder.style.width = boxwidth + "px"; 2645 this.holder.style.width = boxwidth + "px";
2618 var text = this.holder.getElementsByClassName("comment-radio-span-holder")[0]; 2646 var text = this.holder.getElementsByClassName("comment-radio-span-holder")[0];
2619 var options = this.holder.getElementsByClassName("comment-radio-inputs-holder")[0]; 2647 var options = this.holder.getElementsByClassName("comment-radio-inputs-holder")[0];
2620 var optCount = options.childElementCount; 2648 var optCount = options.childElementCount;
2621 var spanMargin = Math.floor(((boxwidth - 20 - (optCount * 80)) / (optCount)) / 2) + 'px'; 2649 var spanMargin = Math.floor(((boxwidth - 20 - (optCount * 80)) / (optCount)) / 2) + 'px';
2622 var options = options.firstChild; 2650 options = options.firstChild;
2623 var text = text.firstChild; 2651 text = text.firstChild;
2624 options.style.marginRight = spanMargin; 2652 options.style.marginRight = spanMargin;
2625 options.style.marginLeft = spanMargin; 2653 options.style.marginLeft = spanMargin;
2626 text.style.marginRight = spanMargin; 2654 text.style.marginRight = spanMargin;
2627 text.style.marginLeft = spanMargin; 2655 text.style.marginLeft = spanMargin;
2628 while (options.nextSibling !== undefined) { 2656 while (options.nextSibling !== undefined) {
2716 this.holder.style.width = boxwidth + "px"; 2744 this.holder.style.width = boxwidth + "px";
2717 var text = this.holder.getElementsByClassName("comment-checkbox-span-holder")[0]; 2745 var text = this.holder.getElementsByClassName("comment-checkbox-span-holder")[0];
2718 var options = this.holder.getElementsByClassName("comment-checkbox-inputs-holder")[0]; 2746 var options = this.holder.getElementsByClassName("comment-checkbox-inputs-holder")[0];
2719 var optCount = options.childElementCount; 2747 var optCount = options.childElementCount;
2720 var spanMargin = Math.floor(((boxwidth - 20 - (optCount * 80)) / (optCount)) / 2) + 'px'; 2748 var spanMargin = Math.floor(((boxwidth - 20 - (optCount * 80)) / (optCount)) / 2) + 'px';
2721 var options = options.firstChild; 2749 options = options.firstChild;
2722 var text = text.firstChild; 2750 text = text.firstChild;
2723 options.style.marginRight = spanMargin; 2751 options.style.marginRight = spanMargin;
2724 options.style.marginLeft = spanMargin; 2752 options.style.marginLeft = spanMargin;
2725 text.style.marginRight = spanMargin; 2753 text.style.marginRight = spanMargin;
2726 text.style.marginLeft = spanMargin; 2754 text.style.marginLeft = spanMargin;
2727 while (options.nextSibling !== undefined) { 2755 while (options.nextSibling !== undefined) {
2886 this.object.appendChild(this.scrubberTrack); 2914 this.object.appendChild(this.scrubberTrack);
2887 2915
2888 this.timePerPixel = 0; 2916 this.timePerPixel = 0;
2889 this.maxTime = 0; 2917 this.maxTime = 0;
2890 2918
2891 this.playbackObject; 2919 this.playbackObject = undefined;
2892 2920
2893 this.setTimePerPixel = function (audioObject) { 2921 this.setTimePerPixel = function (audioObject) {
2894 //maxTime must be in seconds 2922 //maxTime must be in seconds
2895 this.playbackObject = audioObject; 2923 this.playbackObject = audioObject;
2896 this.maxTime = audioObject.buffer.buffer.duration; 2924 this.maxTime = audioObject.buffer.buffer.duration;
2936 this.interval = undefined; 2964 this.interval = undefined;
2937 2965
2938 this.start = function () { 2966 this.start = function () {
2939 if (this.playbackObject !== undefined && this.interval === undefined) { 2967 if (this.playbackObject !== undefined && this.interval === undefined) {
2940 if (this.maxTime < 60) { 2968 if (this.maxTime < 60) {
2941 this.interval = setInterval(function () { 2969 this.interval = window.setInterval(function () {
2942 interfaceContext.playhead.update(); 2970 interfaceContext.playhead.update();
2943 }, 10); 2971 }, 10);
2944 } else { 2972 } else {
2945 this.interval = setInterval(function () { 2973 this.interval = window.setInterval(function () {
2946 interfaceContext.playhead.update(); 2974 interfaceContext.playhead.update();
2947 }, 100); 2975 }, 100);
2948 } 2976 }
2949 } 2977 }
2950 }; 2978 };
2951 this.stop = function () { 2979 this.stop = function () {
2952 clearInterval(this.interval); 2980 window.clearInterval(this.interval);
2953 this.interval = undefined; 2981 this.interval = undefined;
2954 this.scrubberHead.style.left = '0px'; 2982 this.scrubberHead.style.left = '0px';
2955 if (this.maxTime < 60) { 2983 if (this.maxTime < 60) {
2956 this.curTimeSpan.textContent = '0.00'; 2984 this.curTimeSpan.textContent = '0.00';
2957 } else { 2985 } else {
3097 f0 *= 2; 3125 f0 *= 2;
3098 } 3126 }
3099 inject.appendChild(this.holder); 3127 inject.appendChild(this.holder);
3100 }; 3128 };
3101 this.collect = function () { 3129 this.collect = function () {
3102 for (var obj of this.calibrationNodes) { 3130 this.calibrationNodes.forEach(function (obj) {
3103 var node = storage.document.createElement("calibrationresult"); 3131 var node = storage.document.createElement("calibrationresult");
3104 node.setAttribute("frequency", obj.f); 3132 node.setAttribute("frequency", obj.f);
3105 node.setAttribute("range-min", obj.input.min); 3133 node.setAttribute("range-min", obj.input.min);
3106 node.setAttribute("range-max", obj.input.max); 3134 node.setAttribute("range-max", obj.input.max);
3107 node.setAttribute("gain-lin", obj.gain.gain.value); 3135 node.setAttribute("gain-lin", obj.gain.gain.value);
3108 this.storeDOM.appendChild(node); 3136 this.storeDOM.appendChild(node);
3109 } 3137 }, this);
3110 }; 3138 };
3111 }; 3139 };
3112 3140
3113 3141
3114 // Global Checkers 3142 // Global Checkers
3115 // These functions will help enforce the checkers 3143 // These functions will help enforce the checkers
3116 this.checkHiddenAnchor = function () { 3144 this.checkHiddenAnchor = function () {
3117 for (var ao of audioEngineContext.audioObjects) { 3145 audioEngineContext.audioObjects.forEach(function (ao) {
3118 if (ao.specification.type == "anchor") { 3146 if (ao.specification.type === "anchor") {
3119 if (ao.interfaceDOM.getValue() > (ao.specification.marker / 100) && ao.specification.marker > 0) { 3147 if (ao.interfaceDOM.getValue() > (ao.specification.marker / 100) && ao.specification.marker > 0) {
3120 // Anchor is not set below 3148 // Anchor is not set below
3121 console.log('Anchor node not below marker value'); 3149 console.log('Anchor node not below marker value');
3122 interfaceContext.lightbox.post("Message", 'Please keep listening'); 3150 interfaceContext.lightbox.post("Message", 'Please keep listening');
3123 this.storeErrorNode('Anchor node not below marker value'); 3151 this.storeErrorNode('Anchor node not below marker value');
3124 return false; 3152 return false;
3125 } 3153 }
3126 } 3154 }
3127 } 3155 }, this);
3128 return true; 3156 return true;
3129 }; 3157 };
3130 3158
3131 this.checkHiddenReference = function () { 3159 this.checkHiddenReference = function () {
3132 for (var ao of audioEngineContext.audioObjects) { 3160 audioEngineContext.audioObjects.forEach(function (ao) {
3133 if (ao.specification.type == "reference") { 3161 if (ao.specification.type == "reference") {
3134 if (ao.interfaceDOM.getValue() < (ao.specification.marker / 100) && ao.specification.marker > 0) { 3162 if (ao.interfaceDOM.getValue() < (ao.specification.marker / 100) && ao.specification.marker > 0) {
3135 // Anchor is not set below 3163 // Anchor is not set below
3136 console.log('Reference node not above marker value'); 3164 console.log('Reference node not above marker value');
3137 this.storeErrorNode('Reference node not above marker value'); 3165 this.storeErrorNode('Reference node not above marker value');
3138 interfaceContext.lightbox.post("Message", 'Please keep listening'); 3166 interfaceContext.lightbox.post("Message", 'Please keep listening');
3139 return false; 3167 return false;
3140 } 3168 }
3141 } 3169 }
3142 } 3170 }, this);
3143 return true; 3171 return true;
3144 }; 3172 };
3145 3173
3146 this.checkFragmentsFullyPlayed = function () { 3174 this.checkFragmentsFullyPlayed = function () {
3147 // Checks the entire file has been played back 3175 // Checks the entire file has been played back
3149 if (audioEngineContext.loopPlayback) { 3177 if (audioEngineContext.loopPlayback) {
3150 console.log("WARNING - Looped source: Cannot check fragments are fully played"); 3178 console.log("WARNING - Looped source: Cannot check fragments are fully played");
3151 return true; 3179 return true;
3152 } 3180 }
3153 var check_pass = true; 3181 var check_pass = true;
3154 var error_obj = []; 3182 var error_obj = [],
3155 for (var i = 0; i < audioEngineContext.audioObjects.length; i++) { 3183 i;
3184 for (i = 0; i < audioEngineContext.audioObjects.length; i++) {
3156 var object = audioEngineContext.audioObjects[i]; 3185 var object = audioEngineContext.audioObjects[i];
3157 var time = object.buffer.buffer.duration; 3186 var time = object.buffer.buffer.duration;
3158 var metric = object.metric; 3187 var metric = object.metric;
3159 var passed = false; 3188 var passed = false;
3160 for (var j = 0; j < metric.listenTracker.length; j++) { 3189 for (var j = 0; j < metric.listenTracker.length; j++) {
3173 error_obj.push(object.interfaceDOM.getPresentedId()); 3202 error_obj.push(object.interfaceDOM.getPresentedId());
3174 } 3203 }
3175 } 3204 }
3176 if (check_pass === false) { 3205 if (check_pass === false) {
3177 var str_start = "You have not completely listened to fragments "; 3206 var str_start = "You have not completely listened to fragments ";
3178 for (var i = 0; i < error_obj.length; i++) { 3207 for (i = 0; i < error_obj.length; i++) {
3179 str_start += error_obj[i]; 3208 str_start += error_obj[i];
3180 if (i != error_obj.length - 1) { 3209 if (i != error_obj.length - 1) {
3181 str_start += ', '; 3210 str_start += ', ';
3182 } 3211 }
3183 } 3212 }
3190 return true; 3219 return true;
3191 }; 3220 };
3192 this.checkAllMoved = function () { 3221 this.checkAllMoved = function () {
3193 var str = "You have not moved "; 3222 var str = "You have not moved ";
3194 var failed = []; 3223 var failed = [];
3195 for (var ao of audioEngineContext.audioObjects) { 3224 audioEngineContext.audioObjects.forEach(function (ao) {
3196 if (ao.metric.wasMoved === false && ao.interfaceDOM.canMove() === true) { 3225 if (ao.metric.wasMoved === false && ao.interfaceDOM.canMove() === true) {
3197 failed.push(ao.interfaceDOM.getPresentedId()); 3226 failed.push(ao.interfaceDOM.getPresentedId());
3198 } 3227 }
3199 } 3228 }, this);
3200 if (failed.length === 0) { 3229 if (failed.length === 0) {
3201 return true; 3230 return true;
3202 } else if (failed.length == 1) { 3231 } else if (failed.length == 1) {
3203 str += 'track ' + failed[0]; 3232 str += 'track ' + failed[0];
3204 } else { 3233 } else {
3215 return false; 3244 return false;
3216 }; 3245 };
3217 this.checkAllPlayed = function () { 3246 this.checkAllPlayed = function () {
3218 var str = "You have not played "; 3247 var str = "You have not played ";
3219 var failed = []; 3248 var failed = [];
3220 for (var ao of audioEngineContext.audioObjects) { 3249 audioEngineContext.audioObjects.forEach(function (ao) {
3221 if (ao.metric.wasListenedTo === false) { 3250 if (ao.metric.wasListenedTo === false) {
3222 failed.push(ao.interfaceDOM.getPresentedId()); 3251 failed.push(ao.interfaceDOM.getPresentedId());
3223 } 3252 }
3224 } 3253 }, this);
3225 if (failed.length === 0) { 3254 if (failed.length === 0) {
3226 return true; 3255 return true;
3227 } else if (failed.length == 1) { 3256 } else if (failed.length == 1) {
3228 str += 'track ' + failed[0]; 3257 str += 'track ' + failed[0];
3229 } else { 3258 } else {
3260 var audioObjects = audioEngineContext.audioObjects; 3289 var audioObjects = audioEngineContext.audioObjects;
3261 var state = true; 3290 var state = true;
3262 var str = "Please keep listening. "; 3291 var str = "Please keep listening. ";
3263 var minRanking = Infinity; 3292 var minRanking = Infinity;
3264 var maxRanking = -Infinity; 3293 var maxRanking = -Infinity;
3265 for (var ao of audioObjects) { 3294 audioEngineContext.audioObjects.forEach(function (ao) {
3266 var rank = ao.interfaceDOM.getValue(); 3295 var rank = ao.interfaceDOM.getValue();
3267 if (rank < minRanking) { 3296 if (rank < minRanking) {
3268 minRanking = rank; 3297 minRanking = rank;
3269 } 3298 }
3270 if (rank > maxRanking) { 3299 if (rank > maxRanking) {
3271 maxRanking = rank; 3300 maxRanking = rank;
3272 } 3301 }
3273 } 3302 }, this);
3274 if (minRanking * 100 > min) { 3303 if (minRanking * 100 > min) {
3275 str += "At least one fragment must be below the " + min + " mark."; 3304 str += "At least one fragment must be below the " + min + " mark.";
3276 state = false; 3305 state = false;
3277 } 3306 }
3278 if (maxRanking * 100 < max) { 3307 if (maxRanking * 100 < max) {
3346 labelStart = Number(labelStart); 3375 labelStart = Number(labelStart);
3347 if (!isFinite(labelStart)) { 3376 if (!isFinite(labelStart)) {
3348 labelStart = 1; 3377 labelStart = 1;
3349 } 3378 }
3350 break; 3379 break;
3351 case "none":
3352 default: 3380 default:
3353 labelStart = 0; 3381 labelStart = 0;
3354 } 3382 }
3355 if (typeof index == "number") { 3383 if (typeof index == "number") {
3356 return calculateLabel(labelType, index, labelStart); 3384 return calculateLabel(labelType, index, labelStart);
3407 // We need to get the sessionKey 3435 // We need to get the sessionKey
3408 this.SessionKey.requestKey(); 3436 this.SessionKey.requestKey();
3409 this.document = document.implementation.createDocument(null, "waetresult", null); 3437 this.document = document.implementation.createDocument(null, "waetresult", null);
3410 this.root = this.document.childNodes[0]; 3438 this.root = this.document.childNodes[0];
3411 var projectDocument = specification.projectXML; 3439 var projectDocument = specification.projectXML;
3412 projectDocument.setAttribute('file-name', url); 3440 projectDocument.setAttribute('file-name', specification.url);
3413 projectDocument.setAttribute('url', qualifyURL(url)); 3441 projectDocument.setAttribute('url', qualifyURL(specification.url));
3414 this.root.appendChild(projectDocument); 3442 this.root.appendChild(projectDocument);
3415 this.root.appendChild(interfaceContext.returnDateNode()); 3443 this.root.appendChild(interfaceContext.returnDateNode());
3416 this.root.appendChild(interfaceContext.returnNavigator()); 3444 this.root.appendChild(interfaceContext.returnNavigator());
3417 } else { 3445 } else {
3418 this.document = existingStore; 3446 this.document = existingStore;
3518 this.parent = parent; 3546 this.parent = parent;
3519 this.state = "empty"; 3547 this.state = "empty";
3520 this.XMLDOM = this.parent.document.createElement('survey'); 3548 this.XMLDOM = this.parent.document.createElement('survey');
3521 this.XMLDOM.setAttribute('location', this.specification.location); 3549 this.XMLDOM.setAttribute('location', this.specification.location);
3522 this.XMLDOM.setAttribute("state", this.state); 3550 this.XMLDOM.setAttribute("state", this.state);
3523 for (var optNode of this.specification.options) { 3551 this.specification.options.forEach(function (optNode) {
3524 if (optNode.type != 'statement') { 3552 if (optNode.type != 'statement') {
3525 var node = this.parent.document.createElement('surveyresult'); 3553 var node = this.parent.document.createElement('surveyresult');
3526 node.setAttribute("ref", optNode.id); 3554 node.setAttribute("ref", optNode.id);
3527 node.setAttribute('type', optNode.type); 3555 node.setAttribute('type', optNode.type);
3528 this.XMLDOM.appendChild(node); 3556 this.XMLDOM.appendChild(node);
3529 } 3557 }
3530 } 3558 }, this);
3531 root.appendChild(this.XMLDOM); 3559 root.appendChild(this.XMLDOM);
3532 3560
3533 this.postResult = function (node) { 3561 this.postResult = function (node) {
3562 function postNumber(doc, value) {
3563 var child = doc.createElement("response");
3564 child.textContent = value;
3565 return child;
3566 }
3567
3568 function postRadio(doc, node) {
3569 var child = doc.createElement('response');
3570 if (node.response !== null) {
3571 child.setAttribute('name', node.response.name);
3572 child.textContent = node.response.text;
3573 }
3574 return child;
3575 }
3576
3577 function postCheckbox(doc, node) {
3578 var checkNode = doc.createElement('response');
3579 checkNode.setAttribute('name', node.name);
3580 checkNode.setAttribute('checked', node.checked);
3581 return checkNode;
3582 }
3534 // From popup: node is the popupOption node containing both spec. and results 3583 // From popup: node is the popupOption node containing both spec. and results
3535 // ID is the position 3584 // ID is the position
3536 if (node.specification.type == 'statement') { 3585 if (node.specification.type == 'statement') {
3537 return; 3586 return;
3538 } 3587 }
3545 } 3594 }
3546 switch (node.specification.type) { 3595 switch (node.specification.type) {
3547 case "number": 3596 case "number":
3548 case "question": 3597 case "question":
3549 case "slider": 3598 case "slider":
3550 var child = this.parent.document.createElement('response'); 3599 surveyresult.appendChild(postNumber(this.parent.document, node.response));
3551 child.textContent = node.response;
3552 surveyresult.appendChild(child);
3553 break; 3600 break;
3554 case "radio": 3601 case "radio":
3555 var child = this.parent.document.createElement('response'); 3602 surveyresult.appendChild(postRadio(this.parent.document, node));
3556 if (node.response !== null) {
3557 child.setAttribute('name', node.response.name);
3558 child.textContent = node.response.text;
3559 }
3560 surveyresult.appendChild(child);
3561 break; 3603 break;
3562 case "checkbox": 3604 case "checkbox":
3563 if (node.response === undefined) { 3605 if (node.response === undefined) {
3564 surveyresult.appendChild(this.parent.document.createElement('response')); 3606 surveyresult.appendChild(this.parent.document.createElement('response'));
3565 break; 3607 break;
3566 } 3608 }
3567 for (var i = 0; i < node.response.length; i++) { 3609 for (var i = 0; i < node.response.length; i++) {
3568 var checkNode = this.parent.document.createElement('response'); 3610 surveyresult.appendChild(postCheckbox(this.parent.document, node.response[i]));
3569 checkNode.setAttribute('name', node.response[i].name);
3570 checkNode.setAttribute('checked', node.response[i].checked);
3571 surveyresult.appendChild(checkNode);
3572 } 3611 }
3573 break; 3612 break;
3574 } 3613 }
3575 }; 3614 };
3576 this.complete = function () { 3615 this.complete = function () {
3598 // Add any page metrics 3637 // Add any page metrics
3599 var page_metric = this.parent.document.createElement('metric'); 3638 var page_metric = this.parent.document.createElement('metric');
3600 this.XMLDOM.appendChild(page_metric); 3639 this.XMLDOM.appendChild(page_metric);
3601 3640
3602 // Add the audioelement 3641 // Add the audioelement
3603 for (var element of this.specification.audioElements) { 3642 this.specification.audioElements.forEach(function (element) {
3604 var aeNode = this.parent.document.createElement('audioelement'); 3643 var aeNode = this.parent.document.createElement('audioelement');
3605 aeNode.setAttribute('ref', element.id); 3644 aeNode.setAttribute('ref', element.id);
3606 if (element.name !== undefined) { 3645 if (element.name !== undefined) {
3607 aeNode.setAttribute('name', element.name); 3646 aeNode.setAttribute('name', element.name);
3608 } 3647 }
3616 } 3655 }
3617 } 3656 }
3618 var ae_metric = this.parent.document.createElement('metric'); 3657 var ae_metric = this.parent.document.createElement('metric');
3619 aeNode.appendChild(ae_metric); 3658 aeNode.appendChild(ae_metric);
3620 this.XMLDOM.appendChild(aeNode); 3659 this.XMLDOM.appendChild(aeNode);
3621 } 3660 }, this);
3622 3661
3623 this.parent.root.appendChild(this.XMLDOM); 3662 this.parent.root.appendChild(this.XMLDOM);
3624 3663
3625 this.complete = function () { 3664 this.complete = function () {
3626 this.state = "complete"; 3665 this.state = "complete";