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

Unified 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 side-by-side diff with in-line comments
Download patch
« remoting/remoting_webapp_files.gypi ('K') | « remoting/webapp/all_js_load.gtestjs ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/webapp/base.js
diff --git a/remoting/webapp/base.js b/remoting/webapp/base.js
new file mode 100644
index 0000000000000000000000000000000000000000..83b7be623a6fb9833446b28a2a602e8eddc8f3c1
--- /dev/null
+++ b/remoting/webapp/base.js
@@ -0,0 +1,225 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * A module that contains basic utility components and methods for the
+ * chromoting project
+ *
+ */
+
+'use strict';
+
+var base = {};
+base.debug = function () {};
+
+/**
+ * Whether to break in debugger and alert when an assertion fails.
+ * Set it to true for debugging.
+ * @type {boolean}
+ */
+base.debug.breakOnAssert = false;
+
+/**
+ * Assert that |expr| is true else print the |opt_msg|.
+ * @param {boolean} expr
+ * @param {string=} opt_msg
+ */
+base.debug.assert = function(expr, opt_msg) {
+ if (!expr) {
+ var msg = 'Assertion Failed.';
+ if (opt_msg) {
+ msg += ' ' + opt_msg;
+ }
+ console.error(msg);
+ if (base.debug.breakOnAssert) {
+ alert(msg);
+ debugger;
+ }
+ }
+};
+
+/**
+ * @return {string} The callstack of the current method.
+ */
+base.debug.callstack = function() {
+ try {
+ throw new Error();
+ } catch (e) {
+ var error = /** @type {Error} */ e;
+ var callstack = error.stack
+ .replace(/^\s+(at eval )?at\s+/gm, '') // Remove 'at' and indentation.
+ .split('\n')
+ .splice(0,2); // Remove the stack of the current function.
+ }
+ return callstack.join('\n');
+};
+
+/**
+ * @interface
+ */
+base.Disposable = function() {};
+base.Disposable.prototype.dispose = function() {};
+
+/**
+ * A utility function to invoke |obj|.dispose without a null check on |obj|.
+ * @param {base.Disposable} obj
+ */
+base.dispose = function(obj) {
+ if (obj) {
+ base.debug.assert(typeof obj.dispose == 'function');
+ obj.dispose();
+ }
+};
+
+/**
+ * Copy all properties from src to dest.
+ * @param {Object} dest
+ * @param {Object} src
+ */
+base.mix = function(dest, src) {
+ for (var prop in src) {
+ if (src.hasOwnProperty(prop)) {
+ base.debug.assert(!dest.hasOwnProperty(prop),"Don't override properties");
+ dest[prop] = src[prop];
+ }
+ }
+};
+
+/**
+ * Adds a mixin to a class.
+ * @param {Object} dest
+ * @param {Object} src
+ * @suppress {checkTypes}
+ */
+base.extend = function(dest, src) {
+ base.mix(dest.prototype, src.prototype || src);
+};
+
+base.doNothing = function() {};
+
+/**
+ * A mixin for classes with events.
+ *
+ * For example, to create an alarm event for SmokeDetector:
+ * functionSmokeDetector() {
+ * this.defineEvents(['alarm']);
+ * };
+ * base.extend(SmokeDetector, base.EventSource);
+ *
+ * To fire an event:
+ * SmokeDetector.prototype.onCarbonMonoxideDetected = function() {
+ * var param = {} // optional parameters
+ * this.raiseEvent('alarm', param);
+ * }
+ *
+ * To listen to an event:
+ * var smokeDetector = new SmokeDetector();
+ * smokeDetector.addEventListener('alarm', listenerObj.someCallback)
+ *
+ */
+
+/**
+ * Helper interface for the EventSource.
+ * @interface
+ */
+base.EventEntry = function() {
+ /** @type {Array.<Function>} */
Jamie 2014/04/24 20:38:34 Is "Function" a synonym for "function()"?
kelvinp 2014/04/24 21:38:32 Done.
+ this.listeners;
+};
+
+/** @constructor */
+base.EventSource = function() {
+ 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.
+};
+
+/**
+ * @param {base.EventSource} obj
+ * @param {string} type
+ */
+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
+ base.debug.assert(Boolean(obj.eventMap_),
+ "The object doesn't support events");
+ base.debug.assert(Boolean(obj.eventMap_[type]), 'Event <' + type +
+ '> is undefined for the current object');
+};
+base.EventSource.prototype = {
+ /**
+ * Define |events| for this event source.
+ * @param {Array.<string>} events
+ */
+ defineEvents: function(events) {
+ base.debug.assert(!Boolean(this.eventMap_),
+ 'defineEvents can only be called once.');
+ this.eventMap_ = {};
+ events.forEach(
+ /**
+ * @this {base.EventSource}
+ * @param {string} type
+ */
+ function(type) {
+ base.debug.assert(typeof type == 'string');
+ 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
+ recursionCount: 0,
+ sweepRequired: false,
+ listeners: []
+ };
+ }, this);
+ },
+ /**
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.
+ * Add a listener |fn| to listen to |type| event. The listener |fn| will be
+ * 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.
+ * @param {string} type
+ * @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
+ */
+ addEventListener: function(type, fn) {
+ base.debug.assert(typeof fn == 'function');
+ base.EventSource.checkType(this, type);
+
+ 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.
+ listeners.push(fn);
+ },
+ /**
+ * Remove the listener |fn| from the event source.
+ * @param {string} type
+ * @param {function(?=)} fn
+ */
+ removeEventListener: function(type, fn) {
+ base.debug.assert(typeof fn == 'function');
+ base.EventSource.checkType(this, type);
+
+ /** @type {base.EventEntry} */
+ var entry = this.eventMap_[type];
+
+ var listeners = entry.listeners;
+ // find the listener to remove.
+ for (var i = 0; i < listeners.length; i++) {
+ var listener = listeners[i];
+ if (listener && listener == fn) {
+ listeners.splice(i, 1);
+ break;
+ }
+ }
+ },
+ /**
+ * Fire an event of a particular type on this object.
+ * @param {string} type
+ * @param {*} details
+ */
+ raiseEvent: function(type, details) {
+ base.EventSource.checkType(this, type);
+
+ /** @type {base.EventEntry} */
+ var entry = this.eventMap_[type];
+ var listeners = entry.listeners.slice(0); // Make a copy of the listeners.
+
+ listeners.forEach(
+ /** @param {Function} listener */
+ function(listener){
+ if (listener) {
+ listener(details);
+ }
+ });
+ }
+};
« 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