Index: chrome/browser/resources/login/screen.js |
diff --git a/chrome/browser/resources/login/screen.js b/chrome/browser/resources/login/screen.js |
index fa03371f6a3d8384c9a25ee55d0c35e505250a34..f557417861f678e109bed7a68e5d4f8a47326261 100644 |
--- a/chrome/browser/resources/login/screen.js |
+++ b/chrome/browser/resources/login/screen.js |
@@ -8,11 +8,60 @@ |
cr.define('login', function() { |
var Screen = cr.ui.define('div'); |
+ /** @const */ var CALLBACK_USER_ACTED = 'userActed'; |
+ /** @const */ var CALLBACK_CONTEXT_CHANGED = 'contextChanged'; |
+ |
function doNothing() {}; |
+ var querySelectorAll = HTMLDivElement.prototype.querySelectorAll; |
+ |
Screen.prototype = { |
__proto__: HTMLDivElement.prototype, |
+ /** |
+ * Prefix added to sent to Chrome messages' names. |
+ */ |
+ sendPrefix_: '', |
+ |
+ /** |
+ * Context used by this screen. |
+ */ |
+ context_: null, |
+ |
+ /** |
+ * Dictionary of context observers that are methods of |this| bound to |
+ * |this|. |
+ */ |
+ contextObservers_: {}, |
+ |
+ get context() { |
+ return this.context_; |
+ }, |
+ |
+ /** |
+ * Sends recent context changes to C++ handler. |
+ */ |
+ commitContextChanges: function() { |
+ if (!this.context_.hasChanges()) |
+ return; |
+ this.send(CALLBACK_CONTEXT_CHANGED, this.context_.getChangesAndReset()); |
+ }, |
+ |
+ /** |
+ * Sends message to Chrome, adding needed prefix to message name. All |
+ * arguments after |messageName| are packed into message parameters list. |
+ * |
+ * @param {string} messageName Name of message without a prefix. |
+ * @param {...*} varArgs parameters for message. |
+ */ |
+ send: function(messageName, varArgs) { |
+ if (arguments.length == 0) |
+ throw Error('Message name is not provided.'); |
+ var fullMessageName = this.sendPrefix_ + messageName; |
+ var payload = Array.prototype.slice.call(arguments, 1); |
+ chrome.send(fullMessageName, payload); |
+ }, |
+ |
decorate: doNothing, |
/** |
@@ -28,8 +77,104 @@ cr.define('login', function() { |
* Called for currently active screen when screen size changed. |
*/ |
onWindowResize: doNothing, |
+ |
+ /** |
+ * Does the following things: |
+ * * Creates screen context. |
+ * * Looks for elements having "alias" property and adds them as the |
+ * proprties of the screen with name equal to value of "alias", i.e. HTML |
+ * element <div alias="myDiv"></div> will be stored in this.myDiv. |
+ * * Looks for buttons having "action" properties and adds click handlers |
+ * to them. These handlers send |CALLBACK_USER_ACTED| messages to |
+ * C++ with "action" property's value as payload. |
+ */ |
+ initialize: function() { |
+ this.context_ = new login.ScreenContext(); |
+ this.querySelectorAll('[alias]').forEach(function(element) { |
+ this[element.getAttribute('alias')] = element; |
+ }, this); |
+ var self = this; |
+ this.querySelectorAll('button[action]').forEach(function(button) { |
+ button.addEventListener('click', function(e) { |
+ var action = this.getAttribute('action'); |
+ self.send(CALLBACK_USER_ACTED, action); |
+ e.stopPropagation(); |
+ }); |
+ }); |
+ }, |
+ |
+ /** |
+ * Starts observation of property with |key| of the context attached to |
+ * current screen. This method differs from "login.ScreenContext" in that |
+ * it automatically detects if observer is method of |this| and make |
+ * all needed actions to make it work correctly. So it's no need for client |
+ * to bind methods to |this| and keep resulting callback for |
+ * |removeObserver| call: |
+ * |
+ * this.addContextObserver('key', this.onKeyChanged_); |
+ * ... |
+ * this.removeContextObserver('key', this.onKeyChanged_); |
+ */ |
+ addContextObserver: function(key, observer) { |
+ var realObserver = observer; |
+ var propertyName = this.getPropertyNameOf_(observer); |
+ if (propertyName) { |
+ if (!this.contextObservers_.hasOwnProperty(propertyName)) |
+ this.contextObservers_[propertyName] = observer.bind(this); |
+ realObserver = this.contextObservers_[propertyName]; |
+ } |
+ this.context.addObserver(key, realObserver); |
+ }, |
+ |
+ /** |
+ * Removes |observer| from the list of context observers. Supports not only |
+ * regular functions but also screen methods (see comment to |
+ * |addContextObserver|). |
+ */ |
+ removeContextObserver: function(observer) { |
+ var realObserver = observer; |
+ var propertyName = this.getPropertyNameOf_(observer); |
+ if (propertyName) { |
+ if (!this.contextObservers_.hasOwnProperty(propertyName)) |
+ return; |
+ realObserver = this.contextObservers_[propertyName]; |
+ delete this.contextObservers_[propertyName]; |
+ } |
+ this.context.removeObserver(realObserver); |
+ }, |
+ |
+ /** |
+ * Calls standart |querySelectorAll| method and returns its result converted |
+ * to Array. |
+ */ |
+ querySelectorAll: function(selector) { |
+ var list = querySelectorAll.call(this, selector); |
+ return Array.prototype.slice.call(list); |
+ }, |
+ |
+ /** |
+ * Called when context changes are recieved from C++. |
+ * @private |
+ */ |
+ contextChanged_: function(diff) { |
+ this.context.applyChanges(diff); |
+ }, |
+ |
+ /** |
+ * If |value| is the value of some property of |this| returns property's |
+ * name. Otherwise returns empty string. |
+ * @private |
+ */ |
+ getPropertyNameOf_: function(value) { |
+ for (var key in this) |
+ if (this[key] === value) |
+ return key; |
+ return ''; |
+ } |
}; |
+ Screen.CALLBACK_USER_ACTED = CALLBACK_USER_ACTED; |
+ |
return { |
Screen: Screen |
}; |
@@ -87,7 +232,12 @@ cr.define('login', function() { |
})(propertyName); |
} |
}); |
+ constructor.contextChanged = function() { |
+ var screen = $(id); |
+ screen.contextChanged_.apply(screen, arguments); |
+ } |
constructor.prototype.name = function() { return id; }; |
+ constructor.prototype.sendPrefix_ = 'login.' + name + '.'; |
constructor.register = function() { |
var screen = $(id); |