annotate test_create/test_create.html @ 167:fa33bf58d863 Dev_main

Create_test: Submit button exposes completed XML file.
author Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk>
date Wed, 03 Jun 2015 12:15:14 +0100
parents dcc553484103
children f95a30a25a87
rev   line source
n@156 1 <!DOCTYPE html>
n@156 2 <html lang="en">
n@156 3 <head>
n@156 4 <meta charset="utf-8">
n@156 5
n@156 6 <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
n@156 7 Remove this if you use the .htaccess -->
n@156 8 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
n@156 9
n@156 10 <title>WAET Create Test</title>
n@156 11 <meta name="description" content="">
n@156 12 <meta name="author" content="">
n@156 13
n@156 14 <meta name="viewport" content="width=device-width; initial-scale=1.0">
n@157 15
n@157 16 <script type="text/javascript">
n@157 17 // To aid 'one-page set-up' all scripts and CSS must be included directly in this file!
n@157 18 var topLevel;
n@157 19 window.onload = function() {
n@157 20 // Initialise page
n@157 21 topLevel = document.getElementById('topLevelBody');
n@157 22 var setup = document.createElement('div');
n@157 23 setup.id = 'setupTagDiv';
n@157 24
n@157 25 };
n@157 26
n@162 27 function attributePair(string, type, mandatory){
n@157 28 var id = document.createElement("span");
n@157 29 id.textContent = string;
n@157 30 var input = document.createElement("input");
n@157 31 input.type = type;
n@162 32 if (type == 'text') {
n@162 33 if (mandatory == true) {
n@162 34 input.setAttribute('mandatory','true');
n@162 35 }
n@162 36 else {
n@162 37 input.setAttribute('mandatory','false');
n@162 38 }
n@162 39 }
n@157 40 return [id, input];
n@157 41 }
n@157 42
n@159 43 function removeNode(event) {
n@159 44 event.srcElement.parentElement.parentElement.removeChild(event.srcElement.parentElement);
n@159 45 }
n@159 46
n@162 47 function buttonClickedValidate() {
n@162 48 var ready = validate();
n@162 49 if (ready == false) {
n@162 50 var errMsg = document.getElementById('errorMessage');
n@163 51 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.";
n@162 52 errMsg.style.visibility = 'visible';
n@162 53 document.getElementById('createXML').disabled = true;
n@162 54
n@162 55 } else {
n@162 56 var errMsg = document.getElementById('errorMessage');
n@162 57 errMsg.textContent = "";
n@162 58 errMsg.style.visiblity = 'hidden';
n@162 59 document.getElementById('createXML').disabled = false;
n@162 60 }
n@162 61 }
n@162 62
n@163 63 function buttonClickedSubmit() {
n@163 64 var ready = validate();
n@163 65 if (ready == true) {
n@167 66 var xmlDoc = buildXML();
n@167 67 var inject = document.getElementById('errorMessage');
n@167 68 createProjectSave(xmlDoc, inject);
n@167 69 }
n@167 70 }
n@167 71
n@167 72 function createProjectSave(xmlDoc, injectPoint) {
n@167 73 var parent = document.createElement("div");
n@167 74 parent.appendChild(xmlDoc);
n@167 75 var file = [parent.innerHTML];
n@167 76 var bb = new Blob(file,{type : 'application/xml'});
n@167 77 var dnlk = window.URL.createObjectURL(bb);
n@167 78 var a = document.createElement("a");
n@167 79 a.hidden = '';
n@167 80 a.href = dnlk;
n@167 81 a.download = "save.xml";
n@167 82 a.textContent = "Save File";
n@167 83 injectPoint.appendChild(a);
n@167 84 }
n@167 85
n@167 86 function buildXML() {
n@167 87 var xmlDoc = document.createElement('BrowserEvalProjectDocument');
n@167 88 var setup = document.createElement('setup');
n@167 89 setup.setAttribute('interface',document.getElementById('interface').value);
n@167 90 if (document.getElementById('projectReturn').value == "") {
n@167 91 setup.setAttribute('projectReturn',"null");
n@167 92 } else {
n@167 93 setup.setAttribute('projectReturn',document.getElementById('projectReturn').value);
n@167 94 }
n@167 95 setup.setAttribute('randomiseOrder',document.getElementById('randomisePageOrder').checked);
n@167 96 setup.setAttribute('collectMetrics',document.getElementById('collectMetrics').checked);
n@167 97
n@167 98 var globalPreTest = document.createElement('preTest');
n@167 99 var options = document.getElementById('globalPreTest').getElementsByClassName('head');
n@167 100 constructPrePost(globalPreTest, options);
n@167 101
n@167 102 var globalPostTest = document.createElement('postTest');
n@167 103 options = document.getElementById('globalPostTest').getElementsByClassName('head');
n@167 104 constructPrePost(globalPostTest, options);
n@167 105
n@167 106 var globalMetrics = document.createElement('metric');
n@167 107 options = document.getElementById('globalMetric').getElementsByClassName('attrib')[0].getElementsByTagName('input');
n@167 108 for (var i=0; i<options.length; i++) {
n@167 109 if (options[i].checked) {
n@167 110 var metric = document.createElement('metricEnable');
n@167 111 metric.textContent = options[i].id;
n@167 112 globalMetrics.appendChild(metric);
n@163 113 }
n@167 114 }
n@167 115 setup.appendChild(globalPreTest);
n@167 116 setup.appendChild(globalPostTest);
n@167 117 setup.appendChild(globalMetrics);
n@167 118 xmlDoc.appendChild(setup);
n@167 119
n@167 120 var audioHolders = document.getElementsByName('audio-holder');
n@167 121 for (var i=0; i<audioHolders.length; i++) {
n@167 122 var audioHolder = document.createElement('audioHolder');
n@167 123 var audioHolderDOM = audioHolders[i];
n@167 124 var attribs = audioHolderDOM.getElementsByClassName('attrib')[0].getElementsByTagName('input');
n@167 125 audioHolder.id = attribs[0].value;
n@167 126 if (attribs[1].value != "") {audioHolder.setAttribute('sampleRate',attribs[1].value);}
n@167 127 if (attribs[2].value != "") {audioHolder.setAttribute('hostURL',attribs[2].value);}
n@167 128 audioHolder.setAttribute('randomiseOrder',attribs[3].checked);
n@167 129 audioHolder.setAttribute('repeatCount',attribs[4].checked);
n@167 130 audioHolder.setAttribute('loop',attribs[5].checked);
n@167 131 audioHolder.setAttribute('elementComments',attribs[6].checked);
n@163 132
n@167 133 // Audio-Holder PreTests
n@167 134 var audioHolderPreTest = document.createElement('preTest');
n@167 135 var audioHolderPostTest = document.createElement('postTest');
n@167 136 options = audioHolderDOM.childNodes[2].getElementsByClassName('head');
n@167 137 constructPrePost(audioHolderPreTest, options);
n@167 138 options = audioHolderDOM.childNodes[3].getElementsByClassName('head');
n@167 139 constructPrePost(audioHolderPostTest, options);
n@163 140
n@167 141 audioHolder.appendChild(audioHolderPreTest);
n@167 142 audioHolder.appendChild(audioHolderPostTest);
n@163 143
n@167 144 // audio-Elements
n@167 145 var audioElementsDOM = [];
n@167 146 var commentQuestionDOM = [];
n@167 147 for (var j=0; j<audioHolderDOM.childElementCount; j++) {
n@167 148 var child = audioHolderDOM.childNodes[j];
n@167 149 var name = child.getAttribute('name');
n@167 150 if (name == 'audio-element') {audioElementsDOM.push(child);}
n@167 151 else if (name == 'comment-question') {commentQuestionDOM.push(child);}
n@163 152 }
n@163 153
n@167 154 for (var j=0; j<audioElementsDOM.length; j++) {
n@167 155 var audioElement = document.createElement('audioElement');
n@167 156 attribs = audioElementsDOM[j].getElementsByClassName('attrib')[0].getElementsByTagName('input');
n@167 157 audioElement.id = attribs[0].value;
n@167 158 audioElement.setAttribute('url',attribs[1].value);
n@167 159 audioHolder.appendChild(audioElement);
n@166 160 }
n@167 161
n@167 162 for (var j=0; j<commentQuestionDOM.length; j++) {
n@167 163 var commentQuestion = document.createElement('commentQuestion');
n@167 164 attribs = commentQuestionDOM[j].getElementsByClassName('attrib')[0].getElementsByTagName('input');
n@167 165 commentQuestion.id = attribs[0].value;
n@167 166 commentQuestion.textContent = attribs[1].value;
n@167 167 audioHolder.appendChild(commentQuestion);
n@167 168 }
n@167 169 xmlDoc.appendChild(audioHolder);
n@163 170 }
n@167 171 return xmlDoc;
n@163 172 }
n@163 173
n@163 174 function constructPrePost(parent, options) {
n@163 175 for (var i=0; i<options.length; i++) {
n@163 176 var elem = options[i];
n@163 177 var attributes = elem.getElementsByClassName('attrib')[0].getElementsByTagName('input');
n@163 178 if (elem.getAttribute('name') == 'question-node') {
n@163 179 var node = document.createElement('question');
n@163 180 node.setAttribute('id',attributes[0].value);
n@163 181 node.textContent = attributes[1].value;
n@163 182 } else if (elem.getAttribute('name') == 'statement-node') {
n@163 183 var node = document.createElement('statment');
n@163 184 node.textContent = attributes[0].value;
n@163 185 }
n@163 186 parent.appendChild(node);
n@163 187 }
n@163 188 }
n@163 189
n@162 190 function validate() {
n@162 191 var canExport = true;
n@162 192 // Checks if the XML can be created from the given entries
n@162 193 var inputs = document.getElementsByTagName('input');
n@162 194 for (var i=0; i<inputs.length; i++) {
n@162 195 if (inputs[i].type == 'text') {
n@162 196 if (inputs[i].value == "") {
n@162 197 var mandatory = inputs[i].getAttribute('mandatory');
n@162 198 if (mandatory == "true") {
n@162 199 errorInput(inputs[i]);
n@162 200 canExport = false;
n@162 201 } else {
n@162 202 warningInput(inputs[i]);
n@162 203 }
n@162 204 } else {
n@162 205 goodInput(inputs[i]);
n@162 206 }
n@162 207 }
n@162 208 }
n@163 209
n@163 210 var audioHolders = document.getElementsByName('audio-holder');
n@163 211 for (var i=0; i<audioHolders.length; i++) {
n@163 212 var divs = audioHolders[i].getElementsByClassName('head');
n@163 213 var IDs = [];
n@163 214 for (var j=0; j<divs.length; j++) {
n@163 215 if (divs[j].getAttribute('name') == 'audio-element') {
n@163 216 var obj = divs[j].getElementsByClassName('attrib')[0].children[1];
n@163 217 var aeID = obj.value;
n@163 218 if (aeID != "") {
n@163 219 var unique = true;
n@163 220 for (var k=0; k<IDs.length; k++) {
n@163 221 if (aeID == IDs[k]) {
n@163 222 unique = false;
n@163 223 break;
n@163 224 }
n@163 225 }
n@163 226 if (unique == true) {
n@163 227 IDs.push(aeID);
n@163 228 } else {
n@163 229 errorInput(obj);
n@163 230 canExport = false;
n@163 231 }
n@163 232 }
n@163 233 }
n@163 234 }
n@163 235 }
n@162 236 return canExport;
n@162 237 };
n@162 238
n@162 239 function errorInput(node) {
n@162 240 node.style.backgroundColor = "#FF0000";
n@162 241 }
n@162 242
n@162 243 function warningInput(node) {
n@162 244 node.style.backgroundColor = "#FFFF00";
n@162 245 }
n@162 246
n@162 247 function goodInput(node) {
n@162 248 node.style.backgroundColor = "#FFFFFF";
n@162 249 }
n@162 250
n@157 251 function questionNode() {
n@157 252 var node = document.createElement("div");
n@157 253 node.setAttribute('class','head');
n@157 254 node.setAttribute('name','question-node');
n@157 255 var nodeTitle = document.createElement("span");
n@157 256 nodeTitle.textContent = "Question";
n@157 257 var attributes = document.createElement("div");
n@157 258 attributes.setAttribute('class','attrib');
n@162 259 var id = attributePair("ID:","text", true);
n@162 260 var question = attributePair("Question:","text", false);
n@157 261 node.appendChild(nodeTitle);
n@157 262 id.forEach(function(item){attributes.appendChild(item);},false);
n@157 263 question.forEach(function(item){attributes.appendChild(item);},false);
n@157 264 node.appendChild(attributes);
n@159 265
n@159 266 var removeButton = document.createElement("button");
n@159 267 removeButton.textContent = "Remove";
n@159 268 removeButton.onclick = removeNode;
n@159 269 node.appendChild(removeButton);
n@157 270 return node;
n@157 271 }
n@157 272
n@157 273 function statementNode() {
n@157 274 var node = document.createElement("div");
n@157 275 node.setAttribute('class','head');
n@162 276 node.setAttribute('name','statement-node');
n@157 277 var nodeTitle = document.createElement("span");
n@157 278 nodeTitle.textContent = "Statement";
n@157 279 var attributes = document.createElement("div");
n@157 280 attributes.setAttribute('class','attrib');
n@162 281 var statement = attributePair("Statement:","text",false);
n@157 282 node.appendChild(nodeTitle);
n@157 283 statement.forEach(function(item){attributes.appendChild(item);},false);
n@157 284 node.appendChild(attributes);
n@159 285
n@159 286 var removeButton = document.createElement("button");
n@159 287 removeButton.textContent = "Remove";
n@159 288 removeButton.onclick = removeNode;
n@159 289 node.appendChild(removeButton);
n@157 290 return node;
n@157 291 }
n@157 292
n@157 293 function audioHolderNode() {
n@157 294 var audioHolderCounts = document.getElementsByName("audio-holder").length;
n@157 295 var node = document.createElement("div");
n@157 296 node.setAttribute("class","head");
n@157 297 node.setAttribute("name","audio-holder");
n@159 298 node.setAttribute("id","audio-holder-"+audioHolderCounts);
n@157 299 var nodeTitle = document.createElement("span");
n@159 300 nodeTitle.textContent = "Audio Holder "+(audioHolderCounts+1);
n@157 301
n@157 302 var attributes = document.createElement("div");
n@157 303 attributes.setAttribute('class','attrib');
n@162 304 var id = attributePair("ID:","text",true);
n@159 305 id[1].value=audioHolderCounts;
n@162 306 var hostURL = attributePair("Host URL:", "text",false);
n@162 307 var sampleRate = attributePair("Sample Rate:","text",false);
n@159 308 var randomiseOrder = attributePair("Randomise Element Order:","checkbox");
n@159 309 var repeatCount = attributePair("Repeat Page Count:","number");
n@159 310 repeatCount[1].value = 0;
n@159 311 var loop = attributePair("Loop Element Playback","checkbox");
n@159 312 var elementComments = attributePair("Enable Comment Boxes","checkbox");
n@159 313 id.forEach(function(item){attributes.appendChild(item);},false);
n@159 314 hostURL.forEach(function(item){attributes.appendChild(item);},false);
n@159 315 sampleRate.forEach(function(item){attributes.appendChild(item);},false);
n@159 316 hostURL.forEach(function(item){attributes.appendChild(item);},false);
n@159 317 randomiseOrder.forEach(function(item){attributes.appendChild(item);},false);
n@159 318 repeatCount.forEach(function(item){attributes.appendChild(item);},false);
n@159 319 loop.forEach(function(item){attributes.appendChild(item);},false);
n@159 320 elementComments.forEach(function(item){attributes.appendChild(item);},false);
n@159 321
n@159 322 node.appendChild(nodeTitle);
n@159 323 node.appendChild(attributes);
n@159 324
n@159 325 var pretest = document.createElement("div");
n@159 326 pretest.setAttribute('class','head');
n@159 327 pretest.setAttribute('name','pre-test');
n@159 328 var pretestTitle = document.createElement("h4");
n@159 329 pretestTitle.textContent = "Pre Test";
n@159 330 var buttonAddQ = document.createElement("button");
n@159 331 buttonAddQ.textContent = "Add Pre Test Question";
n@159 332 buttonAddQ.onclick = function(){event.srcElement.parentElement.appendChild(questionNode());};
n@159 333 var buttonAddS = document.createElement("button");
n@159 334 buttonAddS.textContent = "Add Pre Test Statement";
n@159 335 buttonAddS.onclick = function(){event.srcElement.parentElement.appendChild(statementNode());};
n@159 336 pretest.appendChild(pretestTitle);
n@159 337 pretest.appendChild(buttonAddQ);
n@159 338 pretest.appendChild(buttonAddS);
n@159 339
n@159 340 var posttest = document.createElement("div");
n@159 341 posttest.setAttribute('class','head');
n@159 342 posttest.setAttribute('name','post-test');
n@159 343 var posttestTitle = document.createElement("h4");
n@159 344 posttestTitle.textContent = "Post Test";
n@159 345 var buttonAddQ = document.createElement("button");
n@159 346 buttonAddQ.textContent = "Add Post Test Question";
n@159 347 buttonAddQ.onclick = function(){event.srcElement.parentElement.appendChild(questionNode());};
n@159 348 var buttonAddS = document.createElement("button");
n@159 349 buttonAddS.textContent = "Add Post Test Statement";
n@159 350 buttonAddS.onclick = function(){event.srcElement.parentElement.appendChild(statementNode());};
n@159 351 posttest.appendChild(posttestTitle);
n@159 352 posttest.appendChild(buttonAddQ);
n@159 353 posttest.appendChild(buttonAddS);
n@159 354
n@159 355 node.appendChild(pretest);
n@159 356 node.appendChild(posttest);
n@159 357
n@159 358 var newAudioElementButton = document.createElement("button");
n@159 359 newAudioElementButton.textContent = "Add audio element";
n@159 360 newAudioElementButton.onclick = function(){
n@159 361 event.srcElement.parentElement.appendChild(audioElementNode());
n@159 362 };
n@159 363 node.appendChild(newAudioElementButton);
n@159 364
n@159 365 var newCommentButton = document.createElement("button");
n@159 366 newCommentButton.textContent = "Add Comment Box";
n@159 367 newCommentButton.onclick = function() {
n@159 368 event.srcElement.parentElement.appendChild(commentBox());
n@159 369 };
n@159 370 node.appendChild(newCommentButton);
n@159 371
n@159 372 var removeButton = document.createElement("button");
n@159 373 removeButton.textContent = "Remove Audio Holder";
n@159 374 removeButton.onclick = removeNode;
n@159 375 node.appendChild(removeButton);
n@159 376 return node;
n@159 377 }
n@159 378
n@159 379 function audioElementNode() {
n@159 380 var parentStructure = event.srcElement.parentElement.childNodes;
n@159 381 var audioElemCounts = 0;
n@159 382 for (var i=0; i<parentStructure.length; i++) {
n@159 383 if (parentStructure[i].getAttribute('name') == "audio-element")
n@159 384 {audioElemCounts++;}
n@159 385 }
n@159 386 var node = document.createElement('div');
n@159 387 node.setAttribute('class','head');
n@159 388 node.setAttribute('name','audio-element');
n@159 389 var nodeTitle = document.createElement('span');
n@159 390 nodeTitle.textContent = 'Audio Element '+(audioElemCounts+1);
n@159 391
n@159 392 var attributes = document.createElement("div");
n@159 393 attributes.setAttribute('class','attrib');
n@162 394 var id = attributePair("ID:","text",true);
n@159 395 id[1].value = audioElemCounts;
n@162 396 var url = attributePair("URL:","text",true);
n@159 397 id.forEach(function(item){attributes.appendChild(item);},false);
n@159 398 url.forEach(function(item){attributes.appendChild(item);},false);
n@159 399
n@159 400 node.appendChild(nodeTitle);
n@159 401 node.appendChild(attributes);
n@159 402
n@159 403 var removeButton = document.createElement("button");
n@159 404 removeButton.textContent = "Remove Audio Element";
n@159 405 removeButton.onclick = removeNode;
n@159 406 node.appendChild(removeButton);
n@159 407 return node;
n@159 408 }
n@159 409
n@159 410 function commentBox() {
n@159 411 var node = document.createElement('div');
n@159 412 node.setAttribute('class','head');
n@159 413 node.setAttribute('name','comment-question');
n@159 414 var nodeTitle = document.createElement('h4');
n@159 415 nodeTitle.textContent = "Comment Box";
n@159 416
n@159 417 var attributes = document.createElement('div');
n@159 418 attributes.setAttribute('class','attrib');
n@162 419 var id = attributePair("ID:",'text',true);
n@162 420 var question = attributePair("Question:",'text',true);
n@159 421 id.forEach(function(item){attributes.appendChild(item);},false);
n@159 422 question.forEach(function(item){attributes.appendChild(item);},false);
n@159 423
n@159 424 var removeButton = document.createElement("button");
n@159 425 removeButton.textContent = "Remove Comment Box";
n@159 426 removeButton.onclick = removeNode;
n@159 427
n@159 428 node.appendChild(nodeTitle);
n@159 429 node.appendChild(attributes);
n@159 430 node.appendChild(removeButton);
n@159 431 return node;
n@157 432 }
n@157 433 </script>
n@157 434 <style>
n@157 435 div {
n@157 436 padding: 2px;
n@157 437 margin-top: 2px;
n@157 438 margin-bottom: 2px;
n@157 439 }
n@157 440 div.head{
n@157 441 margin-left: 10px;
n@157 442 border: black;
n@157 443 border-width: 2px;
n@157 444 border-style: solid;
n@157 445 }
n@157 446 div.attrib{
n@157 447 margin-left:25px;
n@157 448 border: black;
n@157 449 border-width: 2px;
n@157 450 border-style: dashed;
n@157 451 margin-bottom: 10px;
n@157 452 }
n@157 453 </style>
n@157 454
n@156 455 </head>
n@156 456
n@156 457 <body>
n@157 458 <h1>Create Test Setup XML</h1>
n@162 459 <button id="validateXML" onclick="buttonClickedValidate();">Validate</button>
n@167 460 <button id="createXML" onclick="buttonClickedSubmit();" disabled>Submit</button>
n@162 461 <span id="errorMessage" visibility="hidden"></span>
n@157 462 <div id="topLevelBody" align="left">
n@156 463 <!-- Interface goes here -->
n@157 464 <div name='test-setup'>
n@157 465 <div id="setup" class="head">
n@157 466 <h2>Setup Tag</h2>
n@157 467 <div id="setup-attribs" class="attrib">
n@157 468 <span>Interface</span>
n@157 469 <select id="interface">
n@157 470 <option value='APE'>APE</option>
n@157 471 </select>
n@157 472 <span>Project Return</span>
n@162 473 <input type="text" id="projectReturn" mandatory="false">
n@157 474 <span>Randomise Test Page Order</span>
n@157 475 <input id="randomisePageOrder" type="checkbox" value="false">
n@157 476 <span>Collect Session Metrics</span>
n@157 477 <input id="collectMetrics" type="checkbox">
n@157 478 </div>
n@157 479 <div id="globalPreTest" class="head">
n@157 480 <h3>Pre Test</h3>
n@157 481 <button id="addPreTestQ" onclick="event.srcElement.parentElement.appendChild(questionNode());">Add Pre Test Question</button>
n@157 482 <button id="addPreTestS" onclick="event.srcElement.parentElement.appendChild(statementNode());">Add Pre Test Statement</button>
n@157 483 </div>
n@157 484 <div id="globalPostTest" class="head">
n@157 485 <h3>Post Test</h3>
n@157 486 <button id="addPreTestQ" onclick="event.srcElement.parentElement.appendChild(questionNode());">Add Post Test Question</button>
n@157 487 <button id="addPreTestS" onclick="event.srcElement.parentElement.appendChild(statementNode());">Add Post Test Statement</button>
n@157 488 </div>
n@157 489 <div id="globalMetric" class="head">
n@157 490 <h3>Global Metrics</h3>
n@157 491 <div id="globalMetric-attrib" class="attrib">
n@157 492 <span>Test Timer</span>
n@157 493 <input type="checkbox" id="testTimer" />
n@157 494 <span>Element Playback Timer</span>
n@157 495 <input type="checkbox" id="elementTimer" />
n@157 496 <span>Element Initial Position</span>
n@157 497 <input type="checkbox" id="elementInitialPosition" />
n@157 498 <span>Element Tracker</span>
n@157 499 <input type="checkbox" id="elementTracker" />
n@157 500 <span>Element Flag Listened To</span>
n@163 501 <input type="checkbox" id="elementFlagListenedTo" />
n@157 502 <span>Element Flag Moved</span>
n@157 503 <input type="checkbox" id="elementFlagMoved" />
n@157 504 </div>
n@157 505 </div>
n@159 506 <button id="addAudioHolder" onclick="event.srcElement.parentElement.appendChild(audioHolderNode());">Add AudioHolder / Test Page</button>
n@157 507 </div>
n@157 508 </div>
n@156 509 </div>
n@156 510 </body>
n@156 511 </html>