annotate ape.js @ 1701:86bad9132601

Added cross-browser support for webkit / non-webkit audioContext. Confirmed Chrome & Safari Support. Firefox: does not support innerText or dragging!
author Nicholas Jillings <nickjillings@users.noreply.github.com>
date Wed, 08 Apr 2015 18:18:17 +0100
parents 4177fb1da6f8
children 542c613e31d6
rev   line source
nickjillings@1683 1 /**
nickjillings@1683 2 * ape.js
nickjillings@1683 3 * Create the APE interface
nickjillings@1683 4 */
nickjillings@1683 5
nickjillings@1683 6 // Once this is loaded and parsed, begin execution
nickjillings@1683 7 loadInterface(projectXML);
nickjillings@1683 8
nickjillings@1683 9 function loadInterface(xmlDoc) {
nickjillings@1683 10
nickjillings@1697 11 // Get the dimensions of the screen available to the page
nickjillings@1683 12 var width = window.innerWidth;
nickjillings@1683 13 var height = window.innerHeight;
nickjillings@1683 14
nickjillings@1683 15 // Set background to grey #ddd
nickjillings@1683 16 document.getElementsByTagName('body')[0].style.backgroundColor = '#ddd';
nickjillings@1683 17
nickjillings@1683 18 // The injection point into the HTML page
nickjillings@1683 19 var insertPoint = document.getElementById("topLevelBody");
nickjillings@1683 20
nickjillings@1688 21
nickjillings@1683 22 // Decode parts of the xmlDoc that are needed
nickjillings@1683 23 // xmlDoc MUST already be parsed by jQuery!
nickjillings@1683 24 var xmlSetup = xmlDoc.find('setup');
nickjillings@1683 25 // Should put in an error function here incase of malprocessed or malformed XML
nickjillings@1683 26
nickjillings@1683 27 // Create the top div for the Title element
nickjillings@1683 28 var titleAttr = xmlSetup[0].attributes['title'];
nickjillings@1683 29 var title = document.createElement('div');
nickjillings@1683 30 title.className = "title";
nickjillings@1683 31 title.align = "center";
nickjillings@1683 32 var titleSpan = document.createElement('span');
nickjillings@1683 33
nickjillings@1683 34 // Set title to that defined in XML, else set to default
nickjillings@1683 35 if (titleAttr != undefined) {
nickjillings@1683 36 titleSpan.innerText = titleAttr.value;
nickjillings@1683 37 } else {
nickjillings@1683 38 titleSpan.innerText = 'APE Tool';
nickjillings@1683 39 }
nickjillings@1683 40 // Insert the titleSpan element into the title div element.
nickjillings@1683 41 title.appendChild(titleSpan);
nickjillings@1683 42
nickjillings@1688 43 // Store the return URL path in global projectReturn
nickjillings@1688 44 projectReturn = xmlSetup[0].attributes['projectReturn'].value;
nickjillings@1688 45
nickjillings@1688 46 // Create Interface buttons!
nickjillings@1688 47 var interfaceButtons = document.createElement('div');
nickjillings@1688 48 interfaceButtons.id = 'interface-buttons';
nickjillings@1688 49
nickjillings@1688 50 // MANUAL DOWNLOAD POINT
nickjillings@1688 51 // If project return is null, this MUST be specified as the location to create the download link
nickjillings@1688 52 var downloadPoint = document.createElement('div');
nickjillings@1688 53 downloadPoint.id = 'download-point';
nickjillings@1688 54
nickjillings@1688 55 // Create playback start/stop points
nickjillings@1688 56 var playback = document.createElement("button");
nickjillings@1688 57 playback.innerText = 'Start';
nickjillings@1697 58 // onclick function. Check if it is playing or not, call the correct function in the
nickjillings@1697 59 // audioEngine, change the button text to reflect the next state.
nickjillings@1688 60 playback.onclick = function() {
nickjillings@1688 61 if (audioEngineContext.status == 0) {
nickjillings@1688 62 audioEngineContext.play();
nickjillings@1688 63 this.innerText = 'Stop';
nickjillings@1688 64 } else {
nickjillings@1688 65 audioEngineContext.stop();
nickjillings@1688 66 this.innerText = 'Start';
nickjillings@1688 67 }
nickjillings@1697 68 };
nickjillings@1688 69 // Create Submit (save) button
nickjillings@1688 70 var submit = document.createElement("button");
nickjillings@1688 71 submit.innerText = 'Submit';
nickjillings@1688 72 submit.onclick = function() {
nickjillings@1696 73 // TODO: Update this for postTest tags
nickjillings@1688 74 createProjectSave(projectReturn)
nickjillings@1697 75 };
nickjillings@1697 76 // Append the interface buttons into the interfaceButtons object.
nickjillings@1688 77 interfaceButtons.appendChild(playback);
nickjillings@1688 78 interfaceButtons.appendChild(submit);
nickjillings@1688 79 interfaceButtons.appendChild(downloadPoint);
nickjillings@1688 80
nickjillings@1683 81 // Now create the slider and HTML5 canvas boxes
nickjillings@1683 82
nickjillings@1697 83 // Create the div box to center align
nickjillings@1683 84 var sliderBox = document.createElement('div');
nickjillings@1683 85 sliderBox.className = 'sliderCanvasDiv';
nickjillings@1697 86 sliderBox.id = 'sliderCanvasHolder';
nickjillings@1683 87 sliderBox.align = 'center';
nickjillings@1683 88
nickjillings@1697 89 // Create the slider box to hold the slider elements
nickjillings@1686 90 var canvas = document.createElement('div');
nickjillings@1683 91 canvas.id = 'slider';
nickjillings@1697 92 // Must have a known EXACT width, as this is used later to determine the ratings
nickjillings@1686 93 canvas.style.width = width - 100 +"px";
nickjillings@1686 94 canvas.style.height = 150 + "px";
nickjillings@1697 95 canvas.style.marginBottom = "25px";
nickjillings@1683 96 canvas.style.backgroundColor = '#eee';
nickjillings@1686 97 canvas.align = "left";
nickjillings@1683 98 sliderBox.appendChild(canvas);
nickjillings@1697 99
nickjillings@1697 100 // Global parent for the comment boxes on the page
nickjillings@1684 101 var feedbackHolder = document.createElement('div');
nickjillings@1697 102 // Find the parent audioHolder object.
nickjillings@1697 103 var audioHolder = xmlDoc.find('audioHolder');
nickjillings@1697 104 audioHolder = audioHolder[0]; // Remove from one field array
nickjillings@1697 105 // Extract the hostURL attribute. If not set, create an empty string.
nickjillings@1697 106 var hostURL = audioHolder.attributes['hostURL'];
nickjillings@1688 107 if (hostURL == undefined) {
nickjillings@1688 108 hostURL = "";
nickjillings@1688 109 } else {
nickjillings@1688 110 hostURL = hostURL.value;
nickjillings@1688 111 }
nickjillings@1697 112 // Extract the sampleRate. If set, convert the string to a Number.
nickjillings@1697 113 var hostFs = audioHolder.attributes['sampleRate'];
nickjillings@1696 114 if (hostFs != undefined) {
nickjillings@1696 115 hostFs = Number(hostFs.value);
nickjillings@1688 116 }
nickjillings@1688 117
nickjillings@1688 118 /// CHECK FOR SAMPLE RATE COMPATIBILITY
nickjillings@1696 119 if (hostFs != undefined) {
nickjillings@1688 120 if (Number(hostFs) != audioContext.sampleRate) {
nickjillings@1688 121 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 122 alert(errStr);
nickjillings@1688 123 return;
nickjillings@1688 124 }
nickjillings@1688 125 }
nickjillings@1697 126 // Find all the audioElements from the audioHolder
nickjillings@1697 127 var audioElements = $(audioHolder).find('audioElements');
nickjillings@1697 128 audioElements.each(function(index,element){
nickjillings@1688 129 // Find URL of track
nickjillings@1697 130 // In this jQuery loop, variable 'this' holds the current audioElement.
nickjillings@1697 131
nickjillings@1697 132 // Now load each audio sample. First create the new track by passing the full URL
nickjillings@1688 133 var trackURL = hostURL + this.attributes['url'].value;
nickjillings@1688 134 audioEngineContext.newTrack(trackURL);
nickjillings@1697 135 // Create document objects to hold the comment boxes
nickjillings@1697 136 var trackComment = document.createElement('div');
nickjillings@1697 137 // Create a string next to each comment asking for a comment
nickjillings@1697 138 var trackString = document.createElement('span');
nickjillings@1697 139 trackString.innerText = 'Comment on track '+index;
nickjillings@1697 140 // Create the HTML5 comment box 'textarea'
nickjillings@1697 141 var trackCommentBox = document.createElement('textarea');
nickjillings@1697 142 trackCommentBox.rows = '4';
nickjillings@1697 143 trackCommentBox.cols = '100';
nickjillings@1697 144 trackCommentBox.name = 'trackComment'+index;
nickjillings@1697 145 trackCommentBox.className = 'trackComment';
nickjillings@1697 146 // Add to the holder.
nickjillings@1697 147 trackComment.appendChild(trackString);
nickjillings@1697 148 trackComment.appendChild(trackCommentBox);
nickjillings@1697 149 feedbackHolder.appendChild(trackComment);
nickjillings@1697 150
nickjillings@1686 151 // Create a slider per track
nickjillings@1686 152
nickjillings@1686 153 var trackSliderObj = document.createElement('div');
nickjillings@1686 154 trackSliderObj.className = 'track-slider';
nickjillings@1686 155 trackSliderObj.id = 'track-slider-'+index;
nickjillings@1686 156 trackSliderObj.style.position = 'absolute';
nickjillings@1686 157 // Distribute it randomnly
nickjillings@1686 158 var w = window.innerWidth - 100;
nickjillings@1686 159 w = Math.random()*w;
nickjillings@1686 160 trackSliderObj.style.left = Math.floor(w)+50+'px';
nickjillings@1686 161 trackSliderObj.style.height = "150px";
nickjillings@1686 162 trackSliderObj.style.width = "10px";
nickjillings@1686 163 trackSliderObj.style.backgroundColor = 'rgb(100,200,100)';
nickjillings@1686 164 trackSliderObj.innerHTML = '<span>'+index+'</span>';
nickjillings@1686 165 trackSliderObj.style.float = "left";
nickjillings@1686 166 trackSliderObj.draggable = true;
nickjillings@1686 167 trackSliderObj.ondragend = dragEnd;
nickjillings@1689 168
nickjillings@1689 169 // Onclick, switch playback to that track
nickjillings@1689 170 trackSliderObj.onclick = function() {
nickjillings@1689 171 // Get the track ID from the object ID
nickjillings@1689 172 var id = Number(this.id.substr(13,2)); // Maximum theoretical tracks is 99!
nickjillings@1689 173 audioEngineContext.selectedTrack(id);
nickjillings@1696 174 };
nickjillings@1689 175
nickjillings@1686 176 canvas.appendChild(trackSliderObj);
nickjillings@1696 177 });
nickjillings@1684 178
nickjillings@1683 179
nickjillings@1683 180 // Inject into HTML
nickjillings@1683 181 insertPoint.innerHTML = null; // Clear the current schema
nickjillings@1683 182 insertPoint.appendChild(title); // Insert the title
nickjillings@1688 183 insertPoint.appendChild(interfaceButtons);
nickjillings@1683 184 insertPoint.appendChild(sliderBox);
nickjillings@1684 185 insertPoint.appendChild(feedbackHolder);
nickjillings@1683 186 }
nickjillings@1686 187
nickjillings@1686 188 function dragEnd(ev) {
nickjillings@1686 189 // Function call when a div has been dropped
nickjillings@1686 190 if (ev.x >= 50 && ev.x < window.innerWidth-50) {
nickjillings@1686 191 this.style.left = (ev.x)+'px';
nickjillings@1686 192 } else {
nickjillings@1686 193 if (ev.x<50) {
nickjillings@1686 194 this.style.left = '50px';
nickjillings@1686 195 } else {
nickjillings@1686 196 this.style.left = window.innerWidth-50 + 'px';
nickjillings@1686 197 }
nickjillings@1686 198 }
nickjillings@1686 199 }
nickjillings@1688 200
nickjillings@1688 201 // Only other global function which must be defined in the interface class. Determines how to create the XML document.
nickjillings@1688 202 function interfaceXMLSave(){
nickjillings@1688 203 // Create the XML string to be exported with results
nickjillings@1688 204 var xmlDoc = document.createElement("BrowserEvaluationResult");
nickjillings@1688 205 var trackSliderObjects = document.getElementsByClassName('track-slider');
nickjillings@1688 206 var commentObjects = document.getElementsByClassName('trackComment');
nickjillings@1688 207 var rateMin = 50;
nickjillings@1688 208 var rateMax = window.innerWidth-50;
nickjillings@1688 209 for (var i=0; i<trackSliderObjects.length; i++)
nickjillings@1688 210 {
nickjillings@1688 211 var trackObj = document.createElement("Track");
nickjillings@1688 212 trackObj.id = i;
nickjillings@1688 213 var slider = document.createElement("Rating");
nickjillings@1688 214 var rate = Number(trackSliderObjects[i].style.left.substr(0,trackSliderObjects[i].style.left.length-2));
nickjillings@1688 215 rate = (rate-rateMin)/rateMax;
nickjillings@1688 216 slider.innerText = Math.floor(rate*100);
nickjillings@1688 217 var comment = document.createElement("Comment");
nickjillings@1688 218 comment.innerText = commentObjects[i].value;
nickjillings@1688 219 trackObj.appendChild(slider);
nickjillings@1688 220 trackObj.appendChild(comment);
nickjillings@1688 221 xmlDoc.appendChild(trackObj);
nickjillings@1688 222 }
nickjillings@1688 223
nickjillings@1688 224 return xmlDoc;
nickjillings@1688 225 }
nickjillings@1688 226