changeset 964:9c09cb530ec1

Major Update. All new state machine to track the session state and hold session data. Will enable new interfaces to be built on top and have the same common structures.
author Nicholas Jillings <nicholas.jillings@eecs.qmul.ac.uk>
date Wed, 27 May 2015 16:45:48 +0100
parents ba734075da2d
children 2dc61bd6494e
files ape.js core.js example_eval/project.xml
diffstat 3 files changed, 164 insertions(+), 100 deletions(-) [+]
line wrap: on
line diff
--- a/ape.js	Wed May 27 11:49:20 2015 +0100
+++ b/ape.js	Wed May 27 16:45:48 2015 +0100
@@ -30,12 +30,25 @@
 	var xmlSetup = xmlDoc.find('setup');
 	// Should put in an error function here incase of malprocessed or malformed XML
 	
+	// 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 = xmlDoc.find('audioHolder');
+	var testXMLSetups = [];
 	audioHolders.each(function(index,element) {
 		var repeatN = element.attributes['repeatCount'].value;
 		for (var r=0; r<=repeatN; r++) {
-			testXMLSetups[testXMLSetups.length] = element;
+			testXMLSetups.push(element);
 		}
 	});
 	 
@@ -55,6 +68,12 @@
 	{
  		testXMLSetups = randomiseOrder(testXMLSetups);
 	}
+	
+	$(testXMLSetups).each(function(index,elem){
+		testState.stateMap.push(elem);
+	})
+	 
+	 testState.stateMap.push(postTest);
 	 
 	// Obtain the metrics enabled
 	var metricNode = xmlSetup.find('Metric');
@@ -232,23 +251,8 @@
 	testContent.style.zIndex = 1;
 	insertPoint.innerHTML = null; // Clear the current schema
 	
-	// Create pre and post test questions
-	
-	var preTest = xmlSetup.find('PreTest');
-	var postTest = xmlSetup.find('PostTest');
-	preTest = preTest[0];
-	postTest = postTest[0];
-	
 	currentState = 'preTest';
 	
-	// Create Pre-Test Box
-	if (preTest != undefined && preTest.childElementCount >= 1)
-	{
-		//popup.showPopup();
-		//preTestPopupStart(preTest);
-		popup.initState(preTest);
-	}
-	
 	// Inject into HTML
 	testContent.appendChild(title); // Insert the title
 	testContent.appendChild(pagetitle);
@@ -258,17 +262,17 @@
 	insertPoint.appendChild(testContent);
 
 	// Load the full interface
-	
+	testState.initialise();
+	testState.advanceState();
 }
 
-function loadTest(id)
+function loadTest(textXML)
 {
 	
 	// Reset audioEngineContext.Metric globals for new test
 	audioEngineContext.newTestPage();
 	
-	// Used to load a specific test page
-	var textXML = testXMLSetups[id];
+	var id = textXML.id;
 	
 	var feedbackHolder = document.getElementById('feedbackHolder');
 	var canvas = document.getElementById('slider');
@@ -483,19 +487,6 @@
 		trackComment.appendChild(trackCommentBox);
 		feedbackHolder.appendChild(trackComment);
 	});
-	
-	// Now process any pre-test commands
-	
-	var preTest = $(testXMLSetups[id]).find('PreTest')[0];
-	if (preTest.childElementCount > 0)
-	{
-		currentState = 'testRunPre-'+id;
-		//preTestPopupStart(preTest);
-		popup.initState(preTest);
-		//popup.showPopup();
-	} else {
-		currentState = 'testRun-'+id;
-	}
 }
 
 
@@ -534,12 +525,7 @@
 	            return;
 	        }
 	    }
-	    if (currentState.substr(0,7) == 'testRun')
-	    {
-	        hasBeenPlayed = []; // clear array to prepare for next test
-	        audioEngineContext.timer.stopTest();
-	        advanceState();
-	    }
+	    testState.advanceState();
     } else // if a fragment has not been played yet
     {
     	str = "";
@@ -605,13 +591,13 @@
 	});
 }
 
-function pageXMLSave(testId)
+function pageXMLSave(store, testXML, testId)
 {
 	// Saves a specific test page
-	var xmlDoc = currentTestHolder;
+	var xmlDoc = store;
 	// Check if any session wide metrics are enabled
 	
-	var commentShow = testXMLSetups[testId].attributes['elementComments'];
+	var commentShow = testXML.attributes['elementComments'];
 	if (commentShow != undefined) {
 		if (commentShow.value == 'false') {commentShow = false;}
 		else {commentShow = true;}
@@ -716,21 +702,5 @@
 		cqHolder.appendChild(comment);
 		xmlDoc.appendChild(cqHolder);
 	}
-	testResultsHolders[testId] = xmlDoc;
-}
-
-// 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");
-	xmlDoc.appendChild(returnDateNode());
-	for (var i=0; i<testResultsHolders.length; i++)
-	{
-		xmlDoc.appendChild(testResultsHolders[i]);
-	}
-	// Append Pre/Post Questions
-	xmlDoc.appendChild(preTestQuestions);
-	xmlDoc.appendChild(postTestQuestions);
-	
-	return xmlDoc;
+	store = xmlDoc;
 }
\ No newline at end of file
--- a/core.js	Wed May 27 11:49:20 2015 +0100
+++ b/core.js	Wed May 27 16:45:48 2015 +0100
@@ -9,15 +9,16 @@
 var audioContext; // Hold the browser web audio API
 var projectXML; // Hold the parsed setup XML
 var popup; // Hold the interfacePopup object
+var testState;
 var currentState; // Keep track of the current state (pre/post test, which test, final test? first test?)
-var testXMLSetups = []; // Hold the parsed test instances
-var testResultsHolders =[]; // Hold the results from each test for publishing to XML
+//var testXMLSetups = []; // Hold the parsed test instances
+//var testResultsHolders =[]; // Hold the results from each test for publishing to XML
 var currentTrackOrder = []; // Hold the current XML tracks in their (randomised) order
-var currentTestHolder; // Hold any intermediate results during test - metrics
+//var currentTestHolder; // Hold any intermediate results during test - metrics
 var audioEngineContext; // The custome AudioEngine object
 var projectReturn; // Hold the URL for the return
-var preTestQuestions = document.createElement('PreTest'); // Store any pre-test question response
-var postTestQuestions = document.createElement('PostTest'); // Store any post-test question response
+//var preTestQuestions = document.createElement('PreTest'); // Store any pre-test question response
+//var postTestQuestions = document.createElement('PostTest'); // Store any post-test question response
 
 // Add a prototype to the bufferSourceNode to reference to the audioObject holding it
 AudioBufferSourceNode.prototype.owner = undefined;
@@ -31,6 +32,9 @@
 	var AudioContext = window.AudioContext || window.webkitAudioContext;
 	audioContext = new AudioContext;
 	
+	// Create test state
+	testState = new stateMachine();
+	
 	// Create the audio engine object
 	audioEngineContext = new AudioEngine();
 	
@@ -163,6 +167,11 @@
 		} else {
 			// Reached the end of the popupOptions
 			this.hidePopup();
+			if (this.responses.nodeName == testState.stateResults[testState.stateIndex].nodeName) {
+				testState.stateResults[testState.stateIndex] = this.responses;
+			} else {
+				testState.stateResults[testState.stateIndex].appendChild(this.responses);
+			}
 			advanceState();
 		}
 	}
@@ -170,44 +179,114 @@
 
 function advanceState()
 {
-	console.log(currentState);
-	if (currentState == 'preTest')
-	{
-		// End of pre-test, begin the test
-		preTestQuestions = popup.responses;
-		loadTest(0);
-	} else if (currentState == 'postTest') {
-		postTestQuestions = popup.responses;
-		console.log('ALL COLLECTED!');
-		 createProjectSave(projectReturn);
-	}else if (currentState.substr(0,10) == 'testRunPre')
-	{
-		// Start the test
-		var testId = currentState.substr(11,currentState.length-10);
-		currentState = 'testRun-'+testId;
-		currentTestHolder.appendChild(popup.responses);
-		//audioEngineContext.timer.startTest();
-		//audioEngineContext.play();
-	} else if (currentState.substr(0,11) == 'testRunPost')
-	{
-		var testId = currentState.substr(12,currentState.length-11);
-		currentTestHolder.appendChild(popup.responses);
-		testEnded(testId);
-	} else if (currentState.substr(0,7) == 'testRun')
-	{
-		var testId = currentState.substr(8,currentState.length-7);
-		// Check if we have any post tests to perform
-		var postXML = $(testXMLSetups[testId]).find('PostTest')[0];
-		if (postXML == undefined || postXML.childElementCount == 0) {
-			testEnded(testId);
+	// Just for complete clarity
+	testState.advanceState();
+}
+
+function stateMachine()
+{
+	// Object prototype for tracking and managing the test state
+	this.stateMap = [];
+	this.stateIndex = null;
+	this.currentStateMap = [];
+	this.currentIndex = null;
+	this.currentTestId = 0;
+	this.stateResults = [];
+	this.initialise = function(){
+		if (this.stateMap.length > 0) {
+			if(this.stateIndex != null) {
+				console.log('NOTE - State already initialise');
+			}
+			this.stateIndex = -1;
+			var that = this;
+			for (var id=0; id<this.stateMap.length; id++){
+				var name = this.stateMap[id].nodeName;
+				var obj = document.createElement(name);
+				this.stateResults.push(obj);
+			}
+		} else {
+			conolse.log('FATAL - StateMap not correctly constructed. EMPTY_STATE_MAP');
 		}
-		else if (postXML.childElementCount > 0)
-		{
-			currentState = 'testRunPost-'+testId; 
-			popup.initState(postXML);
+	};
+	this.advanceState = function(){
+		if (this.stateIndex == null) {
+			this.initialise();
+		}
+		if (this.stateIndex == -1) {
+			console.log('Starting test...');
+		}
+		if (this.currentIndex == null){
+			if (this.currentStateMap.nodeName == "audioHolder") {
+				// Save current page
+				this.testPageCompleted(this.stateResults[this.stateIndex],this.currentStateMap,this.currentTestId);
+				this.currentTestId++;
+			}
+			this.stateIndex++;
+			if (this.stateIndex >= this.stateMap.length) {
+				console.log('Test Completed');
+				createProjectSave(projectReturn);
+			} else {
+				this.currentStateMap = this.stateMap[this.stateIndex];
+				if (this.currentStateMap.nodeName == "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) {
+						popup.initState(this.currentStateMap);
+					} else {
+						this.advanceState();
+					}
+				} else {
+					this.advanceState();
+				}
+			}
+		} else {
+			this.advanceInnerState();
+		}
+	};
+	
+	this.testPageCompleted = function(store, testXML, testId) {
+		// Function called each time a test page has been completed
+		// Can be used to over-rule default behaviour
+		
+		pageXMLSave(store, testXML, testId);
+	}
+	
+	this.initialiseInnerState = function(testXML) {
+		// Parses the received testXML for pre and post test options
+		this.currentStateMap = [];
+		var preTest = $(testXML).find('PreTest')[0];
+		var postTest = $(testXML).find('PostTest')[0];
+		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(postTest);
+		this.currentIndex = -1;
+		this.advanceInnerState();
+	}
+	
+	this.advanceInnerState = function() {
+		this.currentIndex++;
+		if (this.currentIndex >= this.currentStateMap.length) {
+			this.currentIndex = null;
+			this.currentStateMap = this.stateMap[this.stateIndex];
+			this.advanceState();
+		} else {
+			if (this.currentStateMap[this.currentIndex].nodeName == "audioHolder") {
+				console.log("Loading test page"+this.currentTestId);
+			} else if (this.currentStateMap[this.currentIndex].nodeName == "PreTest") {
+				popup.initState(this.currentStateMap[this.currentIndex]);
+			} else if (this.currentStateMap[this.currentIndex].nodeName == "PostTest") {
+				popup.initState(this.currentStateMap[this.currentIndex]);
+			} else {
+				this.advanceInnerState();
+			}
 		}
 	}
-	console.log(currentState);
+	
+	this.previousState = function(){};
 }
 
 function testEnded(testId)
@@ -303,6 +382,19 @@
 	return submitDiv;
 }
 
+// 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");
+	xmlDoc.appendChild(returnDateNode());
+	for (var i=0; i<testState.stateResults.length; i++)
+	{
+		xmlDoc.appendChild(testState.stateResults[i]);
+	}
+	
+	return xmlDoc;
+}
+
 function AudioEngine() {
 	
 	// Create two output paths, the main outputGain and fooGain.
@@ -634,4 +726,4 @@
 	hold.appendChild(time);
 	return hold
 	
-}
+}
\ No newline at end of file
--- a/example_eval/project.xml	Wed May 27 11:49:20 2015 +0100
+++ b/example_eval/project.xml	Wed May 27 16:45:48 2015 +0100
@@ -38,9 +38,11 @@
 		<audioElements url="9.wav" id="9"/>
 		<audioElements url="10.wav" id="10"/>-->
 		<CommentQuestion id='mixingExperiance'>What is your mixing experiance</CommentQuestion>
+		<!--
 		<PreTest>
 			<statement>Start the Test 3</statement>
 		</PreTest>
+		-->
 		<PostTest>
 			<question id="genre" mandatory="true">Please enter the genre</question>
 		</PostTest>