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