comparison js/specification.js @ 2224:760719986df3

Tidy up file locations.
author Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk>
date Thu, 14 Apr 2016 13:54:24 +0100
parents
children 0de305726129
comparison
equal deleted inserted replaced
2222:4d1aa94202e3 2224:760719986df3
1 function Specification() {
2 // Handles the decoding of the project specification XML into a simple JavaScript Object.
3
4 this.interface = null;
5 this.projectReturn = "null";
6 this.randomiseOrder = null;
7 this.testPages = null;
8 this.pages = [];
9 this.metrics = null;
10 this.interfaces = null;
11 this.loudness = null;
12 this.errors = [];
13 this.schema = null;
14 this.exitText = "Thank you.";
15
16 this.processAttribute = function(attribute,schema,schemaRoot)
17 {
18 // attribute is the string returned from getAttribute on the XML
19 // schema is the <xs:attribute> node
20 if (schema.getAttribute('name') == undefined && schema.getAttribute('ref') != undefined)
21 {
22 schema = schemaRoot.getAllElementsByName(schema.getAttribute('ref'))[0];
23 }
24 var defaultOpt = schema.getAttribute('default');
25 if (attribute == null) {
26 attribute = defaultOpt;
27 }
28 var dataType = schema.getAttribute('type');
29 if (typeof dataType == "string") { dataType = dataType.substr(3);}
30 else {
31 var rest = schema.getAllElementsByTagName("xs:restriction").concat(schema.getAllElementsByTagName("xs:enumeration"));
32 if (rest.length > 0) {
33 dataType = rest[0].getAttribute("base");
34 if (typeof dataType == "string") {
35 dataType = dataType.substr(3);
36 } else {
37 dataType = "string";
38 }
39 } else {
40 dataType = "string";
41 }
42 }
43 if (attribute == null)
44 {
45 return attribute;
46 }
47 switch(dataType)
48 {
49 case "boolean":
50 if (attribute == 'true'){attribute = true;}else{attribute=false;}
51 break;
52 case "negativeInteger":
53 case "positiveInteger":
54 case "nonNegativeInteger":
55 case "nonPositiveInteger":
56 case "integer":
57 case "decimal":
58 case "short":
59 attribute = Number(attribute);
60 break;
61 case "string":
62 default:
63 attribute = String(attribute);
64 break;
65 }
66 return attribute;
67 };
68
69 this.decode = function(projectXML) {
70 this.errors = [];
71 // projectXML - DOM Parsed document
72 this.projectXML = projectXML.childNodes[0];
73 var setupNode = projectXML.getElementsByTagName('setup')[0];
74 var schemaSetup = this.schema.getAllElementsByName('setup')[0];
75 // First decode the attributes
76 var attributes = schemaSetup.getAllElementsByTagName('xs:attribute');
77 for (var i in attributes)
78 {
79 if (isNaN(Number(i)) == true){break;}
80 var attributeName = attributes[i].getAttribute('name') || attributes[i].getAttribute('ref');
81 var projectAttr = setupNode.getAttribute(attributeName);
82 projectAttr = this.processAttribute(projectAttr,attributes[i],this.schema);
83 switch(typeof projectAttr)
84 {
85 case "number":
86 case "boolean":
87 eval('this.'+attributeName+' = '+projectAttr);
88 break;
89 case "string":
90 eval('this.'+attributeName+' = "'+projectAttr+'"');
91 break;
92 }
93
94 }
95
96 var exitTextNode = setupNode.getElementsByTagName('exitText');
97 if (exitTextNode.length == 1) {
98 this.exitText = exitTextNode[0].textContent;
99 }
100
101 this.metrics = new this.metricNode();
102
103 this.metrics.decode(this,setupNode.getElementsByTagName('metric')[0]);
104
105 // Now process the survey node options
106 var survey = setupNode.getElementsByTagName('survey');
107 for (var i in survey) {
108 if (isNaN(Number(i)) == true){break;}
109 var location = survey[i].getAttribute('location');
110 if (location == 'pre' || location == 'before')
111 {
112 if (this.preTest != null){this.errors.push("Already a pre/before test survey defined! Ignoring second!!");}
113 else {
114 this.preTest = new this.surveyNode(this);
115 this.preTest.decode(this,survey[i]);
116 }
117 } else if (location == 'post' || location == 'after') {
118 if (this.postTest != null){this.errors.push("Already a post/after test survey defined! Ignoring second!!");}
119 else {
120 this.postTest = new this.surveyNode(this);
121 this.postTest.decode(this,survey[i]);
122 }
123 }
124 }
125
126 var interfaceNode = setupNode.getElementsByTagName('interface');
127 if (interfaceNode.length > 1)
128 {
129 this.errors.push("Only one <interface> node in the <setup> node allowed! Others except first ingnored!");
130 }
131 this.interfaces = new this.interfaceNode(this);
132 if (interfaceNode.length != 0)
133 {
134 interfaceNode = interfaceNode[0];
135 this.interfaces.decode(this,interfaceNode,this.schema.getAllElementsByName('interface')[1]);
136 }
137
138 // Page tags
139 var pageTags = projectXML.getElementsByTagName('page');
140 var pageSchema = this.schema.getAllElementsByName('page')[0];
141 for (var i=0; i<pageTags.length; i++)
142 {
143 var node = new this.page(this);
144 node.decode(this,pageTags[i],pageSchema);
145 this.pages.push(node);
146 }
147 };
148
149 this.encode = function()
150 {
151 var RootDocument = document.implementation.createDocument(null,"waet");
152 var root = RootDocument.children[0];
153 root.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
154 root.setAttribute("xsi:noNamespaceSchemaLocation","test-schema.xsd");
155 // Build setup node
156 var setup = RootDocument.createElement("setup");
157 var schemaSetup = this.schema.getAllElementsByName('setup')[0];
158 // First decode the attributes
159 var attributes = schemaSetup.getAllElementsByTagName('xs:attribute');
160 for (var i=0; i<attributes.length; i++)
161 {
162 var name = attributes[i].getAttribute("name");
163 if (name == undefined) {
164 name = attributes[i].getAttribute("ref");
165 }
166 if(eval("this."+name+" != undefined") || attributes[i].getAttribute("use") == "required")
167 {
168 eval("setup.setAttribute('"+name+"',this."+name+")");
169 }
170 }
171 root.appendChild(setup);
172 // Survey node
173 if (this.exitText != null) {
174 var exitTextNode = RootDocument.createElement('exitText');
175 exitTextNode.textContent = this.exitText;
176 setup.appendChild(exitTextNode);
177 }
178 setup.appendChild(this.preTest.encode(RootDocument));
179 setup.appendChild(this.postTest.encode(RootDocument));
180 setup.appendChild(this.metrics.encode(RootDocument));
181 setup.appendChild(this.interfaces.encode(RootDocument));
182 for (var page of this.pages)
183 {
184 root.appendChild(page.encode(RootDocument));
185 }
186 return RootDocument;
187 };
188
189 this.surveyNode = function(specification) {
190 this.location = null;
191 this.options = [];
192 this.parent = null;
193 this.schema = specification.schema.getAllElementsByName('survey')[0];
194 this.specification = specification;
195
196 this.OptionNode = function(specification) {
197 this.type = undefined;
198 this.schema = specification.schema.getAllElementsByName('surveyentry')[0];
199 this.id = undefined;
200 this.name = undefined;
201 this.mandatory = undefined;
202 this.statement = undefined;
203 this.boxsize = undefined;
204 this.options = [];
205 this.min = undefined;
206 this.max = undefined;
207 this.step = undefined;
208
209 this.decode = function(parent,child)
210 {
211 var attributeMap = this.schema.getAllElementsByTagName('xs:attribute');
212 for (var i in attributeMap){
213 if(isNaN(Number(i)) == true){break;}
214 var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref');
215 var projectAttr = child.getAttribute(attributeName);
216 projectAttr = parent.processAttribute(projectAttr,attributeMap[i],parent.schema);
217 switch(typeof projectAttr)
218 {
219 case "number":
220 case "boolean":
221 eval('this.'+attributeName+' = '+projectAttr);
222 break;
223 case "string":
224 eval('this.'+attributeName+' = "'+projectAttr+'"');
225 break;
226 }
227 }
228 this.statement = child.getElementsByTagName('statement')[0].textContent;
229 if (this.type == "checkbox" || this.type == "radio") {
230 var children = child.getElementsByTagName('option');
231 if (children.length == null) {
232 console.log('Malformed' +child.nodeName+ 'entry');
233 this.statement = 'Malformed' +child.nodeName+ 'entry';
234 this.type = 'statement';
235 } else {
236 this.options = [];
237 for (var i in children)
238 {
239 if (isNaN(Number(i))==true){break;}
240 this.options.push({
241 name: children[i].getAttribute('name'),
242 text: children[i].textContent
243 });
244 }
245 }
246 }
247 };
248
249 this.exportXML = function(doc)
250 {
251 var node = doc.createElement('surveyentry');
252 node.setAttribute('type',this.type);
253 var statement = doc.createElement('statement');
254 statement.textContent = this.statement;
255 node.appendChild(statement);
256 node.id = this.id;
257 if (this.name != undefined) { node.setAttribute("name",this.name);}
258 if (this.mandatory != undefined) { node.setAttribute("mandatory",this.mandatory);}
259 node.id = this.id;
260 if (this.name != undefined) {node.setAttribute("name",this.name);}
261 switch(this.type)
262 {
263 case "checkbox":
264 case "radio":
265 for (var i=0; i<this.options.length; i++)
266 {
267 var option = this.options[i];
268 var optionNode = doc.createElement("option");
269 optionNode.setAttribute("name",option.name);
270 optionNode.textContent = option.text;
271 node.appendChild(optionNode);
272 }
273 case "number":
274 if (this.min != undefined) {node.setAttribute("min", this.min);}
275 if (this.max != undefined) {node.setAttribute("max", this.max);}
276 case "question":
277 if (this.boxsize != undefined) {node.setAttribute("boxsize",this.boxsize);}
278 if (this.mandatory != undefined) {node.setAttribute("mandatory",this.mandatory);}
279 default:
280 break;
281 }
282 return node;
283 };
284 };
285 this.decode = function(parent,xml) {
286 this.parent = parent;
287 this.location = xml.getAttribute('location');
288 if (this.location == 'before'){this.location = 'pre';}
289 else if (this.location == 'after'){this.location = 'post';}
290 for (var i in xml.children)
291 {
292 if(isNaN(Number(i))==true){break;}
293 var node = new this.OptionNode(this.specification);
294 node.decode(parent,xml.children[i]);
295 this.options.push(node);
296 }
297 };
298 this.encode = function(doc) {
299 var node = doc.createElement('survey');
300 node.setAttribute('location',this.location);
301 for (var i=0; i<this.options.length; i++)
302 {
303 node.appendChild(this.options[i].exportXML(doc));
304 }
305 return node;
306 };
307 };
308
309 this.interfaceNode = function(specification)
310 {
311 this.title = null;
312 this.name = null;
313 this.options = [];
314 this.scales = [];
315 this.schema = specification.schema.getAllElementsByName('interface')[1];
316
317 this.decode = function(parent,xml) {
318 this.name = xml.getAttribute('name');
319 var titleNode = xml.getElementsByTagName('title');
320 if (titleNode.length == 1)
321 {
322 this.title = titleNode[0].textContent;
323 }
324 var interfaceOptionNodes = xml.getElementsByTagName('interfaceoption');
325 // Extract interfaceoption node schema
326 var interfaceOptionNodeSchema = this.schema.getAllElementsByName('interfaceoption')[0];
327 var attributeMap = interfaceOptionNodeSchema.getAllElementsByTagName('xs:attribute');
328 for (var i=0; i<interfaceOptionNodes.length; i++)
329 {
330 var ioNode = interfaceOptionNodes[i];
331 var option = {};
332 for (var j=0; j<attributeMap.length; j++)
333 {
334 var attributeName = attributeMap[j].getAttribute('name') || attributeMap[j].getAttribute('ref');
335 var projectAttr = ioNode.getAttribute(attributeName);
336 if(parent.processAttribute) {
337 parent.processAttribute(projectAttr, attributeMap[j], parent.schema)
338 } else {
339 parent.parent.processAttribute(projectAttr, attributeMap[j], parent.parent.schema)
340 }
341 switch(typeof projectAttr)
342 {
343 case "number":
344 case "boolean":
345 eval('option.'+attributeName+' = '+projectAttr);
346 break;
347 case "string":
348 eval('option.'+attributeName+' = "'+projectAttr+'"');
349 break;
350 }
351 }
352 this.options.push(option);
353 }
354
355 // Now the scales nodes
356 var scaleParent = xml.getElementsByTagName('scales');
357 if (scaleParent.length == 1) {
358 scaleParent = scaleParent[0];
359 for (var i=0; i<scaleParent.children.length; i++) {
360 var child = scaleParent.children[i];
361 this.scales.push({
362 text: child.textContent,
363 position: Number(child.getAttribute('position'))
364 });
365 }
366 }
367 };
368
369 this.encode = function(doc) {
370 var node = doc.createElement("interface");
371 if (typeof name == "string")
372 node.setAttribute("name",this.name);
373 for (var option of this.options)
374 {
375 var child = doc.createElement("interfaceoption");
376 child.setAttribute("type",option.type);
377 child.setAttribute("name",option.name);
378 node.appendChild(child);
379 }
380 if (this.scales.length != 0) {
381 var scales = doc.createElement("scales");
382 for (var scale of this.scales)
383 {
384 var child = doc.createElement("scalelabel");
385 child.setAttribute("position",scale.position);
386 child.textContent = scale.text;
387 scales.appendChild(child);
388 }
389 node.appendChild(scales);
390 }
391 return node;
392 };
393 };
394
395 this.metricNode = function() {
396 this.enabled = [];
397 this.decode = function(parent, xml) {
398 var children = xml.getElementsByTagName('metricenable');
399 for (var i in children) {
400 if (isNaN(Number(i)) == true){break;}
401 this.enabled.push(children[i].textContent);
402 }
403 }
404 this.encode = function(doc) {
405 var node = doc.createElement('metric');
406 for (var i in this.enabled)
407 {
408 if (isNaN(Number(i)) == true){break;}
409 var child = doc.createElement('metricenable');
410 child.textContent = this.enabled[i];
411 node.appendChild(child);
412 }
413 return node;
414 }
415 }
416
417 this.page = function(specification) {
418 this.presentedId = undefined;
419 this.id = undefined;
420 this.hostURL = undefined;
421 this.randomiseOrder = undefined;
422 this.loop = undefined;
423 this.showElementComments = undefined;
424 this.outsideReference = null;
425 this.loudness = null;
426 this.label = null;
427 this.preTest = null;
428 this.postTest = null;
429 this.interfaces = [];
430 this.commentBoxPrefix = "Comment on track";
431 this.audioElements = [];
432 this.commentQuestions = [];
433 this.schema = specification.schema.getAllElementsByName("page")[0];
434 this.specification = specification;
435 this.parent = null;
436
437 this.decode = function(parent,xml)
438 {
439 this.parent = parent;
440 var attributeMap = this.schema.getAllElementsByTagName('xs:attribute');
441 for (var i=0; i<attributeMap.length; i++)
442 {
443 var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref');
444 var projectAttr = xml.getAttribute(attributeName);
445 projectAttr = parent.processAttribute(projectAttr,attributeMap[i],parent.schema);
446 switch(typeof projectAttr)
447 {
448 case "number":
449 case "boolean":
450 eval('this.'+attributeName+' = '+projectAttr);
451 break;
452 case "string":
453 eval('this.'+attributeName+' = "'+projectAttr+'"');
454 break;
455 }
456 }
457
458 // Get the Comment Box Prefix
459 var CBP = xml.getElementsByTagName('commentboxprefix');
460 if (CBP.length != 0) {
461 this.commentBoxPrefix = CBP[0].textContent;
462 }
463
464 // Now decode the interfaces
465 var interfaceNode = xml.getElementsByTagName('interface');
466 for (var i=0; i<interfaceNode.length; i++)
467 {
468 var node = new parent.interfaceNode(this.specification);
469 node.decode(this,interfaceNode[i],parent.schema.getAllElementsByName('interface')[1]);
470 this.interfaces.push(node);
471 }
472
473 // Now process the survey node options
474 var survey = xml.getElementsByTagName('survey');
475 var surveySchema = parent.schema.getAllElementsByName('survey')[0];
476 for (var i in survey) {
477 if (isNaN(Number(i)) == true){break;}
478 var location = survey[i].getAttribute('location');
479 if (location == 'pre' || location == 'before')
480 {
481 if (this.preTest != null){this.errors.push("Already a pre/before test survey defined! Ignoring second!!");}
482 else {
483 this.preTest = new parent.surveyNode(this.specification);
484 this.preTest.decode(parent,survey[i],surveySchema);
485 }
486 } else if (location == 'post' || location == 'after') {
487 if (this.postTest != null){this.errors.push("Already a post/after test survey defined! Ignoring second!!");}
488 else {
489 this.postTest = new parent.surveyNode(this.specification);
490 this.postTest.decode(parent,survey[i],surveySchema);
491 }
492 }
493 }
494
495 // Now process the audioelement tags
496 var audioElements = xml.getElementsByTagName('audioelement');
497 for (var i=0; i<audioElements.length; i++)
498 {
499 var node = new this.audioElementNode(this.specification);
500 node.decode(this,audioElements[i]);
501 this.audioElements.push(node);
502 }
503
504 // Now decode the commentquestions
505 var commentQuestions = xml.getElementsByTagName('commentquestion');
506 for (var i=0; i<commentQuestions.length; i++)
507 {
508 var node = new this.commentQuestionNode(this.specification);
509 node.decode(parent,commentQuestions[i]);
510 this.commentQuestions.push(node);
511 }
512 };
513
514 this.encode = function(root)
515 {
516 var AHNode = root.createElement("page");
517 // First decode the attributes
518 var attributes = this.schema.getAllElementsByTagName('xs:attribute');
519 for (var i=0; i<attributes.length; i++)
520 {
521 var name = attributes[i].getAttribute("name");
522 if (name == undefined) {
523 name = attributes[i].getAttribute("ref");
524 }
525 if(eval("this."+name+" != undefined") || attributes[i].getAttribute("use") == "required")
526 {
527 eval("AHNode.setAttribute('"+name+"',this."+name+")");
528 }
529 }
530 if(this.loudness != null) {AHNode.setAttribute("loudness",this.loudness);}
531 // <commentboxprefix>
532 var commentboxprefix = root.createElement("commentboxprefix");
533 commentboxprefix.textContent = this.commentBoxPrefix;
534 AHNode.appendChild(commentboxprefix);
535
536 for (var i=0; i<this.interfaces.length; i++)
537 {
538 AHNode.appendChild(this.interfaces[i].encode(root));
539 }
540
541 for (var i=0; i<this.audioElements.length; i++) {
542 AHNode.appendChild(this.audioElements[i].encode(root));
543 }
544 // Create <CommentQuestion>
545 for (var i=0; i<this.commentQuestions.length; i++)
546 {
547 AHNode.appendChild(this.commentQuestions[i].encode(root));
548 }
549
550 AHNode.appendChild(this.preTest.encode(root));
551 AHNode.appendChild(this.postTest.encode(root));
552 return AHNode;
553 };
554
555 this.commentQuestionNode = function(specification) {
556 this.id = null;
557 this.name = undefined;
558 this.type = undefined;
559 this.options = [];
560 this.statement = undefined;
561 this.schema = specification.schema.getAllElementsByName('commentquestion')[0];
562 this.decode = function(parent,xml)
563 {
564 this.id = xml.id;
565 this.name = xml.getAttribute('name');
566 this.type = xml.getAttribute('type');
567 this.statement = xml.getElementsByTagName('statement')[0].textContent;
568 var optNodes = xml.getElementsByTagName('option');
569 for (var i=0; i<optNodes.length; i++)
570 {
571 var optNode = optNodes[i];
572 this.options.push({
573 name: optNode.getAttribute('name'),
574 text: optNode.textContent
575 });
576 }
577 };
578
579 this.encode = function(root)
580 {
581 var node = root.createElement("commentquestion");
582 node.id = this.id;
583 node.setAttribute("type",this.type);
584 if (this.name != undefined){node.setAttribute("name",this.name);}
585 var statement = root.createElement("statement");
586 statement.textContent = this.statement;
587 node.appendChild(statement);
588 for (var option of this.options)
589 {
590 var child = root.createElement("option");
591 child.setAttribute("name",option.name);
592 child.textContent = option.text;
593 node.appendChild(child);
594 }
595 return node;
596 };
597 };
598
599 this.audioElementNode = function(specification) {
600 this.url = null;
601 this.id = null;
602 this.name = null;
603 this.parent = null;
604 this.type = null;
605 this.marker = null;
606 this.enforce = false;
607 this.gain = 0.0;
608 this.schema = specification.schema.getAllElementsByName('audioelement')[0];;
609 this.parent = null;
610 this.decode = function(parent,xml)
611 {
612 this.parent = parent;
613 var attributeMap = this.schema.getAllElementsByTagName('xs:attribute');
614 for (var i=0; i<attributeMap.length; i++)
615 {
616 var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref');
617 var projectAttr = xml.getAttribute(attributeName);
618 projectAttr = parent.parent.processAttribute(projectAttr,attributeMap[i],parent.parent.schema);
619 switch(typeof projectAttr)
620 {
621 case "number":
622 case "boolean":
623 eval('this.'+attributeName+' = '+projectAttr);
624 break;
625 case "string":
626 eval('this.'+attributeName+' = "'+projectAttr+'"');
627 break;
628 }
629 }
630
631 };
632 this.encode = function(root)
633 {
634 var AENode = root.createElement("audioelement");
635 var attributes = this.schema.getAllElementsByTagName('xs:attribute');
636 for (var i=0; i<attributes.length; i++)
637 {
638 var name = attributes[i].getAttribute("name");
639 if (name == undefined) {
640 name = attributes[i].getAttribute("ref");
641 }
642 if(eval("this."+name+" != undefined") || attributes[i].getAttribute("use") == "required")
643 {
644 eval("AENode.setAttribute('"+name+"',this."+name+")");
645 }
646 }
647 return AENode;
648 };
649 };
650 };
651 }