Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: remoting/webapp/base.js

Issue 245923002: Bring events to JavaScript components (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Simplify event handling Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 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
5 /**
6 * @fileoverview
7 * A module that contains basic utility components and methods for the
8 * chromoting project
9 *
10 */
11
12 'use strict';
13
14 var base = {};
15 base.debug = function () {};
16
17 /**
18 * Whether to break in debugger and alert when an assertion fails.
19 * Set it to true for debugging.
20 * @type {boolean}
21 */
22 base.debug.breakOnAssert = false;
23
24 /**
25 * Assert that |expr| is true else print the |opt_msg|.
26 * @param {boolean} expr
27 * @param {string=} opt_msg
28 */
29 base.debug.assert = function(expr, opt_msg) {
30 if (!expr) {
31 var msg = 'Assertion Failed.';
32 if (opt_msg) {
33 msg += ' ' + opt_msg;
34 }
35 console.error(msg);
36 if (base.debug.breakOnAssert) {
37 alert(msg);
38 debugger;
39 }
40 }
41 };
42
43 /**
44 * @return {string} The callstack of the current method.
45 */
46 base.debug.callstack = function() {
47 try {
48 throw new Error();
49 } catch (e) {
50 var error = /** @type {Error} */ e;
51 var callstack = error.stack
52 .replace(/^\s+(at eval )?at\s+/gm, '') // Remove 'at' and indentation.
53 .split('\n')
54 .splice(0,2); // Remove the stack of the current function.
55 }
56 return callstack.join('\n');
57 };
58
59 /**
60 * @interface
61 */
62 base.Disposable = function() {};
63 base.Disposable.prototype.dispose = function() {};
64
65 /**
66 * A utility function to invoke |obj|.dispose without a null check on |obj|.
67 * @param {base.Disposable} obj
68 */
69 base.dispose = function(obj) {
70 if (obj) {
71 base.debug.assert(typeof obj.dispose == 'function');
72 obj.dispose();
73 }
74 };
75
76 /**
77 * Copy all properties from src to dest.
78 * @param {Object} dest
79 * @param {Object} src
80 */
81 base.mix = function(dest, src) {
82 for (var prop in src) {
83 if (src.hasOwnProperty(prop)) {
84 base.debug.assert(!dest.hasOwnProperty(prop),"Don't override properties");
85 dest[prop] = src[prop];
86 }
87 }
88 };
89
90 /**
91 * Adds a mixin to a class.
92 * @param {Object} dest
93 * @param {Object} src
94 * @suppress {checkTypes}
95 */
96 base.extend = function(dest, src) {
97 base.mix(dest.prototype, src.prototype || src);
98 };
99
100 base.doNothing = function() {};
101
102 /**
103 * A mixin for classes with events.
104 *
105 * For example, to create an alarm event for SmokeDetector:
106 * functionSmokeDetector() {
107 * this.defineEvents(['alarm']);
108 * };
109 * base.extend(SmokeDetector, base.EventSource);
110 *
111 * To fire an event:
112 * SmokeDetector.prototype.onCarbonMonoxideDetected = function() {
113 * var param = {} // optional parameters
114 * this.raiseEvent('alarm', param);
115 * }
116 *
117 * To listen to an event:
118 * var smokeDetector = new SmokeDetector();
119 * smokeDetector.addEventListener('alarm', listenerObj.someCallback)
120 *
121 */
122
123 /**
124 * Helper interface for the EventSource.
125 * @interface
126 */
127 base.EventEntry = function() {
128 /** @type {Array.<Function>} */
Jamie 2014/04/24 20:38:34 Is "Function" a synonym for "function()"?
kelvinp 2014/04/24 21:38:32 Done.
129 this.listeners;
130 };
131
132 /** @constructor */
133 base.EventSource = function() {
134 this.eventMap_ = {};
Jamie 2014/04/24 20:38:34 Add type? I think it should be Object.<string, Eve
kelvinp 2014/04/24 21:38:32 Done.
135 };
136
137 /**
138 * @param {base.EventSource} obj
139 * @param {string} type
140 */
141 base.EventSource.checkType = function(obj, type) {
Jamie 2014/04/24 20:38:34 Why not make this a regular member function? Also,
kelvinp 2014/04/24 21:38:32 Renamed to isDefined. Don't want to make it a reg
142 base.debug.assert(Boolean(obj.eventMap_),
143 "The object doesn't support events");
144 base.debug.assert(Boolean(obj.eventMap_[type]), 'Event <' + type +
145 '> is undefined for the current object');
146 };
147 base.EventSource.prototype = {
148 /**
149 * Define |events| for this event source.
150 * @param {Array.<string>} events
151 */
152 defineEvents: function(events) {
153 base.debug.assert(!Boolean(this.eventMap_),
154 'defineEvents can only be called once.');
155 this.eventMap_ = {};
156 events.forEach(
157 /**
158 * @this {base.EventSource}
159 * @param {string} type
160 */
161 function(type) {
162 base.debug.assert(typeof type == 'string');
163 this.eventMap_[type] = {
Jamie 2014/04/24 20:38:34 I think you want "new EventEntry" here.
kelvinp 2014/04/24 21:38:32 Don't know how I miss that. Good catch
164 recursionCount: 0,
165 sweepRequired: false,
166 listeners: []
167 };
168 }, this);
169 },
170 /**
Wez 2014/04/24 20:45:15 nit: I prefer a blank line between the }, and the
kelvinp 2014/04/24 21:38:32 Done.
171 * Add a listener |fn| to listen to |type| event. The listener |fn| will be
172 * invoked with |thisObj| as the this pointer.
Jamie 2014/04/24 20:38:34 thisObj no longer exists.
kelvinp 2014/04/24 21:38:32 Done.
173 * @param {string} type
174 * @param {function(?=)} fn
Jamie 2014/04/24 20:38:34 No need for "?=" in the type, here and below.
kelvinp 2014/04/24 21:38:32 Spoke offline. I want to indicate that the parame
175 */
176 addEventListener: function(type, fn) {
177 base.debug.assert(typeof fn == 'function');
178 base.EventSource.checkType(this, type);
179
180 var listeners = /** @type {Array} */ this.eventMap_[type].listeners;
Jamie 2014/04/24 20:38:34 This cast should not be necessary if you add @type
kelvinp 2014/04/24 21:38:32 Done.
181 listeners.push(fn);
182 },
183 /**
184 * Remove the listener |fn| from the event source.
185 * @param {string} type
186 * @param {function(?=)} fn
187 */
188 removeEventListener: function(type, fn) {
189 base.debug.assert(typeof fn == 'function');
190 base.EventSource.checkType(this, type);
191
192 /** @type {base.EventEntry} */
193 var entry = this.eventMap_[type];
194
195 var listeners = entry.listeners;
196 // find the listener to remove.
197 for (var i = 0; i < listeners.length; i++) {
198 var listener = listeners[i];
199 if (listener && listener == fn) {
200 listeners.splice(i, 1);
201 break;
202 }
203 }
204 },
205 /**
206 * Fire an event of a particular type on this object.
207 * @param {string} type
208 * @param {*} details
209 */
210 raiseEvent: function(type, details) {
211 base.EventSource.checkType(this, type);
212
213 /** @type {base.EventEntry} */
214 var entry = this.eventMap_[type];
215 var listeners = entry.listeners.slice(0); // Make a copy of the listeners.
216
217 listeners.forEach(
218 /** @param {Function} listener */
219 function(listener){
220 if (listener) {
221 listener(details);
222 }
223 });
224 }
225 };
OLDNEW
« remoting/remoting_webapp_files.gypi ('K') | « remoting/webapp/all_js_load.gtestjs ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698