nickjillings@1683: /** nickjillings@1683: * ape.js nickjillings@1683: * Create the APE interface nickjillings@1683: */ nickjillings@1683: nickjillings@1683: // Once this is loaded and parsed, begin execution nickjillings@1683: loadInterface(projectXML); nickjillings@1683: nickjillings@1683: function loadInterface(xmlDoc) { nickjillings@1683: nickjillings@1697: // Get the dimensions of the screen available to the page nickjillings@1683: var width = window.innerWidth; nickjillings@1683: var height = window.innerHeight; nickjillings@1683: nickjillings@1683: // Set background to grey #ddd nickjillings@1683: document.getElementsByTagName('body')[0].style.backgroundColor = '#ddd'; nickjillings@1683: nickjillings@1683: // The injection point into the HTML page nickjillings@1683: var insertPoint = document.getElementById("topLevelBody"); nickjillings@1702: var testContent = document.createElement('div'); nickjillings@1702: testContent.id = 'testContent'; nickjillings@1683: nickjillings@1688: nickjillings@1683: // Decode parts of the xmlDoc that are needed nickjillings@1683: // xmlDoc MUST already be parsed by jQuery! nickjillings@1683: var xmlSetup = xmlDoc.find('setup'); nickjillings@1683: // Should put in an error function here incase of malprocessed or malformed XML nickjillings@1683: nickjillings@1683: // Create the top div for the Title element nickjillings@1683: var titleAttr = xmlSetup[0].attributes['title']; nickjillings@1683: var title = document.createElement('div'); nickjillings@1683: title.className = "title"; nickjillings@1683: title.align = "center"; nickjillings@1683: var titleSpan = document.createElement('span'); nickjillings@1683: nickjillings@1683: // Set title to that defined in XML, else set to default nickjillings@1683: if (titleAttr != undefined) { nickjillings@1705: titleSpan.innerHTML = titleAttr.value; nickjillings@1683: } else { nickjillings@1705: titleSpan.innerHTML = 'APE Tool'; nickjillings@1683: } nickjillings@1683: // Insert the titleSpan element into the title div element. nickjillings@1683: title.appendChild(titleSpan); nickjillings@1683: nickjillings@1688: // Store the return URL path in global projectReturn nickjillings@1688: projectReturn = xmlSetup[0].attributes['projectReturn'].value; nickjillings@1688: nickjillings@1688: // Create Interface buttons! nickjillings@1688: var interfaceButtons = document.createElement('div'); nickjillings@1688: interfaceButtons.id = 'interface-buttons'; nickjillings@1688: nickjillings@1688: // MANUAL DOWNLOAD POINT nickjillings@1688: // If project return is null, this MUST be specified as the location to create the download link nickjillings@1688: var downloadPoint = document.createElement('div'); nickjillings@1688: downloadPoint.id = 'download-point'; nickjillings@1688: nickjillings@1688: // Create playback start/stop points nickjillings@1688: var playback = document.createElement("button"); nickjillings@1705: playback.innerHTML = 'Start'; nickjillings@1697: // onclick function. Check if it is playing or not, call the correct function in the nickjillings@1697: // audioEngine, change the button text to reflect the next state. nickjillings@1688: playback.onclick = function() { nickjillings@1688: if (audioEngineContext.status == 0) { nickjillings@1688: audioEngineContext.play(); nickjillings@1705: this.innerHTML = 'Stop'; nickjillings@1688: } else { nickjillings@1688: audioEngineContext.stop(); nickjillings@1705: this.innerHTML = 'Start'; nickjillings@1688: } nickjillings@1697: }; nickjillings@1688: // Create Submit (save) button nickjillings@1688: var submit = document.createElement("button"); nickjillings@1705: submit.innerHTML = 'Submit'; nickjillings@1688: submit.onclick = function() { nickjillings@1696: // TODO: Update this for postTest tags nickjillings@1688: createProjectSave(projectReturn) nickjillings@1697: }; nickjillings@1697: // Append the interface buttons into the interfaceButtons object. nickjillings@1688: interfaceButtons.appendChild(playback); nickjillings@1688: interfaceButtons.appendChild(submit); nickjillings@1688: interfaceButtons.appendChild(downloadPoint); nickjillings@1688: nickjillings@1683: // Now create the slider and HTML5 canvas boxes nickjillings@1683: nickjillings@1697: // Create the div box to center align nickjillings@1683: var sliderBox = document.createElement('div'); nickjillings@1683: sliderBox.className = 'sliderCanvasDiv'; nickjillings@1697: sliderBox.id = 'sliderCanvasHolder'; nickjillings@1683: sliderBox.align = 'center'; nickjillings@1683: nickjillings@1697: // Create the slider box to hold the slider elements nickjillings@1686: var canvas = document.createElement('div'); nickjillings@1683: canvas.id = 'slider'; nickjillings@1697: // Must have a known EXACT width, as this is used later to determine the ratings nickjillings@1686: canvas.style.width = width - 100 +"px"; nickjillings@1686: canvas.style.height = 150 + "px"; nickjillings@1697: canvas.style.marginBottom = "25px"; nickjillings@1683: canvas.style.backgroundColor = '#eee'; nickjillings@1686: canvas.align = "left"; nickjillings@1683: sliderBox.appendChild(canvas); nickjillings@1697: nickjillings@1697: // Global parent for the comment boxes on the page nickjillings@1684: var feedbackHolder = document.createElement('div'); nickjillings@1697: // Find the parent audioHolder object. nickjillings@1697: var audioHolder = xmlDoc.find('audioHolder'); nickjillings@1697: audioHolder = audioHolder[0]; // Remove from one field array nickjillings@1697: // Extract the hostURL attribute. If not set, create an empty string. nickjillings@1697: var hostURL = audioHolder.attributes['hostURL']; nickjillings@1688: if (hostURL == undefined) { nickjillings@1688: hostURL = ""; nickjillings@1688: } else { nickjillings@1688: hostURL = hostURL.value; nickjillings@1688: } nickjillings@1697: // Extract the sampleRate. If set, convert the string to a Number. nickjillings@1697: var hostFs = audioHolder.attributes['sampleRate']; nickjillings@1696: if (hostFs != undefined) { nickjillings@1696: hostFs = Number(hostFs.value); nickjillings@1688: } nickjillings@1688: nickjillings@1688: /// CHECK FOR SAMPLE RATE COMPATIBILITY nickjillings@1696: if (hostFs != undefined) { nickjillings@1688: if (Number(hostFs) != audioContext.sampleRate) { nickjillings@1688: var errStr = 'Sample rates do not match! Requested '+Number(hostFs)+', got '+audioContext.sampleRate+'. Please set the sample rate to match before completing this test.'; nickjillings@1688: alert(errStr); nickjillings@1688: return; nickjillings@1688: } nickjillings@1688: } nickjillings@1697: // Find all the audioElements from the audioHolder nickjillings@1697: var audioElements = $(audioHolder).find('audioElements'); nickjillings@1697: audioElements.each(function(index,element){ nickjillings@1688: // Find URL of track nickjillings@1697: // In this jQuery loop, variable 'this' holds the current audioElement. nickjillings@1697: nickjillings@1697: // Now load each audio sample. First create the new track by passing the full URL nickjillings@1688: var trackURL = hostURL + this.attributes['url'].value; nickjillings@1688: audioEngineContext.newTrack(trackURL); nickjillings@1697: // Create document objects to hold the comment boxes nickjillings@1697: var trackComment = document.createElement('div'); nickjillings@1697: // Create a string next to each comment asking for a comment nickjillings@1697: var trackString = document.createElement('span'); nickjillings@1705: trackString.innerHTML = 'Comment on track '+index; nickjillings@1697: // Create the HTML5 comment box 'textarea' nickjillings@1697: var trackCommentBox = document.createElement('textarea'); nickjillings@1697: trackCommentBox.rows = '4'; nickjillings@1697: trackCommentBox.cols = '100'; nickjillings@1697: trackCommentBox.name = 'trackComment'+index; nickjillings@1697: trackCommentBox.className = 'trackComment'; nickjillings@1697: // Add to the holder. nickjillings@1697: trackComment.appendChild(trackString); nickjillings@1697: trackComment.appendChild(trackCommentBox); nickjillings@1697: feedbackHolder.appendChild(trackComment); nickjillings@1697: nickjillings@1686: // Create a slider per track nickjillings@1686: nickjillings@1686: var trackSliderObj = document.createElement('div'); nickjillings@1686: trackSliderObj.className = 'track-slider'; nickjillings@1686: trackSliderObj.id = 'track-slider-'+index; nickjillings@1686: trackSliderObj.style.position = 'absolute'; nickjillings@1686: // Distribute it randomnly nickjillings@1686: var w = window.innerWidth - 100; nickjillings@1686: w = Math.random()*w; nickjillings@1686: trackSliderObj.style.left = Math.floor(w)+50+'px'; nickjillings@1686: trackSliderObj.style.height = "150px"; nickjillings@1686: trackSliderObj.style.width = "10px"; nickjillings@1686: trackSliderObj.style.backgroundColor = 'rgb(100,200,100)'; nickjillings@1686: trackSliderObj.innerHTML = ''+index+''; nickjillings@1686: trackSliderObj.style.float = "left"; nickjillings@1686: trackSliderObj.draggable = true; nickjillings@1686: trackSliderObj.ondragend = dragEnd; nickjillings@1689: nickjillings@1689: // Onclick, switch playback to that track nickjillings@1689: trackSliderObj.onclick = function() { nickjillings@1689: // Get the track ID from the object ID nickjillings@1689: var id = Number(this.id.substr(13,2)); // Maximum theoretical tracks is 99! nickjillings@1689: audioEngineContext.selectedTrack(id); nickjillings@1696: }; nickjillings@1689: nickjillings@1686: canvas.appendChild(trackSliderObj); nickjillings@1696: }); nickjillings@1684: nickjillings@1683: nickjillings@1702: // Create pre and post test questions nickjillings@1702: nickjillings@1683: // Inject into HTML nickjillings@1683: insertPoint.innerHTML = null; // Clear the current schema nickjillings@1702: testContent.appendChild(title); // Insert the title nickjillings@1702: testContent.appendChild(interfaceButtons); nickjillings@1702: testContent.appendChild(sliderBox); nickjillings@1702: testContent.appendChild(feedbackHolder); nickjillings@1702: insertPoint.appendChild(testContent); nickjillings@1702: nickjillings@1702: var preTest = xmlDoc.find('PreTest'); nickjillings@1702: var postTest = xmlDoc.find('PostTest'); nickjillings@1702: preTest = preTest[0]; nickjillings@1702: postTest = postTest[0]; nickjillings@1702: if (preTest != undefined || postTest != undefined) nickjillings@1702: { nickjillings@1702: testContent.style.zIndex = 1; nickjillings@1702: var blank = document.createElement('div'); nickjillings@1702: blank.id = 'testHalt'; nickjillings@1702: blank.style.zIndex = 2; nickjillings@1702: blank.style.width = window.innerWidth + 'px'; nickjillings@1702: blank.style.height = window.innerHeight + 'px'; nickjillings@1702: blank.style.position = 'absolute'; nickjillings@1702: blank.style.top = '0'; nickjillings@1702: blank.style.left = '0'; nickjillings@1702: insertPoint.appendChild(blank); nickjillings@1702: } nickjillings@1702: nickjillings@1702: // Create Pre-Test Box nickjillings@1702: if (preTest != undefined && preTest.children.length >= 1) nickjillings@1702: { nickjillings@1702: nickjillings@1702: var preTestHolder = document.createElement('div'); nickjillings@1702: preTestHolder.id = 'preTestHolder'; nickjillings@1702: preTestHolder.style.zIndex = 2; nickjillings@1702: preTestHolder.style.width = '500px'; nickjillings@1702: preTestHolder.style.height = '250px'; nickjillings@1702: preTestHolder.style.backgroundColor = '#fff'; nickjillings@1702: preTestHolder.style.position = 'absolute'; nickjillings@1702: preTestHolder.style.left = (window.innerWidth/2)-250 + 'px'; nickjillings@1702: preTestHolder.style.top = (window.innerHeight/2)-125 + 'px'; nickjillings@1702: // Parse the first box nickjillings@1702: var preTestOption = document.createElement('div'); nickjillings@1702: preTestOption.id = 'preTest'; nickjillings@1702: preTestOption.style.marginTop = '25px'; nickjillings@1702: preTestOption.align = "center"; nickjillings@1702: var child = preTest.children[0]; nickjillings@1702: if (child.nodeName == 'statement') nickjillings@1702: { nickjillings@1702: preTestOption.innerHTML = ''+child.innerHTML+''; nickjillings@1702: } else if (child.nodeName == 'question') nickjillings@1702: { nickjillings@1703: var questionId = child.attributes['id'].value; nickjillings@1702: var textHold = document.createElement('span'); nickjillings@1702: textHold.innerHTML = child.innerHTML; nickjillings@1703: textHold.id = questionId + 'response'; nickjillings@1702: var textEnter = document.createElement('textarea'); nickjillings@1702: preTestOption.appendChild(textHold); nickjillings@1702: preTestOption.appendChild(textEnter); nickjillings@1702: } nickjillings@1702: var nextButton = document.createElement('button'); nickjillings@1702: nextButton.id = 'preTestNext'; nickjillings@1702: nextButton.value = '1'; nickjillings@1702: nextButton.innerHTML = 'next'; nickjillings@1702: nextButton.style.position = 'relative'; nickjillings@1702: nextButton.style.left = '450px'; nickjillings@1702: nextButton.style.top = '175px'; nickjillings@1702: nextButton.onclick = function() { nickjillings@1702: // Need to find and parse preTest again! nickjillings@1702: var preTest = projectXML.find('PreTest')[0]; nickjillings@1703: // Check if current state is a question! nickjillings@1703: if (preTest.children[this.value-1].nodeName == 'question') { nickjillings@1703: var questionId = preTest.children[this.value-1].attributes['id'].value; nickjillings@1703: var questionHold = document.createElement('comment'); nickjillings@1703: var questionResponse = document.getElementById(questionId + 'response'); nickjillings@1703: questionHold.id = questionId; nickjillings@1703: questionHold.innerHTML = questionResponse.value; nickjillings@1703: preTestQuestions.appendChild(questionHold); nickjillings@1703: } nickjillings@1702: if (this.value < preTest.children.length) nickjillings@1702: { nickjillings@1702: // More to process nickjillings@1702: var child = preTest.children[this.value]; nickjillings@1702: if (child.nodeName == 'statement') nickjillings@1702: { nickjillings@1702: preTestOption.innerHTML = ''+child.innerHTML+''; nickjillings@1702: } else if (child.nodeName == 'question') nickjillings@1702: { nickjillings@1702: var textHold = document.createElement('span'); nickjillings@1702: textHold.innerHTML = child.innerHTML; nickjillings@1702: var textEnter = document.createElement('textarea'); nickjillings@1703: textEnter.id = child.attributes['id'].value + 'response'; nickjillings@1703: preTestOption.innerHTML = null; nickjillings@1702: preTestOption.appendChild(textHold); nickjillings@1702: preTestOption.appendChild(textEnter); nickjillings@1702: } nickjillings@1702: } else { nickjillings@1702: // Time to clear nickjillings@1702: preTestHolder.style.zIndex = -1; nickjillings@1702: preTestHolder.style.visibility = 'hidden'; nickjillings@1702: var blank = document.getElementById('testHalt'); nickjillings@1702: blank.style.zIndex = -2; nickjillings@1702: blank.style.visibility = 'hidden'; nickjillings@1702: } nickjillings@1702: this.value++; nickjillings@1702: }; nickjillings@1702: nickjillings@1702: preTestHolder.appendChild(preTestOption); nickjillings@1702: preTestHolder.appendChild(nextButton); nickjillings@1702: insertPoint.appendChild(preTestHolder); nickjillings@1702: } nickjillings@1702: nickjillings@1683: } nickjillings@1686: nickjillings@1686: function dragEnd(ev) { nickjillings@1686: // Function call when a div has been dropped nickjillings@1686: if (ev.x >= 50 && ev.x < window.innerWidth-50) { nickjillings@1686: this.style.left = (ev.x)+'px'; nickjillings@1686: } else { nickjillings@1686: if (ev.x<50) { nickjillings@1686: this.style.left = '50px'; nickjillings@1686: } else { nickjillings@1686: this.style.left = window.innerWidth-50 + 'px'; nickjillings@1686: } nickjillings@1686: } nickjillings@1686: } nickjillings@1688: nickjillings@1688: // Only other global function which must be defined in the interface class. Determines how to create the XML document. nickjillings@1688: function interfaceXMLSave(){ nickjillings@1688: // Create the XML string to be exported with results nickjillings@1688: var xmlDoc = document.createElement("BrowserEvaluationResult"); nickjillings@1688: var trackSliderObjects = document.getElementsByClassName('track-slider'); nickjillings@1688: var commentObjects = document.getElementsByClassName('trackComment'); nickjillings@1688: var rateMin = 50; nickjillings@1688: var rateMax = window.innerWidth-50; nickjillings@1688: for (var i=0; i