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