comparison analysis/analysis.js @ 1284:6c819878ac85

Major updates. Specification Nodes now own file (specification.js). Updating Analysis to allow filtering based on survey responses.
author Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk>
date Thu, 31 Mar 2016 13:31:42 +0100
parents b4a0244bf5ed
children ae57d9f618cb
comparison
equal deleted inserted replaced
1283:b24d861c96b3 1284:6c819878ac85
1 /* 1 /*
2 * Analysis script for WAET 2 * Analysis script for WAET
3 */ 3 */
4 4
5 var chartContext; 5 // Firefox does not have an XMLDocument.prototype.getElementsByName
6 // and there is no searchAll style command, this custom function will
7 // search all children recusrively for the name. Used for XSD where all
8 // element nodes must have a name and therefore can pull the schema node
9 XMLDocument.prototype.getAllElementsByName = function(name)
10 {
11 name = String(name);
12 var selected = this.documentElement.getAllElementsByName(name);
13 return selected;
14 }
15
16 Element.prototype.getAllElementsByName = function(name)
17 {
18 name = String(name);
19 var selected = [];
20 var node = this.firstElementChild;
21 while(node != null)
22 {
23 if (node.getAttribute('name') == name)
24 {
25 selected.push(node);
26 }
27 if (node.childElementCount > 0)
28 {
29 selected = selected.concat(node.getAllElementsByName(name));
30 }
31 node = node.nextElementSibling;
32 }
33 return selected;
34 }
35
36 XMLDocument.prototype.getAllElementsByTagName = function(name)
37 {
38 name = String(name);
39 var selected = this.documentElement.getAllElementsByTagName(name);
40 return selected;
41 }
42
43 Element.prototype.getAllElementsByTagName = function(name)
44 {
45 name = String(name);
46 var selected = [];
47 var node = this.firstElementChild;
48 while(node != null)
49 {
50 if (node.nodeName == name)
51 {
52 selected.push(node);
53 }
54 if (node.childElementCount > 0)
55 {
56 selected = selected.concat(node.getAllElementsByTagName(name));
57 }
58 node = node.nextElementSibling;
59 }
60 return selected;
61 }
62
63 // Firefox does not have an XMLDocument.prototype.getElementsByName
64 if (typeof XMLDocument.prototype.getElementsByName != "function") {
65 XMLDocument.prototype.getElementsByName = function(name)
66 {
67 name = String(name);
68 var node = this.documentElement.firstElementChild;
69 var selected = [];
70 while(node != null)
71 {
72 if (node.getAttribute('name') == name)
73 {
74 selected.push(node);
75 }
76 node = node.nextElementSibling;
77 }
78 return selected;
79 }
80 }
81
82 var chartContext, testData;
6 window.onload = function() { 83 window.onload = function() {
7 // Load the Visualization API and the corechart package. 84 // Load the Visualization API and the corechart package.
8 google.charts.load('current', {'packages':['corechart']}); 85 google.charts.load('current', {'packages':['corechart']});
9 chartContext = new Chart(); 86 chartContext = new Chart();
87 testData = new Data();
88 }
89
90 function get(url) {
91 // Return a new promise.
92 return new Promise(function(resolve, reject) {
93 // Do the usual XHR stuff
94 var req = new XMLHttpRequest();
95 req.open('GET', url);
96 req.onload = function() {
97 // This is called even on 404 etc
98 // so check the status
99 if (req.status == 200) {
100 // Resolve the promise with the response text
101 resolve(req.response);
102 }
103 else {
104 // Otherwise reject with the status text
105 // which will hopefully be a meaningful error
106 reject(Error(req.statusText));
107 }
108 };
109
110 // Handle network errors
111 req.onerror = function() {
112 reject(Error("Network Error"));
113 };
114
115 // Make the request
116 req.send();
117 });
10 } 118 }
11 119
12 function arrayMean(values) { 120 function arrayMean(values) {
13 var mean = 0; 121 var mean = 0;
14 for (var value of values) { 122 for (var value of values) {
113 } 221 }
114 return histogram; 222 return histogram;
115 } 223 }
116 224
117 function Chart() { 225 function Chart() {
118 this.valueData = null; 226 this.valueData;
119 this.commentData = null;
120 this.loadStatus = 0;
121 this.charts = []; 227 this.charts = [];
122
123 var XMLHttp = new XMLHttpRequest();
124 XMLHttp.parent = this;
125 XMLHttp.open("GET","../scripts/score_parser.php?format=JSON",true);
126 XMLHttp.onload = function() {
127 // Now we have the JSON data, extract
128 this.parent.valueData = JSON.parse(this.responseText);
129 this.parent.loadStatus++;
130 }
131 XMLHttp.send();
132 var XMLHttp2 = new XMLHttpRequest();
133 XMLHttp2.parent = this;
134 XMLHttp2.open("GET","../scripts/comment_parser.php?format=JSON",true);
135 XMLHttp2.onload = function() {
136 // Now we have the JSON data, extract
137 this.parent.commentData = JSON.parse(this.responseText);
138 this.parent.loadStatus++;
139 }
140 XMLHttp2.send();
141 228
142 this.chartObject = function(name) { 229 this.chartObject = function(name) {
143 // Create the charting object 230 // Create the charting object
144 this.name = name; 231 this.name = name;
145 this.root = document.createElement("div"); 232 this.root = document.createElement("div");
490 this.charts.push(chart); 577 this.charts.push(chart);
491 } 578 }
492 } 579 }
493 } 580 }
494 } 581 }
582
583 function Data() {
584 // This holds the link between the server side calculations and the client side visualisation of the data
585
586 // Dynamically generate the test filtering / page filterting tools
587 var self = this;
588 // Collect the test types and counts
589 this.testSavedDiv = document.getElementById("test-saved");
590 this.testSaves = null;
591 this.selectURL = null;
592
593 this.specification = new Specification();
594 get("../test-schema.xsd").then(function(response){
595 var parse = new DOMParser();
596 self.specification.schema = parse.parseFromString(response,'text/xml');
597 },function(error){
598 console.log("ERROR: Could not get Test Schema");
599 });
600 this.update = function(url) {
601 var self = this;
602 get(url).then(function(response){
603 var parse = new DOMParser();
604 self.specification.decode(parse.parseFromString(response,'text/xml'));
605 interfaceContext.generateFilters(self.specification);
606 return true;
607 },function(error){
608 console.log("ERROR: Could not get"+url);
609 return false;
610 });
611 }
612 var get_test = new XMLHttpRequest();
613 get_test.parent = this;
614 get_test.open("GET","../scripts/get_tests.php?format=JSON",true);
615 get_test.onload = function() {
616 this.parent.testSavedDiv.innerHTML = null;
617 var table = document.createElement("table");
618 table.innerHTML = "<tr><td>Test Filename</td><td>Count</td><td>Include</td></tr>";
619 this.parent.testSaves = JSON.parse(this.responseText);
620 for (var test of this.parent.testSaves.tests) {
621 var tableRow = document.createElement("tr");
622 var tableRowFilename = document.createElement("td");
623 tableRowFilename.textContent = test.testName;
624 var tableRowCount = document.createElement("td");
625 tableRowCount.textContent = test.files.length;
626 tableRow.appendChild(tableRowFilename);
627 tableRow.appendChild(tableRowCount);
628 var tableRowInclude = document.createElement("td");
629 var tableRowIncludeInput = document.createElement("input");
630 tableRowIncludeInput.type = "radio";
631 tableRowIncludeInput.name = "test-include";
632 tableRowIncludeInput.setAttribute("source",test.testName);
633 tableRowIncludeInput.addEventListener("change",this.parent);
634 tableRowInclude.appendChild(tableRowIncludeInput);
635 tableRow.appendChild(tableRowInclude);
636 table.appendChild(tableRow);
637 }
638 this.parent.testSavedDiv.appendChild(table);
639 }
640 get_test.send();
641 this.handleEvent = function(event) {
642 if (event.currentTarget.nodeName == "INPUT" && event.currentTarget.name == "test-include") {
643 // Changed the test specification
644 this.selectURL = event.currentTarget.getAttribute("source");
645 this.update(this.selectURL);
646 }
647 }
648 }
649
650 var interfaceContext = new function() {
651 // This creates the interface for the user to connect with the dynamic back-end to retrieve data
652 this.rootDOM = document.createElement("div");
653 this.filterDOM = document.createElement("div");
654 this.filterDOM.innerHTML = "<p>PreTest Filters</p><div id='filter-count'></div>";
655 this.filterObjects = [];
656 this.generateFilters = function(specification) {
657 // Filters are based on the pre and post global surverys
658 var FilterObject = function(parent,specification) {
659 this.parent = parent;
660 this.specification = specification;
661 this.rootDOM = document.createElement("div");
662 this.rootDOM.innerHTML = "<span>ID: "+specification.id+", Type: "+specification.type+"</span>";
663 this.rootDOM.className = "filter-entry";
664 this.handleEvent = function(event) {
665 switch(this.specification.type) {
666 case "number":
667 var name = event.currentTarget.name;
668 eval("this."+name+" = event.currentTarget.value");
669 break;
670 case "checkbox":
671 break;
672 case "radio":
673 break;
674 }
675 this.parent.getFileCount();
676 }
677 this.getFilterPairs = function() {
678 var pairs = [];
679 switch(this.specification.type) {
680 case "number":
681 if (this.min != "") {
682 pairs.push([specification.id+"-min",this.min]);
683 }
684 if (this.max != "") {
685 pairs.push([specification.id+"-max",this.max]);
686 }
687 break;
688 case "radio":
689 case "checkbox":
690 for (var i=0; i<this.options.length; i++) {
691 if (!this.options[i].checked) {
692 pairs.push([specification.id+"-exclude-"+i,specification.options[i].name]);
693 }
694 }
695 break;
696 }
697 return pairs;
698 }
699 switch(specification.type) {
700 case "number":
701 // Number can be ranged by min/max levels
702 this.min = "";
703 this.max = "";
704 this.minDOM = document.createElement("input");
705 this.minDOM.type = "number";
706 this.minDOM.name = "min";
707 this.minDOM.addEventListener("change",this);
708 this.minDOMText = document.createElement("span");
709 this.minDOMText.textContent = "Minimum: ";
710 var pairHolder = document.createElement("div");
711 pairHolder.appendChild(this.minDOMText);
712 pairHolder.appendChild(this.minDOM);
713 this.rootDOM.appendChild(pairHolder);
714
715 this.maxDOM = document.createElement("input");
716 this.maxDOM.type = "number";
717 this.maxDOM.name = "max";
718 this.maxDOM.addEventListener("change",this);
719 this.maxDOMText = document.createElement("span");
720 this.maxDOMText.textContent = "Maximum: ";
721 var pairHolder = document.createElement("div");
722 pairHolder.appendChild(this.maxDOMText);
723 pairHolder.appendChild(this.maxDOM);
724 this.rootDOM.appendChild(pairHolder);
725 break;
726 case "radio":
727 case "checkbox":
728 this.options = [];
729 for (var i=0; i<specification.options.length; i++) {
730 var option = specification.options[i];
731 var pairHolder = document.createElement("div");
732 var text = document.createElement("span");
733 text.textContent = option.text;
734 var check = document.createElement("input");
735 check.type = "checkbox";
736 check.setAttribute("option-index",i);
737 check.checked = true;
738 check.addEventListener("click",this);
739 this.options.push(check);
740 pairHolder.appendChild(text);
741 pairHolder.appendChild(check);
742 this.rootDOM.appendChild(pairHolder);
743 }
744 break;
745 default:
746 break;
747 }
748 }
749 for (var survey_entry of specification.preTest.options) {
750 switch(survey_entry.type) {
751 case "number":
752 case "radio":
753 case "checkbox":
754 var node = new FilterObject(this,survey_entry);
755 this.filterObjects.push(node);
756 this.filterDOM.appendChild(node.rootDOM);
757 break;
758 default:
759 break;
760 }
761 }
762 for (var survey_entry of specification.postTest.options) {
763 switch(survey_entry.type) {
764 case "number":
765 case "radio":
766 case "checkbox":
767 var node = new FilterObject(this,survey_entry);
768 this.filterObjects.push(node);
769 this.filterDOM.appendChild(node.rootDOM);
770 break;
771 default:
772 break;
773 }
774 }
775 document.getElementById("test-saved").appendChild(this.filterDOM);
776 }
777 this.getFileCount = function() {
778 // First we must get the filter pairs
779 var pairs = [];
780 for (var obj of this.filterObjects) {
781 pairs = pairs.concat(obj.getFilterPairs());
782 }
783 var req_str = "../scripts/get_filtered_count.php?url="+testData.selectURL;
784 var index = 0;
785 while(pairs[index] != undefined) {
786 req_str += '&';
787 req_str += pairs[index][0]+"="+pairs[index][1];
788 index++;
789 }
790 get(req_str).then(function(response){
791 var urls = JSON.parse(response);
792 var str = "Filtered to "+urls.urls.length+" file";
793 if (urls.urls.length != 1) {
794 str += "s.";
795 } else {
796 str += ".";
797 }
798 document.getElementById("filter-count").textContent = str;
799 },function(error){
800 console.error(error);
801 });
802 }
803 }