Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 5e56fbd2469c86100d6309f04d4e028c46b81e8f Nathan committed Dec 10, 2009
Showing with 226 additions and 0 deletions.
  1. +54 −0 README.md
  2. +23 −0 examples/person.js
  3. +139 −0 lib/observable.js
  4. +10 −0 package.json
@@ -0,0 +1,54 @@
+## Observable
+
+A CommonJS JavaScript package containing the Observable mixin.
+
+## Example
+
+ var observable = require("observable");
+
+ function Person(firstName, lastName, jobTitle) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.jobTitle = jobTitle;
+ }
+
+ Person.prototype.promote = function(newJobTitle) {
+ this.jobTitle = newJobTitle;
+ this.publish("after_promote", this, newJobTitle);
+ }
+
+ observable.mixin(Person.prototype);
+ Person.subscribeTo = Person.prototype.subscribeTo; // conveniance accessor
+
+ Person.subscribeTo("after_promote", function(person, newJobTitle) {
+ print("Congrats " + person.firstName + " on your promotion to " + newJobTitle);
+ });
+
+ var bob = new Person("Bob", "Smith", "Rookie");
+ bob.promote("Veteran"); // prints "Congrats Bob on your promotion to Veteran"
+
+## Contributors
+
+<[Nathan Stott](mailto:nathan.stott@whiteboard-it.com)>
+
+## License
+
+Copyright (c) 2009 Nathan Stott <[nathan.whiteboard-it.com](http://nathan.whiteboard-it.com/)\>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
@@ -0,0 +1,23 @@
+var observable = require("observable");
+
+function Person(firstName, lastName, jobTitle) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.jobTitle = jobTitle;
+}
+
+Person.prototype.promote = function(newJobTitle) {
+ this.jobTitle = newJobTitle;
+ this.publish("after_promote", this, newJobTitle);
+}
+
+observable.mixin(Person.prototype);
+Person.subscribeTo = Person.prototype.subscribeTo; // conveniance accessor
+
+Person.subscribeTo("after_promote", function(person, newJobTitle) {
+ print("Congrats " + person.firstName + " on your promotion to " + newJobTitle);
+});
+
+var bob = new Person("Bob", "Smith", "Rookie");
+bob.promote("Veteran");
+
@@ -0,0 +1,139 @@
+var util = require("util");
+
+/**
+ * Creates an Observable object. The Observable publishes events to which callbacks
+ * can be subscribed.
+ *
+ * example:
+ * var observable = Object.create(Observable());
+ * observable.subscribeTo("greeting", function() { print("Hello World"); });
+ * observable.publish("greeting"); # -> "Hello World"
+ *
+ * @param subscribers Subscribers hash in the form of { "event_name": callback }
+ * @constructor
+ */
+var Observable = exports.Observable = function (subscribers, followers) {
+ subscribers = subscribers || {};
+ followers = followers || [];
+
+ /**
+ * Publish an event.
+ *
+ * The first argument must be the event to publish. Additional arguments
+ * will be passed to the callbacks subscribed to the event.
+ *
+ * Example: publish("before_lookup_route", verb, path) would expect a callback in the form of
+ * fun(app, verb, path) -> undefined
+ * e.g.
+ * function(app, verb, path) { ... }
+ *
+ * @returns The App from which publish was called
+ * @type {App}
+ * @public
+ */
+ this.publish = function() {
+ var args = Array.prototype.slice.call(arguments);
+ var event = args.shift();
+ var i, subscriber;
+
+ subscribers[event] = subscribers[event] || [];
+ for (i=0;i<subscribers[event].length;++i) {
+ subscriber = subscribers[event][i];
+ if (typeof subscriber === "function" ) {
+ subscriber.apply({}, args);
+ }
+ }
+
+ followers.forEach(function(x) {
+ x.apply({}, args);
+ });
+ };
+
+ /**
+ * Subscribe to all events
+ *
+ * @param callback Callback to handle any event
+ */
+ this.follow = function(callback) {
+ followers.push(callback);
+ };
+
+ this.subscribeTo = function(event, callback) {
+ subscribers[event] = subscribers[event] || [];
+ subscribers[event].push(callback);
+ };
+
+ this.unsubscribe = function(callback) {
+ for (var key in subscribers) {
+ subscribers[key] = subscribers[key].filter(function(x) {
+ return x !== callback;
+ });
+ }
+ };
+
+ this.unsubscribeAll = function() {
+ subscribers = {};
+ followers = [];
+ };
+};
+
+var ObservableWithPlugins = exports.ObservableWithPlugins = function (options) {
+ var observable;
+ var oldPublish;
+ var plugins;
+
+ options = options || {};
+ plugins = options.plugins || [];
+
+ observable = new Observable(options.callbacks || {});
+ oldPublish = observable.publish;
+
+ Object.defineProperty(observable, "plugins", {
+ get: function() { return plugins; }
+ });
+
+ observable.addPlugin = function(obj) {
+ plugins.push(obj);
+ return observable;
+ };
+
+ observable.removePlugin = function(obj) {
+ plugins = plugins.filter(function(x) { return x !== obj; });
+ return observable;
+ };
+
+ observable.removeAllPlugins = function() {
+ plugins = [];
+ return observable;
+ };
+
+ observable.publish = function() {
+ var event;
+ var args = [];
+
+ for (var i=0;i<arguments.length;++i) {
+ args.push(arguments[i]);
+ }
+
+ oldPublish.apply(this, args);
+
+ event = args.shift();
+
+ // Check plugins to see if there is a key matching the event name. If the key points to a function,
+ // execute the function.
+ plugins.forEach(function(x) {
+ if (util.no(x.callbacks)) { return; }
+
+ if (typeof x.callbacks[event] === "function") {
+ x.callbacks[event].apply({}, args);
+ }
+ });
+ };
+
+ return observable;
+};
+
+exports.mixin = function(other, options) {
+ var observable = new ObservableWithPlugins(options || {});
+ util.update(other, observable);
+};
@@ -0,0 +1,10 @@
+{
+ "name": "observable",
+ "description": "JavaScript framework for Observable mixins with plugin support",
+ "keywords": ["observable", "mixin", "event", "plugin"],
+ "author": "Nathan Stott",
+ "email": "nathan.stott@whiteboard-it.com",
+ "dependencies": [],
+ "lib": "lib"
+}
+

0 comments on commit 5e56fbd

Please sign in to comment.