Browse files

Update sammy and jquery

  • Loading branch information...
1 parent 5eacca9 commit 43fa9bd3e1475ca584365784e6dd02356c3f0c16 @quirkey committed Feb 4, 2012
View
2 Gemfile.lock
@@ -43,6 +43,7 @@ GEM
yajl-ruby
yajl-ruby
json (1.4.6)
+ keychain_services (0.1.1)
leftright (0.9.1)
metaclass (0.0.1)
mime-types (1.16)
@@ -74,6 +75,7 @@ DEPENDENCIES
jeweler
jim (~> 0.3.1)
json (~> 1.4.6)
+ keychain_services (~> 0.1.1)
mime-types (~> 1.16)
mustache (~> 0.99)
rake
View
4 lib/soca/templates/Jimfile
@@ -5,9 +5,9 @@
"bundles": {
"default": [
"sha1",
- [ "jquery", "1.4.2" ],
+ [ "jquery", "1.7.1" ],
[ "jquery.couch", "0.11" ],
- [ "sammy", "0.6.3" ],
+ [ "sammy", "0.7.1" ],
[ "sammy.couch", "0.1.0" ],
"js/app"
]
View
6,240 lib/soca/templates/js/vendor/jquery-1.4.2.js
0 additions, 6,240 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
9,266 lib/soca/templates/js/vendor/jquery-1.7.1.js
9,266 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
384 lib/soca/templates/js/vendor/sammy-0.6.3.js → lib/soca/templates/js/vendor/sammy-0.7.1.js
@@ -1,5 +1,5 @@
// name: sammy
-// version: 0.6.3
+// version: 0.7.1
// Sammy.js / http://sammyjs.org
@@ -8,13 +8,13 @@
var Sammy,
PATH_REPLACER = "([^\/]+)",
PATH_NAME_MATCHER = /:([\w\d]+)/g,
- QUERY_STRING_MATCHER = /\?([^#]*)$/,
+ QUERY_STRING_MATCHER = /\?([^#]*)?$/,
// mainly for making `arguments` an Array
_makeArray = function(nonarray) { return Array.prototype.slice.call(nonarray); },
// borrowed from jQuery
_isFunction = function( obj ) { return Object.prototype.toString.call(obj) === "[object Function]"; },
_isArray = function( obj ) { return Object.prototype.toString.call(obj) === "[object Array]"; },
- _decode = function( str ) { return decodeURIComponent(str.replace(/\+/g, ' ')); },
+ _decode = function( str ) { return decodeURIComponent((str || '').replace(/\+/g, ' ')); },
_encode = encodeURIComponent,
_escapeHTML = function(s) {
return String(s).replace(/&(?!\w+;)/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
@@ -23,6 +23,7 @@
return function(path, callback) { return this.route.apply(this, [verb, path, callback]); };
},
_template_cache = {},
+ _has_history = !!(window.history && history.pushState),
loggers = [];
@@ -43,7 +44,7 @@
// // returns the app at #main or a new app
// Sammy('#main')
//
- // // equivilent to "new Sammy.Application", except appends to apps
+ // // equivalent to "new Sammy.Application", except appends to apps
// Sammy();
// Sammy(function() { ... });
//
@@ -64,7 +65,7 @@
app.use(plugin);
});
}
- // if the selector changes make sure the refrence in Sammy.apps changes
+ // if the selector changes make sure the reference in Sammy.apps changes
if (app.element_selector != selector) {
delete Sammy.apps[selector];
}
@@ -73,7 +74,7 @@
}
};
- Sammy.VERSION = '0.6.3';
+ Sammy.VERSION = '0.7.1';
// Add to the global logger pool. Takes a function that accepts an
// unknown number of arguments and should print them or send them somewhere
@@ -113,7 +114,7 @@
makeArray: _makeArray,
isFunction: _isFunction,
isArray: _isArray
- })
+ });
// Sammy.Object is the base for all other Sammy classes. It provides some useful
// functionality, including cloning, iterating, etc.
@@ -171,7 +172,7 @@
// Checks if the object has a value at `key` and that the value is not empty
has: function(key) {
- return this[key] && $.trim(this[key].toString()) != '';
+ return this[key] && $.trim(this[key].toString()) !== '';
},
// convenience method to join as many arguments as you want
@@ -201,86 +202,136 @@
}
});
- // The HashLocationProxy is the default location proxy for all Sammy applications.
+ // The DefaultLocationProxy is the default location proxy for all Sammy applications.
// A location proxy is a prototype that conforms to a simple interface. The purpose
// of a location proxy is to notify the Sammy.Application its bound to when the location
- // or 'external state' changes. The HashLocationProxy considers the state to be
- // changed when the 'hash' (window.location.hash / '#') changes. It does this in two
- // different ways depending on what browser you are using. The newest browsers
- // (IE, Safari > 4, FF >= 3.6) support a 'onhashchange' DOM event, thats fired whenever
- // the location.hash changes. In this situation the HashLocationProxy just binds
- // to this event and delegates it to the application. In the case of older browsers
- // a poller is set up to track changes to the hash. Unlike Sammy 0.3 or earlier,
- // the HashLocationProxy allows the poller to be a global object, eliminating the
- // need for multiple pollers even when thier are multiple apps on the page.
- Sammy.HashLocationProxy = function(app, run_interval_every) {
+ // or 'external state' changes.
+ //
+ // The `DefaultLocationProxy` watches for changes to the path of the current window and
+ // is also able to set the path based on changes in the application. It does this by
+ // using different methods depending on what is available in the current browser. In
+ // the latest and greatest browsers it used the HTML5 History API and the `pushState`
+ // `popState` events/methods. This allows you to use Sammy to serve a site behind normal
+ // URI paths as opposed to the older default of hash (#) based routing. Because the server
+ // can interpret the changed path on a refresh or re-entry, though, it requires additional
+ // support on the server side. If you'd like to force disable HTML5 history support, please
+ // use the `disable_push_state` setting on `Sammy.Application`. If pushState support
+ // is enabled, `DefaultLocationProxy` also binds to all links on the page. If a link is clicked
+ // that matches the current set of routes, the URL is changed using pushState instead of
+ // fully setting the location and the app is notified of the change.
+ //
+ // If the browser does not have support for HTML5 History, `DefaultLocationProxy` automatically
+ // falls back to the older hash based routing. The newest browsers (IE, Safari > 4, FF >= 3.6)
+ // support a 'onhashchange' DOM event, thats fired whenever the location.hash changes.
+ // In this situation the DefaultLocationProxy just binds to this event and delegates it to
+ // the application. In the case of older browsers a poller is set up to track changes to the
+ // hash.
+ Sammy.DefaultLocationProxy = function(app, run_interval_every) {
this.app = app;
// set is native to false and start the poller immediately
this.is_native = false;
+ this.has_history = _has_history;
this._startPolling(run_interval_every);
};
- Sammy.HashLocationProxy.prototype = {
-
+ Sammy.DefaultLocationProxy.fullPath = function(location_obj) {
+ // Bypass the `window.location.hash` attribute. If a question mark
+ // appears in the hash IE6 will strip it and all of the following
+ // characters from `window.location.hash`.
+ var matches = location_obj.toString().match(/^[^#]*(#.+)$/);
+ var hash = matches ? matches[1] : '';
+ return [location_obj.pathname, location_obj.search, hash].join('');
+ };
+ Sammy.DefaultLocationProxy.prototype = {
// bind the proxy events to the current app.
bind: function() {
- var proxy = this, app = this.app;
+ var proxy = this, app = this.app, lp = Sammy.DefaultLocationProxy;
$(window).bind('hashchange.' + this.app.eventNamespace(), function(e, non_native) {
// if we receive a native hash change event, set the proxy accordingly
// and stop polling
if (proxy.is_native === false && !non_native) {
- Sammy.log('native hash change exists, using');
proxy.is_native = true;
- window.clearInterval(Sammy.HashLocationProxy._interval);
+ window.clearInterval(lp._interval);
}
app.trigger('location-changed');
});
- if (!Sammy.HashLocationProxy._bindings) {
- Sammy.HashLocationProxy._bindings = 0;
+ if (_has_history && !app.disable_push_state) {
+ // bind to popstate
+ $(window).bind('popstate.' + this.app.eventNamespace(), function(e) {
+ app.trigger('location-changed');
+ });
+ // bind to link clicks that have routes
+ $('a').live('click.history-' + this.app.eventNamespace(), function(e) {
+ if (e.isDefaultPrevented()) {
+ return;
+ }
+ var full_path = lp.fullPath(this);
+ if (this.hostname == window.location.hostname && app.lookupRoute('get', full_path)) {
+ e.preventDefault();
+ proxy.setLocation(full_path);
+ return false;
+ }
+ });
+ }
+ if (!lp._bindings) {
+ lp._bindings = 0;
}
- Sammy.HashLocationProxy._bindings++;
+ lp._bindings++;
},
// unbind the proxy events from the current app
unbind: function() {
$(window).unbind('hashchange.' + this.app.eventNamespace());
- Sammy.HashLocationProxy._bindings--;
- if (Sammy.HashLocationProxy._bindings <= 0) {
- window.clearInterval(Sammy.HashLocationProxy._interval);
+ $(window).unbind('popstate.' + this.app.eventNamespace());
+ $('a').die('click.history-' + this.app.eventNamespace());
+ Sammy.DefaultLocationProxy._bindings--;
+ if (Sammy.DefaultLocationProxy._bindings <= 0) {
+ window.clearInterval(Sammy.DefaultLocationProxy._interval);
}
},
// get the current location from the hash.
getLocation: function() {
- // Bypass the `window.location.hash` attribute. If a question mark
- // appears in the hash IE6 will strip it and all of the following
- // characters from `window.location.hash`.
- var matches = window.location.toString().match(/^[^#]*(#.+)$/);
- return matches ? matches[1] : '';
+ return Sammy.DefaultLocationProxy.fullPath(window.location);
},
// set the current location to `new_location`
setLocation: function(new_location) {
- return (window.location = new_location);
+ if (/^([^#\/]|$)/.test(new_location)) { // non-prefixed url
+ if (_has_history) {
+ new_location = '/' + new_location;
+ } else {
+ new_location = '#!/' + new_location;
+ }
+ }
+ if (new_location != this.getLocation()) {
+ // HTML5 History exists and new_location is a full path
+ if (_has_history && /^\//.test(new_location)) {
+ history.pushState({ path: new_location }, window.title, new_location);
+ this.app.trigger('location-changed');
+ } else {
+ return (window.location = new_location);
+ }
+ }
},
_startPolling: function(every) {
// set up interval
var proxy = this;
- if (!Sammy.HashLocationProxy._interval) {
+ if (!Sammy.DefaultLocationProxy._interval) {
if (!every) { every = 10; }
var hashCheck = function() {
var current_location = proxy.getLocation();
- if (!Sammy.HashLocationProxy._last_location ||
- current_location != Sammy.HashLocationProxy._last_location) {
+ if (typeof Sammy.DefaultLocationProxy._last_location == 'undefined' ||
+ current_location != Sammy.DefaultLocationProxy._last_location) {
window.setTimeout(function() {
$(window).trigger('hashchange', [true]);
}, 0);
}
- Sammy.HashLocationProxy._last_location = current_location;
+ Sammy.DefaultLocationProxy._last_location = current_location;
};
hashCheck();
- Sammy.HashLocationProxy._interval = window.setInterval(hashCheck, every);
+ Sammy.DefaultLocationProxy._interval = window.setInterval(hashCheck, every);
}
}
};
@@ -304,9 +355,9 @@
if (_isFunction(app_function)) {
app_function.apply(this, [this]);
}
- // set the location proxy if not defined to the default (HashLocationProxy)
+ // set the location proxy if not defined to the default (DefaultLocationProxy)
if (!this._location_proxy) {
- this.setLocationProxy(new Sammy.HashLocationProxy(this, this.run_interval_every));
+ this.setLocationProxy(new Sammy.DefaultLocationProxy(this, this.run_interval_every));
}
if (this.debug) {
this.bindToAllEvents(function(e, data) {
@@ -335,18 +386,22 @@
// When set to true, logs all of the default events using `log()`
debug: false,
- // When set to true, and the error() handler is not overriden, will actually
+ // When set to true, and the error() handler is not overridden, will actually
// raise JS errors in routes (500) and when routes can't be found (404)
raise_errors: false,
// The time in milliseconds that the URL is queried for changes
run_interval_every: 50,
+ // if using the `DefaultLocationProxy` setting this to true will force the app to use
+ // traditional hash based routing as opposed to the new HTML5 PushState support
+ disable_push_state: false,
+
// The default template engine to use when using `partial()` in an
// `EventContext`. `template_engine` can either be a string that
// corresponds to the name of a method/helper on EventContext or it can be a function
// that takes two arguments, the content of the unrendered partial and an optional
- // JS object that contains interpolation data. Template engine is only called/refered
+ // JS object that contains interpolation data. Template engine is only called/referred
// to if the extension of the partial is null or unknown. See `partial()`
// for more information
template_engine: null,
@@ -395,7 +450,7 @@
// });
//
// If plugin is passed as a string it assumes your are trying to load
- // Sammy."Plugin". This is the prefered way of loading core Sammy plugins
+ // Sammy."Plugin". This is the preferred way of loading core Sammy plugins
// as it allows for better error-messaging.
//
// ### Example
@@ -430,9 +485,9 @@
},
// Sets the location proxy for the current app. By default this is set to
- // a new `Sammy.HashLocationProxy` on initialization. However, you can set
+ // a new `Sammy.DefaultLocationProxy` on initialization. However, you can set
// the location_proxy inside you're app function to give your app a custom
- // location mechanism. See `Sammy.HashLocationProxy` and `Sammy.DataLocationProxy`
+ // location mechanism. See `Sammy.DefaultLocationProxy` and `Sammy.DataLocationProxy`
// for examples.
//
// `setLocationProxy()` takes an initialized location proxy.
@@ -456,6 +511,12 @@
}
},
+ // provide log() override for inside an app that includes the relevant application element_selector
+ log: function() {
+ Sammy.log.apply(Sammy, Array.prototype.concat.apply([this.element_selector],arguments));
+ },
+
+
// `route()` is the main method for defining routes within an application.
// For great detail on routes, check out:
// [http://sammyjs.org/docs/routes](http://sammyjs.org/docs/routes)
@@ -469,7 +530,7 @@
// the first argument is the path, the second is the callback and the verb
// is assumed to be 'any'.
// * `path` A Regexp or a String representing the path to match to invoke this verb.
- // * `callback` A Function that is called/evaluated whent the route is run see: `runRoute()`.
+ // * `callback` A Function that is called/evaluated when the route is run see: `runRoute()`.
// It is also possible to pass a string as the callback, which is looked up as the name
// of a method on the application.
//
@@ -499,7 +560,7 @@
param_names.push(path_match[1]);
}
// replace with the path replacement
- path = new RegExp("^" + path.replace(PATH_NAME_MATCHER, PATH_REPLACER) + "$");
+ path = new RegExp(path.replace(PATH_NAME_MATCHER, PATH_REPLACER) + "$");
}
// lookup callback
if (typeof callback == 'string') {
@@ -570,7 +631,7 @@
return ['sammy-app', this.namespace].join('-');
},
- // Works just like `jQuery.fn.bind()` with a couple noteable differences.
+ // Works just like `jQuery.fn.bind()` with a couple notable differences.
//
// * It binds all events to the application element
// * All events are bound within the `eventNamespace()`
@@ -683,7 +744,7 @@
// that take a single argument `callback` which is the entire route
// execution path wrapped up in a closure. This means you can decide whether
// or not to proceed with execution by not invoking `callback` or,
- // more usefuly wrapping callback inside the result of an asynchronous execution.
+ // more usefully wrapping callback inside the result of an asynchronous execution.
//
// ### Example
//
@@ -821,7 +882,7 @@
this._running = true;
// set last location
this.last_location = null;
- if (this.getLocation() == '' && typeof start_url != 'undefined') {
+ if (!(/\#(.+)/.test(this.getLocation())) && typeof start_url != 'undefined') {
this.setLocation(start_url);
}
// check url
@@ -847,7 +908,7 @@
},
// The opposite of `run()`, un-binds all event listeners and intervals
- // `run()` Automaticaly binds a `onunload` event to run this when
+ // `run()` Automatically binds a `onunload` event to run this when
// the document is closed.
unload: function() {
if (!this.isRunning()) { return false; }
@@ -880,7 +941,7 @@
});
// next, bind to listener names (only if they dont exist in APP_EVENTS)
$.each(this.listeners.keys(true), function(i, name) {
- if (app.APP_EVENTS.indexOf(name) == -1) {
+ if ($.inArray(name, app.APP_EVENTS) == -1) {
app.bind(name, callback);
}
});
@@ -896,15 +957,16 @@
// Given a verb and a String path, will return either a route object or false
// if a matching route can be found within the current defined set.
lookupRoute: function(verb, path) {
- var app = this, routed = false;
- this.trigger('lookup-route', {verb: verb, path: path});
+ var app = this, routed = false, i = 0, l, route;
if (typeof this.routes[verb] != 'undefined') {
- $.each(this.routes[verb], function(i, route) {
+ l = this.routes[verb].length;
+ for (; i < l; i++) {
+ route = this.routes[verb][i];
if (app.routablePath(path).match(route.path)) {
routed = route;
- return false;
+ break;
}
- });
+ }
}
return routed;
},
@@ -913,7 +975,7 @@
// possible URL params and then invokes the route's callback within a new
// `Sammy.EventContext`. If the route can not be found, it calls
// `notFound()`. If `raise_errors` is set to `true` and
- // the `error()` has not been overriden, it will throw an actual JS
+ // the `error()` has not been overridden, it will throw an actual JS
// error.
//
// You probably will never have to call this directly.
@@ -1020,7 +1082,7 @@
// // match against a path string
// app.contextMatchesOptions(context, '#/mypath'); //=> true
// app.contextMatchesOptions(context, '#/otherpath'); //=> false
- // // equivilent to
+ // // equivalent to
// app.contextMatchesOptions(context, {only: {path:'#/mypath'}}); //=> true
// app.contextMatchesOptions(context, {only: {path:'#/otherpath'}}); //=> false
// // match against a path regexp
@@ -1035,11 +1097,20 @@
// // match all except a path
// app.contextMatchesOptions(context, {except: {path:'#/otherpath'}}); //=> true
// app.contextMatchesOptions(context, {except: {path:'#/mypath'}}); //=> false
+ // // match multiple paths
+ // app.contextMatchesOptions(context, {path: ['#/mypath', '#/otherpath']}); //=> true
+ // app.contextMatchesOptions(context, {path: ['#/otherpath', '#/thirdpath']}); //=> false
+ // // equivalent to
+ // app.contextMatchesOptions(context, {only: {path: ['#/mypath', '#/otherpath']}}); //=> true
+ // app.contextMatchesOptions(context, {only: {path: ['#/otherpath', '#/thirdpath']}}); //=> false
+ // // match all except multiple paths
+ // app.contextMatchesOptions(context, {except: {path: ['#/mypath', '#/otherpath']}}); //=> false
+ // app.contextMatchesOptions(context, {except: {path: ['#/otherpath', '#/thirdpath']}}); //=> true
//
contextMatchesOptions: function(context, match_options, positive) {
// empty options always match
var options = match_options;
- if (typeof options === 'undefined' || options == {}) {
+ if (typeof options === 'undefined' || $.isPlainObject(options)) {
return true;
}
if (typeof positive === 'undefined') {
@@ -1049,35 +1120,49 @@
if (typeof options === 'string' || _isFunction(options.test)) {
options = {path: options};
}
+ // Do we have to match against multiple paths?
+ if (_isArray(options.path)){
+ var results, numopt, opts;
+ results = [];
+ for (numopt in options.path){
+ opts = $.extend({}, options, {path: options.path[numopt]});
+ results.push(this.contextMatchesOptions(context, opts));
+ }
+ var matched = $.inArray(true, results) > -1 ? true : false;
+ return positive ? matched : !matched;
+ }
if (options.only) {
return this.contextMatchesOptions(context, options.only, true);
} else if (options.except) {
return this.contextMatchesOptions(context, options.except, false);
}
var path_matched = true, verb_matched = true;
if (options.path) {
- // wierd regexp test
- if (_isFunction(options.path.test)) {
- path_matched = options.path.test(context.path);
- } else {
- path_matched = (options.path.toString() === context.path);
+ // weird regexp test
+ if (!_isFunction(options.path.test)) {
+ options.path = new RegExp(options.path.toString() + '$');
}
+ path_matched = options.path.test(context.path);
}
if (options.verb) {
- verb_matched = options.verb === context.verb;
+ if(typeof options.verb === 'string') {
+ verb_matched = options.verb === context.verb;
+ } else {
+ verb_matched = options.verb.indexOf(context.verb) > -1;
+ }
}
return positive ? (verb_matched && path_matched) : !(verb_matched && path_matched);
},
// Delegates to the `location_proxy` to get the current location.
- // See `Sammy.HashLocationProxy` for more info on location proxies.
+ // See `Sammy.DefaultLocationProxy` for more info on location proxies.
getLocation: function() {
return this._location_proxy.getLocation();
},
// Delegates to the `location_proxy` to set the current location.
- // See `Sammy.HashLocationProxy` for more info on location proxies.
+ // See `Sammy.DefaultLocationProxy` for more info on location proxies.
//
// ### Arguments
//
@@ -1096,23 +1181,29 @@
// var app = $.sammy(function() {
//
// // implements a 'fade out'/'fade in'
- // this.swap = function(content) {
- // this.$element().hide('slow').html(content).show('slow');
- // }
- //
- // get('#/', function() {
- // this.partial('index.html.erb') // will fade out and in
- // });
+ // this.swap = function(content, callback) {
+ // var context = this;
+ // context.$element().fadeOut('slow', function() {
+ // context.$element().html(content);
+ // context.$element().fadeIn('slow', function() {
+ // if (callback) {
+ // callback.apply();
+ // }
+ // });
+ // });
+ // };
//
// });
//
- swap: function(content) {
- return this.$element().html(content);
+ swap: function(content, callback) {
+ var $el = this.$element().html(content);
+ if (_isFunction(callback)) { callback(content); }
+ return $el;
},
// a simple global cache for templates. Uses the same semantics as
// `Sammy.Cache` and `Sammy.Storage` so can easily be replaced with
- // a persistant storage that lasts beyond the current request.
+ // a persistent storage that lasts beyond the current request.
templateCache: function(key, value) {
if (typeof value != 'undefined') {
return _template_cache[key] = value;
@@ -1126,7 +1217,7 @@
return _template_cache = {};
},
- // This thows a '404 Not Found' error by invoking `error()`.
+ // This throws a '404 Not Found' error by invoking `error()`.
// Override this method or `error()` to provide custom
// 404 behavior (i.e redirecting to / or showing a warning)
notFound: function(verb, path) {
@@ -1178,16 +1269,18 @@
var $form, path, verb, params, returned;
this.trigger('check-form-submission', {form: form});
$form = $(form);
- path = $form.attr('action');
+ path = $form.attr('action') || '';
verb = this._getFormVerb($form);
this.log('_checkFormSubmission', $form, path, verb);
if (verb === 'get') {
- this.setLocation(path + '?' + this._serializeFormParams($form));
+ params = this._serializeFormParams($form);
+ if (params !== '') { path += '?' + params; }
+ this.setLocation(path);
returned = false;
} else {
params = $.extend({}, this._parseFormParams($form));
returned = this.runRoute(verb, path, params, form.get(0));
- };
+ }
return (typeof returned == 'undefined') ? false : returned;
},
@@ -1233,7 +1326,7 @@
},
_parseParamPair: function(params, key, value) {
- if (params[key]) {
+ if (typeof params[key] !== 'undefined') {
if (_isArray(params[key])) {
params[key].push(value);
} else {
@@ -1256,11 +1349,11 @@
});
// `Sammy.RenderContext` is an object that makes sequential template loading,
- // rendering and interpolation seamless even when dealing with asyncronous
+ // rendering and interpolation seamless even when dealing with asynchronous
// operations.
//
// `RenderContext` objects are not usually created directly, rather they are
- // instatiated from an `Sammy.EventContext` by using `render()`, `load()` or
+ // instantiated from an `Sammy.EventContext` by using `render()`, `load()` or
// `partial()` which all return `RenderContext` objects.
//
// `RenderContext` methods always returns a modified `RenderContext`
@@ -1269,7 +1362,7 @@
// The core magic is in the `then()` method which puts the callback passed as
// an argument into a queue to be executed once the previous callback is complete.
// All the methods of `RenderContext` are wrapped in `then()` which allows you
- // to queue up methods by chaining, but maintaing a guarunteed execution order
+ // to queue up methods by chaining, but maintaining a guaranteed execution order
// even with remote calls to fetch templates.
//
Sammy.RenderContext = function(event_context) {
@@ -1290,9 +1383,9 @@
// is executed immediately.
//
// The value returned from the callback is stored in `content` for the
- // subsiquent operation. If you return `false`, the queue will pause, and
+ // subsequent operation. If you return `false`, the queue will pause, and
// the next callback in the queue will not be executed until `next()` is
- // called. This allows for the guarunteed order of execution while working
+ // called. This allows for the guaranteed order of execution while working
// with async operations.
//
// If then() is passed a string instead of a function, the string is looked
@@ -1380,7 +1473,7 @@
},
// Load a template into the context.
- // The `location` can either be a string specifiying the remote path to the
+ // The `location` can either be a string specifying the remote path to the
// file, a jQuery object, or a DOM element.
//
// No interpolation happens by default, the content is stored in
@@ -1429,7 +1522,7 @@
$.ajax($.extend({
url: location,
data: {},
- dataType: is_json ? 'json' : null,
+ dataType: is_json ? 'json' : 'text',
type: 'get',
success: function(data) {
if (should_cache) {
@@ -1457,6 +1550,28 @@
});
},
+ // Load partials
+ //
+ // ### Example
+ //
+ // this.loadPartials({mypartial: '/path/to/partial'});
+ //
+ loadPartials: function(partials) {
+ var name;
+ if(partials) {
+ this.partials = this.partials || {};
+ for(name in partials) {
+ (function(context, name) {
+ context.load(partials[name])
+ .then(function(template) {
+ this.partials[name] = template;
+ });
+ })(this, name);
+ }
+ }
+ return this;
+ },
+
// `load()` a template and then `interpolate()` it with data.
//
// ### Example
@@ -1465,20 +1580,28 @@
// this.render('mytemplate.template', {name: 'test'});
// });
//
- render: function(location, data, callback) {
+ render: function(location, data, callback, partials) {
if (_isFunction(location) && !data) {
return this.then(location);
} else {
- return this.load(location)
+ return this.loadPartials(partials)
+ .load(location)
.interpolate(data, location)
.then(callback);
}
},
- // `render()` the the `location` with `data` and then `swap()` the
+ // `render()` the `location` with `data` and then `swap()` the
// app's `$element` with the rendered content.
- partial: function(location, data) {
- return this.render(location, data).swap();
+ partial: function(location, data, callback) {
+ if (_isFunction(callback)) {
+ return this.render(location, data).swap(callback);
+ } else if (!callback && _isFunction(data)) {
+ // invoked as partial(location, callback)
+ return this.render(location).swap(data);
+ } else {
+ return this.render(location, data).swap();
+ }
},
// defers the call of function to occur in order of the render queue.
@@ -1510,7 +1633,7 @@
});
},
- // itterates over an array, applying the callback for each item item. the
+ // iterates over an array, applying the callback for each item item. the
// callback takes the same style of arguments as `jQuery.each()` (index, item).
// The return value of each callback is collected as a single string and stored
// as `content` to be used in the next iteration of the `RenderContext`.
@@ -1579,15 +1702,16 @@
engine = this.next_engine;
this.next_engine = false;
}
- var rendered = context.event_context.interpolate(content, data, engine);
+ var rendered = context.event_context.interpolate(content, data, engine, this.partials);
return retain ? prev + rendered : rendered;
});
},
- // executes `EventContext#swap()` with the `content`
- swap: function() {
+ // Swap the return contents ensuring order. See `Application#swap`
+ swap: function(callback) {
return this.then(function(content) {
- this.event_context.swap(content);
+ this.event_context.swap(content, callback);
+ return content;
}).trigger('changed', {});
},
@@ -1614,12 +1738,13 @@
},
// trigger the event in the order of the event context. Same semantics
- // as `Sammy.EventContext#trigger()`. If data is ommitted, `content`
+ // as `Sammy.EventContext#trigger()`. If data is omitted, `content`
// is sent as `{content: content}`
trigger: function(name, data) {
return this.then(function(content) {
if (typeof data == 'undefined') { data = {content: content}; }
this.event_context.trigger(name, data);
+ return content;
});
}
@@ -1674,10 +1799,10 @@
// Look up a templating engine within the current app and context.
// `engine` can be one of the following:
//
- // * a function: should conform to `function(content, data) { return interploated; }`
+ // * a function: should conform to `function(content, data) { return interpolated; }`
// * a template path: 'template.ejs', looks up the extension to match to
// the `ejs()` helper
- // * a string referering to the helper: "mustache" => `mustache()`
+ // * a string referring to the helper: "mustache" => `mustache()`
//
// If no engine is found, use the app's default `template_engine`
//
@@ -1687,7 +1812,7 @@
if (_isFunction(engine)) { return engine; }
// lookup engine name by path extension
engine = (engine || context.app.template_engine).toString();
- if ((engine_match = engine.match(/\.([^\.]+)$/))) {
+ if ((engine_match = engine.match(/\.([^\.\?\#]+)$/))) {
engine = engine_match[1];
}
// set the engine to the default template engine if no match is found
@@ -1703,8 +1828,8 @@
// using the template `engine` found with `engineFor()`, interpolate the
// `data` into `content`
- interpolate: function(content, data, engine) {
- return this.engineFor(engine).apply(this, [content, data]);
+ interpolate: function(content, data, engine, partials) {
+ return this.engineFor(engine).apply(this, [content, data, partials]);
},
// Create and return a `Sammy.RenderContext` calling `render()` on it.
@@ -1720,8 +1845,8 @@
// .appendTo('ul');
// // appends the rendered content to $('ul')
//
- render: function(location, data, callback) {
- return new Sammy.RenderContext(this).render(location, data, callback);
+ render: function(location, data, callback, partials) {
+ return new Sammy.RenderContext(this).render(location, data, callback, partials);
},
// Create and return a `Sammy.RenderContext` calling `renderEach()` on it.
@@ -1747,10 +1872,10 @@
return new Sammy.RenderContext(this).load(location, options, callback);
},
- // `render()` the the `location` with `data` and then `swap()` the
+ // `render()` the `location` with `data` and then `swap()` the
// app's `$element` with the rendered content.
- partial: function(location, data) {
- return new Sammy.RenderContext(this).partial(location, data);
+ partial: function(location, data, callback) {
+ return new Sammy.RenderContext(this).partial(location, data, callback);
},
// create a new `Sammy.RenderContext` calling `send()` with an arbitrary
@@ -1767,22 +1892,37 @@
// ### Example
//
// redirect('#/other/route');
- // // equivilent to
+ // // equivalent to
// redirect('#', 'other', 'route');
//
redirect: function() {
var to, args = _makeArray(arguments),
- current_location = this.app.getLocation();
- if (args.length > 1) {
- args.unshift('/');
- to = this.join.apply(this, args);
+ current_location = this.app.getLocation(),
+ l = args.length;
+ if (l > 1) {
+ var i = 0, paths = [], pairs = [], params = {}, has_params = false;
+ for (; i < l; i++) {
+ if (typeof args[i] == 'string') {
+ paths.push(args[i]);
+ } else {
+ $.extend(params, args[i]);
+ has_params = true;
+ }
+ }
+ to = paths.join('/');
+ if (has_params) {
+ for (var k in params) {
+ pairs.push(this.app._encodeFormPair(k, params[k]));
+ }
+ to += '?' + pairs.join('&');
+ }
} else {
to = args[0];
}
this.trigger('redirect', {to: to});
this.app.last_location = [this.verb, this.path];
this.app.setLocation(to);
- if (current_location == to) {
+ if (new RegExp(to).test(current_location)) {
this.app.trigger('location-changed');
}
},
@@ -1800,8 +1940,8 @@
},
// A shortcut to app's `swap()`
- swap: function(contents) {
- return this.app.swap(contents);
+ swap: function(contents, callback) {
+ return this.app.swap(contents, callback);
},
// Raises a possible `notFound()` error for the current path.

0 comments on commit 43fa9bd

Please sign in to comment.