106a4b4efedfa6473afd221150152b3fa9815bb6
[matches/MCTX3420.git] / testing / MCTXWeb / public_html / static / mctx.gui.js
1 /**
2  * MCTX3420 2013 GUI stuff.
3  * Coding style:
4  *  - Always end statements with semicolons
5  *  - Egyptian brackets are highly recommended (*cough*).
6  *  - Don't use synchronous stuff - hook events into callbacks
7  *  - $.fn functions should return either themselves or some useful object
8  *    to allow for chaining of method calls
9  */
10
11 mctx = {};
12 //Don't use this in the final version
13 mctx.location = window.location.pathname;
14 mctx.location = mctx.location.substring(0, mctx.location.lastIndexOf('/')) + "/";
15 //mctx.location = location.protocol + "//" + location.host + "/";
16 mctx.api = location.protocol + "//" + location.host + "/" + "api/";
17 mctx.expected_api_version = 0;
18 mctx.has_control = false;
19 mctx.debug = true;
20
21 mctx.statusCodes = {
22   STATUS_OK : 1
23 };
24
25 mctx.statusCodesDescription = {
26   "1" : "Ok",
27   "-1" : "General error",
28   "-2" : "Unauthorized",
29   "-3" : "Not running",
30   "-4" : "Already exists"
31 };
32
33 mctx.sensors = {
34   0 : {name : "Strain gauge 1"},
35   1 : {name : "Strain gauge 2"},
36   2 : {name : "Strain gauge 3"},
37   3 : {name : "Strain gauge 4"},
38   4 : {name : "Pressure sensor 1"},
39   5 : {name : "Pressure sensor 2"},
40   6 : {name : "Pressure sensor 3"}
41 };
42
43 mctx.actuators = {
44   0 : {name : "Solenoid 1"},
45   1 : {name : "Solenoid 2"},
46   2 : {name : "Solenoid 3"},
47   3 : {name : "Pressure regulator"}
48 };
49
50 mctx.strain_gauges = {};
51 mctx.strain_gauges.ids = [0, 1, 2, 3];
52 mctx.strain_gauges.time_limit = 20;
53
54 /**
55  * Logs a message if mctx.debug is enabled. This function takes
56  * a variable number of arguments and passes them 
57  * to alert or console.log (based on browser support).
58  * @returns {undefined}
59  */
60 function debugLog () {
61   if (mctx.debug) {
62     if (typeof console === "undefined" || typeof console.log === "undefined") {
63       for (var i = 0; i < arguments.length; i++) {
64         alert(arguments[i]);
65       }
66     } else {
67       console.log.apply(this, arguments);
68     }
69   }
70 }
71
72 /**
73  * Writes the current date to wherever it's called.
74  */
75 function getDate() {
76         document.write((new Date()).toDateString());
77 }
78
79 /**
80  * Should be run before the load of any GUI page.
81  * To hook events to be called after this function runs,
82  * use the 'always' method, e.g runBeforeLoad().always(function() {my stuff});
83  * @param {type} isLoginPage
84  * @returns The return value of calling $.ajax
85  */
86 function runBeforeLoad(isLoginPage) {
87   return $.ajax({
88     url : mctx.api + "identify"
89   }).done(function (data) {
90     if (data.logged_in && isLoginPage) {
91       if (mctx.debug) {
92         debugLog("Redirect disabled!");
93       } else {
94         window.location = mctx.location;
95       }
96     } else if (!data.logged_in && !isLoginPage) {
97       if (mctx.debug) {
98         debugLog("Redirect disabled!");
99       } else {
100         //Note: this only clears the nameless cookie
101         document.cookie = ""; 
102         window.location = mctx.location + "login.html";
103       }
104     } else {
105       mctx.friendlyName = data.friendly_name;
106     }
107   }).fail(function (jqHXR) {
108     if (mctx.debug) {
109       debugLog("Failed to ident server. Is API running?")
110     } else if (!isLoginPage) {
111       window.location = mctx.location + "login.html";
112     }
113   });
114 }
115
116 /**
117  * Populates a submenu of the navigation bar
118  * @param {string} header The header
119  * @param {object} items An object representing the submenu items
120  * @param {function} translator A function that translates an object item
121  *                              into a text and href.
122  * @returns {$.fn} Itself
123  */
124 $.fn.populateSubmenu = function(header, items, translator) {
125   var submenuHeader = $("<li/>").append($("<a/>", {text : header, href : "#"}));
126   var submenu = $("<ul/>", {"class" : "submenu"});
127   
128   for (var item in items) {
129     var info = translator(item, items);
130     submenu.append($("<li/>").append(
131           $("<a/>", {text : info.text, 
132                      href : info.href, target : "_blank"})
133     ));
134   }
135   
136   this.append(submenuHeader.append(submenu));
137   return this;
138 };
139
140 /** 
141  * Populates the navigation bar
142  */
143 $.fn.populateNavbar = function () {
144   var menu = $("<ul/>", {"class" : "menu"});
145   var sensorTranslator = function(item, items) {
146     var href = mctx.api + "sensors?start_time=0&format=tsv&id=" + item;
147     return {text : items[item].name, href : href};
148   };
149   var actuatorTranslator = function(item, items) {
150     var href = mctx.api + "actuators?start_time=0&format=tsv&id=" + item;
151     return {text : items[item].name, href : href};
152   };
153   
154   menu.populateSubmenu("Sensor data", mctx.sensors, sensorTranslator);
155   menu.populateSubmenu("Actuator data", mctx.actuators, actuatorTranslator);
156   menu.appendTo(this);
157   return this;
158 }
159
160 /**
161  * Sets the camera autoupdater
162  * Obsolete?
163  * @returns {$.fn}
164  */
165 $.fn.setCamera = function () {
166   var url = mctx.api + "image";  //http://beaglebone/api/image
167   var update = true;
168
169   //Stop updating if we can't retrieve an image!
170   this.error(function() {
171     update = false;
172   });
173   
174   var parent = this;
175   
176   var updater = function() {
177     if (!update) {
178       alert("Cam fail");
179       parent.attr("src", "");
180       return;
181     }
182     
183     parent.attr("src", url + "#" + (new Date()).getTime());
184     
185     setTimeout(updater, 1000);
186   };
187   
188   updater();
189   return this;
190 };
191
192 /**
193  * Sets the strain graphs to graph stuff. Obsolete?
194  * @returns {$.fn}
195  */
196 $.fn.setStrainGraphs = function () {
197   var sensor_url = mctx.api + "sensors";
198   var graphdiv = this;
199   
200   var updater = function () {
201     var time_limit = mctx.strain_gauges.time_limit;
202     var responses = new Array(mctx.strain_gauges.ids.length);
203     
204     for (var i = 0; i < mctx.strain_gauges.ids.length; i++) {
205       var parameters = {id : i, start_time: -time_limit};
206       responses[i] = $.ajax({url : sensor_url, data : parameters});
207     }
208     
209     $.when.apply(this, responses).then(function () {
210       var data = new Array(arguments.length);
211       for (var i = 0; i < arguments.length; i++) {
212         var raw_data = arguments[i][0].data;
213         var pruned_data = [];
214         var step = ~~(raw_data.length/100);
215         for (var j = 0; j < raw_data.length; j += step)
216           pruned_data.push(raw_data[j]); 
217         data[i] = pruned_data;
218       }
219       $.plot(graphdiv, data);
220       setTimeout(updater, 500);
221     }, function () {alert("It crashed");});
222   };
223   
224   updater();
225   return this;
226 };
227
228 /**
229  * Performs a login attempt.
230  * @returns The AJAX object of the login request */
231 $.fn.login = function () {
232   var username = this.find("input[name='username']").val();
233   var password = this.find("input[name='pass']").val();
234   var out = this.find("#result");
235   var redirect = function () {
236     window.location.href = mctx.location;
237   };
238   
239   out.removeAttr("class");
240   out.text("Logging in...");
241   
242   return $.ajax({
243     url : mctx.api + "bind",
244     data : {user: username, pass : password}
245   }).done(function (data) {
246     if (data.status < 0) {
247       mctx.has_control = false;
248       out.attr("class", "fail");
249       out.text("Login failed: " + data.description);
250     } else {
251       //todo: error check
252       mctx.has_control = true;
253       out.attr("class", "pass");
254       out.text("Login ok!");
255       setTimeout(redirect, 800);      
256     }
257   }).fail(function (jqXHR) {
258     mctx.has_control = false;
259     out.attr("class", "fail");
260     out.text("Login request failed - connection issues.")
261   });
262 };
263
264 /**
265  * Performs a logout request. The nameless cookie is
266  * always cleared and the browser redirected to the login page,
267  * independent of whether or not logout succeeded.
268  * @returns  The AJAX object of the logout request.
269  */
270 $.fn.logout = function () {
271   return $.ajax({
272     url : mctx.api + "unbind"
273   }).always(function () {
274     //Note: this only clears the nameless cookie
275     document.cookie = ""; 
276     window.location = mctx.location + "login.html";
277   });
278 };
279
280 /**
281  * Sets the error log to continuously update.
282  * @returns itself */
283 $.fn.setErrorLog = function () {
284   var url = mctx.api + "errorlog";
285   var outdiv = this;
286   
287   var updater = function () {
288     $.ajax({url : url}).done(function (data) {
289       outdiv.text(data);
290       outdiv.scrollTop(
291         outdiv[0].scrollHeight - outdiv.height()
292       );
293       setTimeout(updater, 2000);
294     }).fail(function (jqXHR) {
295       if (jqXHR.status === 502 || jqXHR.status === 0) {
296         outdiv.text("Failed to retrieve the error log.");
297       }
298       setTimeout(updater, 4000);
299     });
300   };
301   
302   updater();
303   return this;
304 };
305
306 $(document).ajaxError(function (event, jqXHR) {
307   //console.log("AJAX query failed with: " + jqXHR.status + " (" + jqXHR.statusText + ")");
308 });

UCC git Repository :: git.ucc.asn.au