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

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: Add base.js and Event Listeners 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 (c) 2012 The Chromium Authors. All rights reserved.
Sergey Ulanov 2014/04/22 00:43:21 lose (c). 2014
kelvinp 2014/04/23 00:24:20 Done.
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 var Debug = {};
Sergey Ulanov 2014/04/22 00:43:21 should this be lower-case 'debug'?
Jamie 2014/04/22 01:23:21 Is there a reason for the case difference between
kelvinp 2014/04/23 00:24:20 debug(fn) is an existing function implemented by c
kelvinp 2014/04/23 00:24:20 Done.
16
17 /**
18 * Asserts that expr is true else print the msg
Jamie 2014/04/22 01:23:21 s/Asserts/Assert/
kelvinp 2014/04/23 00:24:20 Done.
19 * @param {boolean} expr
20 * @param {string=} opt_msg
21 */
22 Debug.assert = function (expr, opt_msg) {
Jamie 2014/04/22 01:23:21 Nit: No space after "function" (here and elsewhere
kelvinp 2014/04/23 00:24:20 Done.
23 if (!expr) {
24 window.alert('Assertion Failed: ' + opt_msg);
25 debugger;
26 }
27 };
28
29 /**
30 * @return {string} The callstack of the current method
31 * @suppress {checkTypes}
Jamie 2014/04/22 01:23:21 Is it possible to make this function type-safe?
kelvinp 2014/04/23 00:24:20 Done.
32 */
33 Debug.callstack = function () {
34 var error = null;
35 try {
36 throw new Error();
37 } catch (e) {
38 error = e;
39 }
40 var callstack = error.stack
Jamie 2014/04/22 01:23:21 Why can't this be in the catch block?
kelvinp 2014/04/23 00:24:20 Done.
41 .replace(/^\s+(at eval )?at\s+/gm, '') // remove 'at' and indentation
42 .split('\n')
43 .splice(0,2); // Remove the stack of the current function
44 return callstack.join('\n');
45 };
46
47 /**
48 * Called on the dispose method of the obj, without needing to check for
49 * whether the object is null
50 * @param {Disposable} obj
rmsousa 2014/04/22 02:25:35 Disposable isn't base JS. Are you assuming the pre
kelvinp 2014/04/23 00:24:20 No, I am not assuming the presence of any framewor
51 */
52 base.dispose = function (obj) {
53 if (Boolean(obj)) {
Jamie 2014/04/22 01:23:21 What does the cast to Boolean buy us in this case?
kelvinp 2014/04/23 00:24:20 Trying to pre-emptively make Jscompile happy. I g
54 Debug.assert(typeof obj.dispose == 'function');
55 obj.dispose();
56 }
57 };
58
59 /**
60 * Copies properties from the src to dest
61 * @param {Object} dest
62 * @param {Object} src
63 */
64 base.mix = function(dest, src) {
Sergey Ulanov 2014/04/22 00:43:21 call this copyObjectProperties()?
kelvinp 2014/04/23 00:24:20 I will keep it called mix. I think mix is shorter
65 for (var prop in src) {
66 if (src.hasOwnProperty(prop)) {
67 Debug.assert(!dest.hasOwnProperty(prop), 'Do not override properties');
68 dest[prop] = src[prop];
69 }
70 }
71 };
72
73 /**
74 * Copies properties from the src to dest.prototype
Sergey Ulanov 2014/04/22 00:43:21 I think "mixin" is the standard terms for things l
kelvinp 2014/04/23 00:24:20 Done.
75 * @param {*} dest
76 * @param {*} src
Jamie 2014/04/22 01:23:21 Why not Object for these two parameters?
kelvinp 2014/04/23 00:24:20 Done.
77 * @suppress {checkTypes}
Jamie 2014/04/22 01:23:21 Is it possible to make this function type-safe?
kelvinp 2014/04/23 00:24:20 Unfortunately, the access of src.prototype and des
Jamie 2014/04/23 21:52:57 Agreed, it's probably fine, but I'm surprised jsco
78 */
79 base.augment = function(dest, src) {
Sergey Ulanov 2014/04/22 00:43:21 call it base.addClassMixin()? and also rename the
kelvinp 2014/04/23 00:24:20 Augment and extend are the standard terms. I thin
80 base.mix(dest.prototype, src.prototype || src);
81 };
82
83 base.emptyFn = function () {};
Sergey Ulanov 2014/04/22 00:43:21 either emptyFunction() or doNothing() (I would pr
kelvinp 2014/04/23 00:24:20 Done.
84
85 /**
86 * A simple implementation to augment JavaScript objects with events
Sergey Ulanov 2014/04/22 00:43:21 "Mixin for classes with events." nit: comments sh
kelvinp 2014/04/23 00:24:20 Done.
87 *
88 * For example, to create an alarm event for SmokeDetector
89 * function SmokeDetector() {
90 * this.defineEvents(['alarm']);
91 * };
92 * base.augment(SmokeDetector, base.Events);
93 *
94 * To fire an event
95 * SmokeDetector.prototype.onCarbonMonoxideDetected = function () {
96 * var param = {} // optional parameters
97 * this.raiseEvent('alarm', param);
98 * }
99 *
100 * To listen to an event
101 * var smokeDetector = new SmokeDetector();
102 * smokeDetector.addEventListener('alarm',listenerObj.someCallback,listenerObj);
rmsousa 2014/04/22 02:25:35 This mechanism seems a bit dangerous from a lifeti
kelvinp 2014/04/23 00:24:20 Absolutely. You are right in the sense that objec
103 *
104 */
105
106 base.Events = function () {};
Jamie 2014/04/22 01:23:21 s/Events/EventSource/? When I read Events, I assum
kelvinp 2014/04/23 00:24:20 Done.
107
108 base.Events.prototype = {
109 /**
110 * Define the events this event source
Sergey Ulanov 2014/04/22 00:43:21 Comments should end with '.'
Jamie 2014/04/22 01:23:21 Incomplete comment.
kelvinp 2014/04/23 00:24:20 Done.
kelvinp 2014/04/23 00:24:20 Done.
111 * @param {Array.<string>} evts
112 * @this {EventSource}
113 */
114 defineEvents: function (evts) {
115 Debug.assert(!Boolean(this._ev), 'defineEvents can only be called once.');
116 var ev = this._ev = {};
Sergey Ulanov 2014/04/22 00:43:21 s/ev/event/
kelvinp 2014/04/23 00:24:20 Done.
117 evts.forEach(
118 /** @param {String} type*/
119 function(type) {
120 Debug.assert(typeof type == 'string');
121 ev[type] = {
Jamie 2014/04/22 01:23:21 The state you're tracking for each event is somewh
kelvinp 2014/04/23 00:24:20 The way that events are handled here is actually a
Jamie 2014/04/23 21:52:57 As discussed, I think either approach to event han
kelvinp 2014/04/24 01:15:39 It is actually not uncommon for one event handler
122 recursionCount: 0,
123 sweepRequired: false,
124 listeners: []
125 };
126 });
127 },
128 /**
129 * Define the events this event source
Sergey Ulanov 2014/04/22 00:43:21 Update this comment
Jamie 2014/04/22 01:23:21 Copy/paste error?
kelvinp 2014/04/23 00:24:20 Done.
kelvinp 2014/04/23 00:24:20 Done.
130 * @param {string} type
131 * @param {function(Object=)} fn
132 * @param {*} thisObj
Sergey Ulanov 2014/04/22 00:43:21 Why do we need this argument?
Jamie 2014/04/22 01:23:21 I think it would be better to require callers to p
kelvinp 2014/04/23 00:24:20 Why do you think it is better to require callers t
Jamie 2014/04/23 21:52:57 I think the key word is "necessary". If it's a mem
kelvinp 2014/04/24 01:15:39 Done
133 * @suppress {checkTypes}
134 */
135 addEventListener: function (type, fn, thisObj) {
136 Debug.assert(typeof fn == 'function');
137 Debug.Events.chk(this, type);
138 this._ev[type].listeners.push({ fn: fn, thisObj: thisObj});
139 },
140 /**
141 * Define the events this event source
Sergey Ulanov 2014/04/22 00:43:21 update the comment
Jamie 2014/04/22 01:23:21 Copy/paste error.
kelvinp 2014/04/23 00:24:20 Done.
kelvinp 2014/04/23 00:24:20 Done.
142 * @param {string} type
143 * @param {function(Object=)} fn
144 * @param {*} thisObj
145 * @suppress {checkTypes}
146 */
147 removeEventListener: function (type, fn, thisObj) {
148 Debug.assert(typeof fn == 'function');
149 Debug.Events.chk(this, type);
150 var listener;
Sergey Ulanov 2014/04/22 00:43:21 does this need to be defined outside of the for lo
kelvinp 2014/04/23 00:24:20 Done.
151 var evt = this._ev[type];
152 var listeners = evt.listeners;
153 // find the listener to remove
154 for (var i = 0; i < listeners.length; i++) {
155 listener = listeners[i];
156 if (Boolean(listener) && listener.fn == fn &&
157 listener.thisObj == thisObj) {
158 // if the event is unhooked during raiseEvent, do not remove it
159 // immediately, instead set it to null and remove it later.
160 if (evt.recursionCount != 0) {
161 listeners[i] = null;
162 evt.sweepRequired = true;
163 } else {
164 listeners.splice(i, 1);
165 }
166 return;
Jamie 2014/04/22 01:23:21 In general, I prefer to use break to exit a loop,
kelvinp 2014/04/23 00:24:20 Done.
167 }
168 }
169 },
170 /**
171 * Fire an event of a particular type
172 * @param {string} type
173 * @param {*} details
174 * @suppress {checkTypes}
175 */
176 raiseEvent: function (type, details) {
177 Debug.Events.chk(this, type);
178 var evt = this._ev[type];
179 var listeners = evt.listeners;
180 evt.recursionCount++;
181
182 for (var i = 0; i < listeners.length; i++) {
Jamie 2014/04/22 01:23:21 Can you use forEach here?
kelvinp 2014/04/23 00:24:20 Done.
183 var listener = listeners[i];
184 if (listener) {
185 listener.fn.call(listener.thisObj, details);
186 }
187 }
188
189 evt.recursionCount--;
190 if (evt.recursionCount == 0 && evt.sweepRequired) {
191 for (i = listeners.length; i--;) {
Sergey Ulanov 2014/04/22 00:43:21 The following would me more readable: for (var i
kelvinp 2014/04/23 00:24:20 javascript is function scope. var is already decl
192 if (!listeners[i]) {
Sergey Ulanov 2014/04/22 00:43:21 Why do you need this check?
kelvinp 2014/04/23 00:24:20 Comments added
193 listeners.splice(i, 1);
194 }
195 }
196 evt.sweepRequired = false;
197 }
198 }
199 };
200
201 Debug.Events = {
202 /**
203 * @param {EventSource} obj
204 * @param {string} type
205 */
206 chk: function (obj, type) {
Sergey Ulanov 2014/04/22 00:43:21 Nt rdbl nm. (not readable name)
kelvinp 2014/04/23 00:24:20 Done.
207 Debug.assert(Boolean(obj._ev), 'The object doesn\'t support events');
Sergey Ulanov 2014/04/22 00:43:21 nit: double space
Jamie 2014/04/22 01:23:21 For strings with embedded apostrophes, you can use
kelvinp 2014/04/23 00:24:20 Done.
kelvinp 2014/04/23 00:24:20 Done.
208 Debug.assert(Boolean(obj._ev[type]), 'Event <' + type +
209 '> is undefined for the current object');
210 }
211 };
212
213 // Turns off assert in production. Comment out the line below for debugging.
214 Debug.assert = base.emptyFn;
Sergey Ulanov 2014/04/22 00:43:21 Why not have asserts always on? IMO it's better to
kelvinp 2014/04/23 00:24:20 Done.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698