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