diff ape.js @ 656:0a401224660b

Added dev-main branch warning at top of files
author Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk>
date Fri, 10 Apr 2015 10:25:52 +0100
parents
children 1e64848f5940
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ape.js	Fri Apr 10 10:25:52 2015 +0100
@@ -0,0 +1,350 @@
+/**
+ *  ape.js
+ *  Create the APE interface
+ */
+
+/*
+ * 
+ * WARNING!!!
+ * 
+ * 	YOU ARE VIEWING THE DEV VERSION. THERE IS NO GUARANTEE THIS WILL BE FULLY FUNCTIONAL
+ * 
+ * WARNING!!!
+ * 
+ */
+
+
+// Once this is loaded and parsed, begin execution
+loadInterface(projectXML);
+
+function loadInterface(xmlDoc) {
+	
+	// Get the dimensions of the screen available to the page
+	var width = window.innerWidth;
+	var height = window.innerHeight;
+	
+	// Set background to grey #ddd
+	document.getElementsByTagName('body')[0].style.backgroundColor = '#ddd';
+	
+	// The injection point into the HTML page
+	var insertPoint = document.getElementById("topLevelBody");
+	var testContent = document.createElement('div');
+	testContent.id = 'testContent';
+	
+	
+	// Decode parts of the xmlDoc that are needed
+	// xmlDoc MUST already be parsed by jQuery!
+	var xmlSetup = xmlDoc.find('setup');
+	// Should put in an error function here incase of malprocessed or malformed XML
+	
+	// Create the top div for the Title element
+	var titleAttr = xmlSetup[0].attributes['title'];
+	var title = document.createElement('div');
+	title.className = "title";
+	title.align = "center";
+	var titleSpan = document.createElement('span');
+	
+	// Set title to that defined in XML, else set to default
+	if (titleAttr != undefined) {
+		titleSpan.innerHTML = titleAttr.value;
+	} else {
+		titleSpan.innerHTML =  'APE Tool';
+	}
+	// Insert the titleSpan element into the title div element.
+	title.appendChild(titleSpan);
+	
+	// Store the return URL path in global projectReturn
+	projectReturn = xmlSetup[0].attributes['projectReturn'].value;
+	
+	// Create Interface buttons!
+	var interfaceButtons = document.createElement('div');
+	interfaceButtons.id = 'interface-buttons';
+	
+	// MANUAL DOWNLOAD POINT
+	// If project return is null, this MUST be specified as the location to create the download link
+	var downloadPoint = document.createElement('div');
+	downloadPoint.id = 'download-point';
+	
+	// Create playback start/stop points
+	var playback = document.createElement("button");
+	playback.innerHTML = 'Start';
+	// onclick function. Check if it is playing or not, call the correct function in the
+	// audioEngine, change the button text to reflect the next state.
+	playback.onclick = function() {
+		if (audioEngineContext.status == 0) {
+			audioEngineContext.play();
+			this.innerHTML = 'Stop';
+		} else {
+			audioEngineContext.stop();
+			this.innerHTML = 'Start';
+		}
+	};
+	// Create Submit (save) button
+	var submit = document.createElement("button");
+	submit.innerHTML = 'Submit';
+	submit.onclick = function() {
+		// TODO: Update this for postTest tags
+		createProjectSave(projectReturn)
+	};
+	// Append the interface buttons into the interfaceButtons object.
+	interfaceButtons.appendChild(playback);
+	interfaceButtons.appendChild(submit);
+	interfaceButtons.appendChild(downloadPoint);
+	
+	// Now create the slider and HTML5 canvas boxes
+	
+	// Create the div box to center align
+	var sliderBox = document.createElement('div');
+	sliderBox.className = 'sliderCanvasDiv';
+	sliderBox.id = 'sliderCanvasHolder';
+	sliderBox.align = 'center';
+	
+	// Create the slider box to hold the slider elements
+	var canvas = document.createElement('div');
+	canvas.id = 'slider';
+	// Must have a known EXACT width, as this is used later to determine the ratings
+	canvas.style.width = width - 100 +"px";
+	canvas.style.height = 150 + "px";
+	canvas.style.marginBottom = "25px";
+	canvas.style.backgroundColor = '#eee';
+	canvas.align = "left";
+	sliderBox.appendChild(canvas);
+	
+	// Global parent for the comment boxes on the page
+	var feedbackHolder = document.createElement('div');
+	// Find the parent audioHolder object.
+	var audioHolder = xmlDoc.find('audioHolder');
+	audioHolder = audioHolder[0]; // Remove from one field array
+	// Extract the hostURL attribute. If not set, create an empty string.
+	var hostURL = audioHolder.attributes['hostURL'];
+	if (hostURL == undefined) {
+		hostURL = "";
+	} else {
+		hostURL = hostURL.value;
+	}
+	// Extract the sampleRate. If set, convert the string to a Number.
+	var hostFs = audioHolder.attributes['sampleRate'];
+	if (hostFs != undefined) {
+		hostFs = Number(hostFs.value);
+	}
+	
+	/// CHECK FOR SAMPLE RATE COMPATIBILITY
+	if (hostFs != undefined) {
+		if (Number(hostFs) != audioContext.sampleRate) {
+			var errStr = 'Sample rates do not match! Requested '+Number(hostFs)+', got '+audioContext.sampleRate+'. Please set the sample rate to match before completing this test.';
+			alert(errStr);
+			return;
+		}
+	}
+	// Find all the audioElements from the audioHolder
+	var audioElements = $(audioHolder).find('audioElements');
+	audioElements.each(function(index,element){
+		// Find URL of track
+		// In this jQuery loop, variable 'this' holds the current audioElement.
+		
+		// Now load each audio sample. First create the new track by passing the full URL
+		var trackURL = hostURL + this.attributes['url'].value;
+		audioEngineContext.newTrack(trackURL);
+		// Create document objects to hold the comment boxes
+		var trackComment = document.createElement('div');
+		// Create a string next to each comment asking for a comment
+		var trackString = document.createElement('span');
+		trackString.innerHTML = 'Comment on track '+index;
+		// Create the HTML5 comment box 'textarea'
+		var trackCommentBox = document.createElement('textarea');
+		trackCommentBox.rows = '4';
+		trackCommentBox.cols = '100';
+		trackCommentBox.name = 'trackComment'+index;
+		trackCommentBox.className = 'trackComment';
+		// Add to the holder.
+		trackComment.appendChild(trackString);
+		trackComment.appendChild(trackCommentBox);
+		feedbackHolder.appendChild(trackComment);
+		
+		// Create a slider per track
+		
+		var trackSliderObj = document.createElement('div');
+		trackSliderObj.className = 'track-slider';
+		trackSliderObj.id = 'track-slider-'+index;
+		trackSliderObj.style.position = 'absolute';
+		// Distribute it randomnly
+		var w = window.innerWidth - 100;
+		w = Math.random()*w;
+		trackSliderObj.style.left = Math.floor(w)+50+'px';
+		trackSliderObj.style.height = "150px";
+		trackSliderObj.style.width = "10px";
+		trackSliderObj.style.backgroundColor = 'rgb(100,200,100)';
+		trackSliderObj.innerHTML = '<span>'+index+'</span>';
+		trackSliderObj.style.float = "left";
+		trackSliderObj.draggable = true;
+		trackSliderObj.ondragend = dragEnd;
+		
+		// Onclick, switch playback to that track
+		trackSliderObj.onclick = function() {
+			// Get the track ID from the object ID
+			var id = Number(this.id.substr(13,2)); // Maximum theoretical tracks is 99!
+			audioEngineContext.selectedTrack(id);
+		};
+		
+		canvas.appendChild(trackSliderObj);
+	});
+	
+	
+	// Create pre and post test questions
+	
+	// Inject into HTML
+	insertPoint.innerHTML = null; // Clear the current schema
+	testContent.appendChild(title); // Insert the title
+	testContent.appendChild(interfaceButtons);
+	testContent.appendChild(sliderBox);
+	testContent.appendChild(feedbackHolder);
+	insertPoint.appendChild(testContent);
+	
+	var preTest = xmlDoc.find('PreTest');
+	var postTest = xmlDoc.find('PostTest');
+	preTest = preTest[0];
+	postTest = postTest[0];
+	if (preTest != undefined || postTest != undefined)
+	{
+		testContent.style.zIndex = 1;
+		var blank = document.createElement('div');
+		blank.id = 'testHalt';
+		blank.style.zIndex = 2;
+		blank.style.width = window.innerWidth + 'px';
+		blank.style.height = window.innerHeight + 'px';
+		blank.style.position = 'absolute';
+		blank.style.top = '0';
+		blank.style.left = '0';
+		insertPoint.appendChild(blank);
+	}
+	
+	// Create Pre-Test Box
+	if (preTest != undefined && preTest.children.length >= 1)
+	{
+		
+		var preTestHolder = document.createElement('div');
+		preTestHolder.id = 'preTestHolder';
+		preTestHolder.style.zIndex = 2;
+		preTestHolder.style.width = '500px';
+		preTestHolder.style.height = '250px';
+		preTestHolder.style.backgroundColor = '#fff';
+		preTestHolder.style.position = 'absolute';
+		preTestHolder.style.left = (window.innerWidth/2)-250 + 'px';
+		preTestHolder.style.top = (window.innerHeight/2)-125 + 'px';
+		// Parse the first box
+		var preTestOption = document.createElement('div');
+		preTestOption.id = 'preTest';
+		preTestOption.style.marginTop = '25px';
+		preTestOption.align = "center";
+		var child = preTest.children[0];
+		if (child.nodeName == 'statement')
+		{
+			preTestOption.innerHTML = '<span>'+child.innerHTML+'</span>';
+		} else if (child.nodeName == 'question')
+		{
+			var questionId = child.attributes['id'].value;
+			var textHold = document.createElement('span');
+			textHold.innerHTML = child.innerHTML;
+			textHold.id = questionId + 'response';
+			var textEnter = document.createElement('textarea');
+			preTestOption.appendChild(textHold);
+			preTestOption.appendChild(textEnter);
+		}
+		var nextButton = document.createElement('button');
+		nextButton.id = 'preTestNext';
+		nextButton.value = '1';
+		nextButton.innerHTML = 'next';
+		nextButton.style.position = 'relative';
+		nextButton.style.left = '450px';
+		nextButton.style.top = '175px';
+		nextButton.onclick = function() {
+			// Need to find and parse preTest again!
+			var preTest = projectXML.find('PreTest')[0];
+			// Check if current state is a question!
+			if (preTest.children[this.value-1].nodeName == 'question') {
+				var questionId = preTest.children[this.value-1].attributes['id'].value;
+				var questionHold = document.createElement('comment');
+				var questionResponse = document.getElementById(questionId + 'response');
+				questionHold.id = questionId;
+				questionHold.innerHTML = questionResponse.value;
+				preTestQuestions.appendChild(questionHold);
+			}
+			if (this.value < preTest.children.length)
+			{
+				// More to process
+				var child = preTest.children[this.value];
+				if (child.nodeName == 'statement')
+				{
+					preTestOption.innerHTML = '<span>'+child.innerHTML+'</span>';
+				} else if (child.nodeName == 'question')
+				{
+					var textHold = document.createElement('span');
+					textHold.innerHTML = child.innerHTML;
+					var textEnter = document.createElement('textarea');
+					textEnter.id = child.attributes['id'].value + 'response';
+					preTestOption.innerHTML = null;
+					preTestOption.appendChild(textHold);
+					preTestOption.appendChild(textEnter);
+				}
+			} else {
+				// Time to clear
+				preTestHolder.style.zIndex = -1;
+				preTestHolder.style.visibility = 'hidden';
+				var blank = document.getElementById('testHalt');
+				blank.style.zIndex = -2;
+				blank.style.visibility = 'hidden';
+			}
+			this.value++;
+		};
+		
+		preTestHolder.appendChild(preTestOption);
+		preTestHolder.appendChild(nextButton);
+		insertPoint.appendChild(preTestHolder);
+	}
+
+}
+
+function dragEnd(ev) {
+	// Function call when a div has been dropped
+	if (ev.x >= 50 && ev.x < window.innerWidth-50) {
+		this.style.left = (ev.x)+'px';
+	} else {
+		if (ev.x<50) {
+			this.style.left = '50px';
+		} else {
+			this.style.left = window.innerWidth-50 + 'px';
+		}
+	}
+}
+
+// Only other global function which must be defined in the interface class. Determines how to create the XML document.
+function interfaceXMLSave(){
+	// Create the XML string to be exported with results
+	var xmlDoc = document.createElement("BrowserEvaluationResult");
+	var trackSliderObjects = document.getElementsByClassName('track-slider');
+	var commentObjects = document.getElementsByClassName('trackComment');
+	var rateMin = 50;
+	var rateMax = window.innerWidth-50;
+	for (var i=0; i<trackSliderObjects.length; i++)
+	{
+		var trackObj = document.createElement("audioElement");
+		trackObj.id = i;
+		trackObj.url = audioEngineContext.audioObjects[i].url;
+		var slider = document.createElement("Rating");
+		var rate = Number(trackSliderObjects[i].style.left.substr(0,trackSliderObjects[i].style.left.length-2));
+		rate = (rate-rateMin)/rateMax;
+		slider.innerHTML = Math.floor(rate*100);
+		var comment = document.createElement("Comment");
+		comment.innerHTML = commentObjects[i].value;
+		trackObj.appendChild(slider);
+		trackObj.appendChild(comment);
+		xmlDoc.appendChild(trackObj);
+	}
+	
+	// Append Pre/Post Questions
+	xmlDoc.appendChild(preTestQuestions);
+	xmlDoc.appendChild(postTestQuestions);
+	
+	return xmlDoc;
+}
+