Fix two bugs in mctx.gui.js ++
[matches/MCTX3420.git] / testing / MCTXWeb / public_html / static / mctx.gui.js
index 247484d..3198055 100644 (file)
@@ -1,36 +1,57 @@
 /**
- * MCTX3420 2013 GUI stuff.
- */
+* MCTX3420 2013 GUI stuff.
+* Coding style:
+*  - Always end statements with semicolons
+*  - Egyptian brackets are highly recommended (*cough*).
+*  - Don't use synchronous stuff - hook events into callbacks
+*  - $.fn functions should return either themselves or some useful object
+*    to allow for chaining of method calls
+*/
 
 mctx = {};
-mctx.api = location.protocol + "//" +  location.host + "/api/";
+//Don't use this in the final version
+mctx.location = window.location.pathname;
+mctx.location = mctx.location.substring(0, mctx.location.lastIndexOf('/')) + "/";
+//mctx.location = location.protocol + "//" + location.host + "/";
+mctx.api = location.protocol + "//" + location.host + "/" + "api/";
 mctx.expected_api_version = 0;
-mctx.key = undefined;
 mctx.has_control = false;
+mctx.debug = true;
+
+mctx.menu = [
+    {'text' : 'Home', href : mctx.location + 'index.html'},
+    {'text' : 'Experiment control', href : mctx.location + 'control.html'},
+    {'text' : 'Pin debugging', href : mctx.location + 'pintest.html'},
+    {'text' : 'Help', href : mctx.location + 'help.html'}
+];
+
+mctx.statusCodes = {
+    STATUS_OK : 1
+};
 
-mctx.return_codes = {
-  "1" : "Ok",
-  "-1" : "General error",
-  "-2" : "Unauthorized",
-  "-3" : "Not running",
-  "-4" : "Already exists"
+mctx.statusCodesDescription = {
+    "1" : "Ok",
+    "-1" : "General error",
+    "-2" : "Unauthorized",
+    "-3" : "Not running",
+    "-4" : "Already exists"
 };
 
 mctx.sensors = {
-  0 : {name : "Strain gauge 1"},
-  1 : {name : "Strain gauge 2"},
-  2 : {name : "Strain gauge 3"},
-  3 : {name : "Strain gauge 4"},
-  4 : {name : "Pressure sensor 1"},
-  5 : {name : "Pressure sensor 2"},
-  6 : {name : "Pressure sensor 3"}
+    0 : {name : "Strain gauge 1"},
+    1 : {name : "Strain gauge 2"},
+    2 : {name : "Strain gauge 3"},
+    3 : {name : "Strain gauge 4"},
+    4 : {name : "Pressure sensor 1"},
+    5 : {name : "Pressure sensor 2"},
+    6 : {name : "Pressure sensor 3"}
 };
 
 mctx.actuators = {
-  0 : {name : "Solenoid 1"},
-  1 : {name : "Solenoid 2"},
-  2 : {name : "Solenoid 3"},
-  3 : {name : "Pressure regulator"}
+    0 : {name : "Solenoid 1"},
+    1 : {name : "Solenoid 2"},
+    2 : {name : "Solenoid 3"},
+    3 : {name : "Pressure regulator"}
 };
 
 mctx.strain_gauges = {};
@@ -38,171 +59,273 @@ mctx.strain_gauges.ids = [0, 1, 2, 3];
 mctx.strain_gauges.time_limit = 20;
 
 /**
- * Writes the current date to wherever it's called.
- */
-function getDate(){
-       document.write((new Date()).toDateString());
+* Logs a message if mctx.debug is enabled. This function takes
+* a variable number of arguments and passes them 
+* to alert or console.log (based on browser support).
+* @returns {undefined}
+*/
+function debugLog () {
+    if (mctx.debug) {
+        if (typeof console === "undefined" || typeof console.log === "undefined") {
+            for (var i = 0; i < arguments.length; i++) {
+                alert(arguments[i]);
+            }
+        } else {
+            try {
+              console.log.apply(this, arguments);
+            } catch (e) {
+              //Chromie
+              for (var i = 0; i < arguments.length; i++) {
+                console.log(arguments[i]);
+              }
+            }
+        }
+    }
 }
 
 /**
- * Populates a submenu of the navigation bar
- * @param {string} header The header
- * @param {object} items An object representing the submenu items
- * @param {function} translator A function that translates an object item
- *                              into a text and href.
- * @returns {$.fn} Itself
- */
-$.fn.populateSubmenu = function(header, items, translator) {
-  var submenuHeader = $("<li/>").append($("<a/>", {text : header, href : "#"}));
-  var submenu = $("<ul/>", {"class" : "submenu"});
-  
-  for (var item in items) {
-    var info = translator(item, items);
-    submenu.append($("<li/>").append(
-          $("<a/>", {text : info.text, 
-                     href : info.href, target : "_blank"})
-    ));
-  }
-  
-  this.append(submenuHeader.append(submenu));
-  return this;
-};
+* Writes the current date to wherever it's called.
+*/
+function getDate() {
+    document.write((new Date()).toDateString());
+}
 
-/** 
- * Populates the navigation bar
- */
-$.fn.populateNavbar = function () {
-  var menu = $("<ul/>", {"class" : "menu"});
-  var sensorTranslator = function(item, items) {
-    var href = mctx.api + "sensors?start_time=0&format=tsv&id=" + item;
-    return {text : items[item].name, href : href};
-  };
-  var actuatorTranslator = function(item, items) {
-    var href = mctx.api + "actuators?start_time=0&format=tsv&id=" + item;
-    return {text : items[item].name, href : href};
-  };
-  
-  menu.populateSubmenu("Sensor data", mctx.sensors, sensorTranslator);
-  menu.populateSubmenu("Actuator data", mctx.actuators, actuatorTranslator);
-  menu.appendTo(this);
-  return this;
+/**
+* Should be run before the load of any GUI page.
+* To hook events to be called after this function runs,
+* use the 'always' method, e.g runBeforeLoad().always(function() {my stuff});
+* @param {type} isLoginPage
+* @returns The return value of calling $.ajax
+*/
+function runBeforeLoad(isLoginPage) {
+    return $.ajax({
+        url : mctx.api + "identify"
+    }).done(function (data) {
+        if (data.logged_in && isLoginPage) {
+            if (mctx.debug) {
+                debugLog("Redirect disabled!");
+            } else {
+                window.location = mctx.location;
+            }
+        } else if (!data.logged_in && !isLoginPage) {
+            if (mctx.debug) {
+                debugLog("Redirect disabled!");
+            } else {
+                //Note: this only clears the nameless cookie
+                document.cookie = ""; 
+                window.location = mctx.location + "login.html";
+            }
+        } else {
+            mctx.friendlyName = data.friendly_name;
+        }
+    }).fail(function (jqHXR) {
+        if (mctx.debug) {
+            debugLog("Failed to ident server. Is API running?")
+        } else if (!isLoginPage) {
+            window.location = mctx.location + "login.html";
+        }
+    }).always(function () {
+        
+    });
 }
 
 /**
- * Sets the camera autoupdater
- * @returns {$.fn}
+ * Populates the navigation menu.
  */
+$.fn.populateNavMenu = function() {
+    var root = $("<ul/>")
+    for (var i = 0; i < mctx.menu.length; i++) {
+        var item = mctx.menu[i];
+        var entry = $("<li/>").append(
+            $("<a/>", {text : item.text, href: item.href})
+        );
+        root.append(entry);
+    }
+    $(this).append(root);
+    return this;
+}
+
+/**
+* Sets the camera autoupdater
+* Obsolete?
+* @returns {$.fn}
+*/
 $.fn.setCamera = function () {
-  var url = mctx.api + "image";  //http://beaglebone/api/image
-  var update = true;
+    var url = mctx.api + "image";  //http://beaglebone/api/image
+    var update = true;
 
-  //Stop updating if we can't retrieve an image!
-  this.error(function() {
-    update = false;
-  });
-  
-  var parent = this;
-  
-  var updater = function() {
-    if (!update) {
-      alert("Cam fail");
-      parent.attr("src", "");
-      return;
-    }
-    
-    parent.attr("src", url + "#" + (new Date()).getTime());
-    
-    setTimeout(updater, 1000);
-  };
-  
-  updater();
-  return this;
+    //Stop updating if we can't retrieve an image!
+    this.error(function() {
+        update = false;
+    });
+
+    var parent = this;
+
+    var updater = function() {
+        if (!update) {
+            alert("Cam fail");
+            parent.attr("src", "");
+            return;
+        }
+        
+        parent.attr("src", url + "#" + (new Date()).getTime());
+        
+        setTimeout(updater, 10000);
+    };
+
+    updater();
+    return this;
 };
 
+/**
+* Sets the strain graphs to graph stuff. Obsolete?
+* @returns {$.fn}
+*/
 $.fn.setStrainGraphs = function () {
-  var sensor_url = mctx.api + "sensors";
-  var graphdiv = this;
-  
-  var updater = function () {
-    var time_limit = mctx.strain_gauges.time_limit;
-    var responses = new Array(mctx.strain_gauges.ids.length);
-    
-    for (var i = 0; i < mctx.strain_gauges.ids.length; i++) {
-      var parameters = {id : i, start_time: -time_limit};
-      responses[i] = $.ajax({url : sensor_url, data : parameters});
-    }
-    
-    $.when.apply(this, responses).then(function () {
-      var data = new Array(arguments.length);
-      for (var i = 0; i < arguments.length; i++) {
-        var raw_data = arguments[i][0].data;
-        var pruned_data = [];
-        var step = ~~(raw_data.length/100);
-        for (var j = 0; j < raw_data.length; j += step)
-          pruned_data.push(raw_data[j]); 
-        data[i] = pruned_data;
-      }
-      $.plot(graphdiv, data);
-      setTimeout(updater, 500);
-    }, function () {alert("It crashed");});
-  };
-  
-  updater();
-  return this;
+    var sensor_url = mctx.api + "sensors";
+    var graphdiv = this;
+
+    var updater = function () {
+        var time_limit = mctx.strain_gauges.time_limit;
+        var responses = new Array(mctx.strain_gauges.ids.length);
+        
+        for (var i = 0; i < mctx.strain_gauges.ids.length; i++) {
+            var parameters = {id : i, start_time: -time_limit};
+            responses[i] = $.ajax({url : sensor_url, data : parameters});
+        }
+        
+        $.when.apply(this, responses).then(function () {
+            var data = new Array(arguments.length);
+            for (var i = 0; i < arguments.length; i++) {
+                var raw_data = arguments[i][0].data;
+                var pruned_data = [];
+                var step = ~~(raw_data.length/100);
+                for (var j = 0; j < raw_data.length; j += step)
+                pruned_data.push(raw_data[j]); 
+                data[i] = pruned_data;
+            }
+            $.plot(graphdiv, data);
+            setTimeout(updater, 1000);
+        }, function () {debugLog("It crashed");});
+    };
+
+    updater();
+    return this;
 };
 
+/**
+* Performs a login attempt.
+* @returns The AJAX object of the login request */
 $.fn.login = function () {
-  var username = this.find("input[name='username']").val();
-  var password = this.find("input[name='pass']").val();
-  var force = this.find("input[name='force']").is(":checked");
-  var url = mctx.api + "control";
-  
-  var authFunc = function(xhr) {
-    xhr.setRequestHeader("Authorization",
-        "Basic " + base64.encode(username + ":" + password));
-  };
-
-  $.ajax({
-    url : url,
-    data : {action : "lock", force : (force ? true : undefined)},
-    beforeSend : authFunc
-  }).done(function (data) {
-    mctx.key = data.key;
-    if (data.status < 0) {
-      alert("no - " + data.description);
-    } else {
-      mctx.has_control = true;
-      alert("yes - " + mctx.key);
-    }
-  }).fail(function (jqXHR) {
-    mctx.key = undefined;
-    mctx.has_control = false;
-    alert("no");
-  });
+    var username = this.find("input[name='username']").val();
+    var password = this.find("input[name='pass']").val();
+    var out = this.find("#result");
+    var redirect = function () {
+        window.location.href = mctx.location;
+    };
+
+    out.removeAttr("class");
+    out.text("Logging in...");
+
+    return $.ajax({
+        url : mctx.api + "bind",
+        data : {user: username, pass : password}
+    }).done(function (data) {
+        if (data.status < 0) {
+            mctx.has_control = false;
+            out.attr("class", "fail");
+            out.text("Login failed: " + data.description);
+        } else {
+            //todo: error check
+            mctx.has_control = true;
+            out.attr("class", "pass");
+            out.text("Login ok!");
+            setTimeout(redirect, 800);      
+        }
+    }).fail(function (jqXHR) {
+        mctx.has_control = false;
+        out.attr("class", "fail");
+        out.text("Login request failed - connection issues.")
+    });
+};
+
+/**
+* Performs a logout request. The nameless cookie is
+* always cleared and the browser redirected to the login page,
+* independent of whether or not logout succeeded.
+* @returns  The AJAX object of the logout request.
+*/
+$.fn.logout = function () {
+    return $.ajax({
+        url : mctx.api + "unbind"
+    }).always(function () {
+        //Note: this only clears the nameless cookie
+        document.cookie = ""; 
+        window.location = mctx.location + "login.html";
+    });
 };
 
+/**
+* Sets the error log to continuously update.
+* @returns itself */
 $.fn.setErrorLog = function () {
-  var url = mctx.api + "errorlog";
-  var outdiv = this;
+    var url = mctx.api + "errorlog";
+    var outdiv = this;
+
+    if ($(this).length <= 0) {
+      //No error log, so do nothing.
+      return;
+    }
+
+    var updater = function () {
+        $.ajax({url : url}).done(function (data) {
+            outdiv.text(data);
+            outdiv.scrollTop(
+              outdiv[0].scrollHeight - outdiv.height()
+            );
+            setTimeout(updater, 3000);
+        }).fail(function (jqXHR) {
+            if (jqXHR.status === 502 || jqXHR.status === 0) {
+                outdiv.text("Failed to retrieve the error log.");
+            }
+            setTimeout(updater, 10000); //poll at slower rate
+        });
+    };
+
+    updater();
+    return this;
+};
+
+$(document).ready(function () {
+  //Show the content!
+  $("#content").css("display", "block");
   
-  var updater = function () {
-    $.ajax({url : url}).done(function (data) {
-      outdiv.text(data);
-      outdiv.scrollTop(
-        outdiv[0].scrollHeight - outdiv.height()
-      );
-      setTimeout(updater, 1000);
-    }).fail(function (jqXHR) {
-      if (jqXHR.status === 502 || jqXHR.status === 0) {
-        outdiv.text("Failed to retrieve the error log.");
-      }
-      setTimeout(updater, 1500);
-    });
-  };
+  //Set the welcome bar
+  var name = " " + (mctx.friendlyName ? mctx.friendlyName : "");
+  $("#welcome-container").text("Welcome"+ name + "!");
+  $("#logout-container").css("display", "block");
+  //$("#menu-container").populateNavbar();
+
+  $("#logout").click(function () {
+    $("#logout").logout();
+  });
   
-  updater();
-};
+  //Enable the error log, if present
+  $("#errorlog").setErrorLog();
+  
+  //Enable the hide/show clicks
+  $("#sidebar-hide").click(function () {
+    $("#sidebar").css("display", "none");
+    $("#sidebar-show").css("display", "inherit");
+    return this;
+  });
 
+  $("#sidebar-show").click(function () {
+    $("#sidebar-show").css("display", "none");
+    $("#sidebar").css("display", "inherit");
+    return this;
+  });
+});
 $(document).ajaxError(function (event, jqXHR) {
-  //console.log("AJAX query failed with: " + jqXHR.status + " (" + jqXHR.statusText + ")");
+    //console.log("AJAX query failed with: " + jqXHR.status + " (" + jqXHR.statusText + ")");
 });
\ No newline at end of file

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