changeset 1581:284251e3a6a3

Everything tied into Specification object which needs information from specification document.
author Nicholas Jillings <nickjillings@users.noreply.github.com>
date Thu, 04 Jun 2015 15:54:56 +0100
parents b6c808cac38c
children d4b626a4bc76
files ape.js core.js
diffstat 2 files changed, 79 insertions(+), 175 deletions(-) [+]
line wrap: on
line diff
--- a/ape.js	Thu Jun 04 14:31:23 2015 +0100
+++ b/ape.js	Thu Jun 04 15:54:56 2015 +0100
@@ -11,9 +11,9 @@
 
 
 // Once this is loaded and parsed, begin execution
-loadInterface(projectXML);
+loadInterface();
 
-function loadInterface(xmlDoc) {
+function loadInterface() {
 	
 	// Get the dimensions of the screen available to the page
 	var width = window.innerWidth;
@@ -24,12 +24,6 @@
 	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 APE specific metric functions
@@ -78,7 +72,7 @@
 	// Bindings for audioObjects
 	
 	// Create the top div for the Title element
-	var titleAttr = xmlSetup[0].attributes['title'];
+	var titleAttr = specification.title;
 	var title = document.createElement('div');
 	title.className = "title";
 	title.align = "center";
@@ -86,9 +80,9 @@
 	
 	// Set title to that defined in XML, else set to default
 	if (titleAttr != undefined) {
-		titleSpan.innerHTML = titleAttr.value;
+		titleSpan.textContent = titleAttr;
 	} else {
-		titleSpan.innerHTML =  'Listening test';
+		titleSpan.textContent =  'Listening test';
 	}
 	// Insert the titleSpan element into the title div element.
 	title.appendChild(titleSpan);
@@ -100,24 +94,10 @@
 	titleSpan.id = "pageTitle";
 	pagetitle.appendChild(titleSpan);
 	
-	// Store the return URL path in global projectReturn
-	projectReturn = xmlSetup[0].attributes['projectReturn'];
-	if (projectReturn == undefined) {
-		console.log("WARNING - projectReturn not specified! Will assume null.");
-		projectReturn = "null";
-	} else {
-		projectReturn = 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 = 'Stop';
@@ -140,7 +120,6 @@
 	// 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
 	
@@ -194,13 +173,13 @@
 	
 }
 
-function loadTest(textXML)
+function loadTest(audioHolderObject)
 {
 	
 	// Reset audioEngineContext.Metric globals for new test
 	audioEngineContext.newTestPage();
 	
-	var id = textXML.id;
+	var id = audioHolderObject.id;
 	
 	var feedbackHolder = document.getElementById('feedbackHolder');
 	var canvas = document.getElementById('slider');
@@ -208,7 +187,7 @@
 	canvas.innerHTML = null;
 	
 	// Setup question title
-	var interfaceObj = $(textXML).find('interface');
+	var interfaceObj = $(audioHolderObject).find('interface');
 	var titleNode = interfaceObj.find('title');
 	if (titleNode[0] != undefined)
 	{
@@ -237,46 +216,19 @@
 		commentBoxPrefix = "Comment on track";
 	}
 
-	// Extract the hostURL attribute. If not set, create an empty string.
-	var hostURL = textXML.attributes['hostURL'];
-	if (hostURL == undefined) {
-		hostURL = "";
-	} else {
-		hostURL = hostURL.value;
-	}
-	// Extract the sampleRate. If set, convert the string to a Number.
-	var hostFs = textXML.attributes['sampleRate'];
-	if (hostFs != undefined) {
-		hostFs = Number(hostFs.value);
-	}
-	
 	/// CHECK FOR SAMPLE RATE COMPATIBILITY
-	if (hostFs != undefined) {
-		if (Number(hostFs) != audioContext.sampleRate) {
+	if (audioHolderObject.sampleRate != undefined) {
+		if (Number(audioHolderObject.sampleRate) != 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;
 		}
 	}
 	
-	var commentShow = textXML.attributes['elementComments'];
-	if (commentShow != undefined) {
-		if (commentShow.value == 'false') {commentShow = false;}
-		else {commentShow = true;}
-	} else {commentShow = true;}
+	var commentShow = audioHolderObject.elementComments;
 	
-	var loopPlayback = textXML.attributes['loop'];
-	if (loopPlayback != undefined)
-	{
-		loopPlayback = loopPlayback.value;
-		if (loopPlayback == 'true') {
-			loopPlayback = true;
-		} else {
-			loopPlayback = false;
-		}
-	} else {
-		loopPlayback = false;
-	}
+	var loopPlayback = audioHolderObject.loop;
+
 	audioEngineContext.loopPlayback = loopPlayback;
 	// Create AudioEngine bindings for playback
 	if (loopPlayback) {
@@ -305,36 +257,28 @@
 	}
 	
 	currentTestHolder = document.createElement('audioHolder');
-	currentTestHolder.id = textXML.id;
-	currentTestHolder.repeatCount = textXML.attributes['repeatCount'].value;
+	currentTestHolder.id = audioHolderObject.id;
+	currentTestHolder.repeatCount = audioHolderObject.repeatCount;
 	
-	var randomise = textXML.attributes['randomiseOrder'];
-	if (randomise != undefined) {randomise = randomise.value;}
-	else {randomise = false;}
+	var randomise = audioHolderObject.randomiseOrder;
 	
-	var audioElements = $(textXML).find('audioElements');
+	var audioElements = audioHolderObject.audioElements;
 	currentTrackOrder = [];
-	audioElements.each(function(index,element){
-		// Find any blind-repeats
-		// Not implemented yet, but just in case
-		currentTrackOrder[index] = element;
-	});
 	if (randomise) {
-		currentTrackOrder = randomiseOrder(currentTrackOrder);
+		audioHolderObject.audioElements = randomiseOrder(audioHolderObject.audioElements);
 	}
 	
 	// Delete any previous audioObjects associated with the audioEngine
 	audioEngineContext.audioObjects = [];
 	
 	// Find all the audioElements from the audioHolder
-	$(currentTrackOrder).each(function(index,element){
+	$(audioHolderObject.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;
+		var trackURL = audioHolderObject.hostURL + element.url;
 		var audioObject = audioEngineContext.newTrack(trackURL);
-		audioObject.id = this.attributes['id'].value;
 		
 		if (commentShow) {
 			// Create document objects to hold the comment boxes
@@ -412,15 +356,14 @@
 	});
 	
 	// Append any commentQuestion boxes
-	var commentQuestions = $(textXML).find('CommentQuestion');
-	$(commentQuestions).each(function(index,element) {
+	$(audioHolderObject.commentQuestions).each(function(index,element) {
 		// Create document objects to hold the comment boxes
 		var trackComment = document.createElement('div');
 		trackComment.className = 'comment-div commentQuestion';
-		trackComment.id = element.attributes['id'].value;
+		trackComment.id = element.id;
 		// Create a string next to each comment asking for a comment
 		var trackString = document.createElement('span');
-		trackString.innerHTML = element.textContent;
+		trackString.innerHTML = element.question;
 		// Create the HTML5 comment box 'textarea'
 		var trackCommentBox = document.createElement('textarea');
 		trackCommentBox.rows = '4';
@@ -541,17 +484,13 @@
 	});
 }
 
-function pageXMLSave(store, testXML, testId)
+function pageXMLSave(store, testXML)
 {
 	// Saves a specific test page
 	var xmlDoc = store;
 	// Check if any session wide metrics are enabled
 	
-	var commentShow = testXML.attributes['elementComments'];
-	if (commentShow != undefined) {
-		if (commentShow.value == 'false') {commentShow = false;}
-		else {commentShow = true;}
-	} else {commentShow = true;}
+	var commentShow = testXML.elementComments;
 	
 	var metric = document.createElement('metric');
 	if (audioEngineContext.metric.enableTestTimer)
--- a/core.js	Thu Jun 04 14:31:23 2015 +0100
+++ b/core.js	Thu Jun 04 15:54:56 2015 +0100
@@ -8,6 +8,7 @@
 /* create the web audio API context and store in audioContext*/
 var audioContext; // Hold the browser web audio API
 var projectXML; // Hold the parsed setup XML
+var specification;
 var popup; // Hold the interfacePopup object
 var testState;
 var currentTrackOrder = []; // Hold the current XML tracks in their (randomised) order
@@ -35,6 +36,9 @@
 	
 	// Create the popup interface object
 	popup = new interfacePopup();
+	
+	// Create the specification object
+	specification = new Specification();
 };
 
 function interfacePopup() {
@@ -45,6 +49,7 @@
 	this.popupOptions = null;
 	this.currentIndex = null;
 	this.responses = null;
+	
 	this.createPopup = function(){
 		// Create popup window interface
 		var insertPoint = document.getElementById("topLevelBody");
@@ -68,12 +73,16 @@
 		this.popupButton.className = 'popupButton';
 		this.popupButton.innerHTML = 'Next';
 		this.popupButton.onclick = function(){popup.buttonClicked();};
+		this.popup.style.zIndex = -1;
+		this.popup.style.visibility = 'hidden';
+		blank.style.zIndex = -2;
+		blank.style.visibility = 'hidden';
 		insertPoint.appendChild(this.popup);
 		insertPoint.appendChild(blank);
 	};
 	
 	this.showPopup = function(){
-		if (this.popup == null || this.popup == undefined) {
+		if (this.popup == null) {
 			this.createPopup();
 		}
 		this.popup.style.zIndex = 3;
@@ -95,13 +104,13 @@
 		// This will take the node from the popupOptions and display it
 		var node = this.popupOptions[this.currentIndex];
 		this.popupContent.innerHTML = null;
-		if (node.nodeName == 'statement') {
+		if (node.type == 'statement') {
 			var span = document.createElement('span');
-			span.textContent = node.textContent;
+			span.textContent = node.statement;
 			this.popupContent.appendChild(span);
-		} else if (node.nodeName == 'question') {
+		} else if (node.type == 'question') {
 			var span = document.createElement('span');
-			span.textContent = node.textContent;
+			span.textContent = node.question;
 			var textArea = document.createElement('textarea');
 			var br = document.createElement('br');
 			this.popupContent.appendChild(span);
@@ -115,11 +124,11 @@
 	this.initState = function(node) {
 		//Call this with your preTest and postTest nodes when needed to
 		// initialise the popup procedure.
-		this.popupOptions = $(node).children();
+		this.popupOptions = node.options;
 		if (this.popupOptions.length > 0) {
-			if (node.nodeName == 'preTest' || node.nodeName == 'PreTest') {
+			if (node.type == 'pretest') {
 				this.responses = document.createElement('PreTest');
-			} else if (node.nodeName == 'postTest' || node.nodeName == 'PostTest') {
+			} else if (node.type == 'posttest') {
 				this.responses = document.createElement('PostTest');
 			} else {
 				console.log ('WARNING - popup node neither pre or post!');
@@ -128,29 +137,24 @@
 			this.currentIndex = 0;
 			this.showPopup();
 			this.postNode();
+		} else {
+			advanceState();
 		}
 	};
 	
 	this.buttonClicked = function() {
 		// Each time the popup button is clicked!
 		var node = this.popupOptions[this.currentIndex];
-		if (node.nodeName == 'question') {
+		if (node.type == 'question') {
 			// Must extract the question data
-			var mandatory = node.attributes['mandatory'];
-			if (mandatory == undefined) {
-				mandatory = false;
-			} else {
-				if (mandatory.value == 'true'){mandatory = true;}
-				else {mandatory = false;}
-			}
 			var textArea = $(popup.popupContent).find('textarea')[0];
-			if (mandatory == true && textArea.value.length == 0) {
+			if (node.mandatory == true && textArea.value.length == 0) {
 				alert('This question is mandatory');
 				return;
 			} else {
 				// Save the text content
 				var hold = document.createElement('comment');
-				hold.id = node.attributes['id'].value;
+				hold.id = node.id;
 				hold.innerHTML = textArea.value;
 				console.log("Question: "+ node.textContent);
 				console.log("Question Response: "+ textArea.value);
@@ -197,11 +201,8 @@
 			this.stateIndex = -1;
 			var that = this;
 			for (var id=0; id<this.stateMap.length; id++){
-				var name = this.stateMap[id].nodeName;
+				var name = this.stateMap[id].type;
 				var obj = document.createElement(name);
-				if (name == "audioHolder") {
-					obj.id = this.stateMap[id].id;
-				}
 				this.stateResults.push(obj);
 			}
 		} else {
@@ -216,7 +217,7 @@
 			console.log('Starting test...');
 		}
 		if (this.currentIndex == null){
-			if (this.currentStateMap.nodeName == "audioHolder") {
+			if (this.currentStateMap.type == "audioHolder") {
 				// Save current page
 				this.testPageCompleted(this.stateResults[this.stateIndex],this.currentStateMap,this.currentTestId);
 				this.currentTestId++;
@@ -227,12 +228,12 @@
 				createProjectSave(projectReturn);
 			} else {
 				this.currentStateMap = this.stateMap[this.stateIndex];
-				if (this.currentStateMap.nodeName == "audioHolder") {
+				if (this.currentStateMap.type == "audioHolder") {
 					console.log('Loading test page');
 					loadTest(this.currentStateMap);
 					this.initialiseInnerState(this.currentStateMap);
-				} else if (this.currentStateMap.nodeName == "PreTest" || this.currentStateMap.nodeName == "PostTest") {
-					if (this.currentStateMap.childElementCount >= 1) {
+				} else if (this.currentStateMap.type == "pretest" || this.currentStateMap.type == "posttest") {
+					if (this.currentStateMap.options.length >= 1) {
 						popup.initState(this.currentStateMap);
 					} else {
 						this.advanceState();
@@ -250,18 +251,18 @@
 		// Function called each time a test page has been completed
 		// Can be used to over-rule default behaviour
 		
-		pageXMLSave(store, testXML, testId);
+		pageXMLSave(store, testXML);
 	};
 	
-	this.initialiseInnerState = function(testXML) {
+	this.initialiseInnerState = function(node) {
 		// Parses the received testXML for pre and post test options
 		this.currentStateMap = [];
-		var preTest = $(testXML).find('PreTest')[0];
-		var postTest = $(testXML).find('PostTest')[0];
+		var preTest = node.preTest;
+		var postTest = node.postTest;
 		if (preTest == undefined) {preTest = document.createElement("preTest");}
 		if (postTest == undefined){postTest= document.createElement("postTest");}
 		this.currentStateMap.push(preTest);
-		this.currentStateMap.push(testXML);
+		this.currentStateMap.push(node);
 		this.currentStateMap.push(postTest);
 		this.currentIndex = -1;
 		this.advanceInnerState();
@@ -274,11 +275,11 @@
 			this.currentStateMap = this.stateMap[this.stateIndex];
 			this.advanceState();
 		} else {
-			if (this.currentStateMap[this.currentIndex].nodeName == "audioHolder") {
+			if (this.currentStateMap[this.currentIndex].type == "audioHolder") {
 				console.log("Loading test page"+this.currentTestId);
-			} else if (this.currentStateMap[this.currentIndex].nodeName == "PreTest") {
+			} else if (this.currentStateMap[this.currentIndex].type == "pretest") {
 				popup.initState(this.currentStateMap[this.currentIndex]);
-			} else if (this.currentStateMap[this.currentIndex].nodeName == "PostTest") {
+			} else if (this.currentStateMap[this.currentIndex].type == "posttest") {
 				popup.initState(this.currentStateMap[this.currentIndex]);
 			} else {
 				this.advanceInnerState();
@@ -327,61 +328,27 @@
 	var parse = new DOMParser();
 	projectXML = parse.parseFromString(response,'text/xml');
 	
-	// Now extract the setup tag
-	var xmlSetup = projectXML.find('setup');
+	// Build the specification
+	specification.decode();
 	
-	
-	// Create pre and post test questions
-	
-	var preTest = xmlSetup.find('PreTest');
-	var postTest = xmlSetup.find('PostTest');
-	preTest = preTest[0];
-	postTest = postTest[0];
-	
-	if (preTest == undefined) {preTest = document.createElement("preTest");}
-	if (postTest == undefined){postTest= document.createElement("postTest");}
-	
-	testState.stateMap.push(preTest);
-	
-	// Extract the different test XML DOM trees
-	var audioHolders = projectXML.find('audioHolder');
-	var testXMLSetups = [];
-	audioHolders.each(function(index,element) {
-		var repeatN = element.attributes['repeatCount'].value;
-		for (var r=0; r<=repeatN; r++) {
-			testXMLSetups.push(element);
-		}
-	});
+	testState.stateMap.push(specification.preTest);
 	 
 	// New check if we need to randomise the test order
-	var randomise = xmlSetup[0].attributes['randomiseOrder'];
-	if (randomise != undefined) {
-		if (randomise.value === 'true'){
-			randomise = true;
-		} else {
-			randomise = false;
-		}
-	} else {
-		randomise = false;
+	if (specification.randomiseOrder)
+	{
+ 		specification.audioHolders = randomiseOrder(specification.audioHolders);
 	}
 	
-	if (randomise)
-	{
- 		testXMLSetups = randomiseOrder(testXMLSetups);
-	}
-	
-	$(testXMLSetups).each(function(index,elem){
+	$(specification.audioHolders).each(function(index,elem){
 		testState.stateMap.push(elem);
 	});
 	 
-	 testState.stateMap.push(postTest);
+	 testState.stateMap.push(specification.postTest);
 	 
 	// Obtain the metrics enabled
-	var metricNode = xmlSetup.find('Metric');
-	var metricNode = metricNode.find('metricEnable');
-	metricNode.each(function(index,node){
+	$(specification.metrics).each(function(index,node){
 		var enabled = node.textContent;
-		switch(enabled)
+		switch(node.enabled)
 		{
 		case 'testTimer':
 			sessionMetrics.prototype.enableTestTimer = true;
@@ -413,10 +380,9 @@
 	
 	
 	// Detect the interface to use and load the relevant javascripts.
-	var interfaceType = xmlSetup[0].attributes['interface'];
 	var interfaceJS = document.createElement('script');
 	interfaceJS.setAttribute("type","text/javascript");
-	if (interfaceType.value == 'APE') {
+	if (specification.interfaceType == 'APE') {
 		interfaceJS.setAttribute("src","ape.js");
 		
 		// APE comes with a css file
@@ -450,11 +416,9 @@
 		a.download = "save.xml";
 		a.textContent = "Save File";
 		
-		var submitDiv = document.getElementById('download-point');
-		submitDiv.appendChild(a);
 		popup.showPopup();
 		popup.popupContent.innerHTML = null;
-		popup.popupContent.appendChild(submitDiv)
+		popup.popupContent.appendChild(a)
 	} else {
 		var xmlhttp = new XMLHttpRequest;
 		xmlhttp.open("POST",destURL,true);
@@ -1003,13 +967,13 @@
 		} else {this.setup.collectMetrics = false;}
 		var metricCollection = setupNode.getElementsByTagName('Metric');
 		
-		this.preTest = new this.prepostNode('pre',setupNode.getElementsByTagName('PreTest'));
-		this.postTest = new this.prepostNode('post',setupNode.getElementsByTagName('PostTest'));
+		this.preTest = new this.prepostNode('pretest',setupNode.getElementsByTagName('PreTest'));
+		this.postTest = new this.prepostNode('posttest',setupNode.getElementsByTagName('PostTest'));
 		
 		if (metricCollection.length > 0) {
 			metricCollection = metricCollection[0].getElementsByTagName('metricEnable');
 			for (var i=0; i<metricCollection.length; i++) {
-				this.metrics.push(new this.metricNode(metricCollection[0].textContent));
+				this.metrics.push(new this.metricNode(metricCollection[i].textContent));
 			}
 		}
 		
@@ -1033,7 +997,7 @@
 				else {this.mandatory = false;}
 				this.question = child.textContent;
 			} else if (child.nodeName == "statement") {
-				this.statment = child.textContent;
+				this.statement = child.textContent;
 			}
 		};
 		
@@ -1052,6 +1016,7 @@
 	};
 	
 	this.audioHolderNode = function(parent,xml) {
+		this.type = 'audioHolder';
 		this.interfaceNode = function(DOM) {
 			var title = DOM.getElementsByTagName('title');
 			if (title.length == 0) {this.title = null;}
@@ -1090,8 +1055,8 @@
 		if (xml.getAttribute('elementComments') == "true") {this.elementComments = true;}
 		else {this.elementComments = false;}
 		
-		this.preTest = new parent.prepostNode('pre',xml.getElementsByTagName('PreTest'));
-		this.postTest = new parent.prepostNode('post',xml.getElementsByTagName('PostTest'));
+		this.preTest = new parent.prepostNode('pretest',xml.getElementsByTagName('PreTest'));
+		this.postTest = new parent.prepostNode('posttest',xml.getElementsByTagName('PostTest'));
 		
 		this.interfaces = [];
 		var interfaceDOM = xml.getElementsByTagName('interface');