view static-files/index.js @ 32:0429f7860b30

Moved some UI logic to Config logic.
author Atul Varma <avarma@mozilla.com>
date Sat, 26 Jun 2010 09:23:48 -0700
parents b92bb0974500
children 2ba086ce137d
line wrap: on
line source

// -----------------------------------------------------------------------
// Config object
// -----------------------------------------------------------------------
// 
// This manages interactions with client-side persistent storage and the
// current login state of the app.

(
  function(window) {
    var Config = window.Config = {
      get value() {
        var val = localStorage.getItem("SUMMIT_CFG");
        if (val)
          return JSON.parse(val);
        return {};
      },
      get lastChanged() {
        var ts = localStorage.getItem("SUMMIT_CFG_TIMESTAMP");
        if (ts)
          return new Date(ts);
        return new Date(0);
      },
      setValue: function Config_setValue(val) {
        localStorage.setItem("SUMMIT_CFG", JSON.stringify(val));
        localStorage.setItem("SUMMIT_CFG_TIMESTAMP",
                             (new Date()).toString());
        this.observers.forEach(function(cb) { cb(); });
      },
      wipe: function Config_wipe() {
        localStorage.removeItem("SUMMIT_CFG");
        localStorage.removeItem("SUMMIT_CFG_TIMESTAMP");
        this.observers.forEach(function(cb) { cb(); });
      },
      observers: []
    };

    function ensureStateIsValid() {
      if (!('state' in Config.value))
        Config.setValue({state: "login"});
    }

    Config.observers.push(ensureStateIsValid);

    // This is useful for finding out whether our configuration has
    // been changed by another instance of our same window.
    function setupConfigWatcher() {
      var lastChanged = Config.lastChanged;

      function onConfigChanged() {
        lastChanged = Config.lastChanged;
      };

      Config.observers.push(onConfigChanged);

      window.setInterval(
        function() {
          if (Config.lastChanged > lastChanged)
            Config.observers.forEach(function(cb) { cb(); });
        },
        1000
      );
    }

    function initConfig() {
      ensureStateIsValid();
      setupConfigWatcher();
    }

    $(window).ready(initConfig);
  }
)(window);

// -----------------------------------------------------------------------
// Attendees object
// -----------------------------------------------------------------------
// 
// This manages the list of Summit attendees and their shared metadata.

(
  function(window) {
    var req;

    var Attendees = window.Attendees = {
      refresh: function refresh() {
        if (req)
          return;
        var self = this;
        if (Config.value.token) {
          req = jQuery.getJSON(
            "api/profile",
            {token: Config.value.token},
            function(data, textStatus) {
              // TODO: Might need to add a failure callback too?
              req = null;
              if (textStatus == "success") {
                self.value = data.contents;
                self.observers.forEach(function(cb) { cb(); });
              } else {
                // TODO: Raise an error?
              }
            });
        }
      },
      value: null,
      observers: []
    };

    function refreshAttendees() {
      if (Config.value.state == "logged-in" && !Attendees.users)
        Attendees.refresh();
    }

    Config.observers.push(refreshAttendees);
    $(window).ready(refreshAttendees);
  }
)(window);

jQuery.postJSON = function postJSON(path, obj, cb) {
  var options = {
    url: path,
    type: "POST",
    contentType: "application/json",
    data: JSON.stringify(obj),
    dataType: "json",
    success: function(data) {
      cb(true, data);
    },
    error: function(req, textStatus, errorThrown) {
      var data = null;
      if (req.getResponseHeader("Content-Type") == "application/json") {
        try {
          data = JSON.parse(req.responseText);
        } catch (e) {}
      }
      cb(false, data);
    }
  };
  return jQuery.ajax(options);
};

// -----------------------------------------------------------------------
// UserInterface object
// -----------------------------------------------------------------------
// 
// This manages the user interface logic.

(
  function(window) {
    var UserInterface = window.UserInterface = {};

    function updateUI() {
      $(".screen").hide();
      $("#" + Config.value.state).show();
      switch (Config.value.state) {
      case "login":
        break;
      case "wait-for-verify":
        break;
      case "logged-in":
        $(".login-email").text(Config.value.email);
        break;
      }
    }

    function fillUserInfo() {
      var userInfo = Attendees.value[Config.value.userID];
      if (!userInfo)
        userInfo = {};
      $(".usr").each(
        function() {
          var prop = this.id.match(/usr_(.+)/)[1];
          $(this).val(userInfo[prop] || "");
        });
    }

    Attendees.observers.push(fillUserInfo);
    Config.observers.push(updateUI);

    function initUI() {
      $(".start-over").submit(
        function(event) {
          event.preventDefault();
          Config.wipe();
        });

      $("#login form").submit(
        function(event) {
          event.preventDefault();
          $("#login .error").hide();
          jQuery.postJSON(
            "api/challenge/request",
            {email: $(this).find("#email").val() },
            function(success, data) {
              if (success) {
                Config.setValue({state: "wait-for-verify"});
              } else {
                $("#login .error").slideDown();
              }
            });
        });

      $("#logged-in form").submit(
        function(event) {
          event.preventDefault();
          $("#logged-in .success").hide();
          $("#logged-in .error").hide();

          var contents = {};

          $(".usr").each(
            function() {
              var prop = this.id.match(/usr_(.+)/)[1];
              contents[prop] = this.value;
            });

          jQuery.postJSON(
            "api/profile",
            {token: Config.value.token,
             contents: contents},
            function(success, data) {
              if (success) {
                $("#logged-in .success").slideDown();
              } else {
                $("#logged-in .error").slideDown();
              }
            });
        });

      var verify = window.location.hash.match(/#verify=(.+)/);
      if (verify && Config.value.state != "logged-in") {
        verify = verify[1];
        Config.setValue({state: "wait-for-verify"});
        jQuery.postJSON(
          "api/challenge/respond",
          {token: verify},
          function(success, data) {
            window.location.hash = "";
            updateUI();
            if (success) {
              Config.setValue({state: "logged-in",
                               token: data.token,
                               userID: data.user_id,
                               email: data.email});
            } else {
              $("#wait-for-verify .error").slideDown();
            }
          });
      } else
        updateUI();
    }

    $(window).ready(initUI);
  }
)(window);

// -----------------------------------------------------------------------
// Server object
// -----------------------------------------------------------------------
// 
// This sets up an in-browser "server" that can be accessed from other
// windows via a postMessage API.

(
  function(window) {
    var Server = window.Server = {};

    var attendeeCallbacks = [];

    var myOrigin = window.location.protocol + "//" + window.location.host;
    var handlers = {
      getAllUsers: function(options, cb, origin) {
        if (origin != myOrigin) {
          cb({error: "access denied"});
          return;
        }

        // TODO: Add support for more origins.

        if (Config.value.state != "logged-in") {
          cb({error: "not logged in"});
          return;
        }

        if (Attendees.value) {
          cb({users: Attendees.value});
        } else
          attendeeCallbacks.push(cb);
      }
    };

    var server = new Summit.Server(handlers);

    Attendees.observers.push(
      function() {
        var cbs = attendeeCallbacks;
        attendeeCallbacks = [];
        cbs.forEach(function(cb) { cb({users: Attendees.value}); });
      });
  }
)(window);