Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / login / screen_context.js
blobfe1758cb40c41472f3a2956090ba0f4800efb0f9
1 // Copyright (c) 2013 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.
5 /**
6  * @fileoverview Implementation of ScreenContext class: key-value storage for
7  * values that are shared between C++ and JS sides.
8  */
9 cr.define('login', function() {
10   'use strict';
12   function require(condition, message) {
13     if (!condition) {
14       throw Error(message);
15     }
16   }
18   function checkKeyIsValid(key) {
19     var keyType = typeof key;
20     require(keyType === 'string', 'Invalid type of key: "' + keyType + '".');
21   }
23   function checkValueIsValid(value) {
24     var valueType = typeof value;
25     require((['string', 'boolean', 'number'].indexOf(valueType) != -1 ||
26              Array.isArray(value)),
27             'Invalid type of value: "' + valueType + '".');
28   }
30   function ScreenContext() {
31     this.storage_ = {};
32     this.changes_ = {};
33     this.observers_ = {};
34   }
36   ScreenContext.prototype = {
37     /**
38      * Returns stored value for |key| or |defaultValue| if key not found in
39      * storage. Throws Error if key not found and |defaultValue| omitted.
40      */
41     get: function(key, defaultValue) {
42       checkKeyIsValid(key);
43       if (this.hasKey(key)) {
44         return this.storage_[key];
45       } else if (typeof defaultValue !== 'undefined') {
46         return defaultValue;
47       } else {
48         throw Error('Key "' + key + '" not found.');
49       }
50     },
52     /**
53      * Sets |value| for |key|. Returns true if call changes state of context,
54      * false otherwise.
55      */
56     set: function(key, value) {
57       checkKeyIsValid(key);
58       checkValueIsValid(value);
59       if (this.hasKey(key) && this.storage_[key] === value)
60         return false;
61       this.changes_[key] = value;
62       this.storage_[key] = value;
63       return true;
64     },
66     hasKey: function(key) {
67       checkKeyIsValid(key);
68       return this.storage_.hasOwnProperty(key);
69     },
71     hasChanges: function() {
72       return Object.keys(this.changes_).length > 0;
73     },
75     /**
76      * Applies |changes| to context. Returns Array of changed keys' names.
77      */
78     applyChanges: function(changes) {
79       require(!this.hasChanges(), 'Context has changes.');
80       var oldValues = {};
81       for (var key in changes) {
82         checkKeyIsValid(key);
83         checkValueIsValid(changes[key]);
84         oldValues[key] = this.storage_[key];
85         this.storage_[key] = changes[key];
86       }
87       var observers = this.cloneObservers_();
88       for (var key in changes) {
89         if (observers.hasOwnProperty(key)) {
90           var keyObservers = observers[key];
91           for (var observerIndex in keyObservers)
92             keyObservers[observerIndex](changes[key], oldValues[key], key);
93         }
94       }
95       return Object.keys(changes);
96     },
98     /**
99      * Returns changes made on context since previous call.
100      */
101     getChangesAndReset: function() {
102       var result = this.changes_;
103       this.changes_ = {};
104       return result;
105     },
107     addObserver: function(key, observer) {
108       if (!this.observers_.hasOwnProperty(key))
109         this.observers_[key] = [];
110       if (this.observers_[key].indexOf(observer) !== -1) {
111         console.warn('Observer already registered.');
112         return;
113       }
114       this.observers_[key].push(observer);
115     },
117     removeObserver: function(observer) {
118       for (var key in this.observers_) {
119         var observerIndex = this.observers_[key].indexOf(observer);
120         if (observerIndex != -1)
121           this.observers_[key].splice(observerIndex, 1);
122       }
123     },
125     /**
126      * Creates deep copy of observers lists.
127      * @private
128      */
129     cloneObservers_: function() {
130       var result = {};
131       for (var key in this.observers_)
132         result[key] = this.observers_[key].slice();
133       return result;
134     }
135   };
137   return {
138     ScreenContext: ScreenContext
139   };