nicholas@2479: /** nicholas@2479: * WAET Timeline nicholas@2479: * This interface plots a waveform timeline per audio fragment on a page. Clicking on the fragment will generate a comment box for processing. nicholas@2479: */ nicholas@2702: /*globals interfaceContext, window, document, console, audioEngineContext, testState, $, storage */ nicholas@2479: // Once this is loaded and parsed, begin execution nicholas@2479: loadInterface(); nicholas@2479: nicholas@2479: function loadInterface() { nicholas@2481: // Use this to do any one-time page / element construction. For instance, placing any stationary text objects, nicholas@2481: // holding div's, or setting up any nodes which are present for the entire test sequence nicholas@2481: nicholas@2479: interfaceContext.insertPoint.innerHTML = ""; // Clear the current schema nicholas@2481: nicholas@2479: interfaceContext.insertPoint = document.getElementById("topLevelBody"); nicholas@2479: var testContent = document.createElement("div"); nicholas@2481: nicholas@2479: // Create the top div and Title element nicholas@2479: var title = document.createElement("div"); nicholas@2479: title.className = "title"; nicholas@2479: title.align = "center"; nicholas@2479: var titleSpan = document.createElement("span"); nicholas@2479: titleSpan.id = "test-title"; nicholas@2479: titleSpan.textContent = "Listening Test"; nicholas@2479: title.appendChild(titleSpan); nicholas@2481: nicholas@2479: var pagetitle = document.createElement("div"); nicholas@2479: pagetitle.className = "pageTitle"; nicholas@2479: pagetitle.align = "center"; nicholas@2479: titleSpan = document.createElement("span"); nicholas@2479: titleSpan.id = "page-title"; nicholas@2479: pagetitle.appendChild(titleSpan); nicholas@2481: nicholas@2479: // Create Interface buttons nicholas@2479: var interfaceButtons = document.createElement("div"); nicholas@2479: interfaceButtons.id = 'interface-buttons'; nicholas@2479: interfaceButtons.style.height = "25px"; nicholas@2481: nicholas@2479: // Create playback start/stop points nicholas@2479: var playback = document.createElement("button"); nicholas@2479: playback.innerHTML = "Stop"; nicholas@2479: playback.id = "playback-button"; nicholas@2481: playback.onclick = function () { nicholas@2479: if (audioEngineContext.status == 1) { nicholas@2479: audioEngineContext.stop(); nicholas@2479: this.innerHTML = "Stop"; nicholas@2479: var time = audioEngineContext.timer.getTestTime(); nicholas@2481: console.log("Stopped at " + time); nicholas@2479: } nicholas@2479: }; nicholas@2479: // Create Submit (save) button nicholas@2481: var submit = document.createElement("button"); nicholas@2481: submit.innerHTML = 'Next'; nicholas@2481: submit.onclick = buttonSubmitClick; nicholas@2481: submit.id = 'submit-button'; nicholas@2481: submit.style.float = 'left'; nicholas@2481: // Append the interface buttons into the interfaceButtons object. nicholas@2557: interfaceButtons.appendChild(submit); nicholas@2481: interfaceButtons.appendChild(playback); nicholas@2481: nicholas@2479: // Create outside reference holder nicholas@2479: var outsideRef = document.createElement("div"); nicholas@2479: outsideRef.id = "outside-reference-holder"; nicholas@2481: nicholas@2479: // Create content point nicholas@2479: var content = document.createElement("div"); nicholas@2479: content.id = "timeline-test-content"; nicholas@2481: nicholas@2479: //Inject nicholas@2479: testContent.appendChild(title); nicholas@2479: testContent.appendChild(pagetitle); nicholas@2479: testContent.appendChild(interfaceButtons); nicholas@2479: testContent.appendChild(outsideRef); nicholas@2479: testContent.appendChild(content); nicholas@2479: interfaceContext.insertPoint.appendChild(testContent); nicholas@2481: nicholas@2479: // Load the full interface nicholas@2481: testState.initialise(); nicholas@2481: testState.advanceState(); nicholas@2702: } nicholas@2479: nicholas@2481: function loadTest(page) { nicholas@2481: // Called each time a new test page is to be build. The page specification node is the only item passed in nicholas@2479: var content = document.getElementById("timeline-test-content"); nicholas@2479: content.innerHTML = ""; nicholas@2651: var interfaceObj = interfaceContext.getCombinedInterfaces(page); nicholas@2481: if (interfaceObj.length > 1) { nicholas@2479: console.log("WARNING - This interface only supports one node per page. Using first interface node"); nicholas@2479: } nicholas@2479: interfaceObj = interfaceObj[0]; nicholas@2481: nicholas@2479: //Set the page title nicholas@2481: if (typeof page.title == "string" && page.title.length > 0) { nicholas@2479: document.getElementById("test-title").textContent = page.title; nicholas@2479: } nicholas@2481: nicholas@2702: if (interfaceObj.title !== null) { nicholas@2479: document.getElementById("page-title").textContent = interfaceObj.title; nicholas@2479: } nicholas@2481: nicholas@2809: if (interfaceObj.image !== undefined) { nicholas@2807: document.getElementById("timeline-test-content").parentElement.insertBefore(interfaceContext.imageHolder.root, document.getElementById("timeline-test-content")); nicholas@2801: interfaceContext.imageHolder.setImage(interfaceObj.image); nicholas@2801: } nicholas@2801: nicholas@2479: // Delete outside reference nicholas@2481: var outsideReferenceHolder = document.getElementById("outside-reference-holder"); nicholas@2479: outsideReferenceHolder.innerHTML = ""; nicholas@2481: nicholas@2479: var commentBoxPrefix = "Comment on track"; nicholas@2702: if (interfaceObj.commentBoxPrefix !== undefined) { nicholas@2481: commentBoxPrefix = interfaceObj.commentBoxPrefix; nicholas@2481: } nicholas@2607: var index = 0; nicholas@2607: var interfaceScales = testState.currentStateMap.interfaces[0].scales; nicholas@2607: var labelType = page.label; nicholas@2607: if (labelType == "default") { nicholas@2607: labelType = "number"; nicholas@2607: } nicholas@2607: $(page.audioElements).each(function (pageIndex, element) { nicholas@2479: var audioObject = audioEngineContext.newTrack(element); nicholas@2479: if (page.audioElements.type == 'outside-reference') { nicholas@2481: var refNode = interfaceContext.outsideReferenceDOM(audioObject, index, outsideReferenceHolder); nicholas@2702: audioObject.bindInterface(refNode); nicholas@2479: } else { nicholas@2607: var label = interfaceContext.getLabel(labelType, index, page.labelStart); nicholas@2481: var node = new interfaceObject(audioObject, label); nicholas@2481: nicholas@2479: content.appendChild(node.DOM); nicholas@2479: audioObject.bindInterface(node); nicholas@2479: } nicholas@2479: }); nicholas@2481: nicholas@2479: resizeWindow(); nicholas@2479: } nicholas@2479: nicholas@2481: function interfaceObject(audioObject, labelstr) { nicholas@2481: // Each audio object has a waveform guide and self-generated comments nicholas@2479: this.parent = audioObject; nicholas@2479: this.DOM = document.createElement("div"); nicholas@2479: this.DOM.className = "timeline-element"; nicholas@2479: this.DOM.id = audioObject.specification.id; nicholas@2481: nicholas@2479: var root = document.createElement("div"); nicholas@2479: root.className = "timeline-element-content"; nicholas@2479: this.DOM.appendChild(root); nicholas@2481: nicholas@2479: var label = document.createElement("div"); nicholas@2479: label.style.textAlign = "center"; nicholas@2479: var labelSpan = document.createElement("span"); nicholas@2481: labelSpan.textContent = "Fragment " + labelstr; nicholas@2479: label.appendChild(labelSpan); nicholas@2479: root.appendChild(label); nicholas@2481: nicholas@2479: var canvasHolder = document.createElement("div"); nicholas@2479: canvasHolder.className = "timeline-element-canvas-holder"; nicholas@2479: var buttonHolder = document.createElement("div"); nicholas@2479: buttonHolder.className = "timeline-element-button-holder"; nicholas@2479: var commentHolder = document.createElement("div"); nicholas@2479: commentHolder.className = "timeline-element-comment-holder"; nicholas@2481: nicholas@2479: root.appendChild(canvasHolder); nicholas@2479: root.appendChild(buttonHolder); nicholas@2479: root.appendChild(commentHolder); nicholas@2481: nicholas@2479: this.comments = { nicholas@2479: parent: this, nicholas@2479: list: [], nicholas@2481: Comment: function (parent, time, str) { nicholas@2479: this.parent = parent; nicholas@2479: this.time = time; nicholas@2479: this.DOM = document.createElement("div"); nicholas@2480: this.DOM.className = "comment-entry"; nicholas@2480: var titleHolder = document.createElement("div"); nicholas@2480: titleHolder.className = "comment-entry-header"; nicholas@2479: this.title = document.createElement("span"); nicholas@2702: if (str !== undefined) { nicholas@2479: this.title.textContent = str; nicholas@2479: } else { nicholas@2481: this.title.textContent = "Time: " + time.toFixed(2) + "s"; nicholas@2479: } nicholas@2480: titleHolder.appendChild(this.title); nicholas@2479: this.textarea = document.createElement("textarea"); nicholas@2480: this.textarea.className = "comment-entry-text"; nicholas@2480: this.DOM.appendChild(titleHolder); nicholas@2479: this.DOM.appendChild(this.textarea); nicholas@2481: nicholas@2480: this.clear = { nicholas@2480: DOM: document.createElement("button"), nicholas@2480: parent: this, nicholas@2481: handleEvent: function () { nicholas@2480: this.parent.parent.deleteComment(this.parent); nicholas@2480: } nicholas@2702: }; nicholas@2480: this.clear.DOM.textContent = "Delete"; nicholas@2481: this.clear.DOM.addEventListener("click", this.clear); nicholas@2480: titleHolder.appendChild(this.clear.DOM); nicholas@2481: nicholas@2481: this.resize = function () { nicholas@2479: var w = window.innerWidth; nicholas@2481: w = Math.min(w, 800); nicholas@2481: w = Math.max(w, 200); nicholas@2479: var elem_w = w / 2.5; nicholas@2481: elem_w = Math.max(elem_w, 190); nicholas@2481: this.DOM.style.width = elem_w + "px"; nicholas@2481: this.textarea.style.width = (elem_w - 5) + "px"; nicholas@2702: }; nicholas@2481: this.buildXML = function (root) { nicholas@2480: //storage.document.createElement(); nicholas@2480: var node = storage.document.createElement("comment"); nicholas@2480: var question = storage.document.createElement("question"); nicholas@2480: var comment = storage.document.createElement("response"); nicholas@2481: node.setAttribute("time", this.time); nicholas@2480: question.textContent = this.title.textContent; nicholas@2480: comment.textContent = this.textarea.value; nicholas@2480: node.appendChild(question); nicholas@2480: node.appendChild(comment); nicholas@2480: root.appendChild(node); nicholas@2702: }; nicholas@2479: this.resize(); nicholas@2479: }, nicholas@2481: newComment: function (time) { nicholas@2481: var node = new this.Comment(this, time); nicholas@2479: this.list.push(node); nicholas@2479: commentHolder.appendChild(node.DOM); nicholas@2479: return node; nicholas@2479: }, nicholas@2481: deleteComment: function (comment) { nicholas@2481: var index = this.list.findIndex(function (element, index, array) { nicholas@2481: if (element == comment) { nicholas@2481: return true; nicholas@2481: } nicholas@2481: return false; nicholas@2481: }, comment); nicholas@2480: if (index == -1) { nicholas@2480: return false; nicholas@2480: } nicholas@2481: var node = this.list.splice(index, 1); nicholas@2480: comment.DOM.remove(); nicholas@2480: this.parent.canvas.drawMarkers(); nicholas@2480: return true; nicholas@2479: }, nicholas@2481: clearList: function () { nicholas@2481: while (this.list.length > 0) { nicholas@2480: this.deleteComment(this.list[0]); nicholas@2480: } nicholas@2479: } nicholas@2702: }; nicholas@2481: nicholas@2479: this.canvas = { nicholas@2479: parent: this, nicholas@2479: comments: this.comments, nicholas@2479: layer1: document.createElement("canvas"), nicholas@2479: layer2: document.createElement("canvas"), nicholas@2479: layer3: document.createElement("canvas"), nicholas@2479: layer4: document.createElement("canvas"), nicholas@2808: resize: function () { nicholas@2808: var w = $(this.layer1.parentElement).width(); nicholas@2479: this.layer1.width = w; nicholas@2479: this.layer2.width = w; nicholas@2479: this.layer3.width = w; nicholas@2479: this.layer4.width = w; nicholas@2481: this.layer1.style.width = w + "px"; nicholas@2481: this.layer2.style.width = w + "px"; nicholas@2481: this.layer3.style.width = w + "px"; nicholas@2481: this.layer4.style.width = w + "px"; nicholas@2480: this.drawWaveform(); nicholas@2480: this.drawMarkers(); nicholas@2479: }, nicholas@2481: handleEvent: function (event) { nicholas@2481: switch (event.currentTarget) { nicholas@2479: case this.layer1: nicholas@2481: switch (event.type) { nicholas@2479: case "mousemove": nicholas@2479: this.drawMouse(event); nicholas@2479: break; nicholas@2479: case "mouseleave": nicholas@2479: this.clearCanvas(this.layer1); nicholas@2479: break; nicholas@2479: case "click": nicholas@2479: var rect = this.layer1.getBoundingClientRect(); nicholas@2479: var pixX = event.clientX - rect.left; nicholas@2481: var tpp = this.parent.parent.buffer.buffer.duration / this.layer1.width; nicholas@2481: this.comments.newComment(pixX * tpp); nicholas@2479: this.drawMarkers(); nicholas@2479: break; nicholas@2479: } nicholas@2479: break; nicholas@2479: } nicholas@2479: }, nicholas@2481: drawWaveform: function () { nicholas@2702: if (this.parent.parent === undefined || this.parent.parent.buffer === undefined) { nicholas@2480: return; nicholas@2480: } nicholas@2479: var buffer = this.parent.parent.buffer.buffer; nicholas@2479: var context = this.layer4.getContext("2d"); nicholas@2479: context.lineWidth = 1; nicholas@2479: context.strokeStyle = "#888"; nicholas@2481: context.clearRect(0, 0, this.layer4.width, this.layer4.height); nicholas@2479: var data = buffer.getChannelData(0); nicholas@2481: var t_per_pixel = buffer.duration / this.layer4.width; nicholas@2481: var s_per_pixel = data.length / this.layer4.width; nicholas@2479: var pixX = 0; nicholas@2479: while (pixX < this.layer4.width) { nicholas@2481: var start = Math.floor(s_per_pixel * pixX); nicholas@2481: var end = Math.min(Math.ceil(s_per_pixel * (pixX + 1)), data.length); nicholas@2481: var frame = data.subarray(start, end); nicholas@2479: var min = frame[0]; nicholas@2479: var max = min; nicholas@2481: for (var n = 0; n < frame.length; n++) { nicholas@2481: if (frame[n] < min) { nicholas@2481: min = frame[n]; nicholas@2481: } nicholas@2481: if (frame[n] > max) { nicholas@2481: max = frame[n]; nicholas@2481: } nicholas@2479: } nicholas@2479: // Assuming min/max normalised between [-1, 1] to map to [150, 0] nicholas@2479: context.beginPath(); nicholas@2481: context.moveTo(pixX + 0.5, (min + 1) * -75 + 150); nicholas@2481: context.lineTo(pixX + 0.5, (max + 1) * -75 + 150); nicholas@2479: context.stroke(); nicholas@2479: pixX++; nicholas@2479: } nicholas@2479: }, nicholas@2481: drawMouse: function (event) { nicholas@2479: var context = this.layer1.getContext("2d"); nicholas@2481: context.clearRect(0, 0, this.layer1.width, this.layer1.height); nicholas@2479: var rect = this.layer1.getBoundingClientRect(); nicholas@2479: var pixX = event.clientX - rect.left; nicholas@2481: pixX = Math.floor(pixX) - 0.5; nicholas@2479: context.strokeStyle = "#800"; nicholas@2479: context.beginPath(); nicholas@2481: context.moveTo(pixX, 0); nicholas@2481: context.lineTo(pixX, this.layer1.height); nicholas@2479: context.stroke(); nicholas@2479: }, nicholas@2481: drawTicker: function () { nicholas@2479: var context = this.layer2.getContext("2d"); nicholas@2481: context.clearRect(0, 0, this.layer2.width, this.layer2.height); nicholas@2479: var time = this.parent.parent.getCurrentPosition(); nicholas@2479: var ratio = time / this.parent.parent.buffer.buffer.duration; nicholas@2481: var pixX = Math.floor(ratio * this.layer2.width) + 0.5; nicholas@2479: context.strokeStyle = "#080"; nicholas@2479: context.beginPath(); nicholas@2481: context.moveTo(pixX, 0); nicholas@2481: context.lineTo(pixX, this.layer2.height); nicholas@2479: context.stroke(); nicholas@2479: }, nicholas@2481: drawMarkers: function () { nicholas@2702: if (this.parent.parent === undefined || this.parent.parent.buffer === undefined) { nicholas@2480: return; nicholas@2480: } nicholas@2479: var context = this.layer3.getContext("2d"); nicholas@2481: context.clearRect(0, 0, this.layer3.width, this.layer3.height); nicholas@2479: context.strokeStyle = "#008"; nicholas@2481: var tpp = this.parent.parent.buffer.buffer.duration / this.layer1.width; nicholas@2481: for (var i = 0; i < this.comments.list.length; i++) { nicholas@2479: var comment = this.comments.list[i]; nicholas@2481: var pixX = Math.floor(comment.time / tpp) + 0.5; nicholas@2479: context.beginPath(); nicholas@2481: context.moveTo(pixX, 0); nicholas@2481: context.lineTo(pixX, this.layer3.height); nicholas@2479: context.stroke(); nicholas@2479: } nicholas@2479: }, nicholas@2481: clearCanvas: function (canvas) { nicholas@2479: var context = canvas.getContext("2d"); nicholas@2481: context.clearRect(0, 0, canvas.width, canvas.height); nicholas@2479: } nicholas@2702: }; nicholas@2479: this.canvas.layer1.className = "timeline-element-canvas canvas-layer1 canvas-disabled"; nicholas@2479: this.canvas.layer2.className = "timeline-element-canvas canvas-layer2"; nicholas@2479: this.canvas.layer3.className = "timeline-element-canvas canvas-layer3"; nicholas@2479: this.canvas.layer4.className = "timeline-element-canvas canvas-layer3"; nicholas@2809: this.canvas.layer1.height = "160"; nicholas@2809: this.canvas.layer2.height = "160"; nicholas@2809: this.canvas.layer3.height = "160"; nicholas@2809: this.canvas.layer4.height = "160"; nicholas@2809: var canvasDiv = document.createElement("div"); nicholas@2809: canvasDiv.appendChild(this.canvas.layer1); nicholas@2809: canvasDiv.appendChild(this.canvas.layer2); nicholas@2809: canvasDiv.appendChild(this.canvas.layer3); nicholas@2809: canvasDiv.appendChild(this.canvas.layer4); nicholas@2809: canvasHolder.appendChild(canvasDiv); nicholas@2481: this.canvas.layer1.addEventListener("mousemove", this.canvas); nicholas@2481: this.canvas.layer1.addEventListener("mouseleave", this.canvas); nicholas@2481: this.canvas.layer1.addEventListener("click", this.canvas); nicholas@2481: nicholas@2809: if (audioObject.specification.image) { nicholas@2809: canvasDiv.style.width = "80%"; nicholas@2809: var image = document.createElement("img"); nicholas@2809: image.src = audioObject.specification.image; nicholas@2809: image.className = "timeline-element-image"; nicholas@2809: canvasHolder.appendChild(image); nicholas@2809: } else { nicholas@2809: canvasDiv.style.width = "100%"; nicholas@2809: } nicholas@2809: nicholas@2479: var canvasIntervalID = null; nicholas@2481: nicholas@2479: this.playButton = { nicholas@2479: parent: this, nicholas@2479: DOM: document.createElement("button"), nicholas@2481: handleEvent: function (event) { nicholas@2479: var id = this.parent.parent.id; nicholas@2479: var str = this.DOM.textContent; nicholas@2479: if (str == "Play") { nicholas@2479: audioEngineContext.play(id); nicholas@2479: } else if (str == "Stop") { nicholas@2479: audioEngineContext.stop(); nicholas@2479: } nicholas@2479: } nicholas@2702: }; nicholas@2481: this.playButton.DOM.addEventListener("click", this.playButton); nicholas@2479: this.playButton.DOM.className = "timeline-button timeline-button-disabled"; nicholas@2479: this.playButton.DOM.disabled = true; nicholas@2479: this.playButton.DOM.textContent = "Wait"; nicholas@2481: nicholas@2479: buttonHolder.appendChild(this.playButton.DOM); nicholas@2481: nicholas@2481: this.resize = function () { nicholas@2808: this.canvas.resize(); nicholas@2702: }; nicholas@2481: nicholas@2481: this.enable = function () { nicholas@2481: // This is used to tell the interface object that playback of this node is ready nicholas@2481: this.canvas.layer1.addEventListener("click", this.canvas); nicholas@2479: this.canvas.layer1.className = "timeline-element-canvas canvas-layer1"; nicholas@2479: this.playButton.DOM.className = "timeline-button timeline-button-play"; nicholas@2479: this.playButton.DOM.textContent = "Play"; nicholas@2479: this.playButton.DOM.disabled = false; nicholas@2481: nicholas@2479: this.canvas.drawWaveform(); nicholas@2481: }; nicholas@2481: this.updateLoading = function (progress) { nicholas@2481: // progress is a value from 0 to 100 indicating the current download state of media files nicholas@2479: progress = String(progress); nicholas@2481: progress = progress.substr(0, 5); nicholas@2481: this.playButton.DOM.textContent = "Loading: " + progress + '%'; nicholas@2481: }; nicholas@2481: this.startPlayback = function () { nicholas@2479: // Called when playback has begun n@2890: var animate = function () { n@2890: this.canvas.drawTicker.call(this.canvas); n@2890: if (this.playButton.DOM.textContent == "Stop") { n@2890: window.requestAnimationFrame(animate); n@2890: } n@2890: }.bind(this); nicholas@2479: this.playButton.DOM.textContent = "Stop"; nicholas@2726: interfaceContext.commentBoxes.highlightById(audioObject.id); n@2890: canvasIntervalID = window.requestAnimationFrame(animate); nicholas@2479: }; nicholas@2481: this.stopPlayback = function () { nicholas@2479: // Called when playback has stopped. This gets called even if playback never started! nicholas@2479: window.clearInterval(canvasIntervalID); nicholas@2479: this.canvas.clearCanvas(this.canvas.layer2); nicholas@2479: this.playButton.DOM.textContent = "Play"; nicholas@2726: var box = interfaceContext.commentBoxes.boxes.find(function (a) { nicholas@2726: return a.id === audioObject.id; nicholas@2726: }); nicholas@2726: if (box) { nicholas@2726: box.highlight(false); nicholas@2726: } nicholas@2479: }; nicholas@2481: this.getValue = function () { nicholas@2481: // Return the current value of the object. If there is no value, return 0 nicholas@2479: return 0; nicholas@2481: }; nicholas@2481: this.getPresentedId = function () { nicholas@2481: // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale nicholas@2479: return labelSpan.textContent; nicholas@2481: }; nicholas@2481: this.canMove = function () { nicholas@2481: // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale. nicholas@2481: // These are checked primarily if the interface check option 'fragmentMoved' is enabled. nicholas@2479: return false; nicholas@2481: }; nicholas@2481: this.exportXMLDOM = function (audioObject) { nicholas@2481: // Called by the audioObject holding this element to export the interface node. nicholas@2481: // If there is no value node (such as outside reference), return null nicholas@2481: // If there are multiple value nodes (such as multiple scale / 2D scales), return an array of nodes with each value node having an 'interfaceName' attribute nicholas@2481: // Use storage.document.createElement('value'); to generate the XML node. nicholas@2481: return null; nicholas@2481: }; nicholas@2481: this.error = function () { nicholas@2479: // If there is an error with the audioObject, this will be called to indicate a failure nicholas@2702: }; nicholas@2702: } nicholas@2479: nicholas@2481: function resizeWindow(event) { nicholas@2481: // Called on every window resize event, use this to scale your page properly nicholas@2481: for (var i = 0; i < audioEngineContext.audioObjects.length; i++) { nicholas@2479: audioEngineContext.audioObjects[i].interfaceDOM.resize(); nicholas@2479: } nicholas@2479: } nicholas@2479: nicholas@2481: function buttonSubmitClick() { nicholas@2702: if (audioEngineContext.timer.testStarted === false) { nicholas@2481: interfaceContext.lightbox.post("Warning", 'You have not started the test! Please click play on a sample to begin the test!'); nicholas@2481: return; nicholas@2481: } nicholas@2724: var checks = testState.currentStateMap.interfaces[0].options, nicholas@2651: canContinue = true; nicholas@2825: if (interfaceContext.checkFragmentMinPlays() === false) { nicholas@2825: return; nicholas@2825: } nicholas@3035: if (interfaceContext.checkCommentQuestions() === false) { nicholas@3035: return; nicholas@3035: } nicholas@2481: for (var i = 0; i < checks.length; i++) { nicholas@2481: var checkState = true; nicholas@2481: if (checks[i].type == 'check') { nicholas@2481: switch (checks[i].name) { nicholas@2481: case 'fragmentPlayed': nicholas@2481: //Check if all fragments have been played n@2790: checkState = interfaceContext.checkAllPlayed(checks[i].errorMessage); nicholas@2481: break; nicholas@2481: case 'fragmentFullPlayback': nicholas@2481: //Check if all fragments have played to their full length n@2790: checkState = interfaceContext.checkFragmentsFullyPlayed(checks[i].errorMessage); nicholas@2481: break; nicholas@2481: case 'fragmentComments': n@2790: checkState = interfaceContext.checkAllCommented(checks[i].errorMessage); nicholas@2481: break; nicholas@2481: default: nicholas@2481: console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); nicholas@2481: break; nicholas@2481: } nicholas@2702: if (checkState === false) { nicholas@2569: canContinue = false; nicholas@2481: } nicholas@2481: } nicholas@2481: if (!canContinue) { nicholas@2481: return; nicholas@2481: } nicholas@2481: } nicholas@2481: nicholas@2481: if (canContinue) { nicholas@2481: if (audioEngineContext.status == 1) { nicholas@2481: var playback = document.getElementById('playback-button'); nicholas@2481: playback.click(); nicholas@2481: // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options nicholas@2481: } nicholas@2481: testState.advanceState(); nicholas@2481: } nicholas@2479: } nicholas@2479: nicholas@2481: function pageXMLSave(store, pageSpecification) { nicholas@2481: // MANDATORY nicholas@2481: // Saves a specific test page nicholas@2481: // You can use this space to add any extra nodes to your XML saves nicholas@2481: // Get the current information in store (remember to appendChild your data to it) nicholas@2481: // pageSpecification is the current page node configuration nicholas@2481: // To create new XML nodes, use storage.document.createElement(); nicholas@2481: nicholas@2481: for (var i = 0; i < audioEngineContext.audioObjects.length; i++) { nicholas@2480: var id = audioEngineContext.audioObjects[i].specification.id; nicholas@2480: var commentsList = audioEngineContext.audioObjects[i].interfaceDOM.comments.list; nicholas@2480: var root = audioEngineContext.audioObjects[i].storeDOM; nicholas@2481: for (var j = 0; j < commentsList.length; j++) { nicholas@2480: commentsList[j].buildXML(root); nicholas@2480: } nicholas@2480: } nicholas@2481: }