annotate ape.js @ 1704:536818090e6a

Updated results XML generator to match documentation syntax.
author Nicholas Jillings <nickjillings@users.noreply.github.com>
date Thu, 09 Apr 2015 10:59:53 +0100
parents 93eaa894cc97
children d7f85b8bb851
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@1702 20 var testContent = document.createElement('div');
nickjillings@1702 21 testContent.id = 'testContent';
nickjillings@1683 22
nickjillings@1688 23
nickjillings@1683 24 // Decode parts of the xmlDoc that are needed
nickjillings@1683 25 // xmlDoc MUST already be parsed by jQuery!
nickjillings@1683 26 var xmlSetup = xmlDoc.find('setup');
nickjillings@1683 27 // Should put in an error function here incase of malprocessed or malformed XML
nickjillings@1683 28
nickjillings@1683 29 // Create the top div for the Title element
nickjillings@1683 30 var titleAttr = xmlSetup[0].attributes['title'];
nickjillings@1683 31 var title = document.createElement('div');
nickjillings@1683 32 title.className = "title";
nickjillings@1683 33 title.align = "center";
nickjillings@1683 34 var titleSpan = document.createElement('span');
nickjillings@1683 35
nickjillings@1683 36 // Set title to that defined in XML, else set to default
nickjillings@1683 37 if (titleAttr != undefined) {
nickjillings@1683 38 titleSpan.innerText = titleAttr.value;
nickjillings@1683 39 } else {
nickjillings@1683 40 titleSpan.innerText = 'APE Tool';
nickjillings@1683 41 }
nickjillings@1683 42 // Insert the titleSpan element into the title div element.
nickjillings@1683 43 title.appendChild(titleSpan);
nickjillings@1683 44
nickjillings@1688 45 // Store the return URL path in global projectReturn
nickjillings@1688 46 projectReturn = xmlSetup[0].attributes['projectReturn'].value;
nickjillings@1688 47
nickjillings@1688 48 // Create Interface buttons!
nickjillings@1688 49 var interfaceButtons = document.createElement('div');
nickjillings@1688 50 interfaceButtons.id = 'interface-buttons';
nickjillings@1688 51
nickjillings@1688 52 // MANUAL DOWNLOAD POINT
nickjillings@1688 53 // If project return is null, this MUST be specified as the location to create the download link
nickjillings@1688 54 var downloadPoint = document.createElement('div');
nickjillings@1688 55 downloadPoint.id = 'download-point';
nickjillings@1688 56
nickjillings@1688 57 // Create playback start/stop points
nickjillings@1688 58 var playback = document.createElement("button");
nickjillings@1688 59 playback.innerText = 'Start';
nickjillings@1697 60 // onclick function. Check if it is playing or not, call the correct function in the
nickjillings@1697 61 // audioEngine, change the button text to reflect the next state.
nickjillings@1688 62 playback.onclick = function() {
nickjillings@1688 63 if (audioEngineContext.status == 0) {
nickjillings@1688 64 audioEngineContext.play();
nickjillings@1688 65 this.innerText = 'Stop';
nickjillings@1688 66 } else {
nickjillings@1688 67 audioEngineContext.stop();
nickjillings@1688 68 this.innerText = 'Start';
nickjillings@1688 69 }
nickjillings@1697 70 };
nickjillings@1688 71 // Create Submit (save) button
nickjillings@1688 72 var submit = document.createElement("button");
nickjillings@1688 73 submit.innerText = 'Submit';
nickjillings@1688 74 submit.onclick = function() {
nickjillings@1696 75 // TODO: Update this for postTest tags
nickjillings@1688 76 createProjectSave(projectReturn)
nickjillings@1697 77 };
nickjillings@1697 78 // Append the interface buttons into the interfaceButtons object.
nickjillings@1688 79 interfaceButtons.appendChild(playback);
nickjillings@1688 80 interfaceButtons.appendChild(submit);
nickjillings@1688 81 interfaceButtons.appendChild(downloadPoint);
nickjillings@1688 82
nickjillings@1683 83 // Now create the slider and HTML5 canvas boxes
nickjillings@1683 84
nickjillings@1697 85 // Create the div box to center align
nickjillings@1683 86 var sliderBox = document.createElement('div');
nickjillings@1683 87 sliderBox.className = 'sliderCanvasDiv';
nickjillings@1697 88 sliderBox.id = 'sliderCanvasHolder';
nickjillings@1683 89 sliderBox.align = 'center';
nickjillings@1683 90
nickjillings@1697 91 // Create the slider box to hold the slider elements
nickjillings@1686 92 var canvas = document.createElement('div');
nickjillings@1683 93 canvas.id = 'slider';
nickjillings@1697 94 // Must have a known EXACT width, as this is used later to determine the ratings
nickjillings@1686 95 canvas.style.width = width - 100 +"px";
nickjillings@1686 96 canvas.style.height = 150 + "px";
nickjillings@1697 97 canvas.style.marginBottom = "25px";
nickjillings@1683 98 canvas.style.backgroundColor = '#eee';
nickjillings@1686 99 canvas.align = "left";
nickjillings@1683 100 sliderBox.appendChild(canvas);
nickjillings@1697 101
nickjillings@1697 102 // Global parent for the comment boxes on the page
nickjillings@1684 103 var feedbackHolder = document.createElement('div');
nickjillings@1697 104 // Find the parent audioHolder object.
nickjillings@1697 105 var audioHolder = xmlDoc.find('audioHolder');
nickjillings@1697 106 audioHolder = audioHolder[0]; // Remove from one field array
nickjillings@1697 107 // Extract the hostURL attribute. If not set, create an empty string.
nickjillings@1697 108 var hostURL = audioHolder.attributes['hostURL'];
nickjillings@1688 109 if (hostURL == undefined) {
nickjillings@1688 110 hostURL = "";
nickjillings@1688 111 } else {
nickjillings@1688 112 hostURL = hostURL.value;
nickjillings@1688 113 }
nickjillings@1697 114 // Extract the sampleRate. If set, convert the string to a Number.
nickjillings@1697 115 var hostFs = audioHolder.attributes['sampleRate'];
nickjillings@1696 116 if (hostFs != undefined) {
nickjillings@1696 117 hostFs = Number(hostFs.value);
nickjillings@1688 118 }
nickjillings@1688 119
nickjillings@1688 120 /// CHECK FOR SAMPLE RATE COMPATIBILITY
nickjillings@1696 121 if (hostFs != undefined) {
nickjillings@1688 122 if (Number(hostFs) != audioContext.sampleRate) {
nickjillings@1688 123 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 124 alert(errStr);
nickjillings@1688 125 return;
nickjillings@1688 126 }
nickjillings@1688 127 }
nickjillings@1697 128 // Find all the audioElements from the audioHolder
nickjillings@1697 129 var audioElements = $(audioHolder).find('audioElements');
nickjillings@1697 130 audioElements.each(function(index,element){
nickjillings@1688 131 // Find URL of track
nickjillings@1697 132 // In this jQuery loop, variable 'this' holds the current audioElement.
nickjillings@1697 133
nickjillings@1697 134 // Now load each audio sample. First create the new track by passing the full URL
nickjillings@1688 135 var trackURL = hostURL + this.attributes['url'].value;
nickjillings@1688 136 audioEngineContext.newTrack(trackURL);
nickjillings@1697 137 // Create document objects to hold the comment boxes
nickjillings@1697 138 var trackComment = document.createElement('div');
nickjillings@1697 139 // Create a string next to each comment asking for a comment
nickjillings@1697 140 var trackString = document.createElement('span');
nickjillings@1697 141 trackString.innerText = 'Comment on track '+index;
nickjillings@1697 142 // Create the HTML5 comment box 'textarea'
nickjillings@1697 143 var trackCommentBox = document.createElement('textarea');
nickjillings@1697 144 trackCommentBox.rows = '4';
nickjillings@1697 145 trackCommentBox.cols = '100';
nickjillings@1697 146 trackCommentBox.name = 'trackComment'+index;
nickjillings@1697 147 trackCommentBox.className = 'trackComment';
nickjillings@1697 148 // Add to the holder.
nickjillings@1697 149 trackComment.appendChild(trackString);
nickjillings@1697 150 trackComment.appendChild(trackCommentBox);
nickjillings@1697 151 feedbackHolder.appendChild(trackComment);
nickjillings@1697 152
nickjillings@1686 153 // Create a slider per track
nickjillings@1686 154
nickjillings@1686 155 var trackSliderObj = document.createElement('div');
nickjillings@1686 156 trackSliderObj.className = 'track-slider';
nickjillings@1686 157 trackSliderObj.id = 'track-slider-'+index;
nickjillings@1686 158 trackSliderObj.style.position = 'absolute';
nickjillings@1686 159 // Distribute it randomnly
nickjillings@1686 160 var w = window.innerWidth - 100;
nickjillings@1686 161 w = Math.random()*w;
nickjillings@1686 162 trackSliderObj.style.left = Math.floor(w)+50+'px';
nickjillings@1686 163 trackSliderObj.style.height = "150px";
nickjillings@1686 164 trackSliderObj.style.width = "10px";
nickjillings@1686 165 trackSliderObj.style.backgroundColor = 'rgb(100,200,100)';
nickjillings@1686 166 trackSliderObj.innerHTML = '<span>'+index+'</span>';
nickjillings@1686 167 trackSliderObj.style.float = "left";
nickjillings@1686 168 trackSliderObj.draggable = true;
nickjillings@1686 169 trackSliderObj.ondragend = dragEnd;
nickjillings@1689 170
nickjillings@1689 171 // Onclick, switch playback to that track
nickjillings@1689 172 trackSliderObj.onclick = function() {
nickjillings@1689 173 // Get the track ID from the object ID
nickjillings@1689 174 var id = Number(this.id.substr(13,2)); // Maximum theoretical tracks is 99!
nickjillings@1689 175 audioEngineContext.selectedTrack(id);
nickjillings@1696 176 };
nickjillings@1689 177
nickjillings@1686 178 canvas.appendChild(trackSliderObj);
nickjillings@1696 179 });
nickjillings@1684 180
nickjillings@1683 181
nickjillings@1702 182 // Create pre and post test questions
nickjillings@1702 183
nickjillings@1683 184 // Inject into HTML
nickjillings@1683 185 insertPoint.innerHTML = null; // Clear the current schema
nickjillings@1702 186 testContent.appendChild(title); // Insert the title
nickjillings@1702 187 testContent.appendChild(interfaceButtons);
nickjillings@1702 188 testContent.appendChild(sliderBox);
nickjillings@1702 189 testContent.appendChild(feedbackHolder);
nickjillings@1702 190 insertPoint.appendChild(testContent);
nickjillings@1702 191
nickjillings@1702 192 var preTest = xmlDoc.find('PreTest');
nickjillings@1702 193 var postTest = xmlDoc.find('PostTest');
nickjillings@1702 194 preTest = preTest[0];
nickjillings@1702 195 postTest = postTest[0];
nickjillings@1702 196 if (preTest != undefined || postTest != undefined)
nickjillings@1702 197 {
nickjillings@1702 198 testContent.style.zIndex = 1;
nickjillings@1702 199 var blank = document.createElement('div');
nickjillings@1702 200 blank.id = 'testHalt';
nickjillings@1702 201 blank.style.zIndex = 2;
nickjillings@1702 202 blank.style.width = window.innerWidth + 'px';
nickjillings@1702 203 blank.style.height = window.innerHeight + 'px';
nickjillings@1702 204 blank.style.position = 'absolute';
nickjillings@1702 205 blank.style.top = '0';
nickjillings@1702 206 blank.style.left = '0';
nickjillings@1702 207 insertPoint.appendChild(blank);
nickjillings@1702 208 }
nickjillings@1702 209
nickjillings@1702 210 // Create Pre-Test Box
nickjillings@1702 211 if (preTest != undefined && preTest.children.length >= 1)
nickjillings@1702 212 {
nickjillings@1702 213
nickjillings@1702 214 var preTestHolder = document.createElement('div');
nickjillings@1702 215 preTestHolder.id = 'preTestHolder';
nickjillings@1702 216 preTestHolder.style.zIndex = 2;
nickjillings@1702 217 preTestHolder.style.width = '500px';
nickjillings@1702 218 preTestHolder.style.height = '250px';
nickjillings@1702 219 preTestHolder.style.backgroundColor = '#fff';
nickjillings@1702 220 preTestHolder.style.position = 'absolute';
nickjillings@1702 221 preTestHolder.style.left = (window.innerWidth/2)-250 + 'px';
nickjillings@1702 222 preTestHolder.style.top = (window.innerHeight/2)-125 + 'px';
nickjillings@1702 223 // Parse the first box
nickjillings@1702 224 var preTestOption = document.createElement('div');
nickjillings@1702 225 preTestOption.id = 'preTest';
nickjillings@1702 226 preTestOption.style.marginTop = '25px';
nickjillings@1702 227 preTestOption.align = "center";
nickjillings@1702 228 var child = preTest.children[0];
nickjillings@1702 229 if (child.nodeName == 'statement')
nickjillings@1702 230 {
nickjillings@1702 231 preTestOption.innerHTML = '<span>'+child.innerHTML+'</span>';
nickjillings@1702 232 } else if (child.nodeName == 'question')
nickjillings@1702 233 {
nickjillings@1703 234 var questionId = child.attributes['id'].value;
nickjillings@1702 235 var textHold = document.createElement('span');
nickjillings@1702 236 textHold.innerHTML = child.innerHTML;
nickjillings@1703 237 textHold.id = questionId + 'response';
nickjillings@1702 238 var textEnter = document.createElement('textarea');
nickjillings@1702 239 preTestOption.appendChild(textHold);
nickjillings@1702 240 preTestOption.appendChild(textEnter);
nickjillings@1702 241 }
nickjillings@1702 242 var nextButton = document.createElement('button');
nickjillings@1702 243 nextButton.id = 'preTestNext';
nickjillings@1702 244 nextButton.value = '1';
nickjillings@1702 245 nextButton.innerHTML = 'next';
nickjillings@1702 246 nextButton.style.position = 'relative';
nickjillings@1702 247 nextButton.style.left = '450px';
nickjillings@1702 248 nextButton.style.top = '175px';
nickjillings@1702 249 nextButton.onclick = function() {
nickjillings@1702 250 // Need to find and parse preTest again!
nickjillings@1702 251 var preTest = projectXML.find('PreTest')[0];
nickjillings@1703 252 // Check if current state is a question!
nickjillings@1703 253 if (preTest.children[this.value-1].nodeName == 'question') {
nickjillings@1703 254 var questionId = preTest.children[this.value-1].attributes['id'].value;
nickjillings@1703 255 var questionHold = document.createElement('comment');
nickjillings@1703 256 var questionResponse = document.getElementById(questionId + 'response');
nickjillings@1703 257 questionHold.id = questionId;
nickjillings@1703 258 questionHold.innerHTML = questionResponse.value;
nickjillings@1703 259 preTestQuestions.appendChild(questionHold);
nickjillings@1703 260 }
nickjillings@1702 261 if (this.value < preTest.children.length)
nickjillings@1702 262 {
nickjillings@1702 263 // More to process
nickjillings@1702 264 var child = preTest.children[this.value];
nickjillings@1702 265 if (child.nodeName == 'statement')
nickjillings@1702 266 {
nickjillings@1702 267 preTestOption.innerHTML = '<span>'+child.innerHTML+'</span>';
nickjillings@1702 268 } else if (child.nodeName == 'question')
nickjillings@1702 269 {
nickjillings@1702 270 var textHold = document.createElement('span');
nickjillings@1702 271 textHold.innerHTML = child.innerHTML;
nickjillings@1702 272 var textEnter = document.createElement('textarea');
nickjillings@1703 273 textEnter.id = child.attributes['id'].value + 'response';
nickjillings@1703 274 preTestOption.innerHTML = null;
nickjillings@1702 275 preTestOption.appendChild(textHold);
nickjillings@1702 276 preTestOption.appendChild(textEnter);
nickjillings@1702 277 }
nickjillings@1702 278 } else {
nickjillings@1702 279 // Time to clear
nickjillings@1702 280 preTestHolder.style.zIndex = -1;
nickjillings@1702 281 preTestHolder.style.visibility = 'hidden';
nickjillings@1702 282 var blank = document.getElementById('testHalt');
nickjillings@1702 283 blank.style.zIndex = -2;
nickjillings@1702 284 blank.style.visibility = 'hidden';
nickjillings@1702 285 }
nickjillings@1702 286 this.value++;
nickjillings@1702 287 };
nickjillings@1702 288
nickjillings@1702 289 preTestHolder.appendChild(preTestOption);
nickjillings@1702 290 preTestHolder.appendChild(nextButton);
nickjillings@1702 291 insertPoint.appendChild(preTestHolder);
nickjillings@1702 292 }
nickjillings@1702 293
nickjillings@1683 294 }
nickjillings@1686 295
nickjillings@1686 296 function dragEnd(ev) {
nickjillings@1686 297 // Function call when a div has been dropped
nickjillings@1686 298 if (ev.x >= 50 && ev.x < window.innerWidth-50) {
nickjillings@1686 299 this.style.left = (ev.x)+'px';
nickjillings@1686 300 } else {
nickjillings@1686 301 if (ev.x<50) {
nickjillings@1686 302 this.style.left = '50px';
nickjillings@1686 303 } else {
nickjillings@1686 304 this.style.left = window.innerWidth-50 + 'px';
nickjillings@1686 305 }
nickjillings@1686 306 }
nickjillings@1686 307 }
nickjillings@1688 308
nickjillings@1688 309 // Only other global function which must be defined in the interface class. Determines how to create the XML document.
nickjillings@1688 310 function interfaceXMLSave(){
nickjillings@1688 311 // Create the XML string to be exported with results
nickjillings@1688 312 var xmlDoc = document.createElement("BrowserEvaluationResult");
nickjillings@1688 313 var trackSliderObjects = document.getElementsByClassName('track-slider');
nickjillings@1688 314 var commentObjects = document.getElementsByClassName('trackComment');
nickjillings@1688 315 var rateMin = 50;
nickjillings@1688 316 var rateMax = window.innerWidth-50;
nickjillings@1688 317 for (var i=0; i<trackSliderObjects.length; i++)
nickjillings@1688 318 {
nickjillings@1704 319 var trackObj = document.createElement("audioElement");
nickjillings@1688 320 trackObj.id = i;
nickjillings@1704 321 trackObj.url = audioEngineContext.audioObjects[i].url;
nickjillings@1688 322 var slider = document.createElement("Rating");
nickjillings@1688 323 var rate = Number(trackSliderObjects[i].style.left.substr(0,trackSliderObjects[i].style.left.length-2));
nickjillings@1688 324 rate = (rate-rateMin)/rateMax;
nickjillings@1688 325 slider.innerText = Math.floor(rate*100);
nickjillings@1688 326 var comment = document.createElement("Comment");
nickjillings@1688 327 comment.innerText = commentObjects[i].value;
nickjillings@1688 328 trackObj.appendChild(slider);
nickjillings@1688 329 trackObj.appendChild(comment);
nickjillings@1688 330 xmlDoc.appendChild(trackObj);
nickjillings@1688 331 }
nickjillings@1688 332
nickjillings@1703 333 // Append Pre/Post Questions
nickjillings@1703 334 xmlDoc.appendChild(preTestQuestions);
nickjillings@1703 335 xmlDoc.appendChild(postTestQuestions);
nickjillings@1703 336
nickjillings@1688 337 return xmlDoc;
nickjillings@1688 338 }
nickjillings@1688 339