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

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: Last round of CL 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
« no previous file with comments | « remoting/webapp/all_js_load.gtestjs ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 * @constructor
126 */
127 base.EventEntry = function() {
128 /** @type {Array.<function():void>} */
129 this.listeners = [];
130 };
131
132 /**
133 * @constructor
134 * Since this class is implemented as a mixin, the constructor may not be
135 * called. All initializations should be done in defineEvents.
136 */
137 base.EventSource = function() {
138 /** @type {Object.<string, base.EventEntry>} */
139 this.eventMap_;
140 };
141
142 /**
143 * @param {base.EventSource} obj
144 * @param {string} type
145 */
146 base.EventSource.isDefined = function(obj, type) {
147 base.debug.assert(Boolean(obj.eventMap_),
148 "The object doesn't support events");
149 base.debug.assert(Boolean(obj.eventMap_[type]), 'Event <' + type +
150 '> is undefined for the current object');
151 };
152
153 base.EventSource.prototype = {
154 /**
155 * Define |events| for this event source.
156 * @param {Array.<string>} events
157 */
158 defineEvents: function(events) {
159 base.debug.assert(!Boolean(this.eventMap_),
160 'defineEvents can only be called once.');
161 this.eventMap_ = {};
162 events.forEach(
163 /**
164 * @this {base.EventSource}
165 * @param {string} type
166 */
167 function(type) {
168 base.debug.assert(typeof type == 'string');
169 this.eventMap_[type] = new base.EventEntry();
170 }, this);
171 },
172
173 /**
174 * Add a listener |fn| to listen to |type| event.
175 * @param {string} type
176 * @param {function(?=):void} fn
177 */
178 addEventListener: function(type, fn) {
179 base.debug.assert(typeof fn == 'function');
180 base.EventSource.isDefined(this, type);
181
182 var listeners = this.eventMap_[type].listeners;
183 listeners.push(fn);
184 },
185
186 /**
187 * Remove the listener |fn| from the event source.
188 * @param {string} type
189 * @param {function(?=):void} fn
190 */
191 removeEventListener: function(type, fn) {
192 base.debug.assert(typeof fn == 'function');
193 base.EventSource.isDefined(this, type);
194
195 var listeners = this.eventMap_[type].listeners;
196 // find the listener to remove.
197 for (var i = 0; i < listeners.length; i++) {
198 var listener = listeners[i];
199 if (listener == fn) {
200 listeners.splice(i, 1);
201 break;
202 }
203 }
204 },
205
206 /**
207 * Fire an event of a particular type on this object.
208 * @param {string} type
209 * @param {*=} opt_details The type of |opt_details| should be ?= to
210 * match what is defined in add(remove)EventListener. However, JSCompile
211 * cannot handle invoking an unknown type as an argument to |listener|
212 * As a hack, we set the type to *=.
213 */
214 raiseEvent: function(type, opt_details) {
215 base.EventSource.isDefined(this, type);
216
217 var entry = this.eventMap_[type];
218 var listeners = entry.listeners.slice(0); // Make a copy of the listeners.
219
220 listeners.forEach(
221 /** @param {function(*=):void} listener */
222 function(listener){
223 if (listener) {
224 listener(opt_details);
225 }
226 });
227 }
228 };
OLDNEW
« no previous file with comments | « remoting/webapp/all_js_load.gtestjs ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698