Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add 0.7.3 release.

  • Loading branch information...
commit 134e4f40cb0564afdbbe7daa3c05ed6e11b952f2 1 parent 239e925
@fblee fblee authored
View
1  Rakefile
@@ -31,6 +31,7 @@ task :release do
minified.write("/*** model-r-#{version}.min.js ***/")
minified.write(uglified)
end
+ puts "Writing: release/model-r-#{version}.map (source map for minified version)"
File.open("release/model-r-#{version}.map", 'w') {|f| f.write(source_map) }
end
View
1,273 release/model-r-0.7.3.js
@@ -0,0 +1,1273 @@
+/*** model-r-0.7.3.js ***/
+/*jslint nomen: false*/
+/*global lib, _, jQuery*/
+/* A wrapper for lib.hasEvent(_public, _protected, 'destroy') that
+ * also provides a listenUntilDestroyed method for leak-avoiding handlers.
+ */
+lib.destroyable = function (_public, _protected) {
+ lib.hasEvent(_public, _protected, 'destroy');
+
+ // Listen on an event until this component is destroyed.
+ // Works for both jQuery and model-R events
+ //
+ // This is necessary as if you don't do this, the sidebar cannot be garbage collected
+ // correctly and your handlers will keep firing long after your DOM should have been
+ // dismantled.
+ _public.listenUntilDestroyed = function (object, event_name, handler) {
+ // Use the pretty helpers so that typo-prone programmers get exceptions.
+ object[(object.jquery ? event_name : 'on' + lib.camelize(event_name))](handler);
+ _public.onDestroy(function () {
+ object[(object.jquery ? 'unbind' : 'removeHandler')](event_name, handler);
+ });
+ };
+
+ // Create a destroyable sub-component that will be destroyed when the current component
+ // is destroyed.
+ _public.chainedDestroyable = function (destroyable) {
+ _public.onDestroy(destroyable.triggerDestroy);
+ return destroyable;
+ };
+
+ // Make the deferrable fail when the destroyable is destroyed.
+ _public.chainedDeferrable = function (deferrable) {
+ _public.onDestroy(deferrable.reject);
+ return deferrable;
+ };
+
+ // Either chain a DOM node to the current destroyable, or create a new <div> that will
+ // be destroyed when this destroyable is destroyed.
+ _public.destroyableDiv = function (node) {
+ node = node || jQuery('<div>');
+ _public.onDestroy(function () {
+ node.remove();
+ });
+ return node;
+ };
+
+ return _public;
+};
+/**
+ * A fillable model is one that can fill itself from a JSON document,
+ * but wants to use sub-models instead of just plain objects to store data.
+ *
+ * At it's simplest, it is a drop-in replacement for lib.model, but it also
+ * provides a .refill method (which acts the same way as .attributes).
+ *
+ * lib.fillable(_public, _protected, 'profile_url', 'site_name')({
+ * profile_url: 'http://facebook.com/',
+ * site_name: 'Facebook'
+ * });
+ *
+ * At the next level up, it can provide an implementation for .refill itself:
+ *
+ * lib.model(_public, _protected, 'value');
+ * lib.fillable(_public, _protected, function (name) {
+ * _public.value = name;
+ * })('George');
+ *
+ * The most useful way of using it, is for the auto-generated .refill method:
+ *
+ * lib.fillable(_public, _protected, {
+ * 'memberships': [models.membership],
+ * 'name': models.name
+ * })({
+ * memberships: [{site_name: 'Facebook', profile_url: 'http://facebook.com/'}],
+ * name: 'George'
+ * });
+ *
+ * Now, when you assign a JSON document, the properties of the objects will have been
+ * coerced using the constructors you passed in the specification object.
+ *
+ * NOTE: When you specify that a property takes an array of objects, the .identity property
+ * of those objects will be used to detect which objects have not changed during a refill.
+ */
+
+lib.fillable = function (_public, _protected, spec) {
+
+ var remaining_arguments = _.toArray(arguments).slice(3);
+
+ /**
+ * Given a new_array of JSON data, and an old_array of models,
+ * create an array of models re-using the models from the old_array
+ * where the identities match, preserving the order of the new_array,
+ * and creating any missing objects using the constructor.
+ */
+ function mergeSetOfObjects(old_array, new_array, constructor) {
+ return _(new_array).map(function (data) {
+ var new_object = constructor.apply(this, remaining_arguments.concat([data])),
+ existing = _(old_array || []).detect(function (old) {
+ return old.identity && old.identity === new_object.identity;
+ });
+ if (existing) {
+ (existing.refill || existing.attributes)(data);
+ return existing;
+ } else {
+ return new_object;
+ }
+ });
+ }
+
+ // If fillable is called with arguments like lib.model, then we
+ // use .attributes as .refill, assuming all attributes are supposed to
+ // be un-endowed objects.
+ if (!spec || _.isArray(spec) || typeof(spec) === 'string') {
+ lib.model.apply(this, arguments);
+ _public.refill = _public.attributes;
+
+ // If the user has provided an implementation for refill then we'll use
+ // that, passing any remaining arguments on to the lib.model mixin.
+ } else if (_.isFunction(spec)) {
+ lib.model.apply(this, [_public, _protected].concat(remaining_arguments));
+ _public.refill = spec;
+
+ // Now we assume the user has used fillable to provide the implementation of
+ // refill for them. We parse their spec, and coerce arguments appropriately.
+ } else {
+
+ lib.model(_public, _protected, _(spec).keys());
+
+ _public.refill = function (attributes) {
+ return _public.transaction(function () {
+ _(attributes).each(function (value, name) {
+
+ var filler = _public[name] && (_public[name].refill || _public[name].attributes),
+ triggerer = function () {
+ _public.trigger(name + "_change", _public[name]);
+ };
+
+ // Something model-like, let's re-fill the existing object.
+ if (_.isFunction(filler)) {
+ _public[name].onChange(triggerer);
+ filler.call(_public[name], value);
+ _public[name].removeHandler(name + "_change", triggerer);
+
+ // Nothing model-like present already, try making something new.
+ } else if (_.isFunction(spec[name])) {
+ _public[name] = spec[name].apply(this, remaining_arguments.concat(value));
+
+ // or lots of new things
+ } else if (_.isArray(spec[name]) && _.isFunction(spec[name][0])) {
+ _public[name] = mergeSetOfObjects(_public[name], value, spec[name][0]);
+
+ // Otherwise, just assign the value.
+ } else if (typeof value !== 'undefined') {
+ _public[name] = value;
+
+ }
+ });
+
+ _public.triggerChange(_public);
+ });
+ };
+ }
+
+ return _public.refill;
+};
+/*jslint onevar: false, nomen: false */
+/*global lib, _, jQuery */
+
+// Mixin which gives an object event handling capabilities. Call
+// lib.hasEvent(_public, _protected, 'foo') to generate two methods for this event:
+// onFoo(), which takes a handler to be called when the event is triggered, and
+// triggerFoo(), which triggers the event. Any arguments passed to triggerFoo()
+// are passed through to the event handlers.
+//
+// This mixin also creates general methods on() and trigger(), which behave
+// like the methods above, but take an event name as their first argument.
+lib.hasEvent = function (_public, _protected, event_names) {
+
+ _protected.event_handlers = _protected.event_handlers || {};
+
+ // Register a new event handler for an arbitrary event name.
+ _public.on = _public.on || function (name, handler) {
+ if (!_.isFunction(handler)) {
+ throw new TypeError("Tried to bind " + name + " with non-function:" + String(handler));
+ }
+ _protected.event_handlers[name] = _protected.event_handlers[name] || [];
+ _protected.event_handlers[name].push(handler);
+ return _public;
+ };
+
+ _public.onceOn = _public.onceOn || function (name, handler) {
+ if (!_.isFunction(handler)) {
+ throw new TypeError("Tried to bind " + name + " with non-function:" + String(handler));
+ }
+
+ function onceHandler() {
+ _public.removeHandler(name, onceHandler);
+ return handler.apply(this, arguments);
+ }
+ return _public.on(name, onceHandler);
+ };
+
+ _public.nowAndOn = _public.nowAndOn || function (name, handler) {
+ handler.apply(_public, _(arguments).toArray().slice(2));
+ return _public["on" + lib.camelize(name)](handler);
+ };
+
+ _public.removeHandlers = _public.removeHandlers || function (name) {
+ _protected.event_handlers[name] = [];
+ };
+
+ _public.removeHandler = _public.removeHandler || function (name, handler) {
+ var handlers = _protected.event_handlers[name];
+ if (!handlers) {
+ return;
+ }
+ var index = handlers.indexOf(handler);
+ if (index < 0) {
+ return; // no such handler
+ }
+ return handlers.splice(index, 1)[0];
+ };
+
+ // Trigger the event handlers for an arbitrary event name.
+ _public.trigger = _public.trigger || function (name) {
+ var args = Array.prototype.slice.call(arguments, 1), that = this;
+
+ if (_protected.event_handlers.hasOwnProperty(name)) {
+ _(_protected.event_handlers[name]).chain().clone().each(function (handler) {
+ handler.apply(that, args);
+ });
+ }
+
+ return _public;
+ };
+
+ // Returns true if anything is currently listening for the named event, false otherwise.
+ _public.hasHandlers = _public.hasHandlers || function (event_name) {
+ return (_protected.event_handlers[event_name] || []).length > 0;
+ };
+
+ // Allow either lib.hasEvent(_p, _p, ['a', 'b', 'c']),
+ // or lib.hasEvent(_p, _p, 'a', 'b', 'c')
+ if (!_(event_names).isArray()) {
+ event_names = _(arguments).toArray().slice(2);
+ }
+
+ _(event_names).each(function (event_name) {
+
+ _protected.event_handlers[event_name] = _protected.event_handlers[event_name] || [];
+
+ // Register a new event handler for this specific event.
+ _public['on' + lib.camelize(event_name)] = function (handler) {
+ return _public.on(event_name, handler);
+ };
+
+ // Trigger the event handlers for this specific event.
+ _public['trigger' + lib.camelize(event_name)] = function () {
+ return _public.trigger.apply(this, [event_name].concat(_(arguments).toArray()));
+ };
+ });
+};
+/*jslint onevar: false, nomen: false */
+/*global window, lib, _, jQuery */
+
+// lib.model(_public, _protected, attribute_name_one, attribute_name_two, ...)
+// makes this object a model object with accessor methods for named attributes,
+// events when attribute values change, etc.
+//
+lib.model = function (_public, _protected, declared_attributes) {
+ _protected.attributes = _protected.attributes || {};
+
+ // Event methods:
+ // onChange(function () { ... }) and
+ // triggerChange()
+ lib.hasEvent(_public, _protected, 'change');
+
+ // Allow either lib.model(_p, _p, ['a','b','c']);
+ // or lib.model(_p, _p, 'a', 'b', 'c');
+ //
+ // The latter is more pleasant to interact with as a human,
+ // the former is better for automated interaction.
+ if (!_(declared_attributes).isArray()) {
+ declared_attributes = _(arguments).toArray().slice(2);
+ }
+
+ _(declared_attributes).each(function (name) {
+ // If attribute foo is declared, this generates the event methods:
+ // onFooChange(function (new_value) { ... }) and
+ // triggerFooChange(new_value)
+ var change_event_name = name + '_change';
+ lib.hasEvent(_public, _protected, change_event_name);
+ _public.on(change_event_name, function (new_value) {
+ _public.transactionalTrigger('change', _public);
+ });
+
+ // Define getter/setter for the attribute.
+ // See http://ejohn.org/blog/javascript-getters-and-setters/
+ //
+ // So you can write (e.g.):
+ // person.name = "Bob";
+ // print(person.name);
+
+ _public.__defineGetter__(name, function () {
+ return _protected.attributes[name];
+ });
+ _public.__defineSetter__(name, function (new_value) {
+ return _protected.setAttribute(name, new_value, new_value !== _public[name]);
+ });
+
+ // Define delayed setter for the attribute. (see setAttributeLater)
+ _public['set' + lib.camelize(name) + 'Later'] = function (new_value) {
+ _public.setAttributeLater(name, new_value);
+ };
+ });
+
+ // Set the attribute with the given name to the given value, and trigger the change
+ // event if required.
+ _protected.setAttribute = function (name, new_value, trigger_change) {
+ _protected.attributes[name] = new_value;
+ if (trigger_change) {
+ _public.transactionalTrigger(name + '_change', new_value);
+ }
+ };
+
+ // With no arguments, returns a clone of the current attributes hash.
+ // With one argument (a hash), bulk-assigns the attributes given in the hash, and
+ // doesn't modify attributes not mentioned in the hash.
+ _public.attributes = function (new_attributes) {
+ return _public.transaction(function () {
+ if (typeof(new_attributes) !== 'undefined') {
+ var attribute;
+ for (attribute in new_attributes) {
+ if (new_attributes.hasOwnProperty(attribute)) {
+ _public[attribute] = new_attributes[attribute];
+ }
+ }
+ }
+ return _.clone(_protected.attributes);
+ });
+ };
+
+ _public.unbuild = function () {
+ var obj = {};
+ _(_protected.attributes).each(function (attr, name) {
+ obj[name] = _(attr.unbuild).isFunction() ? attr.unbuild() : attr;
+ });
+ return obj;
+ };
+
+ // Sets the attribute with the first argument's name to the second argument, but delays
+ // that action until the current call stack has completed. Useful if we want to trigger
+ // a change of value eventually, but don't want it affecting other handlers of the event
+ // currently being handled.
+ _public.setAttributeLater = function (name, new_value) {
+ window.setTimeout(function () {
+ _public[name] = new_value;
+ }, 0);
+ };
+
+ // Bind this model to a particular attribute event of a container model.
+ // i.e. when a change event fires on this model, a change event will fire on the container's
+ // attribute.
+ _public.bindTo = function (parent, attribute) {
+ _public.onChange(function () {
+ parent.trigger(attribute + '_change', _public);
+ });
+ parent.trigger(attribute + '_change', _public);
+ return _public;
+ };
+
+ // If the attribute with name `name` currently has a value of `expected_value`, calls the
+ // callback immediately; otherwise waits until the attribute is set to that value, and then
+ // calls the callback once. Doesn't call the callback more than once.
+ _public.whenEqual = function (name, expected_value, callback) {
+ if (_public[name] === expected_value) {
+ callback.call(_public);
+ } else {
+ _protected.when_equal = _protected.when_equal || {};
+ if (_protected.when_equal[name]) {
+ _protected.when_equal[name].push({expected_value: expected_value, callback: callback});
+ } else {
+ _protected.when_equal[name] = [{expected_value: expected_value, callback: callback}];
+
+ _public.on(name + '_change', function (new_value) {
+ _protected.when_equal[name] = _(_protected.when_equal[name]).reject(function (item) {
+ if (item.expected_value === new_value) {
+ item.callback.call(_public);
+ return true;
+ }
+ });
+ });
+ }
+ }
+ return _public;
+ };
+
+ // If the attribute with name `name` currently has a value of `expected_value`, calls the
+ // callback immediately. Whenever in future the attribute is changed from something else to
+ // `expected_value`, the callback is called again.
+ _public.wheneverEqual = function (name, expected_value, callback) {
+ return _public.nowAndOn(name + '_change', function () {
+ if (_public[name] === expected_value) {
+ callback.call(_public);
+ }
+ });
+ };
+
+ // Make modifications to the model in isolation. Any listeners will
+ // not get notified until after the modifications are complete.
+ //
+ // On the assumption you don't raise an exception, this makes the changes
+ // appear atomically and consistently (due to javascript's single-threaded-ness).
+ //
+ // This is used by .attributes(), to ensure that when callbacks get
+ // fired, the model is in a consistent state on each callback.
+ //
+ _public.transaction = function (func) {
+ // If we're already in a transaction, then we'll just run func()
+ // straightaway, any transactionalTriggers will be fired at the
+ // end of the existing transaction.
+ if (_protected.transaction_queue) {
+ return func();
+ }
+
+ _protected.transaction_queue = [];
+ var ret = func();
+
+ while (_protected.transaction_queue.length) {
+ // .splice(0) takes a copy of the contents of the array
+ // and empties the array. If anything else does a transactionalTrigger
+ // within these callbacks, it'll be added to the emptied _protected.transaction_queue.
+ _(_protected.transaction_queue.splice(0)).invoke('call');
+ }
+
+ _protected.transaction_queue = null;
+
+ // This happens outside of the transaction so that we can guarantee it happens
+ // once (and only once) per transaction. (Otherwise we'd have to run this multiple
+ // times in the same transaction if the onChange handlers also triggered changes).
+ if (_protected.transaction_triggered_change) {
+ _protected.transaction_triggered_change = false;
+ _public.triggerChange(_public);
+ }
+ return ret;
+ };
+
+ // Like .trigger(), but if there are transactions in process,
+ // defer the triggering until after it completes.
+ _public.transactionalTrigger = function () {
+ var thiz = this,
+ args = arguments;
+
+ if (_protected.transaction_queue) {
+ // We want to debounce the onChange handler within a transaction, though
+ // we don't want to debounce other on*Change events.
+ if (args[0] === 'change') {
+ _protected.transaction_triggered_change = true;
+ } else {
+ _protected.transaction_queue.push(function () {
+ _public.trigger.apply(thiz, args);
+ });
+ }
+ } else {
+ _public.trigger.apply(thiz, args);
+
+ }
+ };
+
+ // If a model wants to support deep cloning, it can call cloneable, passing the
+ // model's constructor function (which will be used to create cloned instances).
+ // This generates a public clone() method on the model.
+ _protected.cloneable = function (model_class) {
+
+ // Keep track of original objects and their clones. Because JavaScript coerces
+ // all object keys to be strings, this uses an array of [original, clone] pairs
+ // which needs to be scanned linearly. Oh noes, O(n^2) badness! :(
+ var clone_cache;
+
+ function deepClone(thing) {
+ if (typeof(thing) !== 'object' || thing === null) {
+ return thing;
+ }
+ if (_(thing).isArray()) {
+ return _(thing).map(deepClone);
+ }
+
+ // 'thing' is an object, but not an array. First try the cache, to resolve circular references.
+ var cached = _(clone_cache).detect(function (pair) {
+ return pair[0] === thing;
+ });
+ if (cached) {
+ return cached[1];
+ }
+
+ // Nothing in the cache. Actually clone the thing.
+ var clone;
+ if (typeof(thing.clone) === 'function') {
+ clone = thing.clone({clone_cache: clone_cache});
+ } else {
+ clone = {};
+ clone_cache.push([thing, clone]);
+
+ _(thing).each(function (attr, name) {
+ clone[name] = deepClone(attr);
+ });
+ }
+ return clone;
+ }
+
+ _public.clone = function (options) {
+ var clone = model_class();
+ clone_cache = options && options.clone_cache || [];
+ clone_cache.push([_public, clone]);
+ _(_protected.attributes).each(function (attr, name) {
+ clone[name] = deepClone(attr);
+ });
+ return clone;
+ };
+ };
+
+ return _public;
+};
+
+// Method to build a new instance of a model from an attributes hash.
+//
+// To use:
+// models.animal = function(...) {
+// ...
+// lib.model(..., 'name', 'species', 'legs');
+// ...
+// };
+// models.animal.build = lib.model.build;
+//
+// var fido = models.animal.build({
+// name: "Fido",
+// species: "dog",
+// legs: 4});
+lib.model.build = function (attributes) {
+ var obj = this();
+ obj.attributes(attributes);
+ return obj;
+};
+
+// Given a list of attributes, create a simple model that contains them.
+lib.model.class_from_attributes = function (attributes) {
+ var klass = function () {
+ var _public = {}, _protected = {};
+ lib.model(_public, _protected, attributes);
+ return _public;
+ };
+ klass.build = lib.model.build;
+ return klass;
+};
+
+// Override the equality checking (by default ===) that is used to decide
+// whether or not to trigger a change event when a model's property is assigned to.
+// This is particular useful in the case of _.isEqual, which gives you deep object
+// equality, though other functions are possible (see lib.timestamps for example).
+//
+// NOTE: An equivalence relation should be *symmetric* *reflexive* and *transitive*,
+// other kinds of function will confuse people.
+lib.model.usingEquality = function (isEqual) {
+ return function (_public, _protected, declared_attributes) {
+ lib.model.apply(lib.model, arguments);
+
+ if (!_(declared_attributes).isArray()) {
+ declared_attributes = _(arguments).toArray().slice(2);
+ }
+
+ _(declared_attributes).each(function (name) {
+ _public.__defineSetter__(name, function (new_value) {
+ return _protected.setAttribute(name, new_value, !isEqual(new_value, _public[name]));
+ });
+
+ _public[lib.camelize(name, true) + 'Equals'] = function (other_value) {
+ return isEqual(_public[name], other_value);
+ };
+ });
+ };
+};
+// Set up a bridge between Model-R and postmessage.
+//
+// The convention is that everything sent via post-message is a JSON-encoded object with a
+// field called "action" which is used to determine which message was sent.
+//
+// So, if we receive '{"action":"complete","status":200}' from the iframe,
+// that will get converted into _public.triggerComplete({action:"complete", // "status":200});
+//
+// Conversely, if you call _public.triggerSubmit({to_url:"http://rapportive.com/foo"})
+// that will be sent to the iframe as // '{"action":"submit","to_url","http://rapportive.com/foo"}'
+//
+// opts is an object with:
+// {
+// iframe|window: the iframe to send messages to and receive messages from
+// receive: [a list of actions we expect to receive],
+// send: [a list of actions we expect to send],
+// model: [a list of fields to copy around amoungst the frames]
+// remote_base_url: the url to send with postMessage to ensure it arrives at the correct domain
+// }
+//
+// remote_base_url can be a function, in which case it is evaluated every time a message is sent.
+// (useful if the destination URL cannot be determined at the time postMessageShim is declared).
+lib.postMessageShim = function (_public, _protected, opts) {
+
+ var other = opts.iframe || opts.window,
+ debug = true;
+
+ function sendMessage(msg) {
+ if (debug) {
+ console.log((opts.name || 'pmshim') + " SENT-->: " + JSON.stringify(msg));
+ }
+ $.message(other, msg, (_.isFunction(opts.remote_base_url) ? opts.remote_base_url() : opts.remote_base_url));
+ }
+
+ if (opts.model) {
+ lib.model(_public, _protected, opts.model);
+
+ opts.receive = (opts.receive || []).concat(_(opts.model).map(function (field) {
+ return field + '_sync';
+ }));
+
+ _(opts.model).each(function (name) {
+ var syncedValue;
+ _public.on(name + '_sync', function (value) {
+ syncedValue = value.value;
+ _public[name] = value.value;
+ syncedValue = undefined;
+ });
+ _public.on(name + '_change', function (value) {
+ if (value !== syncedValue) {
+ sendMessage({action: name + '_sync', rapportive: true, value: value});
+ }
+ });
+ });
+ }
+
+ if (opts.receive) {
+ lib.hasEvent(_public, _protected, opts.receive);
+
+ // TODO: make sure "rapportive:true" is being set on all messages.
+ $.message(other, loggily("postmessageshim.message", function (msg, reply, e) {
+ if (_(opts.receive).include(msg.action)) {
+ if (debug) {
+ console.log((opts.name || 'pmshim') + " -->RECV: " + JSON.stringify(msg));
+ }
+ _public.trigger(msg.action, msg);
+ } else if (msg.rapportive) {
+ console.log((opts.name || 'pmshim') + " got unexpected postMessage: " + JSON.stringify(msg));
+ }
+ }));
+ }
+
+ if (opts.send) {
+ lib.hasEvent(_public, _protected, opts.send);
+
+ _(opts.send).each(function (name) {
+ _public.on(name, function (msg) {
+ sendMessage(jQuery.extend({action: name, rapportive: true}, msg));
+ });
+ });
+ }
+
+};
+/*jslint onevar:false, regexp:false */
+/*global components, window, document, navigator */
+
+// An extraction/port of Backbone.Router & Backbone.history to components.router and components.history, respectively.
+// Backbone.Router
+// -------------------
+
+// Routers map faux-URLs to actions, and fire events when routes are
+// matched. Creating a new one sets its `routes` hash, if not set statically.
+components.RapportiveRouter = function (options) {
+ options = options || {};
+ if (options.routes) {
+ this.routes = options.routes;
+ }
+ this._bindRoutes();
+};
+
+// Cached regular expressions for matching named param parts and splatted
+// parts of route strings.
+var namedParam = /:\w+/g;
+var splatParam = /\*\w+/g;
+var escapeRegExp = /[\-\[\]{}()+?.,\\\^$|#\s]/g;
+
+// Set up all inheritable **Backbone.Router** properties and methods.
+_.extend(components.RapportiveRouter.prototype, /*Events, */ {
+
+ // Instead of #route(path, name, callback), we take name and callbacks in the 'options'
+ reversible_route: function (route, options) {
+ if (!_.isRegExp(route)) {
+ route = this._routeToRegExp(route);
+ }
+ if (!options.enter) {
+ throw "using reversible routing but no 'enter' function was specified.";
+ }
+
+ components.history.route(route, {
+ enter: _.bind(function (fragment) {
+ var args = this._extractParameters(route, fragment);
+ options.enter.apply(this, args);
+ }, this),
+
+ exit: _.bind(function (exiting_from_fragment) {
+ var args = this._extractParameters(route, exiting_from_fragment);
+ options.exit.apply(this, args);
+ }, this)
+ });
+ return this;
+ },
+
+ // Give us better flexibility on URL parts - URI decode values and allow
+ // an underscore character to be used in lieu of a null/empty string.
+ sanitizeUrlBit: function (bit) {
+ if (!bit) {
+ return bit;
+ }
+ bit = bit.trim();
+ if (bit.length === 0 || bit === '_' || bit === encodeURIComponent('_')) {
+ return null;
+ }
+
+ return decodeURIComponent(bit).replace(/\+/g, ' ');
+ },
+
+ routes_by_name: {},
+
+ // Manually bind a single named route to a callback. For example:
+ //
+ // this.route('search/:query/p:num', 'search', function(query, num) {
+ // ...
+ // });
+ //
+ route: function (route, name, callback) {
+ this.routes_by_name[name] = route;
+
+ if (!_.isRegExp(route)) {
+ route = this._routeToRegExp(route);
+ }
+
+ if (!callback) {
+ callback = this[name];
+ }
+ components.history.route(route, _.bind(function (fragment) {
+ var args = this._extractParameters(route, fragment);
+ var that = this;
+ args = _(args).map(function (param) {
+ return that.sanitizeUrlBit(param);
+ });
+ if (callback) {
+ callback.apply(this, args);
+ }
+ }, this));
+ return this;
+ },
+
+ // Simple proxy to `components.history` to save a fragment into the history.
+ navigate: function (fragment, options) {
+ components.history.navigate(fragment, options);
+ },
+
+ // Bind all defined routes to `components.history`. We have to reverse the
+ // order of the routes here to support behavior where the most general
+ // routes can be defined at the bottom of the route map.
+ _bindRoutes: function () {
+ if (!this.routes) {
+ return;
+ }
+ var routes = [];
+ for (var route in this.routes) {
+ if (this.routes.hasOwnProperty(route)) {
+ routes.unshift([route, this.routes[route]]);
+ }
+ }
+ for (var i = 0, l = routes.length; i < l; i += 1) {
+ this.route(routes[i][0], routes[i][1], this[routes[i][1]]);
+ }
+ },
+
+ // Convert a route string into a regular expression, suitable for matching
+ // against the current location hash.
+ _routeToRegExp: function (route) {
+ route = route.replace(escapeRegExp, '\\$&')
+ .replace(namedParam, '([^\/]+)')
+ .replace(splatParam, '(.*?)');
+ return new RegExp('^' + route + '$');
+ },
+
+ // Given a route, and a URL fragment that it matches, return the array of
+ // extracted parameters.
+ _extractParameters: function (route, fragment) {
+ return route.exec(fragment).slice(1);
+ }
+
+});
+
+
+ // New routing functions that let us have an enter/exit pair of functions when setting
+ // up Backbone routes.
+ //
+ // Requires a tiny monkey-patch to Backbone: the checkUrl function needs to save this._priorUrl
+
+
+
+// Backbone.History
+// ----------------
+
+// Handles cross-browser history management, based on URL fragments. If the
+// browser does not support `onhashchange`, falls back to polling.
+var History = function () {
+ this.handlers = [];
+ _.bindAll(this, 'checkUrl');
+};
+
+// Cached regex for cleaning leading hashes and slashes .
+var routeStripper = /^[#\/]/;
+
+// Cached regex for detecting MSIE.
+var isExplorer = /msie [\w.]+/;
+
+// Has the history handling already been started?
+History.started = false;
+
+// Set up all inheritable **Backbone.History** properties and methods.
+_.extend(History.prototype, /*Events,*/ {
+
+ // The default interval to poll for hash changes, if necessary, is
+ // twenty times a second.
+ interval: 50,
+
+ // Gets the true hash value. Cannot use location.hash directly due to bug
+ // in Firefox where location.hash will always be decoded.
+ getHash: function (windowOverride) {
+ var loc = windowOverride ? windowOverride.location : window.location;
+ var match = loc.href.match(/#(.*)$/);
+ return match ? match[1] : '';
+ },
+
+ // Get the cross-browser normalized URL fragment, either from the URL,
+ // the hash, or the override.
+ getFragment: function (fragment, forcePushState) {
+ if (!fragment) {
+ if (this._hasPushState || forcePushState) {
+ fragment = window.location.pathname;
+ var search = window.location.search;
+ if (search) {
+ fragment += search;
+ }
+ } else {
+ fragment = this.getHash();
+ }
+ }
+ if (!fragment.indexOf(this.options.root)) {
+ fragment = fragment.substr(this.options.root.length);
+ }
+ return fragment.replace(routeStripper, '');
+ },
+
+ // Start the hash change handling, returning `true` if the current URL matches
+ // an existing route, and `false` otherwise.
+ start: function (options) {
+ if (History.started) {
+ throw new Error("History has already been started");
+ }
+ History.started = true;
+
+ // Figure out the initial configuration. Do we need an iframe?
+ // Is pushState desired ... is it available?
+ this.options = _.extend({}, {root: '/'}, this.options, options);
+ this._wantsHashChange = this.options.hashChange !== false;
+ this._wantsPushState = !!this.options.pushState;
+ this._hasPushState = !!(this.options.pushState && window.history && window.history.pushState);
+ var fragment = this.getFragment();
+ var docMode = document.documentMode;
+
+ // Depending on whether we're using pushState or hashes, and whether
+ // 'onhashchange' is supported, determine how we check the URL state.
+ if (this._hasPushState) {
+ $(window).bind('popstate', this.checkUrl);
+ } else if (this._wantsHashChange && ('onhashchange' in window)) {
+ $(window).bind('hashchange', this.checkUrl);
+ } else if (this._wantsHashChange) {
+ this._checkUrlInterval = window.setInterval(this.checkUrl, this.interval);
+ }
+
+ // Determine if we need to change the base url, for a pushState link
+ // opened by a non-pushState browser.
+ this.fragment = fragment;
+ var loc = window.location;
+ var atRoot = loc.pathname === this.options.root;
+
+ // If we've started off with a route from a `pushState`-enabled browser,
+ // but we're currently in a browser that doesn't support it...
+ if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
+ this.fragment = this.getFragment(null, true);
+ window.location.replace(this.options.root + '#' + this.fragment);
+ // Return immediately as browser will do redirect to new url
+ return true;
+
+ // Or if we've started out with a hash-based route, but we're currently
+ // in a browser where it could be `pushState`-based instead...
+ } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
+ this.fragment = this.getHash().replace(routeStripper, '');
+ window.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root + this.fragment);
+ }
+
+ // Workaround the root having a trailing slash when the visited URL is misisng it.
+ if (this._wantsPushState && this._hasPushState && this.options.root === ('/' + this.fragment + '/')) {
+ window.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root);
+ }
+
+ if (!this.options.silent) {
+ return this.loadUrl();
+ }
+ },
+
+ // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
+ // but possibly useful for unit testing Routers.
+ stop: function () {
+ $(window).unbind('popstate', this.checkUrl).unbind('hashchange', this.checkUrl);
+ window.clearInterval(this._checkUrlInterval);
+ History.started = false;
+ },
+
+ // Add a route to be tested when the fragment changes. Routes added later
+ // may override previous routes.
+ route: function (route, callback_or_options) {
+ if (_.isFunction(callback_or_options)) {
+ this.handlers.unshift({route: route, callback: callback_or_options});
+ } else {
+ this.handlers.unshift(_.extend({route: route}, callback_or_options));
+ }
+ },
+
+ // Checks the current URL to see if it has changed, and if it has,
+ // calls `loadUrl`, normalizing across the hidden iframe.
+ checkUrl: function (e) {
+ var current = this.getFragment();
+ if (current === this.fragment && this.iframe) {
+ current = this.getFragment(this.getHash(this.iframe));
+ }
+ if (current === this.fragment) {
+ return false;
+ }
+
+ // NOTE: Monkeypatch! -Lee
+ this._priorUrl = this._currentUrl;
+
+ if (this.iframe) {
+ this.navigate(current);
+ }
+ return this.loadUrl() || this.loadUrl(this.getHash());
+ },
+
+ // Attempt to load the current URL fragment. If a route succeeds with a
+ // match, returns `true`. If no defined routes matches the fragment,
+ // returns `false`.
+ loadUrl: function (fragmentOverride) {
+ var that = this;
+ _.each(this.handlers, function (handler) {
+ if (handler.exit && handler.route.test(that._priorUrl)) {
+ handler.exit(that._priorUrl);
+ }
+ });
+
+ var fragment = this.fragment = this.getFragment(fragmentOverride);
+ var matched = _.any(this.handlers, function (handler) {
+ if (handler.route.test(fragment.toLowerCase())) {
+ that._currentUrl = fragment;
+ (handler.enter || handler.callback)(fragment);
+ return true;
+ }
+ });
+ return matched;
+ },
+
+
+ // Save a fragment into the hash history, or replace the URL state if the
+ // 'replace' option is passed. You are responsible for properly URL-encoding
+ // the fragment in advance.
+ //
+ // The options object can contain `trigger: true` if you wish to have the
+ // route callback be fired (not usually desirable), or `replace: true`, if
+ // you wish to modify the current URL without adding an entry to the history.
+ navigate: function (fragment, options) {
+ if (!History.started) {
+ return false;
+ }
+ if (!options || options === true) {
+ options = {trigger: options};
+ }
+ var frag = (fragment || '').replace(routeStripper, '');
+ if (this.fragment === frag) {
+ return;
+ }
+
+ // If pushState is available, we use it to set the fragment as a real URL.
+ if (this._hasPushState) {
+ if (frag.indexOf(this.options.root) !== 0) {
+ frag = this.options.root + frag;
+ }
+ this.fragment = frag;
+ window.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, frag);
+
+ // If hash changes haven't been explicitly disabled, update the hash
+ // fragment to store history.
+ } else if (this._wantsHashChange) {
+ this.fragment = frag;
+ this._updateHash(window.location, frag, options.replace);
+ if (this.iframe && (frag !== this.getFragment(this.getHash(this.iframe)))) {
+ // Opening and closing the iframe tricks IE7 and earlier to push a history entry on hash-tag change.
+ // When replace is true, we don't want this.
+ if (!options.replace) {
+ this.iframe.document.open().close();
+ }
+ this._updateHash(this.iframe.location, frag, options.replace);
+ }
+
+ // If you've told us that you explicitly don't want fallback hashchange-
+ // based history, then `navigate` becomes a page refresh.
+ } else {
+ window.location.assign(this.options.root + fragment);
+ }
+ if (options.trigger) {
+ this.loadUrl(fragment);
+ }
+ },
+
+ // Update the hash location, either replacing the current entry, or adding
+ // a new one to the browser history.
+ _updateHash: function (location, fragment, replace) {
+ if (replace) {
+ location.replace(location.toString().replace(/(javascript:|#).*$/, '') + '#' + fragment);
+ } else {
+ location.hash = fragment;
+ }
+ }
+});
+
+components.history = new History();
+
+/*global lib, JSON */
+lib.saveable = function (_public, _protected, key) {
+ if (!JSON) {
+ throw new Error("JSON does not exist");
+ }
+
+ _public.save = function () {
+ return lib.storage.setItem(key, JSON.stringify(_public.attributes()));
+ };
+
+ _public.fetch = function () {
+ var data = lib.storage.getItem(key);
+ if (data) {
+ data = JSON.parse(data);
+ }
+ return data;
+ };
+
+ _public.loadWithDefaults = function (initialData) {
+ var saved = _public.fetch();
+
+ if (saved) {
+ _public.attributes(saved);
+ } else {
+ _public.attributes(initialData);
+ _public.save();
+ }
+ };
+
+ // Only integrate and save the hash of 'timestampedData' if its fetched_at
+ // property is a more recent (integer) timestamp than that which is already saved.
+ _public.mergeNewest = function (timestampedData) {
+ var saved = _public.fetch();
+
+ if (!saved || !saved.fetched_at || saved.fetched_at < timestampedData.fetched_at) {
+ _public.attributes(timestampedData);
+ _public.save();
+ } else {
+ _public.attributes(saved);
+ }
+ };
+
+ _public.clearStorage = function () {
+ lib.storage.setItem(key, undefined);
+ };
+
+ return _public;
+};
+lib.showable = function (_public, _protected, manager) {
+
+ lib.model(_public, _protected, 'visible');
+ lib.destroyable(_public, _protected);
+
+ _public.visible = false;
+
+ _public.show = function () {
+ _public.visible = true;
+ return _public;
+ };
+
+ _public.hide = function () {
+ _public.visible = false;
+ return _public;
+ };
+
+ _public.toggle = function () {
+ _public.visible = arguments.length ? arguments[0] : !_public.visible;
+ return _public;
+ };
+
+ _public.onDestroy(_public.hide);
+
+ return _public;
+};
+
+// If you have a collection of mutually exclusive showables, this function will
+// ensure that the correct ones are hidden when the correct others are shown.
+// (aka. lib.thereShouldOnlyBeOne)
+lib.showable.manager = function () {
+
+ var _public = {}, visible = null;
+
+ _public.manage = function (showable) {
+ showable.wheneverEqual('visible', true, function () {
+ if (visible && visible !== showable) {
+ visible.hide();
+ }
+ visible = showable;
+ });
+
+ showable.wheneverEqual('visible', false, function () {
+ if (showable === visible) {
+ visible = null;
+ }
+ });
+ };
+
+ _(arguments).chain().flatten().each(_public.manage);
+
+ return _public;
+};
+/*global window */
+
+// A wrapper around localStorage that tries to make the size limit less painful.
+//
+// It does this by maintaining the invariant that if you do storage.setItem()
+// in one browser session, storage.getItem() is guaranteed to return that item.
+//
+// It does not guarantee however that if you do storage.setItem() in one session
+// that that value will be available in the next session.
+//
+// That said, if you can access one key in the next session, you will be able to
+// access all the keys set after that one.
+//
+lib.storage = (function () {
+ var _public = {}, _protected = {},
+
+ localStorage = window.localStorage,
+
+ workingStorage = {};
+
+ // localStorage is our first port of call, but if it fails to work for some
+ // reason (i.e. we're out of quota, or firefox has corrupted the data file)
+ // we fall back to workingStorage, which is not persistant.
+ // (obviously in the case of a corrupted data file, or no local storage at
+ // all, then nothing is actually persistant at all).
+
+ function handleStorageError(name, value, e, opts) {
+
+ opts = jQuery.extend({
+ on_quota_exceeded: function () {
+ // By default retry once, but if that fails, fallback to using
+ // workingStorage.
+ _public.setItem(name, value, {
+ on_quota_exceeded: function () {
+ console.log("Not writing " + name + " to localStorage: this value is too big.");
+ }
+ });
+ }
+ }, opts);
+
+ if (e && /QUOTA/.test(e.name)) {
+ // If we hit a quota error, then we're going to continue hitting quota errors
+ // for all time unless we do something drastic. So we empty localStorage, giving
+ // us more room to play with.
+ //
+ // In order to isolate the current session from this (i.e. to maintain the invariant
+ // that if you've just done .setItem(), .getItem() will return the value), we copy
+ // everything into workingStorage.
+ _(localStorage).each(function (value, name) {
+ if (!workingStorage.hasOwnProperty(name)) {
+ workingStorage[name] = value;
+ }
+ delete localStorage[name];
+ });
+
+ opts.on_quota_exceeded();
+ } else {
+ // Assume localStorage is totally brokened.
+ console.log("Failed to write " + name + " to localStorage: " + e);
+ }
+ }
+
+ _public.getItem = function (name) {
+ if (!workingStorage.hasOwnProperty(name)) {
+ try {
+ workingStorage[name] = localStorage[name];
+ } catch (e) {
+ console.log("Not reading " + name + " from localStorage: " + e);
+ workingStorage[name] = null;
+ }
+ }
+ return workingStorage[name];
+ };
+
+ _public.setItem = function (name, value, opts) {
+ try {
+ workingStorage[name] = value;
+ localStorage[name] = value;
+ } catch (e) {
+ handleStorageError(name, value, e, opts);
+ }
+ };
+
+ // allow testing other storage backends.
+ _public.use = function (storage) {
+ localStorage = storage;
+ };
+
+ return _public;
+}());
+/*jslint nomen: false*/
+/*global lib, _*/
+
+(function () {
+
+ // Turns the first letter of a string into uppercase.
+ function capitalize(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+ }
+
+ // Turns the first letter of a string into lowercase.
+ function uncapitalize(str) {
+ return str.charAt(0).toLowerCase() + str.slice(1);
+ }
+
+ // Turns an expression_with_underscores into an ExpressionInCamelCase.
+ // If the argument is truthy, makes theFirstLetterLowercase.
+ lib.camelize = function (str, first_letter_lowercase) {
+ var camelized = _(str.split(/_/)).map(function (word) {
+ return capitalize(word);
+ }).join('');
+
+ return (first_letter_lowercase ? uncapitalize(camelized) : capitalize(camelized));
+ };
+
+ // Turns a CamelCaseExpression into an underscore_expression.
+ lib.underscore = function (str) {
+ return str
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
+ .replace(/\-/g, '_')
+ .toLowerCase();
+ };
+}());
+lib.view = function (_public, _protected, element_type) {
+ _public.remove = function () {
+ _public.$el.remove();
+ };
+};
View
1  release/model-r-0.7.3.map
@@ -0,0 +1 @@
+{"version":3,"file":null,"sources":["?"],"names":["lib","destroyable","_public","_protected","hasEvent","listenUntilDestroyed","object","event_name","handler","jquery","camelize","onDestroy","chainedDestroyable","triggerDestroy","chainedDeferrable","deferrable","reject","destroyableDiv","node","jQuery","remove","fillable","spec","mergeSetOfObjects","old_array","new_array","constructor","_","map","data","new_object","apply","this","remaining_arguments","concat","existing","detect","old","identity","refill","attributes","toArray","arguments","slice","isArray","model","isFunction","keys","transaction","each","value","name","filler","triggerer","trigger","onChange","call","removeHandler","triggerChange","event_names","event_handlers","on","TypeError","String","push","onceOn","onceHandler","nowAndOn","removeHandlers","handlers","index","indexOf","splice","args","Array","prototype","that","hasOwnProperty","chain","clone","hasHandlers","length","declared_attributes","change_event_name","transactionalTrigger","__defineGetter__","__defineSetter__","new_value","setAttribute","setAttributeLater","trigger_change","new_attributes","attribute","unbuild","obj","attr","window","setTimeout","bindTo","parent","whenEqual","expected_value","callback","when_equal","item","wheneverEqual","func","transaction_queue","ret","invoke","transaction_triggered_change","thiz","cloneable","model_class","deepClone","thing","cached","clone_cache","pair","options","build","class_from_attributes","klass","usingEquality","isEqual","other_value","postMessageShim","opts","sendMessage","msg","debug","console","log","JSON","stringify","$","message","other","remote_base_url","iframe","receive","field","syncedValue","undefined","action","rapportive","loggily","include","send","extend","components","RapportiveRouter","routes","_bindRoutes","namedParam","splatParam","escapeRegExp","reversible_route","route","isRegExp","_routeToRegExp","enter","history","bind","fragment","_extractParameters","exit","exiting_from_fragment","sanitizeUrlBit","bit","trim","encodeURIComponent","decodeURIComponent","replace","routes_by_name","param","navigate","unshift","i","l","RegExp","exec","History","bindAll","routeStripper","isExplorer","started","interval","getHash","windowOverride","loc","location","match","href","getFragment","forcePushState","_hasPushState","pathname","search","root","substr","start","Error","_wantsHashChange","hashChange","_wantsPushState","pushState","document","documentMode","checkUrl","_checkUrlInterval","setInterval","atRoot","hash","replaceState","title","protocol","host","silent","loadUrl","stop","unbind","clearInterval","callback_or_options","current","_priorUrl","_currentUrl","fragmentOverride","test","matched","any","toLowerCase","frag","_updateHash","open","close","assign","toString","saveable","key","save","storage","setItem","fetch","getItem","parse","loadWithDefaults","initialData","saved","mergeNewest","timestampedData","fetched_at","clearStorage","showable","visible","show","hide","toggle","manager","manage","flatten","handleStorageError","e","on_quota_exceeded","localStorage","workingStorage","use","capitalize","str","charAt","toUpperCase","uncapitalize","first_letter_lowercase","camelized","split","word","join","underscore","view","$el"],"mappings":"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"}
View
1  release/model-r-0.7.3.min.js
@@ -0,0 +1 @@
+/*** model-r-0.7.3.min.js ***/lib.destroyable=function(t,e){return lib.hasEvent(t,e,"destroy"),t.listenUntilDestroyed=function(e,n,r){e[e.jquery?n:"on"+lib.camelize(n)](r),t.onDestroy(function(){e[e.jquery?"unbind":"removeHandler"](n,r)})},t.chainedDestroyable=function(e){return t.onDestroy(e.triggerDestroy),e},t.chainedDeferrable=function(e){return t.onDestroy(e.reject),e},t.destroyableDiv=function(e){return e=e||jQuery("<div>"),t.onDestroy(function(){e.remove()}),e},t},lib.fillable=function(t,e,n){function r(t,e,n){return _(e).map(function(e){var r=n.apply(this,i.concat([e])),o=_(t||[]).detect(function(t){return t.identity&&t.identity===r.identity});return o?((o.refill||o.attributes)(e),o):r})}var i=_.toArray(arguments).slice(3);return!n||_.isArray(n)||"string"==typeof n?(lib.model.apply(this,arguments),t.refill=t.attributes):_.isFunction(n)?(lib.model.apply(this,[t,e].concat(i)),t.refill=n):(lib.model(t,e,_(n).keys()),t.refill=function(e){return t.transaction(function(){_(e).each(function(e,o){var a=t[o]&&(t[o].refill||t[o].attributes),s=function(){t.trigger(o+"_change",t[o])};_.isFunction(a)?(t[o].onChange(s),a.call(t[o],e),t[o].removeHandler(o+"_change",s)):_.isFunction(n[o])?t[o]=n[o].apply(this,i.concat(e)):_.isArray(n[o])&&_.isFunction(n[o][0])?t[o]=r(t[o],e,n[o][0]):"undefined"!=typeof e&&(t[o]=e)}),t.triggerChange(t)})}),t.refill},lib.hasEvent=function(t,e,n){e.event_handlers=e.event_handlers||{},t.on=t.on||function(n,r){if(!_.isFunction(r))throw new TypeError("Tried to bind "+n+" with non-function:"+String(r));return e.event_handlers[n]=e.event_handlers[n]||[],e.event_handlers[n].push(r),t},t.onceOn=t.onceOn||function(e,n){function r(){return t.removeHandler(e,r),n.apply(this,arguments)}if(!_.isFunction(n))throw new TypeError("Tried to bind "+e+" with non-function:"+String(n));return t.on(e,r)},t.nowAndOn=t.nowAndOn||function(e,n){return n.apply(t,_(arguments).toArray().slice(2)),t["on"+lib.camelize(e)](n)},t.removeHandlers=t.removeHandlers||function(t){e.event_handlers[t]=[]},t.removeHandler=t.removeHandler||function(t,n){var r=e.event_handlers[t];if(r){var i=r.indexOf(n);if(!(0>i))return r.splice(i,1)[0]}},t.trigger=t.trigger||function(n){var r=Array.prototype.slice.call(arguments,1),i=this;return e.event_handlers.hasOwnProperty(n)&&_(e.event_handlers[n]).chain().clone().each(function(t){t.apply(i,r)}),t},t.hasHandlers=t.hasHandlers||function(t){return(e.event_handlers[t]||[]).length>0},_(n).isArray()||(n=_(arguments).toArray().slice(2)),_(n).each(function(n){e.event_handlers[n]=e.event_handlers[n]||[],t["on"+lib.camelize(n)]=function(e){return t.on(n,e)},t["trigger"+lib.camelize(n)]=function(){return t.trigger.apply(this,[n].concat(_(arguments).toArray()))}})},lib.model=function(t,e,n){return e.attributes=e.attributes||{},lib.hasEvent(t,e,"change"),_(n).isArray()||(n=_(arguments).toArray().slice(2)),_(n).each(function(n){var r=n+"_change";lib.hasEvent(t,e,r),t.on(r,function(){t.transactionalTrigger("change",t)}),t.__defineGetter__(n,function(){return e.attributes[n]}),t.__defineSetter__(n,function(r){return e.setAttribute(n,r,r!==t[n])}),t["set"+lib.camelize(n)+"Later"]=function(e){t.setAttributeLater(n,e)}}),e.setAttribute=function(n,r,i){e.attributes[n]=r,i&&t.transactionalTrigger(n+"_change",r)},t.attributes=function(n){return t.transaction(function(){if("undefined"!=typeof n){var r;for(r in n)n.hasOwnProperty(r)&&(t[r]=n[r])}return _.clone(e.attributes)})},t.unbuild=function(){var t={};return _(e.attributes).each(function(e,n){t[n]=_(e.unbuild).isFunction()?e.unbuild():e}),t},t.setAttributeLater=function(e,n){window.setTimeout(function(){t[e]=n},0)},t.bindTo=function(e,n){return t.onChange(function(){e.trigger(n+"_change",t)}),e.trigger(n+"_change",t),t},t.whenEqual=function(n,r,i){return t[n]===r?i.call(t):(e.when_equal=e.when_equal||{},e.when_equal[n]?e.when_equal[n].push({expected_value:r,callback:i}):(e.when_equal[n]=[{expected_value:r,callback:i}],t.on(n+"_change",function(r){e.when_equal[n]=_(e.when_equal[n]).reject(function(e){return e.expected_value===r?(e.callback.call(t),!0):void 0})}))),t},t.wheneverEqual=function(e,n,r){return t.nowAndOn(e+"_change",function(){t[e]===n&&r.call(t)})},t.transaction=function(n){if(e.transaction_queue)return n();e.transaction_queue=[];for(var r=n();e.transaction_queue.length;)_(e.transaction_queue.splice(0)).invoke("call");return e.transaction_queue=null,e.transaction_triggered_change&&(e.transaction_triggered_change=!1,t.triggerChange(t)),r},t.transactionalTrigger=function(){var n=this,r=arguments;e.transaction_queue?"change"===r[0]?e.transaction_triggered_change=!0:e.transaction_queue.push(function(){t.trigger.apply(n,r)}):t.trigger.apply(n,r)},e.cloneable=function(n){function r(t){if("object"!=typeof t||null===t)return t;if(_(t).isArray())return _(t).map(r);var e=_(i).detect(function(e){return e[0]===t});if(e)return e[1];var n;return"function"==typeof t.clone?n=t.clone({clone_cache:i}):(n={},i.push([t,n]),_(t).each(function(t,e){n[e]=r(t)})),n}var i;t.clone=function(o){var a=n();return i=o&&o.clone_cache||[],i.push([t,a]),_(e.attributes).each(function(t,e){a[e]=r(t)}),a}},t},lib.model.build=function(t){var e=this();return e.attributes(t),e},lib.model.class_from_attributes=function(t){var e=function(){var e={},n={};return lib.model(e,n,t),e};return e.build=lib.model.build,e},lib.model.usingEquality=function(t){return function(e,n,r){lib.model.apply(lib.model,arguments),_(r).isArray()||(r=_(arguments).toArray().slice(2)),_(r).each(function(r){e.__defineSetter__(r,function(i){return n.setAttribute(r,i,!t(i,e[r]))}),e[lib.camelize(r,!0)+"Equals"]=function(n){return t(e[r],n)}})}},lib.postMessageShim=function(t,e,n){function r(t){o&&console.log((n.name||"pmshim")+" SENT-->: "+JSON.stringify(t)),$.message(i,t,_.isFunction(n.remote_base_url)?n.remote_base_url():n.remote_base_url)}var i=n.iframe||n.window,o=!0;n.model&&(lib.model(t,e,n.model),n.receive=(n.receive||[]).concat(_(n.model).map(function(t){return t+"_sync"})),_(n.model).each(function(e){var n;t.on(e+"_sync",function(r){n=r.value,t[e]=r.value,n=void 0}),t.on(e+"_change",function(t){t!==n&&r({action:e+"_sync",rapportive:!0,value:t})})})),n.receive&&(lib.hasEvent(t,e,n.receive),$.message(i,loggily("postmessageshim.message",function(e){_(n.receive).include(e.action)?(o&&console.log((n.name||"pmshim")+" -->RECV: "+JSON.stringify(e)),t.trigger(e.action,e)):e.rapportive&&console.log((n.name||"pmshim")+" got unexpected postMessage: "+JSON.stringify(e))}))),n.send&&(lib.hasEvent(t,e,n.send),_(n.send).each(function(e){t.on(e,function(t){r(jQuery.extend({action:e,rapportive:!0},t))})}))},components.RapportiveRouter=function(t){t=t||{},t.routes&&(this.routes=t.routes),this._bindRoutes()};var namedParam=/:\w+/g,splatParam=/\*\w+/g,escapeRegExp=/[\-\[\]{}()+?.,\\\^$|#\s]/g;_.extend(components.RapportiveRouter.prototype,{reversible_route:function(t,e){if(_.isRegExp(t)||(t=this._routeToRegExp(t)),!e.enter)throw"using reversible routing but no 'enter' function was specified.";return components.history.route(t,{enter:_.bind(function(n){var r=this._extractParameters(t,n);e.enter.apply(this,r)},this),exit:_.bind(function(n){var r=this._extractParameters(t,n);e.exit.apply(this,r)},this)}),this},sanitizeUrlBit:function(t){return t?(t=t.trim(),0===t.length||"_"===t||t===encodeURIComponent("_")?null:decodeURIComponent(t).replace(/\+/g," ")):t},routes_by_name:{},route:function(t,e,n){return this.routes_by_name[e]=t,_.isRegExp(t)||(t=this._routeToRegExp(t)),n||(n=this[e]),components.history.route(t,_.bind(function(e){var r=this._extractParameters(t,e),i=this;r=_(r).map(function(t){return i.sanitizeUrlBit(t)}),n&&n.apply(this,r)},this)),this},navigate:function(t,e){components.history.navigate(t,e)},_bindRoutes:function(){if(this.routes){var t=[];for(var e in this.routes)this.routes.hasOwnProperty(e)&&t.unshift([e,this.routes[e]]);for(var n=0,r=t.length;r>n;n+=1)this.route(t[n][0],t[n][1],this[t[n][1]])}},_routeToRegExp:function(t){return t=t.replace(escapeRegExp,"\\$&").replace(namedParam,"([^/]+)").replace(splatParam,"(.*?)"),new RegExp("^"+t+"$")},_extractParameters:function(t,e){return t.exec(e).slice(1)}});var History=function(){this.handlers=[],_.bindAll(this,"checkUrl")},routeStripper=/^[#\/]/,isExplorer=/msie [\w.]+/;History.started=!1,_.extend(History.prototype,{interval:50,getHash:function(t){var e=t?t.location:window.location,n=e.href.match(/#(.*)$/);return n?n[1]:""},getFragment:function(t,e){if(!t)if(this._hasPushState||e){t=window.location.pathname;var n=window.location.search;n&&(t+=n)}else t=this.getHash();return t.indexOf(this.options.root)||(t=t.substr(this.options.root.length)),t.replace(routeStripper,"")},start:function(t){if(History.started)throw new Error("History has already been started");History.started=!0,this.options=_.extend({},{root:"/"},this.options,t),this._wantsHashChange=this.options.hashChange!==!1,this._wantsPushState=!!this.options.pushState,this._hasPushState=!!(this.options.pushState&&window.history&&window.history.pushState);var e=this.getFragment();document.documentMode,this._hasPushState?$(window).bind("popstate",this.checkUrl):this._wantsHashChange&&"onhashchange"in window?$(window).bind("hashchange",this.checkUrl):this._wantsHashChange&&(this._checkUrlInterval=window.setInterval(this.checkUrl,this.interval)),this.fragment=e;var n=window.location,r=n.pathname===this.options.root;return this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!r?(this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0):(this._wantsPushState&&this._hasPushState&&r&&n.hash&&(this.fragment=this.getHash().replace(routeStripper,""),window.history.replaceState({},document.title,n.protocol+"//"+n.host+this.options.root+this.fragment)),this._wantsPushState&&this._hasPushState&&this.options.root==="/"+this.fragment+"/"&&window.history.replaceState({},document.title,n.protocol+"//"+n.host+this.options.root),this.options.silent?void 0:this.loadUrl())},stop:function(){$(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl),window.clearInterval(this._checkUrlInterval),History.started=!1},route:function(t,e){_.isFunction(e)?this.handlers.unshift({route:t,callback:e}):this.handlers.unshift(_.extend({route:t},e))},checkUrl:function(){var t=this.getFragment();return t===this.fragment&&this.iframe&&(t=this.getFragment(this.getHash(this.iframe))),t===this.fragment?!1:(this._priorUrl=this._currentUrl,this.iframe&&this.navigate(t),this.loadUrl()||this.loadUrl(this.getHash()))},loadUrl:function(t){var e=this;_.each(this.handlers,function(t){t.exit&&t.route.test(e._priorUrl)&&t.exit(e._priorUrl)});var n=this.fragment=this.getFragment(t),r=_.any(this.handlers,function(t){return t.route.test(n.toLowerCase())?(e._currentUrl=n,(t.enter||t.callback)(n),!0):void 0});return r},navigate:function(t,e){if(!History.started)return!1;e&&e!==!0||(e={trigger:e});var n=(t||"").replace(routeStripper,"");this.fragment!==n&&(this._hasPushState?(0!==n.indexOf(this.options.root)&&(n=this.options.root+n),this.fragment=n,window.history[e.replace?"replaceState":"pushState"]({},document.title,n)):this._wantsHashChange?(this.fragment=n,this._updateHash(window.location,n,e.replace),this.iframe&&n!==this.getFragment(this.getHash(this.iframe))&&(e.replace||this.iframe.document.open().close(),this._updateHash(this.iframe.location,n,e.replace))):window.location.assign(this.options.root+t),e.trigger&&this.loadUrl(t))},_updateHash:function(t,e,n){n?t.replace(t.toString().replace(/(javascript:|#).*$/,"")+"#"+e):t.hash=e}}),components.history=new History,lib.saveable=function(t,e,n){if(!JSON)throw new Error("JSON does not exist");return t.save=function(){return lib.storage.setItem(n,JSON.stringify(t.attributes()))},t.fetch=function(){var t=lib.storage.getItem(n);return t&&(t=JSON.parse(t)),t},t.loadWithDefaults=function(e){var n=t.fetch();n?t.attributes(n):(t.attributes(e),t.save())},t.mergeNewest=function(e){var n=t.fetch();!n||!n.fetched_at||n.fetched_at<e.fetched_at?(t.attributes(e),t.save()):t.attributes(n)},t.clearStorage=function(){lib.storage.setItem(n,void 0)},t},lib.showable=function(t,e){return lib.model(t,e,"visible"),lib.destroyable(t,e),t.visible=!1,t.show=function(){return t.visible=!0,t},t.hide=function(){return t.visible=!1,t},t.toggle=function(){return t.visible=arguments.length?arguments[0]:!t.visible,t},t.onDestroy(t.hide),t},lib.showable.manager=function(){var t={},e=null;return t.manage=function(t){t.wheneverEqual("visible",!0,function(){e&&e!==t&&e.hide(),e=t}),t.wheneverEqual("visible",!1,function(){t===e&&(e=null)})},_(arguments).chain().flatten().each(t.manage),t},lib.storage=function(){function t(t,i,o,a){a=jQuery.extend({on_quota_exceeded:function(){e.setItem(t,i,{on_quota_exceeded:function(){console.log("Not writing "+t+" to localStorage: this value is too big.")}})}},a),o&&/QUOTA/.test(o.name)?(_(n).each(function(t,e){r.hasOwnProperty(e)||(r[e]=t),delete n[e]}),a.on_quota_exceeded()):console.log("Failed to write "+t+" to localStorage: "+o)}var e={},n=window.localStorage,r={};return e.getItem=function(t){if(!r.hasOwnProperty(t))try{r[t]=n[t]}catch(e){console.log("Not reading "+t+" from localStorage: "+e),r[t]=null}return r[t]},e.setItem=function(e,i,o){try{r[e]=i,n[e]=i}catch(a){t(e,i,a,o)}},e.use=function(t){n=t},e}(),function(){function t(t){return t.charAt(0).toUpperCase()+t.slice(1)}function e(t){return t.charAt(0).toLowerCase()+t.slice(1)}lib.camelize=function(n,r){var i=_(n.split(/_/)).map(function(e){return t(e)}).join("");return r?e(i):t(i)},lib.underscore=function(t){return t.replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/\-/g,"_").toLowerCase()}}(),lib.view=function(t){t.remove=function(){t.$el.remove()}};
Please sign in to comment.
Something went wrong with that request. Please try again.