changeset 311:f46398fdf56c Dev_main

Updating test create using questions
author Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk>
date Wed, 23 Sep 2015 11:42:11 +0100
parents bcfce203ec91
children f73d9333ab0d
files ape.css core.css core.js test_create/test_create.html test_create/test_create_advanced.html
diffstat 5 files changed, 1597 insertions(+), 756 deletions(-) [+]
line wrap: on
line diff
--- a/ape.css	Tue Sep 15 10:16:34 2015 +0100
+++ b/ape.css	Wed Sep 23 11:42:11 2015 +0100
@@ -21,18 +21,6 @@
 	font-size: 1.5em;
 }
 
-div.testHalt {
-	/* Specify any colouring during the test halt for pre/post questions */
-	background-color: rgba(0,0,0,0.5);
-	/* Don't mess with this bit */
-	z-index: 2;
-	width: 100%;
-	height: 100%;
-	position: absolute;
-	left: 0px;
-	top: 0px;
-}
-
 button {
 	/* Specify any button structure or style */
 	min-width: 20px;
--- a/core.css	Tue Sep 15 10:16:34 2015 +0100
+++ b/core.css	Wed Sep 23 11:42:11 2015 +0100
@@ -58,6 +58,18 @@
 	background-color: #fff;
 }
 
+div.testHalt {
+	/* Specify any colouring during the test halt for pre/post questions */
+	background-color: rgba(0,0,0,0.5);
+	/* Don't mess with this bit */
+	z-index: 2;
+	width: 100%;
+	height: 100%;
+	position: absolute;
+	left: 0px;
+	top: 0px;
+}
+
 textarea.trackComment {
 	max-width: 594px;
 	min-width: 350px;
--- a/core.js	Tue Sep 15 10:16:34 2015 +0100
+++ b/core.js	Wed Sep 23 11:42:11 2015 +0100
@@ -1299,14 +1299,14 @@
 function Specification() {
 	// Handles the decoding of the project specification XML into a simple JavaScript Object.
 	
-	this.interfaceType;
-	this.commonInterface;
-	this.projectReturn;
-	this.randomiseOrder;
-	this.collectMetrics;
-	this.testPages;
-	this.preTest;
-	this.postTest;
+	this.interfaceType = null;
+	this.commonInterface = null;
+	this.projectReturn = null;
+	this.randomiseOrder = null;
+	this.collectMetrics = null;
+	this.testPages = null;
+	this.preTest = null;
+	this.postTest = null;
 	this.metrics =[];
 	
 	this.audioHolders = [];
--- a/test_create/test_create.html	Tue Sep 15 10:16:34 2015 +0100
+++ b/test_create/test_create.html	Wed Sep 23 11:42:11 2015 +0100
@@ -7,791 +7,839 @@
 		Remove this if you use the .htaccess -->
 		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
 
-		<title>WAET Create Test</title>
-		<meta name="description" content="">
-		<meta name="author" content="">
+		<title>WAET: Test Creator</title>
 
 		<meta name="viewport" content="width=device-width; initial-scale=1.0">
+		<script type="text/javascript">
 		
-		<script type="text/javascript">
-			// To aid 'one-page set-up' all scripts and CSS must be included directly in this file!
-			var topLevel;
-			window.onload = function() {
-				// Initialise page
-				topLevel = document.getElementById('topLevelBody');
-				var setup = document.createElement('div');
-				setup.id = 'setupTagDiv';
-				
-				// Setup drag/drop handles
-				var dropBody = document.getElementById('dragFile');
-				dropBody.addEventListener('dragover', handleDragOver, false);
-				dropBody.addEventListener('dragenter',handleDragEnter,false);
-				dropBody.addEventListener('dragleave',handleDragLeave,false);
-				dropBody.addEventListener('drop', handleDrop,false);
+			var APEInterfaceOptions = [["playhead","page-count"],["Show the playhead/scrubber bar", "Show test page count"]];
+			var APEInterfaceChecks = [["fragmentPlayed","fragmentFullPlayback","fragmentMoved","fragmentComments"],["All Fragments Played","All Fragments Played in entirety","All sliders moved","All fragments have comments"]];
+			var MUSHRAInterfaceOptions = [[],[]];
+			var MUSHRAInterfaceChecks = [["fragmentPlayed","fragmentMoved","fragmentComments"],["All Fragments Played","All sliders moved","All fragments have comments"]];
+			var popupInstance;
+			var specificationNode;
+			var audioContext;
+			window.onload = function()
+			{
+				var AudioContext = window.AudioContext || window.webkitAudioContext;
+				audioContext = new AudioContext;
+				popupInstance = new popup();
+				popupInstance.advanceState();
+				specificationNode = new Specification();
 			};
 			
-			function attributePair(string, type, mandatory){
-				var id = document.createElement("span");
-				id.textContent = string;
-				var input = document.createElement("input");
-				input.type = type;
-				if (type == 'text') {
-					if (mandatory == true) {
-						input.setAttribute('mandatory','true');
+			function popup()
+			{
+				var x = window.innerWidth;
+				var y = window.innerHeight;
+				this.popupHolder = document.createElement('div');
+				this.popupHolder.style.visibility = 'hidden';
+				this.popupContent = document.createElement('div');
+				this.popupTitle = document.createElement('div');
+				this.popupBody = document.createElement('div');
+				this.popupFooter = document.createElement('div');
+				this.popupTitleText = document.createElement('span');
+				this.popupTitle.appendChild(this.popupTitleText);
+				
+				this.popupHolder.className = "popup";
+				this.popupHolder.style.left = (x-500)/2 +'px';
+				this.popupHolder.style.top = (y-400)/2 + 'px';
+				this.popupContent.style.padding = "20px";
+				this.popupHolder.appendChild(this.popupContent);
+				
+				this.popupTitle.style.width = "100%";
+				this.popupTitle.style.height = "50px";
+				this.popupTitle.style.fontSize = "xx-large";
+				this.popupContent.appendChild(this.popupTitle);
+				
+				this.popupBody.style.width = "100%";
+				this.popupBody.style.height = "280px";
+				this.popupContent.appendChild(this.popupBody);
+				
+				this.popupFooter.style.width = "100%";
+				this.popupFooter.style.height = "30px";
+				this.popupContent.appendChild(this.popupFooter);
+				var body = document.getElementsByTagName('body')[0];
+				body.appendChild(this.popupHolder);
+				
+				this.pageBlank = document.createElement('div');
+				body.appendChild(this.pageBlank);
+				this.pageBlank.style.width = "100%";
+				this.pageBlank.style.height = "100%";
+				this.pageBlank.style.position = "absolute";
+				this.pageBlank.style.left = "0px";
+				this.pageBlank.style.top = "0px";
+				this.pageBlank.style.backgroundColor = "rgba(0,0,0,0.5)";
+				this.pageBlank.style.visibility = 'hidden';
+				
+				this.state = 0;
+				
+				this.showPopup = function()
+				{
+					this.popupHolder.style.visibility = 'visible';
+					this.popupHolder.style.zIndex = "3";
+					this.pageBlank.style.visibility = 'visible';
+					this.pageBlank.style.zIndex = "2";
+				};
+				
+				this.hidePopup = function()
+				{
+					this.popupHolder.style.visibility = 'hidden';
+					this.popupHolder.style.zIndex = "-1";
+					this.pageBlank.style.visibility = 'hidden';
+					this.pageBlank.style.zIndex = "-2";
+				};
+				
+				this.init = function()
+				{
+					this.popupTitleText.textContent = "Welcome";
+					var text = document.createElement('span');
+					text.textContent = "Thank you for downloading the Web Audio Evaluation Toolbox. This page will help guide you through creating the documents required to run a test. If you have an existing XML file you wish to edit, please drag and drop it into the box below";
+					var dnd = document.createElement('div');
+					dnd.style.width = "100%";
+					dnd.style.height = "50px";
+					dnd.className = "dragndrop";
+					this.popupBody.appendChild(text);
+					this.popupBody.appendChild(dnd);
+					this.showPopup();
+					
+					var button = document.createElement('button');
+					button.className = "popupButton";
+					button.textContent = "New File";
+					button.onclick = function(event) {
+						popupInstance.advanceState();
+					};
+					this.popupFooter.appendChild(button);
+				};
+				
+				this.advanceState = function()
+				{
+					this.popupBody.innerHTML = null;
+					this.popupFooter.innerHTML = null;
+					this.popupTitleText.textContent = null;
+					switch(this.state)
+					{
+					case 0:
+						this.init();
+						break;
+					case 1:
+						this.popupTitleText.textContent = "Test Type";
+						var text = document.createElement("span");
+						text.textContent = "What type of test would you like to use. Currently APE (Audio Perceptual Evaluation) and MUSHRA style interfaces are available";
+						this.popupBody.appendChild(text);
+						var select = document.createElement("select");
+						select.id="interface-select";
+						var opt1 = document.createElement("option");
+						opt1.value = "APE";
+						opt1.textContent = "APE";
+						select.appendChild(opt1);
+						var opt2 = document.createElement("option");
+						opt2.value = "MUSHRA";
+						opt2.textContent = "MUSHRA";
+						select.appendChild(opt2);
+						this.popupBody.appendChild(select);
+						
+						var button = document.createElement('button');
+						button.className = "popupButton";
+						button.textContent = "Submit";
+						button.onclick = function(event) {
+							var select = document.getElementById("interface-select");
+							specificationNode.interfaceType = select.value;
+							specificationNode.collectMetrics = true;
+							popupInstance.advanceState();
+						};
+						this.popupFooter.appendChild(button);
+						break;
+					case 2:
+						this.popupTitleText.textContent = "Test Options";
+						var holder = document.createElement('div');
+						holder.style.margin = "5px";
+						var checkbox = document.createElement('input');
+						checkbox.type = 'checkbox';
+						checkbox.id = "Randomise-Page";
+						var text = document.createElement('span');
+						text.textContent = "Randomise Page Order";
+						holder.appendChild(checkbox);
+						holder.appendChild(text);
+						this.popupBody.appendChild(holder);
+						switch(specificationNode.interfaceType)
+						{
+						case "APE":
+							for (var i=0; i<APEInterfaceOptions[0].length; i++)
+							{
+								holder = document.createElement('div');
+								holder.style.margin = "5px";
+								checkbox = document.createElement('input');
+								checkbox.type = 'checkbox';
+								checkbox.setAttribute("name","option");
+								checkbox.id = APEInterfaceOptions[0][i];
+								text = document.createElement('span');
+								text.textContent = APEInterfaceOptions[1][i];
+								holder.appendChild(checkbox);
+								holder.appendChild(text);
+								this.popupBody.appendChild(holder);
+							}
+							for (var i=0; i<APEInterfaceChecks[0].length; i++)
+							{
+								holder = document.createElement('div');
+								holder.style.margin = "5px";
+								checkbox = document.createElement('input');
+								checkbox.type = 'checkbox';
+								checkbox.setAttribute("name","check");
+								checkbox.id = APEInterfaceChecks[0][i];
+								text = document.createElement('span');
+								text.textContent = APEInterfaceChecks[1][i];
+								holder.appendChild(checkbox);
+								holder.appendChild(text);
+								this.popupBody.appendChild(holder);
+							}
+							break;
+						case "MUSHRA":
+							for (var i=0; i<MUSHRAInterfaceOptions[0].length; i++)
+							{
+								holder = document.createElement('div');
+								holder.style.margin = "5px";
+								checkbox = document.createElement('input');
+								checkbox.type = 'checkbox';
+								checkbox.setAttribute("name","option");
+								checkbox.id = MUSHRAInterfaceOptions[0][i];
+								text = document.createElement('span');
+								text.textContent = MUSHRAInterfaceOptions[1][i];
+								holder.appendChild(checkbox);
+								holder.appendChild(text);
+								this.popupBody.appendChild(holder);
+							}
+							for (var i=0; i<MUSHRAInterfaceChecks[0].length; i++)
+							{
+								holder = document.createElement('div');
+								holder.style.margin = "5px";
+								checkbox = document.createElement('input');
+								checkbox.type = 'checkbox';
+								checkbox.setAttribute("name","check");
+								checkbox.id = MUSHRAInterfaceChecks[0][i];
+								text = document.createElement('span');
+								text.textContent = MUSHRAInterfaceChecks[1][i];
+								holder.appendChild(checkbox);
+								holder.appendChild(text);
+								this.popupBody.appendChild(holder);
+							}
+						}
+						var button = document.createElement('button');
+						button.className = "popupButton";
+						button.textContent = "Submit";
+						button.onclick = function(event) {
+							var optHold = popupInstance.popupBody;
+							var opt = optHold.firstChild;
+							var input = opt.getElementsByTagName('input')[0];
+							specificationNode.randomiseOrder = input.checked;
+							while(opt.nextSibling != null)
+							{
+								opt = opt.nextSibling;
+								input = opt.getElementsByTagName('input')[0];
+								if (input.checked)
+								{
+									specificationNode.commonInterface.options.push(new specificationNode.commonInterface.optionNode(input));
+								}
+								
+							}
+							popupInstance.advanceState();
+						};
+						this.popupFooter.appendChild(button);
+						break;
+					case 3:
+						this.popupTitleText.textContent = "Test Page";
+						var span = document.createElement('span');
+						span.textContent = "Drag and drop your audio files into the box below to add them to a test page";
+						this.popupBody.appendChild(span);
+						var dnd = document.createElement('div');
+						dnd.id = "audio-holder-drop";
+						dnd.style.width = "100%";
+						dnd.style.minHeight = "50px";
+						dnd.style.maxHeight = "220px";
+						dnd.style.overflow = 'auto';
+						dnd.className = "dragndrop";
+						dnd.ondragover = function(e) {
+							if(e.preventDefault) {e.preventDefault();}
+							return false;
+						};
+						dnd.ondragenter = function(e) {
+							if(e.preventDefault) {e.preventDefault();}
+							return false;
+						};
+						dnd.ondrop = function(e) {
+							if(e.preventDefault) {e.preventDefault();}
+							var dt = e.dataTransfer;
+							var body = document.getElementById("audio-holder-drop");
+							var files = dt.files;
+							for (var i = 0, f; f = files[i]; i++)
+							{
+								var dndHeader = document.createElement('div');
+								dndHeader.style.width = "100%";
+								dndHeader.style.height = "20px";
+								dndHeader.style.borderBottom = "#DDD";
+								dndHeader.style.borderBottomWidth = "1px";
+								dndHeader.style.borderBottomStyle = "solid";
+								var dndHInclude = document.createElement('div');
+								dndHInclude.style.width = "30px";
+								dndHInclude.className = "dndheaderelement";
+								var includeCheck = document.createElement('input');
+								includeCheck.type = "checkbox";
+								includeCheck.name = "include-check";
+								includeCheck.checked = true;
+								dndHInclude.appendChild(includeCheck);
+								dndHeader.appendChild(dndHInclude);
+								var dndHTitle = document.createElement('div');
+								dndHTitle.style.width = "180px";
+								dndHTitle.className = "dndheaderelement";
+								var text = document.createElement('span');
+								text.textContent = f.name;
+								dndHTitle.appendChild(text);
+								dndHeader.appendChild(dndHTitle);
+								var dndHID = document.createElement('div');
+								dndHID.style.width = "100px";
+								dndHID.className = "dndheaderelement";
+								var IDInput = document.createElement('input');
+								IDInput.name = "ID";
+								IDInput.value = f.name.split('.')[0];
+								IDInput.style.width = "96px";
+								// TODO: Automatic checking for common ID;
+								dndHID.appendChild(IDInput);
+								dndHeader.appendChild(dndHID);
+								var dndHPlay = document.createElement('div');
+								dndHPlay.style.width = "100px";
+								dndHPlay.className = "dndheaderelement";
+								var audio = document.createElement('audio');
+								dndHPlay.appendChild(audio);
+								dndHeader.appendChild(dndHPlay);
+								dnd.appendChild(dndHeader);
+							}
+						};
+						var dndHeader = document.createElement('div');
+						dndHeader.style.width = "100%";
+						dndHeader.style.height = "15px";
+						dndHeader.style.borderBottom = "#DDD";
+						dndHeader.style.borderBottomWidth = "1px";
+						dndHeader.style.borderBottomStyle = "solid";
+						var dndHInclude = document.createElement('div');
+						dndHInclude.style.width = "30px";
+						dndHInclude.className = "dndheaderelement";
+						var text = document.createElement('span');
+						text.textContent = "Inc.";
+						dndHInclude.appendChild(text);
+						dndHeader.appendChild(dndHInclude);
+						var dndHTitle = document.createElement('div');
+						dndHTitle.style.width = "180px";
+						dndHTitle.className = "dndheaderelement";
+						text = document.createElement('span');
+						text.textContent = "File Name";
+						dndHTitle.appendChild(text);
+						dndHeader.appendChild(dndHTitle);
+						var dndHID = document.createElement('div');
+						dndHID.style.width = "100px";
+						dndHID.className = "dndheaderelement";
+						text = document.createElement('span');
+						text.textContent = "ID";
+						dndHID.appendChild(text);
+						dndHeader.appendChild(dndHID);
+						var dndHPlay = document.createElement('div');
+						dndHPlay.style.width = "100px";
+						dndHPlay.className = "dndheaderelement";
+						text = document.createElement('span');
+						text.textContent = "Sample";
+						dndHPlay.appendChild(text);
+						dndHeader.appendChild(dndHPlay);
+						dnd.appendChild(dndHeader);
+						this.popupBody.appendChild(dnd);
+						var button = document.createElement('button');
+						button.className = "popupButton";
+						button.textContent = "Submit";
+						button.onclick = function(event)
+						{
+							
+						};
+						this.popupFooter.appendChild(button);
 					}
-					else {
-						input.setAttribute('mandatory','false');
+					this.state++;
+				};
+			};
+			
+			function Specification() {
+				// Handles the decoding of the project specification XML into a simple JavaScript Object.
+				
+				this.interfaceType = null;
+				this.commonInterface = new function()
+				{
+					this.options = [];
+					this.optionNode = function(input)
+					{
+						var name = input.getAttribute('name');
+						this.type = name;
+						if(this.type == "option")
+						{
+							this.name = input.id;
+						} else if (this.type == "check")
+						{
+							this.check = input.id;
+						}
+					};
+				};
+				this.projectReturn = null;
+				this.randomiseOrder = null;
+				this.collectMetrics = null;
+				this.testPages = null;
+				this.preTest = null;
+				this.postTest = null;
+				this.audioHolders = [];
+				
+				this.decode = function() {
+					// projectXML - DOM Parsed document
+					this.projectXML = projectXML.childNodes[0];
+					var setupNode = projectXML.getElementsByTagName('setup')[0];
+					this.interfaceType = setupNode.getAttribute('interface');
+					this.projectReturn = setupNode.getAttribute('projectReturn');
+					this.testPages = setupNode.getAttribute('testPages');
+					if (setupNode.getAttribute('randomiseOrder') == "true") {
+						this.randomiseOrder = true;
+					} else {this.randomiseOrder = false;}
+					if (setupNode.getAttribute('collectMetrics') == "true") {
+						this.collectMetrics = true;
+					} else {this.collectMetrics = false;}
+					if (isNaN(Number(this.testPages)) || this.testPages == undefined)
+					{
+						this.testPages = null;
+					} else {
+						this.testPages = Number(this.testPages);
+						if (this.testPages == 0) {this.testPages = null;}
 					}
-				}
-				return [id, input];
-			}
-			
-			function removeNode(event) {
-				event.srcElement.parentElement.parentElement.removeChild(event.srcElement.parentElement);
-			}
-			
-			function buttonClickedValidate() {
-				var ready = validate();
-				if (ready == false) {
-					var errMsg = document.getElementById('errorMessage');
-					errMsg.textContent = "There were some errors with your XML. Any input boxes highlighted in red are invalid because they are empty or because its ID matches another elements ID. Please fill these in correctly. Any boxes which are yellow are not-invalid but will use the default value.";
-					errMsg.style.visibility = 'visible';
-					document.getElementById('createXML').disabled = true;
+					var metricCollection = setupNode.getElementsByTagName('Metric');
 					
-				} else {
-					var errMsg = document.getElementById('errorMessage');
-					errMsg.textContent = "";
-					errMsg.style.visiblity = 'hidden';
-					document.getElementById('createXML').disabled = false;
-				}
-			}
-			
-			function buttonClickedSubmit() {
-				var ready = validate();
-				if (ready == true) {
-					var xmlDoc = buildXML();
-					var inject = document.getElementById('errorMessage');
-					createProjectSave(xmlDoc, inject);
-				}
-			}
-			
-			function createProjectSave(xmlDoc, injectPoint) {
-				var parent = document.createElement("div");
-				parent.appendChild(xmlDoc);
-				var file = [parent.innerHTML];
-				var bb = new Blob(file,{type : 'application/xml'});
-				var dnlk = window.URL.createObjectURL(bb);
-				var a = document.createElement("a");
-				a.hidden = '';
-				a.href = dnlk;
-				a.download = "save.xml";
-				a.textContent = "Save File";
-				injectPoint.appendChild(a);
-			}
-			
-			function buildXML() {
-				var xmlDoc = document.createElement('BrowserEvalProjectDocument');
-				var setup = document.createElement('setup');
-				setup.setAttribute('interface',document.getElementById('interface').value);
-				if (document.getElementById('projectReturn').value == "") {
-					setup.setAttribute('projectReturn',"null");
-				} else {
-					setup.setAttribute('projectReturn',document.getElementById('projectReturn').value);
-				}
-				setup.setAttribute('randomiseOrder',document.getElementById('randomisePageOrder').checked);
-				setup.setAttribute('collectMetrics',document.getElementById('collectMetrics').checked);
-				
-				var globalPreTest = document.createElement('preTest');
-				var options = document.getElementById('globalPreTest').getElementsByClassName('head');
-				constructPrePost(globalPreTest, options);
-				
-				var globalPostTest = document.createElement('postTest');
-				options = document.getElementById('globalPostTest').getElementsByClassName('head');
-				constructPrePost(globalPostTest, options);
-				
-				var globalMetrics = document.createElement('metric');
-				options = document.getElementById('globalMetric').getElementsByClassName('attrib')[0].getElementsByTagName('input');
-				for (var i=0; i<options.length; i++) {
-					if (options[i].checked) {
-						var metric = document.createElement('metricEnable');
-						metric.textContent = options[i].id;
-						globalMetrics.appendChild(metric);
-					}
-				}
-				setup.appendChild(globalPreTest);
-				setup.appendChild(globalPostTest);
-				setup.appendChild(globalMetrics);
-				xmlDoc.appendChild(setup);
-				
-				var audioHolders = document.getElementsByName('audio-holder');
-				for (var i=0; i<audioHolders.length; i++) {
-					var audioHolder = document.createElement('audioHolder');
-					var audioHolderDOM = audioHolders[i];
-					var attribs = audioHolderDOM.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-					audioHolder.id = attribs[0].value;
-					if (attribs[1].value != "") {audioHolder.setAttribute('sampleRate',attribs[1].value);}
-					if (attribs[2].value != "") {audioHolder.setAttribute('hostURL',attribs[2].value);}
-					audioHolder.setAttribute('randomiseOrder',attribs[3].checked);
-					audioHolder.setAttribute('repeatCount',attribs[4].checked);
-					audioHolder.setAttribute('loop',attribs[5].checked);
-					audioHolder.setAttribute('elementComments',attribs[6].checked);
+					this.preTest = new this.prepostNode('pretest',setupNode.getElementsByTagName('PreTest'));
+					this.postTest = new this.prepostNode('posttest',setupNode.getElementsByTagName('PostTest'));
 					
-					// Audio-Holder PreTests
-					var audioHolderPreTest = document.createElement('preTest');
-					var audioHolderPostTest = document.createElement('postTest');
-					options = audioHolderDOM.childNodes[2].getElementsByClassName('head');
-					constructPrePost(audioHolderPreTest, options);
-					options = audioHolderDOM.childNodes[3].getElementsByClassName('head');
-					constructPrePost(audioHolderPostTest, options);
-					
-					audioHolder.appendChild(audioHolderPreTest);
-					audioHolder.appendChild(audioHolderPostTest);
-					
-					// Interface Nodes
-					
-					// audio-Elements
-					var audioElementsDOM = [];
-					var commentQuestionDOM = [];
-					var interfacesDOM = [];
-					for (var j=0; j<audioHolderDOM.childElementCount; j++) {
-						var child = audioHolderDOM.childNodes[j];
-						var name = child.getAttribute('name');
-						if (name == 'audio-element') {audioElementsDOM.push(child);}
-						else if (name == 'comment-question') {commentQuestionDOM.push(child);}
-						else if (name == 'interface-options') {interfacesDOM.push(child);}
+					if (metricCollection.length > 0) {
+						metricCollection = metricCollection[0].getElementsByTagName('metricEnable');
+						for (var i=0; i<metricCollection.length; i++) {
+							this.metrics.push(new this.metricNode(metricCollection[i].textContent));
+						}
 					}
 					
-					for (var j=0; j<interfacesDOM.length; j++) {
-						var interfaceNode = document.createElement('interface');
-						attribs = interfacesDOM[j].getElementsByClassName('attrib')[0].getElementsByTagName('input');
-						var title = document.createElement('title');
-						title.textContent = attribs[0].value;
-						interfaceNode.appendChild(title);
-						
-						
-						var markers = interfacesDOM[j].getElementsByClassName('head');
-						for (var k=0; k<markers.length; k++) {
-							var markerNode = document.createElement('scale');
-							attribs = markers[k].getElementsByClassName('attrib')[0].getElementsByTagName('input');
-							markerNode.textContent = attribs[0].value;
-							markerNode.setAttribute('position',attribs[1].value);
-							interfaceNode.appendChild(markerNode);
-						}
-						audioHolder.appendChild(interfaceNode);
+					var commonInterfaceNode = setupNode.getElementsByTagName('interface');
+					if (commonInterfaceNode.length > 0) {
+						commonInterfaceNode = commonInterfaceNode[0];
+					} else {
+						commonInterfaceNode = undefined;
 					}
 					
-					for (var j=0; j<audioElementsDOM.length; j++) {
-						var audioElement = document.createElement('audioElement');
-						attribs = audioElementsDOM[j].getElementsByClassName('attrib')[0].getElementsByTagName('input');
-						audioElement.id = attribs[0].value;
-						audioElement.setAttribute('url',attribs[1].value);
-						audioHolder.appendChild(audioElement);
+					this.commonInterface = new function() {
+						this.OptionNode = function(child) {
+							this.type = child.nodeName;
+							if (this.type == 'option')
+							{
+								this.name = child.getAttribute('name');
+							}
+							else if (this.type == 'check') {
+								this.check = child.getAttribute('name');
+								if (this.check == 'scalerange') {
+									this.min = child.getAttribute('min');
+									this.max = child.getAttribute('max');
+									if (this.min == null) {this.min = 1;}
+									else if (Number(this.min) > 1 && this.min != null) {
+										this.min = Number(this.min)/100;
+									} else {
+										this.min = Number(this.min);
+									}
+									if (this.max == null) {this.max = 0;}
+									else if (Number(this.max) > 1 && this.max != null) {
+										this.max = Number(this.max)/100;
+									} else {
+										this.max = Number(this.max);
+									}
+								}
+							} else if (this.type == 'anchor' || this.type == 'reference') {
+								this.value = Number(child.textContent);
+								this.enforce = child.getAttribute('enforce');
+								if (this.enforce == 'true') {this.enforce = true;}
+								else {this.enforce = false;}
+							}
+						};
+						this.options = [];
+						if (commonInterfaceNode != undefined) {
+							var child = commonInterfaceNode.firstElementChild;
+							while (child != undefined) {
+								this.options.push(new this.OptionNode(child));
+								child = child.nextElementSibling;
+							}
+						}
+					};
+					
+					var audioHolders = projectXML.getElementsByTagName('audioHolder');
+					for (var i=0; i<audioHolders.length; i++) {
+						this.audioHolders.push(new this.audioHolderNode(this,audioHolders[i]));
 					}
 					
-					for (var j=0; j<commentQuestionDOM.length; j++) {
-						var commentQuestion = document.createElement('commentQuestion');
-						attribs = commentQuestionDOM[j].getElementsByClassName('attrib')[0].getElementsByTagName('input');
-						commentQuestion.id = attribs[0].value;
-						commentQuestion.textContent = attribs[1].value;
-						audioHolder.appendChild(commentQuestion);
+					// New check if we need to randomise the test order
+					if (this.randomiseOrder)
+					{
+				 		this.audioHolders = randomiseOrder(this.audioHolders);
+				 		for (var i=0; i<this.audioHolders.length; i++)
+				 		{
+				 			this.audioHolders[i].presentedId = i;
+				 		}
 					}
-					xmlDoc.appendChild(audioHolder);
-				}
-				return xmlDoc;
-			}
-			
-			function constructPrePost(parent, options) {
-				for (var i=0; i<options.length; i++) {
-					var elem = options[i];
-					var attributes = elem.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-					if (elem.getAttribute('name') == 'question-node') {
-						var node = document.createElement('question');
-						node.setAttribute('id',attributes[0].value);
-						node.textContent = attributes[1].value;
-						node.setAttribute('mandatory',attributes[2].checked);
-					} else if (elem.getAttribute('name') == 'statement-node') {
-						var node = document.createElement('statement');
-						node.textContent = attributes[0].value;
-					}
-					parent.appendChild(node);
-				}
-			}
-			
-			function validate() {
-				var canExport = true;
-				// Checks if the XML can be created from the given entries
-				var inputs = document.getElementsByTagName('input');
-				for (var i=0; i<inputs.length; i++) {
-					if (inputs[i].type == 'text') {
-						if (inputs[i].value == "") {
-							var mandatory = inputs[i].getAttribute('mandatory');
-							if (mandatory == "true") {
-								errorInput(inputs[i]);
-								canExport = false;
-							} else {
-								warningInput(inputs[i]);
-							}
-						} else {
-							goodInput(inputs[i]);
+					
+					if (this.testPages != null || this.testPages != undefined)
+					{
+						if (this.testPages > audioHolders.length)
+						{
+							console.log('Warning: You have specified '+audioHolders.length+' tests but requested '+this.testPages+' be completed!');
+							this.testPages = audioHolders.length;
+						}
+						var aH = this.audioHolders;
+						this.audioHolders = [];
+						for (var i=0; i<this.testPages; i++)
+						{
+							this.audioHolders.push(aH[i]);
 						}
 					}
-				}
+				};
 				
-				var audioHolders = document.getElementsByName('audio-holder');
-				for (var i=0; i<audioHolders.length; i++) {
-					var divs = audioHolders[i].getElementsByClassName('head');
-					var IDs = [];
-					for (var j=0; j<divs.length; j++) {
-						if (divs[j].getAttribute('name') == 'audio-element') {
-							var obj = divs[j].getElementsByClassName('attrib')[0].children[1];
-							var aeID = obj.value;
-							if (aeID != "") {
-								var unique = true;
-								for (var k=0; k<IDs.length; k++) {
-									if (aeID == IDs[k]) {
-										unique = false;
-										break;
+				this.prepostNode = function(type,Collection) {
+					this.type = type;
+					this.options = [];
+					
+					this.OptionNode = function(child) {
+						
+						this.childOption = function(element) {
+							this.type = 'option';
+							this.id = element.id;
+							this.name = element.getAttribute('name');
+							this.text = element.textContent;
+						};
+						
+						this.type = child.nodeName;
+						if (child.nodeName == "question") {
+							this.id = child.id;
+							this.mandatory;
+							if (child.getAttribute('mandatory') == "true") {this.mandatory = true;}
+							else {this.mandatory = false;}
+							this.question = child.textContent;
+							if (child.getAttribute('boxsize') == null) {
+								this.boxsize = 'normal';
+							} else {
+								this.boxsize = child.getAttribute('boxsize');
+							}
+						} else if (child.nodeName == "statement") {
+							this.statement = child.textContent;
+						} else if (child.nodeName == "checkbox" || child.nodeName == "radio") {
+							var element = child.firstElementChild;
+							this.id = child.id;
+							if (element == null) {
+								console.log('Malformed' +child.nodeName+ 'entry');
+								this.statement = 'Malformed' +child.nodeName+ 'entry';
+								this.type = 'statement';
+							} else {
+								this.options = [];
+								while (element != null) {
+									if (element.nodeName == 'statement' && this.statement == undefined){
+										this.statement = element.textContent;
+									} else if (element.nodeName == 'option') {
+										this.options.push(new this.childOption(element));
 									}
+									element = element.nextElementSibling;
 								}
-								if (unique == true) {
-									IDs.push(aeID);
-								} else {
-									errorInput(obj);
-									canExport = false;
-								}
+							}
+						} else if (child.nodeName == "number") {
+							this.statement = child.textContent;
+							this.id = child.id;
+							this.min = child.getAttribute('min');
+							this.max = child.getAttribute('max');
+							this.step = child.getAttribute('step');
+						}
+					};
+					
+					// On construction:
+					if (Collection.length != 0) {
+						Collection = Collection[0];
+						if (Collection.childElementCount != 0) {
+							var child = Collection.firstElementChild;
+							this.options.push(new this.OptionNode(child));
+							while (child.nextElementSibling != null) {
+								child = child.nextElementSibling;
+								this.options.push(new this.OptionNode(child));
 							}
 						}
 					}
-				}
-				return canExport;
-			};
-			
-			function errorInput(node) {
-				node.style.backgroundColor = "#FF0000";
-			}
-			
-			function warningInput(node) {
-				node.style.backgroundColor = "#FFFF00";
-			}
-			
-			function goodInput(node) {
-				node.style.backgroundColor = "#FFFFFF";
-			}
-			
-			function questionNode() {
-				var node = document.createElement("div");
-				node.setAttribute('class','head');
-				node.setAttribute('name','question-node');
-				var nodeTitle = document.createElement("span");
-				nodeTitle.textContent = "Question";
-				var attributes = document.createElement("div");
-				attributes.setAttribute('class','attrib');
-				var id = attributePair("ID:","text", true);
-				var question = attributePair("Question:","text", false);
-				question[1].style.width = "500px";
-				var mandatory = attributePair("Mandatory:","checkbox", false);
-				node.appendChild(nodeTitle);
-				id.forEach(function(item){attributes.appendChild(item);},false);
-				question.forEach(function(item){attributes.appendChild(item);},false);
-				mandatory.forEach(function(item){attributes.appendChild(item);},false);
-				node.appendChild(attributes);
-				
-				var removeButton = document.createElement("button");
-				removeButton.textContent = "Remove";
-				removeButton.onclick = removeNode;
-				node.appendChild(removeButton);
-				return node;
-			}
-			
-			function statementNode() {
-				var node = document.createElement("div");
-				node.setAttribute('class','head');
-				node.setAttribute('name','statement-node');
-				var nodeTitle = document.createElement("span");
-				nodeTitle.textContent = "Statement";
-				var attributes = document.createElement("div");
-				attributes.setAttribute('class','attrib');
-				var statement = attributePair("Statement:","text",false);
-				statement[1].style.width = "500px";
-				node.appendChild(nodeTitle);
-				statement.forEach(function(item){attributes.appendChild(item);},false);
-				node.appendChild(attributes);
-				
-				var removeButton = document.createElement("button");
-				removeButton.textContent = "Remove";
-				removeButton.onclick = removeNode;
-				node.appendChild(removeButton);
-				return node;
-			}
-			
-			function audioHolderNode() {
-				var audioHolderCounts = document.getElementsByName("audio-holder").length;
-				var node = document.createElement("div");
-				node.setAttribute("class","head");
-				node.setAttribute("name","audio-holder");
-				node.setAttribute("id","audio-holder-"+audioHolderCounts);
-				var nodeTitle = document.createElement("span");
-				nodeTitle.textContent = "Audio Holder "+(audioHolderCounts+1);
-				
-				var attributes = document.createElement("div");
-				attributes.setAttribute('class','attrib');
-				var id = attributePair("ID:","text",true);
-				id[1].value=audioHolderCounts;
-				var hostURL = attributePair("Host URL:", "text",false);
-				var sampleRate = attributePair("Sample Rate:","text",false);
-				var randomiseOrder = attributePair("Randomise Element Order:","checkbox");
-				var repeatCount = attributePair("Repeat Page Count:","number");
-				repeatCount[1].value = 0;
-				var loop = attributePair("Loop Element Playback","checkbox");
-				var elementComments = attributePair("Enable Comment Boxes","checkbox");
-				id.forEach(function(item){attributes.appendChild(item);},false);
-				hostURL.forEach(function(item){attributes.appendChild(item);},false);
-				sampleRate.forEach(function(item){attributes.appendChild(item);},false);
-				hostURL.forEach(function(item){attributes.appendChild(item);},false);
-				randomiseOrder.forEach(function(item){attributes.appendChild(item);},false);
-				repeatCount.forEach(function(item){attributes.appendChild(item);},false);
-				loop.forEach(function(item){attributes.appendChild(item);},false);
-				elementComments.forEach(function(item){attributes.appendChild(item);},false);
-				
-				node.appendChild(nodeTitle);
-				node.appendChild(attributes);
-				
-				var pretest = document.createElement("div");
-				pretest.setAttribute('class','head');
-				pretest.setAttribute('name','pre-test');
-				var pretestTitle = document.createElement("h4");
-				pretestTitle.textContent = "Pre Test";
-				var buttonAddQ = document.createElement("button");
-				buttonAddQ.textContent = "Add Pre Test Question";
-				buttonAddQ.onclick = function(){event.srcElement.parentElement.appendChild(questionNode());};
-				var buttonAddS = document.createElement("button");
-				buttonAddS.textContent = "Add Pre Test Statement";
-				buttonAddS.onclick = function(){event.srcElement.parentElement.appendChild(statementNode());};
-				pretest.appendChild(pretestTitle);
-				pretest.appendChild(buttonAddQ);
-				pretest.appendChild(buttonAddS);
-				
-				var posttest = document.createElement("div");
-				posttest.setAttribute('class','head');
-				posttest.setAttribute('name','post-test');
-				var posttestTitle = document.createElement("h4");
-				posttestTitle.textContent = "Post Test";
-				var buttonAddQ = document.createElement("button");
-				buttonAddQ.textContent = "Add Post Test Question";
-				buttonAddQ.onclick = function(){event.srcElement.parentElement.appendChild(questionNode());};
-				var buttonAddS = document.createElement("button");
-				buttonAddS.textContent = "Add Post Test Statement";
-				buttonAddS.onclick = function(){event.srcElement.parentElement.appendChild(statementNode());};
-				posttest.appendChild(posttestTitle);
-				posttest.appendChild(buttonAddQ);
-				posttest.appendChild(buttonAddS);
-				
-				node.appendChild(pretest);
-				node.appendChild(posttest);
-				
-				var newAudioElementButton = document.createElement("button");
-				newAudioElementButton.textContent = "Add audio element";
-				newAudioElementButton.onclick = function(){
-					event.srcElement.parentElement.appendChild(audioElementNode());
-				};
-				node.appendChild(newAudioElementButton);
-				
-				var newCommentButton = document.createElement("button");
-				newCommentButton.textContent = "Add Comment Box";
-				newCommentButton.onclick = function() {
-					event.srcElement.parentElement.appendChild(commentBox());
-				};
-				node.appendChild(newCommentButton);
-				
-				var newInterface = document.createElement("button");
-				newInterface.textContent = "Add Interface";
-				newInterface.onclick = function() {
-					event.srcElement.parentElement.appendChild(interfaceNode());
-				};
-				node.appendChild(newInterface);
-				
-				var removeButton = document.createElement("button");
-				removeButton.textContent = "Remove Audio Holder";
-				removeButton.onclick = removeNode;
-				node.appendChild(removeButton);
-				return node;
-			}
-			
-			function audioElementNode() {
-				var node = document.createElement('div');
-				node.setAttribute('class','head');
-				node.setAttribute('name','audio-element');
-				var nodeTitle = document.createElement('span');
-				nodeTitle.textContent = 'Audio Element';
-				
-				var attributes = document.createElement("div");
-				attributes.setAttribute('class','attrib');
-				var id = attributePair("ID:","text",true);
-				var url = attributePair("URL:","text",true);
-				id.forEach(function(item){attributes.appendChild(item);},false);
-				url.forEach(function(item){attributes.appendChild(item);},false);
-				
-				node.appendChild(nodeTitle);
-				node.appendChild(attributes);
-				
-				var removeButton = document.createElement("button");
-				removeButton.textContent = "Remove Audio Element";
-				removeButton.onclick = removeNode;
-				node.appendChild(removeButton);
-				return node;
-			}
-			
-			function commentBox() {
-				var node = document.createElement('div');
-				node.setAttribute('class','head');
-				node.setAttribute('name','comment-question');
-				var nodeTitle = document.createElement('h4');
-				nodeTitle.textContent = "Comment Box";
-				
-				var attributes = document.createElement('div');
-				attributes.setAttribute('class','attrib');
-				var id = attributePair("ID:",'text',true);
-				var question = attributePair("Question:",'text',true);
-				question[1].style.width = "500px";
-				id.forEach(function(item){attributes.appendChild(item);},false);
-				question.forEach(function(item){attributes.appendChild(item);},false);
-				
-				var removeButton = document.createElement("button");
-				removeButton.textContent = "Remove Comment Box";
-				removeButton.onclick = removeNode;
-				
-				node.appendChild(nodeTitle);
-				node.appendChild(attributes);
-				node.appendChild(removeButton);
-				return node;
-			}
-			
-			function interfaceNode() {
-				var selectedInterface = document.getElementById('interface').value;
-				var node = document.createElement('div');
-				node.setAttribute('class','head');
-				node.setAttribute('name','interface-options');
-				var nodeTitle = document.createElement('h4');
-				nodeTitle.textContent = "Interface";
-				
-				var attributes = document.createElement('div');
-				attributes.setAttribute('class','attrib');
-				var title = attributePair('Title: ','text',false);
-				title[1].style.width = "500px";
-				
-				var addMarker = document.createElement('button');
-				addMarker.textContent = "Add Scale Marker";
-				addMarker.onclick = function() {
-					event.srcElement.parentElement.appendChild(newScaleMarker());
 				};
 				
-				title.forEach(function(item){attributes.appendChild(item);},false);
+				this.metricNode = function(name) {
+					this.enabled = name;
+				};
 				
-				var removeButton = document.createElement("button");
-				removeButton.textContent = "Remove Interface";
-				removeButton.onclick = removeNode;
-				
-				node.appendChild(nodeTitle);
-				node.appendChild(attributes);
-				node.appendChild(addMarker);
-				node.appendChild(removeButton);
-				return node;
-			}
-			
-			function newScaleMarker() {
-				var node = document.createElement('div');
-				node.setAttribute('class','head');
-				node.setAttribute('name','interface-options');
-				var nodeTitle = document.createElement('span');
-				nodeTitle.textContent = "Marker";
-				var attributes = document.createElement('div');
-				attributes.setAttribute('class','attrib');
-				var text = attributePair('Text: ','text',true);
-				var position = attributePair('Positon','number',true);
-				
-				text.forEach(function(item){attributes.appendChild(item);},false);
-				position.forEach(function(item){attributes.appendChild(item);},false);
-				
-				var removeButton = document.createElement("button");
-				removeButton.textContent = "Remove Marker";
-				removeButton.onclick = removeNode;
-				
-				node.appendChild(nodeTitle);
-				node.appendChild(attributes);
-				node.appendChild(removeButton);
-				return node;
-			}
-			
-			function handleDragOver(e) {
-				e.stopPropagation();
-				e.preventDefault();
-			}
-			function handleDragEnter(e) {
-				e.stopPropagation();
-				e.preventDefault();
-				this.style.backgroundColor = '#AAFFAA';
-			}
-			function handleDragLeave(e) {
-				e.stopPropagation();
-				e.preventDefault();
-				this.style.backgroundColor = "#FFFFFF";
-			}
-			function handleDrop(e) {
-				e.stopPropagation();
-				e.preventDefault();
-				
-				var file = e.dataTransfer.files[0];
-				
-				// Uses HTML5 FileAPI - https://w3c.github.io/FileAPI/#filereader-interface
-				var reader = new FileReader();
-				reader.onload = function() {
-					var parse = new DOMParser();
-					var xml = parse.parseFromString(reader.result,'text/xml');
-					importXML(xml);
-				};
-				reader.readAsText(file);
-				
-			}
-			var g_XML;
-			
-			function importXML(xml) {
-				g_XML = xml;
-				
-				var root = xml.getElementsByTagName('BrowserEvalProjectDocument')[0];
-				var setup = xml.getElementsByTagName('setup')[0];
-				document.getElementById('interface').value = setup.getAttribute('interface');
-				document.getElementById('projectReturn').value = setup.getAttribute('projectReturn');
-				document.getElementById('randomisePageOrder').checked = setup.getAttribute('randomiseOrder');
-				document.getElementById('collectMetrics').checked = setup.getAttribute('collectMetrics');
-				
-				var globalPreTest = setup.getElementsByTagName('PreTest')[0];
-				var globalPostTest = setup.getElementsByTagName('PostTest')[0];
-				for (var i=0; i<globalPreTest.childElementCount; i++) {
-					var child = globalPreTest.children[i];
-					var node;
-					if (child.nodeName == "question") {
-						node = questionNode();
-						var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-						attribs[0].value = child.id;
-						attribs[1].value = child.textContent;
-						attribs[2].checked = child.getAttribute('mandatory');
-					} else if (child.nodeName == "statement") {
-						node = statementNode();
-						var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-						attribs[0].value = child.textContent;
+				this.audioHolderNode = function(parent,xml) {
+					this.type = 'audioHolder';
+					this.presentedId = parent.audioHolders.length;
+					this.interfaceNode = function(DOM) {
+						var title = DOM.getElementsByTagName('title');
+						if (title.length == 0) {this.title = null;}
+						else {this.title = title[0].textContent;}
+						this.options = parent.commonInterface.options;
+						var scale = DOM.getElementsByTagName('scale');
+						this.scale = [];
+						for (var i=0; i<scale.length; i++) {
+							var arr = [null, null];
+							arr[0] = scale[i].getAttribute('position');
+							arr[1] = scale[i].textContent;
+							this.scale.push(arr);
+						}
+					};
+					
+					this.audioElementNode = function(parent,xml) {
+						this.url = xml.getAttribute('url');
+						this.id = xml.id;
+						this.parent = parent;
+						this.type = xml.getAttribute('type');
+						if (this.type == null) {this.type = "normal";}
+						if (this.type == 'anchor') {this.anchor = true;}
+						else {this.anchor = false;}
+						if (this.type == 'reference') {this.reference = true;}
+						else {this.reference = false;}
+						
+						this.marker = xml.getAttribute('marker');
+						if (this.marker == null) {this.marker = undefined;}
+						
+						if (this.anchor == true) {
+							if (this.marker != undefined) {this.enforce = true;}
+							else {this.enforce = enforceAnchor;}
+							this.marker = anchor;
+						}
+						else if (this.reference == true) {
+							if (this.marker != undefined) {this.enforce = true;}
+							else {this.enforce = enforceReference;}
+							this.marker = reference;
+						}
+						
+						if (this.marker != undefined) {
+							this.marker = Number(this.marker);
+							if (this.marker > 1) {this.marker /= 100;}
+						}
+					};
+					
+					this.commentQuestionNode = function(xml) {
+						this.childOption = function(element) {
+							this.type = 'option';
+							this.name = element.getAttribute('name');
+							this.text = element.textContent;
+						};
+						this.id = xml.id;
+						if (xml.getAttribute('mandatory') == 'true') {this.mandatory = true;}
+						else {this.mandatory = false;}
+						this.type = xml.getAttribute('type');
+						if (this.type == undefined) {this.type = 'text';}
+						switch (this.type) {
+						case 'text':
+							this.question = xml.textContent;
+							break;
+						case 'radio':
+							var child = xml.firstElementChild;
+							this.options = [];
+							while (child != undefined) {
+								if (child.nodeName == 'statement' && this.statement == undefined) {
+									this.statement = child.textContent;
+								} else if (child.nodeName == 'option') {
+									this.options.push(new this.childOption(child));
+								}
+								child = child.nextElementSibling;
+							}
+							break;
+						case 'checkbox':
+							var child = xml.firstElementChild;
+							this.options = [];
+							while (child != undefined) {
+								if (child.nodeName == 'statement' && this.statement == undefined) {
+									this.statement = child.textContent;
+								} else if (child.nodeName == 'option') {
+									this.options.push(new this.childOption(child));
+								}
+								child = child.nextElementSibling;
+							}
+							break;
+						}
+					};
+					
+					this.id = xml.id;
+					this.hostURL = xml.getAttribute('hostURL');
+					this.sampleRate = xml.getAttribute('sampleRate');
+					if (xml.getAttribute('randomiseOrder') == "true") {this.randomiseOrder = true;}
+					else {this.randomiseOrder = false;}
+					this.repeatCount = xml.getAttribute('repeatCount');
+					if (xml.getAttribute('loop') == 'true') {this.loop = true;}
+					else {this.loop == false;}
+					if (xml.getAttribute('elementComments') == "true") {this.elementComments = true;}
+					else {this.elementComments = false;}
+					
+					var anchor = xml.getElementsByTagName('anchor');
+					var enforceAnchor = false;
+					if (anchor.length == 0) {
+						// Find anchor in commonInterface;
+						for (var i=0; i<parent.commonInterface.options.length; i++) {
+							if(parent.commonInterface.options[i].type == 'anchor') {
+								anchor = parent.commonInterface.options[i].value;
+								enforceAnchor = parent.commonInterface.options[i].enforce;
+								break;
+							}
+						}
+						if (typeof(anchor) == "object") {
+							anchor = null;
+						}
+					} else {
+						anchor = anchor[0].textContent;
 					}
-					document.getElementById('globalPreTest').appendChild(node);
-				}
-				
-				for (var i=0; i<globalPostTest.childElementCount; i++) {
-					var child = globalPostTest.children[i];
-					var node;
-					if (child.nodeName == "question") {
-						node = questionNode();
-						var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-						attribs[0].value = child.id;
-						attribs[1].value = child.textContent;
-						attribs[2].checked = child.getAttribute('mandatory');
-					} else if (child.nodeName == "statement") {
-						node = statementNode();
-						var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-						attribs[0].value = child.textContent;
+					
+					var reference = xml.getElementsByTagName('anchor');
+					var enforceReference = false;
+					if (reference.length == 0) {
+						// Find anchor in commonInterface;
+						for (var i=0; i<parent.commonInterface.options.length; i++) {
+							if(parent.commonInterface.options[i].type == 'reference') {
+								reference = parent.commonInterface.options[i].value;
+								enforceReference = parent.commonInterface.options[i].enforce;
+								break;
+							}
+						}
+						if (typeof(reference) == "object") {
+							reference = null;
+						}
+					} else {
+						reference = reference[0].textContent;
 					}
-					document.getElementById('globalPostTest').appendChild(node);
-				}
-				
-				// Metric Enable Flags
-				var mEnable = setup.getElementsByTagName('Metric')[0].getElementsByTagName('metricEnable');
-				for (var i=0; i<mEnable.length; i++) {
-					var node = mEnable[i];
-					var enabled = node.textContent;
-					document.getElementById(enabled).checked = true;
-				}
-				
-				var audioHolders = root.getElementsByTagName('audioHolder');
-				for (var i=0; i<audioHolders.length; i++) {
-					var audioHolderDOM = audioHolderNode();
-					var attribs = audioHolderDOM.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-					attribs[0].value = audioHolders[i].id;
-					attribs[1].value = audioHolders[i].getAttribute('sampleRate');
-					attribs[2].value = audioHolders[i].getAttribute('hostURL');
-					attribs[3].checked = audioHolders[i].getAttribute('randomiseOrder');
-					attribs[4].value = audioHolders[i].getAttribute('repeatCount');
-					attribs[5].checked = audioHolders[i].getAttribute('loop');
-					attribs[6].checked = audioHolders[i].getAttribute('elementComments');
 					
-					var PreTest = audioHolders[i].getElementsByTagName('PreTest');
-					var PostTest = audioHolders[i].getElementsByTagName('PostTest');
-					if (PreTest.length != 0) {
-						PreTest = PreTest[0];
-						for (var j=0; j<PreTest.childElementCount; j++) {
-							var child = PreTest.children[j];
-							var node;
-							if (child.nodeName == "question") {
-								node = questionNode();
-								var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-								attribs[0].value = child.id;
-								attribs[1].value = child.textContent;
-								attribs[2].checked = child.getAttribute('mandatory');
-							} else if (child.nodeName == "statement") {
-								node = statementNode();
-								var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-								attribs[0].value = child.textContent;
+					if (typeof(anchor) == 'number') {
+						if (anchor > 1 && anchor < 100) {anchor /= 100.0;}
+					}
+					
+					if (typeof(reference) == 'number') {
+						if (reference > 1 && reference < 100) {reference /= 100.0;}
+					}
+					
+					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');
+					for (var i=0; i<interfaceDOM.length; i++) {
+						this.interfaces.push(new this.interfaceNode(interfaceDOM[i]));
+					}
+					
+					this.commentBoxPrefix = xml.getElementsByTagName('commentBoxPrefix');
+					if (this.commentBoxPrefix.length != 0) {
+						this.commentBoxPrefix = this.commentBoxPrefix[0].textContent;
+					} else {
+						this.commentBoxPrefix = "Comment on track";
+					}
+					
+					this.audioElements  =[];
+					var audioElementsDOM = xml.getElementsByTagName('audioElements');
+					this.outsideReference = null;
+					for (var i=0; i<audioElementsDOM.length; i++) {
+						if (audioElementsDOM[i].getAttribute('type') == 'outsidereference') {
+							if (this.outsideReference == null) {
+								this.outsideReference = new this.audioElementNode(this,audioElementsDOM[i]);
+							} else {
+								console.log('Error only one audioelement can be of type outsidereference per audioholder');
+								this.audioElements.push(new this.audioElementNode(this,audioElementsDOM[i]));
+								console.log('Element id '+audioElementsDOM[i].id+' made into normal node');
 							}
-							audioHolderDOM.children[2].appendChild(node);
+						} else {
+							this.audioElements.push(new this.audioElementNode(this,audioElementsDOM[i]));
 						}
 					}
-					if (PostTest.length != 0) {
-						PostTest = PostTest[0];
-						for (var j=0; j<PostTest.childElementCount; j++) {
-							var child = PostTest.children[j];
-							var node;
-							if (child.nodeName == "question") {
-								node = questionNode();
-								var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-								attribs[0].value = child.id;
-								attribs[1].value = child.textContent;
-								attribs[2].checked = child.getAttribute('mandatory');
-							} else if (child.nodeName == "statement") {
-								node = statementNode();
-								var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-								attribs[0].value = child.textContent;
-							}
-							audioHolderDOM.children[3].appendChild(node);
-						}
-					}
-					// Process interface
-					var interfaceNodes = audioHolders[i].getElementsByTagName('interface');
-					for (var j=0; j<interfaceNodes.length; j++) {
-						var node = interfaceNode();
-						var child = interfaceNodes[j];
-						var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-						attribs[0].value = child.getElementsByTagName('title')[0].textContent;
-						
-						var markers = child.getElementsByTagName('scale');
-						for (var k=0; k<markers.length; k++) {
-							var markerNode = newScaleMarker();
-							attribs = markerNode.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-							attribs[0].value = markers[k].textContent;
-							attribs[1].value = markers[k].getAttribute('position');
-							node.appendChild(markerNode);
-						}
-						audioHolderDOM.appendChild(node);
+					
+					if (this.randomiseOrder) {
+						this.audioElements = randomiseOrder(this.audioElements);
 					}
 					
-					
-					// Process audio-element
-					var audioElements = audioHolders[i].getElementsByTagName('audioElements');
-					for (var j=0; j<audioElements.length; j++) {
-						var node = audioElementNode();
-						var child = audioElements[j];
-						var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-						attribs[0].value = child.id;
-						attribs[1].value = child.getAttribute('url');
-						audioHolderDOM.appendChild(node);
+					// Check only one anchor and one reference per audioNode
+					var anchor = [];
+					var reference = [];
+					this.anchorId = null;
+					this.referenceId = null;
+					for (var i=0; i<this.audioElements.length; i++)
+					{
+						if (this.audioElements[i].anchor == true) {anchor.push(i);}
+						if (this.audioElements[i].reference == true) {reference.push(i);}
 					}
 					
-					// Process comment-question
-					var commentQuestion = audioHolders[0].getElementsByTagName('CommentQuestion');
-					for (var j=0; j<commentQuestion.length; j++) {
-						var node = commentBox();
-						var child = commentQuestion[j];
-						var attribs = node.getElementsByClassName('attrib')[0].getElementsByTagName('input');
-						attribs[0].value = child.id;
-						attribs[1].value = child.textContent;
-						audioHolderDOM.appendChild(node);
+					if (anchor.length > 1) {
+						console.log('Error - cannot have more than one anchor!');
+						console.log('Each anchor node will be a normal mode to continue the test');
+						for (var i=0; i<anchor.length; i++)
+						{
+							this.audioElements[anchor[i]].anchor = false;
+							this.audioElements[anchor[i]].value = undefined;
+						}
+					} else {this.anchorId = anchor[0];}
+					if (reference.length > 1) {
+						console.log('Error - cannot have more than one anchor!');
+						console.log('Each anchor node will be a normal mode to continue the test');
+						for (var i=0; i<reference.length; i++)
+						{
+							this.audioElements[reference[i]].reference = false;
+							this.audioElements[reference[i]].value = undefined;
+						}
+					} else {this.referenceId = reference[0];}
+					
+					this.commentQuestions = [];
+					var commentQuestionsDOM = xml.getElementsByTagName('CommentQuestion');
+					for (var i=0; i<commentQuestionsDOM.length; i++) {
+						this.commentQuestions.push(new this.commentQuestionNode(commentQuestionsDOM[i]));
 					}
-					
-					document.getElementById('setup').appendChild(audioHolderDOM);
-				}
+				};
 			}
 		</script>
 		<style>
-			div {
-				padding: 2px;
-				margin-top: 2px;
-				margin-bottom: 2px;
+			div.popup {
+				width: 500px;
+				position: absolute;
+				height: 400px;
+				background-color: #fff;
+				border-radius: 10px;
+				box-shadow: 0px 0px 50px #000;
+				z-index: 2;
 			}
-			div.head{
-				margin-left: 10px;
-				border: black;
+			
+			button.popupButton {
+				/* Button for popup window
+				 */
+				min-width: 50px;
+				height: 25px;
+				position: relative;
+				border-radius: 5px;
+				border: #444;
+				border-width: 1px;
+				border-style: solid;
+				background-color: #fff;
+			}
+			
+			div.dragndrop {
+				margin-top: 10px;
+				border:#000000;
+				border-style: dashed;
 				border-width: 2px;
-				border-style: solid;
 			}
-			div.attrib{
-				margin-left:25px;
-				border: black;
-				border-width: 2px;
-				border-style: dashed;
-				margin-bottom: 10px;
+			div.dndheaderelement {
+				float: left;
+				height: 100%;
+				border-right: #DDDDDD;
+				border-right-width: 1px;
+				border-right-style: solid;
 			}
-			div#dragFile{
-				height:100px;
-				border-width: 2px;
-				border-style: dashed;
-				margin-bottom: 10px;
+			div.dndheaderelement span{
+				padding-left: 5px;
 			}
 		</style>
-		
 	</head>
 
 	<body>
-		<h1>Create Test Setup XML</h1>
-		<div id="dragFile">
-			<span>Drag and Drop an XML specification file here to auto-load.</span>
-		</div>
-		<button id="validateXML" onclick="buttonClickedValidate();">Validate</button>
-		<button id="createXML" onclick="buttonClickedSubmit();" disabled>Submit</button>
-		<span id="errorMessage" visibility="hidden"></span>
-		<div id="topLevelBody" align="left">
-			<!-- Interface goes here -->
-			<div name='test-setup'>
-				<div id="setup" class="head">
-					<h2>Setup Tag</h2>
-					<div id="setup-attribs" class="attrib">
-						<span>Interface</span>
-						<select id="interface">
-							<option value='APE'>APE</option>
-						</select>
-						<span>Project Return</span>
-						<input type="text" id="projectReturn" mandatory="false">
-						<span>Randomise Test Page Order</span>
-						<input id="randomisePageOrder" type="checkbox" value="false">
-						<span>Collect Session Metrics</span>
-						<input id="collectMetrics" type="checkbox">
-					</div>
-					<div id="globalPreTest" class="head">
-						<h3>Pre Test</h3>
-						<button id="addPreTestQ" onclick="event.srcElement.parentElement.appendChild(questionNode());">Add Pre Test Question</button>
-						<button id="addPreTestS" onclick="event.srcElement.parentElement.appendChild(statementNode());">Add Pre Test Statement</button>
-					</div>
-					<div id="globalPostTest" class="head">
-						<h3>Post Test</h3>
-						<button id="addPreTestQ" onclick="event.srcElement.parentElement.appendChild(questionNode());">Add Post Test Question</button>
-						<button id="addPreTestS" onclick="event.srcElement.parentElement.appendChild(statementNode());">Add Post Test Statement</button>
-					</div>
-					<div id="globalMetric" class="head">
-						<h3>Global Metrics</h3>
-						<div id="globalMetric-attrib" class="attrib">
-							<span>Test Timer</span>
-							<input type="checkbox" id="testTimer" />
-							<span>Element Playback Timer</span>
-							<input type="checkbox" id="elementTimer" />
-							<span>Element Initial Position</span>
-							<input type="checkbox" id="elementInitialPosition" />
-							<span>Element Tracker</span>
-							<input type="checkbox" id="elementTracker" />
-							<span>Element Listen Tracker</span>
-							<input type="checkbox" id="elementListenTracker" />
-							<span>Element Flag Listened To</span>
-							<input type="checkbox" id="elementFlagListenedTo" />
-							<span>Element Flag Moved</span>
-							<input type="checkbox" id="elementFlagMoved" />
-						</div>
-					</div>
-					<button id="addAudioHolder" onclick="event.srcElement.parentElement.appendChild(audioHolderNode());">Add AudioHolder / Test Page</button>
-				</div>
-			</div>
-		</div>
+		<div id="content"></div>
 	</body>
 </html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test_create/test_create_advanced.html	Wed Sep 23 11:42:11 2015 +0100
@@ -0,0 +1,793 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8">
+
+		<!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
+		Remove this if you use the .htaccess -->
+		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+
+		<title>test_create_2</title>
+		<meta name="description" content="">
+		<meta name="author" content="Nicholas">
+
+		<meta name="viewport" content="width=device-width; initial-scale=1.0">
+		
+		<script type="text/javascript">
+			window.onload = function() {
+				var dropBody = document.getElementById('dragFile');
+				dropBody.addEventListener('dragover', handleDragOver, false);
+				dropBody.addEventListener('dragenter',handleDragEnter,false);
+				dropBody.addEventListener('dragleave',handleDragLeave,false);
+				dropBody.addEventListener('drop', handleDrop,false);
+			};
+			
+			function handleDragOver(e) {
+				e.stopPropagation();
+				e.preventDefault();
+			}
+			function handleDragEnter(e) {
+				e.stopPropagation();
+				e.preventDefault();
+				this.style.backgroundColor = '#AAFFAA';
+			}
+			function handleDragLeave(e) {
+				e.stopPropagation();
+				e.preventDefault();
+				this.style.backgroundColor = "#FFFFFF";
+			}
+			function handleDrop(e) {
+				e.stopPropagation();
+				e.preventDefault();
+				
+				var file = e.dataTransfer.files[0];
+				
+				// Uses HTML5 FileAPI - https://w3c.github.io/FileAPI/#filereader-interface
+				var reader = new FileReader();
+				reader.onload = function() {
+					var parse = new DOMParser();
+					var xml = parse.parseFromString(reader.result,'text/xml');
+					importXML(xml);
+				};
+				reader.readAsText(file);
+				
+			}
+			
+			function removeNode(event) {
+				event.srcElement.parentElement.parentElement.removeChild(event.srcElement.parentElement);
+			}
+			
+			function removeNodeButton()
+			{
+				var button = document.createElement('button');
+				button.textContent = 'Remove';
+				button.onclick = function(event){removeNode(event);};
+				return button;
+			}
+			
+			function attributePair(type,text,name,mandatory)
+			{
+				var node = document.createElement('div');
+				node.setAttribute('name','attribute');
+				var span = document.createElement('span');
+				span.textContent = text;
+				var input = document.createElement('input');
+				input.type = type;
+				input.setAttribute('attrib-name',name);
+				input.setAttribute('mandatory',mandatory);
+				node.appendChild(span);
+				node.appendChild(input);
+				return node;
+			}
+			
+			function buttonClickedValidate()
+			{
+				var allInputs = document.getElementsByTagName('input');
+				for (var i=0; i<allInputs.length; i++)
+				{goodNode(allInputs[i]);}
+				var errList = document.getElementById('errorMessage');
+				errList.innerHTML = "";
+				validate(document.getElementById('topLevelBody'));
+				var submit = document.getElementById('createXML');
+				if (errList.innerHTML == "")
+				{submit.disabled = false;}
+				else {submit.disabled = true;}
+			}
+			
+			function validate(node)
+			{
+				var name = node.getAttribute('name');
+				if (name != 'attribute' && name != 'element') {
+					var child = node.children;
+					for (var i=0; i<node.childElementCount; i++)
+					{
+						if (child[i].nodeName == "DIV")
+						{
+							validate(child[i]);
+						}
+					}
+				} else if (name == 'attribute')
+				{
+					var child = node.children;
+					for (var i=0; i<node.childElementCount; i++)
+					{
+						if (child[i].nodeName == "INPUT")
+						{
+							var mandatory = child[i].getAttribute('mandatory');
+							if (mandatory == 'true') {mandatory = true;}
+							else {mandatory = false;}
+							if (child[i].type =='text' || child[i].type =='number')
+							{
+								if (child[i].value.length == 0)
+								{
+									if (mandatory == true) {errorNode(child[i]);}
+									else {warningNode(child[i]);}
+								} else {goodNode(child[i]);}
+							}
+						}
+					}
+				} else if (name == 'element')
+				{
+					var child = node.children;
+					for (var i=0; i<node.childElementCount; i++)
+					{
+						if (child[i].nodeName == "INPUT")
+						{
+							if (child[i].value.length == 0){warningNode(child[i]);}
+							else {goodNode(child[i]);}
+						}
+					}
+				}
+			}
+			
+			function buttonClickedSubmit()
+			{
+				var xml = document.createElement('BrowserEvalProjectDocument');
+				var dom = document.getElementById('topLevelBody');
+				xml = extractXML(xml,dom);
+				var drop = document.getElementById('errorMessage');
+				createProjectSave(xml,drop);
+			}
+			
+			function createProjectSave(xmlDoc, injectPoint) {
+				var parent = document.createElement("div");
+				parent.appendChild(xmlDoc);
+				var file = [parent.innerHTML];
+				var bb = new Blob(file,{type : 'application/xml'});
+				var dnlk = window.URL.createObjectURL(bb);
+				var a = document.createElement("a");
+				a.hidden = '';
+				a.href = dnlk;
+				a.download = "save.xml";
+				a.textContent = "Save File";
+				injectPoint.appendChild(a);
+			}
+			
+			function extractXML(xml,node)
+			{
+				if(node.getAttribute('class')=='attrib')
+				{
+					var children = node.children;
+					for (var i=0; i<children.length; i++)
+					{
+						if (children[i].getAttribute('name')=='attribute')
+						{
+							var input = children[i].children[1];
+							if (input.type == 'checkbox')
+							{
+								xml.setAttribute(input.getAttribute('attrib-name'),input.checked);
+							} else {
+								xml.setAttribute(input.getAttribute('attrib-name'),input.value);
+							}
+						} else if (children[i].getAttribute('name') == 'element')
+						{
+							var input = children[i].children[1];
+							xml.textContent = input.value;
+						}
+					}
+					return xml;
+				} else if (node.getAttribute('node-name') != undefined)
+				{
+					var xmlDom = document.createElement(node.getAttribute('node-name'));
+					xml.appendChild(xmlDom);
+					var children = node.children;
+					for (var i=0; i<children.length; i++)
+					{
+						if (children[i].nodeName == "DIV")
+						{
+							xmlDom = extractXML(xmlDom,children[i]);
+						}
+					}
+				} else {
+					var children = node.children;
+					for (var i=0; i<children.length; i++)
+					{
+						if (children[i].nodeName == "DIV")
+						{
+							xml = extractXML(xml,children[i]);
+						}
+					}
+				}
+				return xml;
+			}
+			
+			function goodNode(node)
+			{node.style.backgroundColor="#FFFFFF";}
+			
+			function warningNode(node)
+			{node.style.backgroundColor="#FFFF88";}
+			
+			function errorNode(node)
+			{
+				var errLog = document.getElementById('errorMessage');
+				var div = document.createElement('div');
+				var span = document.createElement('span');
+				span.textContent = 'Invalid Data: ';
+				var list = [node.getAttribute('attrib-name')];
+				var pNode = node;
+				while (pNode.id != 'topLevelBody')
+				{
+					if (pNode.getAttribute('node-name') != undefined)
+					{list.push(pNode.getAttribute('node-name'));}
+					pNode = pNode.parentElement;
+				}
+				for (var i=list.length-1; i>=0; i--)
+				{
+					span.textContent = span.textContent +' ->'+ list[i];
+				}
+				div.appendChild(span);
+				errLog.appendChild(div);
+				errLog.style.visibility = 'visible';
+				node.style.backgroundColor="#FF0000";
+			}
+			
+			function importXML(xml)
+			{
+				xml = xml.children[0];
+				var setup = xml.getElementsByTagName('setup')[0];
+				var DOM = document.getElementById('setup');
+				// Insert any setup node attributes
+				setAttributes(DOM,setup);
+				
+				for (var i=0; i<setup.childElementCount; i++)
+				{
+					var node = DOM.getElementsByClassName(setup.children[i].nodeName);
+					if (node.length != 0)
+					{
+						node = node[0];
+						setAttributes(node,setup.children[i]);
+						buildNode(node,setup.children[i]);
+					}
+				}
+				
+				var holders = xml.getElementsByTagName('audioHolder');
+				for (var i=0; i<holders.length; i++)
+				{
+					var node = addAudioHolder();
+					document.getElementById('topLevelBody').appendChild(node);
+					setAttributes(node,holders[i]);
+					buildNode(node,holders[i]);
+				}
+			}
+			
+			function setAttributes(node,xml)
+			{
+				var attribs = node.getElementsByClassName('attrib');
+				if (attribs.length != 0){
+					attribs = attribs[0];
+					for (var i=0; i < attribs.children.length; i++)
+					{
+						if(attribs.children[i].getAttribute('name')=='attribute'){
+							var input = attribs.children[i].children[1];
+							var value = xml.attributes.getNamedItem(input.getAttribute('attrib-name'));
+							if (value != undefined) {value = value.value;}
+							if (input.type == 'checkbox')
+							{input.checked = value;}
+							else
+							{input.value = value;}
+						} else if(attribs.children[i].getAttribute('name')=='element'){
+							var input = attribs.children[i].children[1];
+							input.value = xml.textContent;
+						}
+					}
+				}
+			}
+			
+			function buildNode(parent,xml)
+			{
+				for (var i=0; i<xml.childElementCount; i++)
+				{
+					var child = xml.children[i];
+					var name = child.nodeName;
+					var node = null;
+					if (name == 'statement'){node = addPPStatement();}
+					else if (name == 'question' || name == 'number'){node = addPPQuestion();}
+					else if (name == 'checkbox'){node = addPPCheckbox();}
+					else if (name == 'radio'){node = addPPRadio();}
+					else if (name == 'metricEnable'){node = addMetricEnable();}
+					else if (name == 'check'){node = addInterfaceCheck();}
+					else if (name == 'option'){node = addInterfaceOption();}
+					else if (name == 'scale'){node = addScaleMarker();}
+					else if (name == 'audioHolder'){node = addAudioHolder();}
+					else if (name == 'audioElements'){node = addAudioElement();}
+					else if (name == 'commentQuestion'){node = addExtraComment();}
+					else if (name == 'interface'){node = parent.getElementsByClassName('interface')[0];}
+					else if (name == 'preTest' || name == 'PreTest')
+					{
+						node = parent.getElementsByClassName('preTest')[0];
+					}
+					else if (name == 'postTest' || name == 'PostTest')
+					{
+						node = parent.getElementsByClassName('postTest')[0];
+					}
+					else if (name == 'title' || name == 'commentBoxPrefix')
+					{
+						node = parent.getElementsByClassName(name)[0];
+					}
+					if (node != null) {
+						if (name == 'radio' || name == 'checkbox')
+						{
+							buildRadio(node,xml.children[i]);
+							parent.appendChild(node);
+						} else
+						{
+							setAttributes(node,child);
+							parent.appendChild(node);
+							buildNode(node,child);
+						}
+					} else {
+						var node = createHead(name,name,'h3');
+						
+						var attrib = document.createElement('div');
+						attrib.className = 'attrib';
+						for (var j=0; j<child.attributes.length; j++)
+						{
+							attrib.appendChild(attributePair('text',child.attributes[j].name,child.attributes[j].name,false));
+						}
+						
+						node.appendChild(attrib);
+						parent.appendChild(node);
+						setAttributes(node,child);
+						/*
+						buildNode(node,child);
+						*/
+					}
+				}
+			}
+			
+			function buildRadio(node,xml)
+			{
+				setAttributes(node,xml);
+				setAttributes(node.getElementsByClassName('statement')[0],xml.getElementsByTagName('statement')[0]);
+				var options = xml.getElementsByTagName('option');
+				var addOptionButton = node.getElementsByTagName('button')[2];
+				for (var i=0; i<options.length; i++)
+				{
+					addOptionButton.click();
+					setAttributes(node.getElementsByClassName('option')[i],options[i]);
+				}
+			}
+			
+			function createHead(name,title,size)
+			{
+				var node = document.createElement('div');
+				node.setAttribute('class','head '+name);
+				node.setAttribute('node-name',name);
+				if (size == undefined)
+				{var node_T = document.createElement('h3');}
+				else{var node_T = document.createElement(size);}
+				node_T.textContent = title;
+				node.appendChild(node_T);
+				node.appendChild(removeNodeButton());
+				return node;
+			}
+			
+			function addPretestNode()
+			{
+				var node = createHead('preTest', 'Pre Test','h3');
+				var addStatement = document.createElement('button');
+				addStatement.textContent = 'Add Statement';
+				addStatement.onclick = function(){event.srcElement.parentElement.appendChild(addPPStatement());};
+				node.appendChild(addStatement);
+				var addQuestion = document.createElement('button');
+				addQuestion.textContent = 'Add Question';
+				addQuestion.onclick = function(){event.srcElement.parentElement.appendChild(addPPQuestion());};
+				node.appendChild(addQuestion);
+				var addCheckbox = document.createElement('button');
+				addCheckbox.textContent = 'Add Checkbox';
+				addCheckbox.onclick = function(){event.srcElement.parentElement.appendChild(addPPCheckbox());};
+				node.appendChild(addCheckbox);
+				var addRadio = document.createElement('button');
+				addRadio.textContent = 'Add Checkbox';
+				addRadio.onclick = function(){event.srcElement.parentElement.appendChild(addPPRadio());};
+				node.appendChild(addRadio);
+				return node;
+			};
+			
+			function addPosttestNode()
+			{
+				var node = createHead('postTest', 'Post Test','h3');
+				var addStatement = document.createElement('button');
+				addStatement.textContent = 'Add Statement';
+				addStatement.onclick = function(){event.srcElement.parentElement.appendChild(addPPStatement());};
+				node.appendChild(addStatement);
+				var addQuestion = document.createElement('button');
+				addQuestion.textContent = 'Add Question';
+				addQuestion.onclick = function(){event.srcElement.parentElement.appendChild(addPPQuestion());};
+				node.appendChild(addQuestion);
+				var addCheckbox = document.createElement('button');
+				addCheckbox.textContent = 'Add Checkbox';
+				addCheckbox.onclick = function(){event.srcElement.parentElement.appendChild(addPPCheckbox());};
+				node.appendChild(addCheckbox);
+				var addRadio = document.createElement('button');
+				addRadio.textContent = 'Add Checkbox';
+				addRadio.onclick = function(){event.srcElement.parentElement.appendChild(addPPRadio());};
+				node.appendChild(addRadio);
+				return node;
+			};
+		
+			function addPPStatement()
+			{
+				var node = createHead('statement', 'Statement','h4');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				var element = document.createElement('div');
+				element.setAttribute('name','element');
+				var span = document.createElement('span');
+				span.textContent = "Enter statement: ";
+				element.appendChild(span);
+				var input = document.createElement('input');
+				input.type = "text";
+				input.style.width = "500px";
+				element.appendChild(input);
+				attrib.appendChild(element);
+				node.appendChild(attrib);
+				return node;
+			};
+			function addPPQuestion()
+			{
+				var node = createHead('question', 'Question','h4');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				attrib.appendChild(attributePair('text','ID: ','id',true));
+				attrib.appendChild(attributePair('checkbox','Mandatory: ','mandatory',false));
+				attrib.appendChild(attributePair('text','Box size: ','boxsize',false));
+				var element = document.createElement('div');
+				element.setAttribute('name','element');
+				var span = document.createElement('span');
+				span.textContent = "Enter Question: ";
+				element.appendChild(span);
+				var input = document.createElement('input');
+				input.type = "text";
+				input.style.width = "500px";
+				element.appendChild(input);
+				attrib.appendChild(element);
+				node.appendChild(attrib);
+				return node;
+			};
+			function addPPCheckbox()
+			{
+				var node = createHead('checkbox', 'Checkbox','h4');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				attrib.appendChild(attributePair('text','ID: ','id',true));
+				attrib.appendChild(attributePair('checkbox','Mandatory: ','mandatory',false));
+				node.appendChild(attrib);
+				node.appendChild(addPPStatement());
+				var addOption = document.createElement('button');
+				addOption.textContent = 'Add Checkbox';
+				addOption.onclick = function() {
+					var node = createHead('option', 'Option','h4');
+					var attrib = document.createElement('div');
+					attrib.className = "attrib";
+					attrib.appendChild(attributePair('text','ID: ','id',true));
+					var element = document.createElement('div');
+					element.setAttribute('name','element');
+					var span = document.createElement('span');
+					span.textContent = "Enter Text: ";
+					var input = document.createElement('input');
+					input.type = 'text';
+					element.appendChild(span);
+					element.appendChild(input);
+					attrib.appendChild(element);
+					node.appendChild(attrib);
+					event.srcElement.parentElement.appendChild(node);
+				};
+				node.appendChild(addOption);
+				return node;
+			};
+			
+			function addPPRadio()
+			{
+				var node = createHead('radio', 'Radio','h4');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				attrib.appendChild(attributePair('text','ID: ','id',true));
+				attrib.appendChild(attributePair('checkbox','Mandatory: ','mandatory',false));
+				node.appendChild(attrib);
+				node.appendChild(addPPStatement());
+				var addOption = document.createElement('button');
+				addOption.textContent = 'Add Radio';
+				addOption.onclick = function() {
+					var node = createHead('option', 'Option','h4');
+					var attrib = document.createElement('div');
+					attrib.className = "attrib";
+					attrib.appendChild(attributePair('text','Name: ','name',true));
+					var element = document.createElement('div');
+					element.setAttribute('name','element');
+					var span = document.createElement('span');
+					span.textContent = "Enter Text: ";
+					var input = document.createElement('input');
+					input.type = 'text';
+					element.appendChild(span);
+					element.appendChild(input);
+					attrib.appendChild(element);
+					node.appendChild(attrib);
+					event.srcElement.parentElement.appendChild(node);
+				};
+				node.appendChild(addOption);
+				return node;
+			};
+			
+			function addMetricEnable()
+			{
+				var node = createHead('metricEnable', '','h4');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				var element = document.createElement('div');
+				element.setAttribute('name','element');
+				var span = document.createElement('span');
+				span.textContent = "Enter Metric Name: ";
+				element.appendChild(span);
+				var input = document.createElement('input');
+				input.type = "text";
+				input.style.width = "500px";
+				element.appendChild(input);
+				attrib.appendChild(element);
+				node.appendChild(attrib);
+				return node;
+			};
+			
+			function addInterfaceCheck()
+			{
+				var node = createHead('check', 'Check','h4');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				attrib.appendChild(attributePair('text','Name','name',true));
+				node.appendChild(attrib);
+				return node;
+			}
+			function addInterfaceOption()
+			{
+				var node = createHead('option', 'Option','h4');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				attrib.appendChild(attributePair('text','Name','name',true));
+				node.appendChild(attrib);
+				return node;
+			}
+			
+			
+			function addAudioHolder()
+			{
+				var node = createHead('audioHolder','Audio Holder / Test Page','h2');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				node.appendChild(attrib);
+				
+				attrib.appendChild(attributePair('text','ID: ','id',true));
+				attrib.appendChild(attributePair('url','Host URL: ','hostURL',false));
+				attrib.appendChild(attributePair('number','Sample Rate: ','sampleRate',false));
+				attrib.appendChild(attributePair('checkbox','Randomise Fragment Order: ','randomiseOrder',false));
+				attrib.appendChild(attributePair('number','Repeat Count: ','repeatCount',false));
+				attrib.appendChild(attributePair('checkbox','Loop Fragments: ','loop',false));
+				attrib.appendChild(attributePair('checkbox','Fragment Comment Boxes: ','enableComments',false));
+				
+				node.appendChild(addPretestNode());
+				
+				node.appendChild(addPosttestNode());
+				
+				var interfaceNode = createHead('interface','Interface','h3');
+				var addOption = document.createElement('button');
+				addOption.textContent = 'Add Option';
+				addOption.onclick = function(){event.srcElement.parentElement.appendChild(addInterfaceOption());};
+				interfaceNode.appendChild(addOption);
+				var scale = document.createElement('button');
+				scale.textContent = 'Add scale';
+				scale.onclick = function(){event.srcElement.parentElement.appendChild(addScaleMarker());};
+				interfaceNode.appendChild(scale);
+				
+				var PageTitle = createHead('title','Page Title','h4');
+				var attrib = document.createElement('div');
+				attrib.className='attrib';
+				var element = document.createElement('div');
+				element.setAttribute('name','element');
+				var span = document.createElement('span');
+				span.textContent = 'Page Title: ';
+				element.appendChild(span);
+				var input = document.createElement('input');
+				input.type = 'text';
+				input.style.width = "500px";
+				element.appendChild(input);
+				attrib.appendChild(element);
+				PageTitle.appendChild(attrib);
+				interfaceNode.appendChild(PageTitle);
+				
+				var commentBoxPrefix = createHead('commentBoxPrefix','Comment Box Prefix','h4');
+				var attrib = document.createElement('div');
+				attrib.className='attrib';
+				var element = document.createElement('div');
+				element.setAttribute('name','element');
+				var span = document.createElement('span');
+				span.textContent = 'Prefix: ';
+				element.appendChild(span);
+				var input = document.createElement('input');
+				input.type = 'text';
+				input.style.width = "500px";
+				element.appendChild(input);
+				attrib.appendChild(element);
+				commentBoxPrefix.appendChild(attrib);
+				interfaceNode.appendChild(commentBoxPrefix);
+				
+				node.appendChild(interfaceNode);
+				
+				var addElement = document.createElement('button');
+				addElement.textContent = 'Add Audio Element';
+				addElement.onclick = function(){event.srcElement.parentElement.appendChild(addAudioElement());};
+				node.appendChild(addElement);
+				
+				var addCQ = document.createElement('button');
+				addCQ.textContent = 'Add Comment Box';
+				addCQ.onclick = function(){event.srcElement.parentElement.appendChild(addExtraComment());};
+				node.appendChild(addCQ);
+				
+				return node;
+			};
+			
+			function addScaleMarker(){
+				var node = createHead('scale','Scale','h4');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				node.appendChild(attrib);
+				attrib.appendChild(attributePair('number','Position','position',true));
+				var element = document.createElement('div');
+				element.setAttribute('name','element');
+				var span = document.createElement('span');
+				span.textContent = 'Marker Text (Optional): ';
+				element.appendChild(span);
+				var input = document.createElement('input');
+				input.type = 'text';
+				element.appendChild(input);
+				attrib.appendChild(element);
+				return node;
+			};
+			
+			function addAudioElement()
+			{
+				var node = createHead('audioElements','Audio Element');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				node.appendChild(attrib);
+				
+				attrib.appendChild(attributePair('text','ID: ','id',true));
+				attrib.appendChild(attributePair('text','URL: ','url',true));
+				attrib.appendChild(attributePair('text','Type: ','type',false));
+				
+				return node;
+			};
+			
+			function addExtraComment()
+			{
+				var node = createHead('CommentQuestion','Comment');
+				var attrib = document.createElement('div');
+				attrib.className = "attrib";
+				node.appendChild(attrib);
+				attrib.appendChild(attributePair('text','ID: ','id',true));
+				
+				var element = document.createElement('div');
+				element.setAttribute('name','element');
+				var span = document.createElement('span');
+				span.textContent = 'Question: ';
+				element.appendChild(span);
+				var input = document.createElement('input');
+				input.type = 'text';
+				input.style.width = "500px";
+				element.appendChild(input);
+				attrib.appendChild(element);
+				return node;
+			}
+		</script>
+
+		<style>
+			h4 {margin: 0px;}
+			div {
+				padding: 2px;
+				margin-top: 2px;
+				margin-bottom: 2px;
+			}
+			div.head{
+				margin-left: 10px;
+				border: black;
+				border-width: 2px;
+				border-style: solid;
+			}
+			div.attrib{
+				margin-left:25px;
+				border: black;
+				border-width: 2px;
+				border-style: dashed;
+				margin-bottom: 10px;
+				display: table;
+				background-color: rgb(200,255,255);
+			}
+			div.attrib div {
+				width: auto;
+				position: relative;
+				display: table-cell;
+			}
+			div#dragFile{
+				height:100px;
+				border-width: 2px;
+				border-style: dashed;
+				margin-bottom: 10px;
+			}
+		</style>
+	</head>
+
+	<body>
+		<h1>Create Test Setup XML</h1>
+		<div id="dragFile">
+			<span>Drag and Drop an XML specification file here to auto-load.</span>
+		</div>
+		<button id="validateXML" onclick="buttonClickedValidate();">Validate</button>
+		<button id="createXML" onclick="buttonClickedSubmit();" disabled>Submit</button>
+		<div id="errorMessage" visibility="hidden"></div>
+		<div id="topLevelBody" align="left">
+			<div id='setup' class="head setup" node-name='setup'>
+				<h2>Setup Node</h2>
+				<div class="attrib">
+					<div name="attribute">
+						<span>Interface: </span>
+						<input type="text" attrib-name='interface' mandatory='true'/>
+					</div>
+					<div name="attribute">
+						<span>Project Return: </span>
+						<input type="url" attrib-name='projectReturn'/>
+					</div>
+					<div name="attribute">
+						<span>Randomise Page Order: </span>
+						<input type="checkbox" attrib-name='randomiseOrder'/>
+					</div>
+					<div name="attribute">
+						<span>Collect Metrics: </span>
+						<input type="checkbox" attrib-name='collectMetrics'/>
+					</div>
+				</div>
+				<div class="head PreTest" node-name="preTest">
+					<h3>Pre Test</h3>
+					<button onclick="event.srcElement.parentElement.appendChild(addPPStatement());">Add Statement</button>
+					<button onclick="event.srcElement.parentElement.appendChild(addPPQuestion());">Add Question</button>
+					<button onclick="event.srcElement.parentElement.appendChild(addPPCheckbox());">Add Checkbox</button>
+					<button onclick="event.srcElement.parentElement.appendChild(addPPRadio());">Add Radio</button>
+				</div>
+				<div class="head PostTest" node-name="postTest">
+					<h3>Post Test</h3>
+					<button onclick="event.srcElement.parentElement.appendChild(addPPStatement());">Add Statement</button>
+					<button onclick="event.srcElement.parentElement.appendChild(addPPQuestion());">Add Question</button>
+					<button onclick="event.srcElement.parentElement.appendChild(addPPCheckbox());">Add Checkbox</button>
+					<button onclick="event.srcElement.parentElement.appendChild(addPPRadio());">Add Radio</button>
+				</div>
+				<div class="head Metric" node-name="metrics">
+					<h3>Metrics</h3>
+					<button onclick="event.srcElement.parentElement.appendChild(addMetricEnable());">Add Metric Enable</button>
+				</div>
+				<div class="head interface" node-name="interface">
+					<h3>Interface</h3>
+					<button onclick="event.srcElement.parentElement.appendChild(addInterfaceCheck());">Add Check</button>
+					<button onclick="event.srcElement.parentElement.appendChild(addInterfaceOption());">Add Option</button>
+				</div>
+			</div>
+			<button onclick="event.srcElement.parentElement.appendChild(addAudioHolder());">Add Audio Holder</button>
+		</div>
+	</body>
+</html>