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@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@1683: titleSpan.innerText = titleAttr.value; nickjillings@1683: } else { nickjillings@1683: titleSpan.innerText = '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@1688: playback.innerText = '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@1688: this.innerText = 'Stop'; nickjillings@1688: } else { nickjillings@1688: audioEngineContext.stop(); nickjillings@1688: this.innerText = 'Start'; nickjillings@1688: } nickjillings@1697: }; nickjillings@1688: // Create Submit (save) button nickjillings@1688: var submit = document.createElement("button"); nickjillings@1688: submit.innerText = '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@1697: trackString.innerText = '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@1683: // Inject into HTML nickjillings@1683: insertPoint.innerHTML = null; // Clear the current schema nickjillings@1683: insertPoint.appendChild(title); // Insert the title nickjillings@1688: insertPoint.appendChild(interfaceButtons); nickjillings@1683: insertPoint.appendChild(sliderBox); nickjillings@1684: insertPoint.appendChild(feedbackHolder); 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