diff core.js @ 608:0256f3748b27 multiple-tests-concatenation

Merge
author Giulio Moro <giuliomoro@yahoo.it>
date Sat, 12 Mar 2016 15:32:30 +0000
parents 328f24798462 640ffb822da1
children 34d8bca65edc
line wrap: on
line diff
--- a/core.js	Fri Mar 11 16:49:47 2016 +0000
+++ b/core.js	Sat Mar 12 15:32:30 2016 +0000
@@ -166,38 +166,10 @@
 	//var decode = $.parseXML(response);
 	//projectXML = $(decode);
 	
-	// First perform XML schema validation
-	var Module = {
-		xml: response,
-		schema: schemaXSD,
-		arguments:["--noout", "--schema", 'test-schema.xsd','document.xml']
-	};
-	
-	var xmllint = validateXML(Module);
-	console.log(xmllint);
-	if(xmllint != 'document.xml validates\n')
-	{
-		document.getElementsByTagName('body')[0].innerHTML = null;
-		var msg = document.createElement("h3");
-		msg.textContent = "FATAL ERROR";
-		var span = document.createElement("h4");
-		span.textContent = "The XML validator returned the following errors when decoding your XML file";
-		document.getElementsByTagName('body')[0].appendChild(msg);
-		document.getElementsByTagName('body')[0].appendChild(span);
-		xmllint = xmllint.split('\n');
-		for (var i in xmllint)
-		{
-			document.getElementsByTagName('body')[0].appendChild(document.createElement('br'));
-			var span = document.createElement("span");
-			span.textContent = xmllint[i];
-			document.getElementsByTagName('body')[0].appendChild(span);
-		}
-		return;
-	}
-	
-	var parse = new DOMParser();
-	projectXML = parse.parseFromString(response,'text/xml');
-	var errorNode = projectXML.getElementsByTagName('parsererror');
+    // Check if XML is new or a resumption
+    var parse = new DOMParser();
+	var responseDocument = parse.parseFromString(response,'text/xml');
+    var errorNode = responseDocument.getElementsByTagName('parsererror');
 	if (errorNode.length >= 1)
 	{
 		var msg = document.createElement("h3");
@@ -210,10 +182,90 @@
 		document.getElementsByTagName('body')[0].appendChild(errorNode[0]);
 		return;
 	}
-	
-	// Build the specification
-	specification.decode(projectXML);
-	storage.initialise();
+    if (responseDocument.children[0].nodeName == "waet") {
+        // document is a specification
+        
+        // Perform XML schema validation
+        var Module = {
+            xml: response,
+            schema: schemaXSD,
+            arguments:["--noout", "--schema", 'test-schema.xsd','document.xml']
+        };
+            projectXML = responseDocument;
+        var xmllint = validateXML(Module);
+        console.log(xmllint);
+        if(xmllint != 'document.xml validates\n')
+        {
+            document.getElementsByTagName('body')[0].innerHTML = null;
+            var msg = document.createElement("h3");
+            msg.textContent = "FATAL ERROR";
+            var span = document.createElement("h4");
+            span.textContent = "The XML validator returned the following errors when decoding your XML file";
+            document.getElementsByTagName('body')[0].appendChild(msg);
+            document.getElementsByTagName('body')[0].appendChild(span);
+            xmllint = xmllint.split('\n');
+            for (var i in xmllint)
+            {
+                document.getElementsByTagName('body')[0].appendChild(document.createElement('br'));
+                var span = document.createElement("span");
+                span.textContent = xmllint[i];
+                document.getElementsByTagName('body')[0].appendChild(span);
+            }
+            return;
+        }
+        // Build the specification
+	   specification.decode(projectXML);
+        // Generate the session-key
+        storage.initialise();
+        
+    } else if (responseDocument.children[0].nodeName == "waetresult") {
+        // document is a result
+        projectXML = document.implementation.createDocument(null,"waet");
+        projectXML.children[0].appendChild(responseDocument.getElementsByTagName('waet')[0].getElementsByTagName("setup")[0].cloneNode(true));
+        var child = responseDocument.children[0].children[0];
+        while (child != null) {
+            if (child.nodeName == "survey") {
+                // One of the global survey elements
+                if (child.getAttribute("state") == "complete") {
+                    // We need to remove this survey from <setup>
+                    var location = child.getAttribute("location");
+                    var globalSurveys = projectXML.getElementsByTagName("setup")[0].getElementsByTagName("survey")[0];
+                    while(globalSurveys != null) {
+                        if (location == "pre" || location == "before") {
+                            if (globalSurveys.getAttribute("location") == "pre" || globalSurveys.getAttribute("location") == "before") {
+                                projectXML.getElementsByTagName("setup")[0].removeChild(globalSurveys);
+                                break;
+                            }
+                        } else {
+                            if (globalSurveys.getAttribute("location") == "post" || globalSurveys.getAttribute("location") == "after") {
+                                projectXML.getElementsByTagName("setup")[0].removeChild(globalSurveys);
+                                break;
+                            }
+                        }
+                        globalSurveys = globalSurveys.nextElementSibling;
+                    }
+                } else {
+                    // We need to complete this, so it must be regenerated by store
+                    var copy = child;
+                    child = child.previousElementSibling;
+                    responseDocument.children[0].removeChild(copy);
+                }
+            } else if (child.nodeName == "page") {
+                if (child.getAttribute("state") == "empty") {
+                    // We need to complete this page
+                    projectXML.children[0].appendChild(responseDocument.getElementById(child.getAttribute("ref")).cloneNode(true));
+                    var copy = child;
+                    child = child.previousElementSibling;
+                    responseDocument.children[0].removeChild(copy);
+                }
+            }
+            child = child.nextElementSibling;
+        }
+        // Build the specification
+	    specification.decode(projectXML);
+        // Use the original
+        storage.initialise(responseDocument);
+    }
 	/// CHECK FOR SAMPLE RATE COMPATIBILITY
 	if (specification.sampleRate != undefined) {
 		if (Number(specification.sampleRate) != audioContext.sampleRate) {
@@ -297,27 +349,6 @@
 	
 	// Create the audio engine object
 	audioEngineContext = new AudioEngine(specification);
-	
-	$(specification.pages).each(function(index,elem){
-		$(elem.audioElements).each(function(i,audioElem){
-			var URL = elem.hostURL + audioElem.url;
-			var buffer = null;
-			for (var i=0; i<audioEngineContext.buffers.length; i++)
-			{
-				if (URL == audioEngineContext.buffers[i].url)
-				{
-					buffer = audioEngineContext.buffers[i];
-					break;
-				}
-			}
-			if (buffer == null)
-			{
-				buffer = new audioEngineContext.bufferObj();
-				buffer.getMedia(URL);
-				audioEngineContext.buffers.push(buffer);
-			}
-		});
-	});
 }
 
 function createProjectSave(destURL) {
@@ -328,7 +359,7 @@
 	var parent = document.createElement("div");
 	parent.appendChild(xmlDoc);
 	var file = [parent.innerHTML];
-	if (destURL == "null" || destURL == undefined) {
+	if (destURL == "local") {
 		var bb = new Blob(file,{type : 'application/xml'});
 		var dnlk = window.URL.createObjectURL(bb);
 		var a = document.createElement("a");
@@ -341,8 +372,7 @@
 		popup.popupContent.innerHTML = "<span>Please save the file below to give to your test supervisor</span><br>";
 		popup.popupContent.appendChild(a);
 	} else {
-		var xmlhttp = new XMLHttpRequest;
-		destUrlFull = destURL;
+		destUrlFull = destURL+"?key="+storage.SessionKey.key;
 		var saveFilenamePrefix;
 		// parse the querystring of destUrl, get the "id" (if any) and append it to destUrl
 		var qs = returnUrl.split("?");
@@ -357,43 +387,39 @@
 			}
 		}
 		if(typeof(saveFilenamePrefix) !== "undefined"){
-			destUrlFull+="?saveFilenamePrefix="+saveFilenamePrefix;
+			destUrlFull+="&saveFilenamePrefix="+saveFilenamePrefix;
 		}
+		var xmlhttp = new XMLHttpRequest;
 		xmlhttp.open("POST",destUrlFull,true);
 		xmlhttp.setRequestHeader('Content-Type', 'text/xml');
 		xmlhttp.onerror = function(){
 			console.log('Error saving file to server! Presenting download locally');
-			createProjectSave(null);
+			createProjectSave("local");
 		};
-		xmlhttp.onreadystatechange  = function() {
-			console.log(xmlhttp.status);
-			if (xmlhttp.status != 200 && xmlhttp.readyState == 4) {
-				createProjectSave(null);
-			} else {
-				var parser = new DOMParser();
-				var xmlDoc = parser.parseFromString(xmlhttp.responseText, "application/xml");
-				if (xmlDoc == null)
-				{
-					createProjectSave('null');
-				}
-				var response = xmlDoc.childNodes[0];
-				if (response.getAttribute('state') == "OK")
-				{
-					var file = response.getElementsByTagName('file')[0];
-					console.log('Save OK: Filename '+file.textContent+','+file.getAttribute('bytes')+'B');
-					popup.showPopup();
-					popup.popupContent.innerHTML = null;
-					popup.popupContent.textContent = "Thank you!";
-					window.onbeforeunload=null;
-					if(typeof(returnUrl) !== "undefined"){
-						window.location = returnUrl;
-					}
-				} else {
-					var message = response.getElementsByTagName('message')[0];
-					errorSessionDump(message.textContent);
-				}
-			}
-		};
+		xmlhttp.onload = function() {
+            console.log(xmlhttp);
+            if (this.status >= 300) {
+                console.log("WARNING - Could not update at this time");
+                createProjectSave("local");
+            } else {
+                var parser = new DOMParser();
+                var xmlDoc = parser.parseFromString(xmlhttp.responseText, "application/xml");
+                var response = xmlDoc.getElementsByTagName('response')[0];
+      					window.onbeforeunload=null;
+                if (response.getAttribute("state") == "OK") {
+                    var file = response.getElementsByTagName("file")[0];
+      							if(typeof(returnUrl) !== "undefined"){
+												window.location = returnUrl;
+										}
+                    console.log("Save: OK, written "+file.getAttribute("bytes")+"B");
+                    popup.popupContent.textContent = "Thank you. Your session has been saved.";
+    	          } else {
+                    var message = response.getElementsByTagName("message");
+                    console.log("Save: Error! "+message.textContent);
+                    createProjectSave("local");
+                }
+            }
+        };
 		xmlhttp.send(file);
 		popup.showPopup();
 		popup.popupContent.innerHTML = null;
@@ -452,6 +478,10 @@
 	return Math.pow(10,gain/20.0);
 }
 
+function randomString(length) {
+    return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1);
+}
+
 function interfacePopup() {
 	// Creates an object to manage the popup
 	this.popup = null;
@@ -747,6 +777,7 @@
 			{
 				this.store.postResult(node);
 			}
+            this.store.complete();
 			advanceState();
 		}
 	};
@@ -825,6 +856,22 @@
 		{
 			if (specification.testPages <= i && specification.testPages != 0) {break;}
 			this.stateMap.push(pageHolder[i]);
+            storage.createTestPageStore(pageHolder[i]);
+            for (var element of pageHolder[i].audioElements) {
+                var URL = pageHolder[i].hostURL + element.url;
+                var buffer = null;
+                for (var buffObj of audioEngineContext.buffers) {
+                    if (URL == buffObj.url) {
+                        buffer = buffObj;
+                        break;
+                    }
+                }
+                if (buffer == null) {
+                    buffer = new audioEngineContext.bufferObj();
+                    buffer.getMedia(URL);
+                    audioEngineContext.buffers.push(buffer);
+                }
+            }
 		}
         
 		if (specification.preTest != null) {this.preTestSurvey = specification.preTest;}
@@ -843,6 +890,7 @@
 		if (this.stateIndex == null) {
 			this.initialise();
 		}
+        storage.update();
 		if (this.stateIndex == -1) {
 			this.stateIndex++;
 			console.log('Starting test...');
@@ -875,7 +923,7 @@
 				{
 					this.currentStateMap.audioElements = randomiseOrder(this.currentStateMap.audioElements);
 				}
-                this.currentStore = storage.createTestPageStore(this.currentStateMap);
+                this.currentStore = storage.testPages[this.stateIndex];
 				if (this.currentStateMap.preTest != null)
 				{
 					this.currentStatePosition = 'pre';
@@ -936,6 +984,7 @@
 			element.exportXMLDOM(storePoint);
 		}
 		pageXMLSave(storePoint.XMLDOM, this.currentStateMap);
+        storePoint.complete();
 	};
 }
 
@@ -1189,7 +1238,7 @@
 		var aeNodes = this.pageStore.XMLDOM.getElementsByTagName('audioelement');
 		for (var i=0; i<aeNodes.length; i++)
 		{
-			if(aeNodes[i].id == element.id)
+			if(aeNodes[i].getAttribute("ref") == element.id)
 			{
 				this.audioObjects[audioObjectId].storeDOM = aeNodes[i];
 				break;
@@ -1931,6 +1980,7 @@
 			this.type = undefined;
 			this.schema = specification.schema.getAllElementsByName('surveyentry')[0];
 			this.id = undefined;
+            this.name = undefined;
 			this.mandatory = undefined;
 			this.statement = undefined;
 			this.boxsize = undefined;
@@ -1986,34 +2036,32 @@
 				var statement = doc.createElement('statement');
 				statement.textContent = this.statement;
 				node.appendChild(statement);
-				switch(this.type)
-				{
-				case "statement":
-					break;
-				case "question":
+                if (this.type != "statement") {
                     node.id = this.id;
+                    if (this.name != undefined) { node.setAttribute("name",this.name);}
                     if (this.mandatory != undefined) { node.setAttribute("mandatory",this.mandatory);}
-                    if (this.boxsize != undefined) {node.setAttribute("boxsize",this.boxsize);}
-                    break;
-                case "number":
-                    node.id = this.id;
-                    if (this.mandatory != undefined) { node.setAttribute("mandatory",this.mandatory);}
-                    if (this.min != undefined) {node.setAttribute("min", this.min);}
-                    if (this.max != undefined) {node.setAttribute("max", this.max);}
-                    break;
-				case "checkbox":
-				case "radio":
-					node.id = this.id;
-					for (var i=0; i<this.options.length; i++)
-					{
-						var option = this.options[i];
-						var optionNode = doc.createElement("option");
-						optionNode.setAttribute("name",option.name);
-						optionNode.textContent = option.text;
-						node.appendChild(optionNode);
-					}
-					break;
-				}
+                    switch(this.type)
+                    {
+                    case "question":
+                        if (this.boxsize != undefined) {node.setAttribute("boxsize",this.boxsize);}
+                        break;
+                    case "number":
+                        if (this.min != undefined) {node.setAttribute("min", this.min);}
+                        if (this.max != undefined) {node.setAttribute("max", this.max);}
+                        break;
+                    case "checkbox":
+                    case "radio":
+                        for (var i=0; i<this.options.length; i++)
+                        {
+                            var option = this.options[i];
+                            var optionNode = doc.createElement("option");
+                            optionNode.setAttribute("name",option.name);
+                            optionNode.textContent = option.text;
+                            node.appendChild(optionNode);
+                        }
+                        break;
+                    }
+                }
 				return node;
 			};
 		};
@@ -2153,6 +2201,7 @@
 		this.showElementComments = undefined;
 		this.outsideReference = null;
 		this.loudness = null;
+        this.label = null;
 		this.preTest = null;
 		this.postTest = null;
 		this.interfaces = [];
@@ -2280,6 +2329,7 @@
 		
 		this.commentQuestionNode = function() {
 			this.id = null;
+            this.name = undefined;
 			this.type = undefined;
 			this.options = [];
 			this.statement = undefined;
@@ -2287,6 +2337,7 @@
 			this.decode = function(parent,xml)
 			{
 				this.id = xml.id;
+                this.name = xml.getAttribute('name');
 				this.type = xml.getAttribute('type');
 				this.statement = xml.getElementsByTagName('statement')[0].textContent;
 				var optNodes = xml.getElementsByTagName('option');
@@ -2305,6 +2356,7 @@
 				var node = root.createElement("commentquestion");
                 node.id = this.id;
                 node.setAttribute("type",this.type);
+                if (this.name != undefined){node.setAttribute("name",this.name);}
                 var statement = root.createElement("statement");
                 statement.textContent = this.statement;
                 node.appendChild(statement);
@@ -2322,6 +2374,7 @@
 		this.audioElementNode = function() {
 			this.url = null;
 			this.id = null;
+            this.name = null;
 			this.parent = null;
 			this.type = null;
 			this.marker = null;
@@ -3013,8 +3066,8 @@
 			if (passed == false)
 			{
 				check_pass = false;
-				console.log("Continue listening to track-"+audioEngineContext.audioObjects.interfaceDOM.getPresentedId());
-				error_obj.push(audioEngineContext.audioObjects.interfaceDOM.getPresentedId());
+				console.log("Continue listening to track-"+object.interfaceDOM.getPresentedId());
+				error_obj.push(object.interfaceDOM.getPresentedId());
 			}
 		}
 		if (check_pass == false)
@@ -3113,15 +3166,82 @@
 	this.globalPreTest = null;
 	this.globalPostTest = null;
 	this.testPages = [];
-	this.document = document.implementation.createDocument(null,"waetresult");
-	this.root = this.document.childNodes[0];
+	this.document = null;
+	this.root = null;
 	this.state = 0;
 	
-	this.initialise = function()
+	this.initialise = function(existingStore)
 	{
-		if (specification.preTest != undefined){this.globalPreTest = new this.surveyNode(this,this.root,specification.preTest);}
-		if (specification.postTest != undefined){this.globalPostTest = new this.surveyNode(this,this.root,specification.postTest);}
+        if (existingStore == undefined) {
+            // We need to get the sessionKey
+            this.SessionKey.generateKey();
+            this.document = document.implementation.createDocument(null,"waetresult");
+            this.root = this.document.childNodes[0];
+            var projectDocument = specification.projectXML;
+            projectDocument.setAttribute('file-name',url);
+            this.root.appendChild(projectDocument);
+            this.root.appendChild(returnDateNode());
+            this.root.appendChild(interfaceContext.returnNavigator());
+        } else {
+            this.document = existingStore;
+            this.root = existingStore.children[0];
+            this.SessionKey.key = this.root.getAttribute("key");
+        }
+        if (specification.preTest != undefined){this.globalPreTest = new this.surveyNode(this,this.root,specification.preTest);}
+        if (specification.postTest != undefined){this.globalPostTest = new this.surveyNode(this,this.root,specification.postTest);}
 	};
+    
+    this.SessionKey = {
+        key: null,
+        request: new XMLHttpRequest(),
+        parent: this,
+        handleEvent: function() {
+            var parse = new DOMParser();
+            var xml = parse.parseFromString(this.request.response,"text/xml");
+            if (xml.getAllElementsByTagName("state")[0].textContent == "OK") {
+                this.key = xml.getAllElementsByTagName("key")[0].textContent;
+                this.parent.root.setAttribute("key",this.key);
+                this.parent.root.setAttribute("state","empty");
+            } else {
+                this.generateKey();
+            }
+        },
+        generateKey: function() {
+            var temp_key = randomString(32);
+            this.request.open("GET","keygen.php?key="+temp_key,true);
+            this.request.addEventListener("load",this);
+            this.request.send();
+        },
+        update: function() {
+            this.parent.root.setAttribute("state","update");
+            var xmlhttp = new XMLHttpRequest();
+            xmlhttp.open("POST",specification.projectReturn+"?key="+this.key);
+            xmlhttp.setRequestHeader('Content-Type', 'text/xml');
+            xmlhttp.onerror = function(){
+                console.log('Error updating file to server!');
+            };
+            var hold = document.createElement("div");
+            var clone = this.parent.root.cloneNode(true);
+            hold.appendChild(clone);
+            xmlhttp.onload = function() {
+                if (this.status >= 300) {
+                    console.log("WARNING - Could not update at this time");
+                } else {
+                    var parser = new DOMParser();
+                    var xmlDoc = parser.parseFromString(xmlhttp.responseText, "application/xml");
+                    var response = xmlDoc.getElementsByTagName('response')[0];
+                    if (response.getAttribute("state") == "OK") {
+                        var file = response.getElementsByTagName("file")[0];
+                        console.log("Intermediate save: OK, written "+file.getAttribute("bytes")+"B");
+                    } else {
+                        var message = response.getElementsByTagName("message");
+                        console.log("Intermediate save: Error! "+message.textContent);
+                    }
+                }
+            }
+            xmlhttp.send([hold.innerHTML]);
+        }
+    }
 	
 	this.createTestPageStore = function(specification)
 	{
@@ -3134,14 +3254,16 @@
 	{
 		this.specification = specification;
 		this.parent = parent;
+        this.state = "empty";
 		this.XMLDOM = this.parent.document.createElement('survey');
 		this.XMLDOM.setAttribute('location',this.specification.location);
+        this.XMLDOM.setAttribute("state",this.state);
 		for (var optNode of this.specification.options)
 		{
 			if (optNode.type != 'statement')
 			{
 				var node = this.parent.document.createElement('surveyresult');
-				node.id = optNode.id;
+				node.setAttribute("ref",optNode.id);
 				node.setAttribute('type',optNode.type);
 				this.XMLDOM.appendChild(node);
 			}
@@ -3153,7 +3275,14 @@
 			// From popup: node is the popupOption node containing both spec. and results
 			// ID is the position
 			if (node.specification.type == 'statement'){return;}
-			var surveyresult = this.parent.document.getElementById(node.specification.id);
+			var surveyresult = this.XMLDOM.children[0];
+            while(surveyresult != null) {
+                if (surveyresult.getAttribute("ref") == node.specification.id)
+                {
+                    break;
+                }
+                surveyresult = surveyresult.nextElementSibling;
+            }
 			switch(node.specification.type)
 			{
 			case "number":
@@ -3179,6 +3308,10 @@
 				break;
 			}
 		};
+        this.complete = function() {
+            this.state = "complete";
+            this.XMLDOM.setAttribute("state",this.state);
+        }
 	};
 	
 	this.pageNode = function(parent,specification)
@@ -3186,9 +3319,11 @@
 		// Create one store per test page
 		this.specification = specification;
 		this.parent = parent;
+        this.state = "empty";
 		this.XMLDOM = this.parent.document.createElement('page');
-		this.XMLDOM.setAttribute('id',specification.id);
+		this.XMLDOM.setAttribute('ref',specification.id);
 		this.XMLDOM.setAttribute('presentedId',specification.presentedId);
+        this.XMLDOM.setAttribute("state",this.state);
 		if (specification.preTest != undefined){this.preTest = new this.parent.surveyNode(this.parent,this.XMLDOM,this.specification.preTest);}
 		if (specification.postTest != undefined){this.postTest = new this.parent.surveyNode(this.parent,this.XMLDOM,this.specification.postTest);}
 		
@@ -3200,7 +3335,8 @@
 		for (var element of this.specification.audioElements)
 		{
 			var aeNode = this.parent.document.createElement('audioelement');
-			aeNode.id = element.id;
+			aeNode.setAttribute('ref',element.id);
+            if (element.name != undefined){aeNode.setAttribute('name',element.name)};
 			aeNode.setAttribute('type',element.type);
 			aeNode.setAttribute('url', element.url);
 			aeNode.setAttribute('gain', element.gain);
@@ -3217,16 +3353,20 @@
 		}
 		
 		this.parent.root.appendChild(this.XMLDOM);
+        
+        this.complete = function() {
+            this.state = "complete";
+            this.XMLDOM.setAttribute("state","complete");
+        }
 	};
+    this.update = function() {
+        this.SessionKey.update();
+    }
 	this.finish = function()
 	{
 		if (this.state == 0)
 		{
-			var projectDocument = specification.projectXML;
-			projectDocument.setAttribute('file-name',url);
-			this.root.appendChild(projectDocument);
-			this.root.appendChild(returnDateNode());
-			this.root.appendChild(interfaceContext.returnNavigator());
+            this.update();
 		}
 		this.state = 1;
 		return this.root;