1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5var chrome = chrome || {};
6
7/**
8 * Organizes all signin event listeners and asynchronous requests.
9 * This object has no public constructor.
10 * @type {Object}
11 */
12chrome.signin = chrome.signin || {};
13
14(function() {
15
16// TODO(vishwath): This function is identical to the one in sync_internals.js
17// Merge both if possible.
18// Accepts a DOM node and sets its highlighted attribute oldVal != newVal
19function highlightIfChanged(node, oldVal, newVal) {
20  var oldStr = oldVal.toString();
21  var newStr = newVal.toString();
22  if (oldStr != '' && oldStr != newStr) {
23    // Note the addListener function does not end up creating duplicate
24    // listeners.  There can be only one listener per event at a time.
25    // Reference: https://developer.mozilla.org/en/DOM/element.addEventListener
26    node.addEventListener('webkitAnimationEnd',
27                          function() { this.removeAttribute('highlighted'); },
28                          false);
29    node.setAttribute('highlighted', '');
30  }
31}
32
33// Wraps highlightIfChanged for multiple conditions.
34function highlightIfAnyChanged(node, oldToNewValList) {
35  for (var i = 0; i < oldToNewValList.length; i++)
36    highlightIfChanged(node, oldToNewValList[i][0], oldToNewValList[i][1]);
37}
38
39function setClassFromValue(value) {
40  if (value == 0)
41    return 'zero';
42  if (value == 'Successful')
43    return 'ok';
44
45  return '';
46}
47
48// Allow signin_index.html to access the functions above using the
49// corresponding chrome.signin.<method> calls.
50chrome.signin['highlightIfChanged'] = highlightIfChanged;
51chrome.signin['highlightIfAnyChanged'] = highlightIfAnyChanged;
52chrome.signin['setClassFromValue'] = setClassFromValue;
53
54// Simplified Event class, borrowed (ok, stolen) from chrome_sync.js
55function Event() {
56  this.listeners_ = [];
57}
58
59// Add a new listener to the list.
60Event.prototype.addListener = function(listener) {
61  this.listeners_.push(listener);
62};
63
64// Remove a listener from the list.
65Event.prototype.removeListener = function(listener) {
66  var i = this.findListener_(listener);
67  if (i == -1) {
68    return;
69  }
70  this.listeners_.splice(i, 1);
71};
72
73// Check if the listener has already been registered so we can prevent
74// duplicate registrations.
75Event.prototype.hasListener = function(listener) {
76  return this.findListener_(listener) > -1;
77};
78
79// Are there any listeners registered yet?
80Event.prototype.hasListeners = function() {
81  return this.listeners_.length > 0;
82};
83
84// Returns the index of the given listener, or -1 if not found.
85Event.prototype.findListener_ = function(listener) {
86  for (var i = 0; i < this.listeners_.length; i++) {
87    if (this.listeners_[i] == listener) {
88      return i;
89    }
90  }
91  return -1;
92};
93
94// Fires the event.  Called by the actual event callback.  Any
95// exceptions thrown by a listener are caught and logged.
96Event.prototype.fire = function() {
97  var args = Array.prototype.slice.call(arguments);
98  for (var i = 0; i < this.listeners_.length; i++) {
99    try {
100      this.listeners_[i].apply(null, args);
101    } catch (e) {
102      if (e instanceof Error) {
103        // Non-standard, but useful.
104        console.error(e.stack);
105      } else {
106        console.error(e);
107      }
108    }
109  }
110};
111
112// These are the events that will be registered.
113chrome.signin.events = {
114  'signin_manager': [
115    'onSigninInfoChanged'
116 ]
117};
118
119for (var eventType in chrome.signin.events) {
120  var events = chrome.signin.events[eventType];
121  for (var i = 0; i < events.length; ++i) {
122    var event = events[i];
123    chrome.signin[event] = new Event();
124  }
125}
126
127// Creates functions that call into SigninInternalsUI.
128function makeSigninFunction(name) {
129  var callbacks = [];
130
131  // Calls the function, assuming the last argument is a callback to be
132  // called with the return value.
133  var fn = function() {
134    var args = Array.prototype.slice.call(arguments);
135    callbacks.push(args.pop());
136    chrome.send(name, args);
137  };
138
139  // Handle a reply, assuming that messages are processed in FIFO order.
140  // Called by SigninInternalsUI::HandleJsReply().
141  fn.handleReply = function() {
142    var args = Array.prototype.slice.call(arguments);
143    // Remove the callback before we call it since the callback may
144    // throw.
145    var callback = callbacks.shift();
146    callback.apply(null, args);
147  };
148
149  return fn;
150}
151
152// The list of js functions that call into SigninInternalsUI
153var signinFunctions = [
154  // Signin Summary Info
155  'getSigninInfo'
156];
157
158for (var i = 0; i < signinFunctions.length; ++i) {
159  var signinFunction = signinFunctions[i];
160  chrome.signin[signinFunction] = makeSigninFunction(signinFunction);
161}
162
163chrome.signin.internalsInfo = {};
164
165// Replace the displayed values with the latest fetched ones.
166function refreshSigninInfo(signinInfo) {
167  chrome.signin.internalsInfo = signinInfo;
168  var internalsInfoDiv = $('signin-info');
169  jstProcess(new JsEvalContext(signinInfo), internalsInfoDiv);
170  var tokenInfoDiv = $('token-info');
171  jstProcess(new JsEvalContext(signinInfo), tokenInfoDiv);
172}
173
174// On load, do an initial refresh and register refreshSigninInfo to be invoked
175// whenever we get new signin information from SigninInternalsUI.
176function onLoad() {
177  chrome.signin.getSigninInfo(refreshSigninInfo);
178
179  chrome.signin.onSigninInfoChanged.addListener(function(info) {
180    refreshSigninInfo(info);
181  });
182}
183
184document.addEventListener('DOMContentLoaded', onLoad, false);
185})();
186