jim 0.2.3 → 0.3.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. data/Gemfile +2 -1
  2. data/Gemfile.lock +2 -0
  3. data/HISTORY +13 -0
  4. data/README.md +148 -0
  5. data/Rakefile +6 -3
  6. data/bin/jim +1 -2
  7. data/default +0 -0
  8. data/jim.gemspec +142 -105
  9. data/lib/jim.rb +1 -1
  10. data/lib/jim/bundler.rb +168 -73
  11. data/lib/jim/cli.rb +200 -151
  12. data/lib/jim/index.rb +20 -9
  13. data/lib/jim/installer.rb +46 -46
  14. data/lib/jim/rack.rb +57 -20
  15. data/lib/jim/templates/jimfile +11 -5
  16. data/lib/jim/version_parser.rb +3 -3
  17. data/test/fixtures/infoincomments.js +1 -1
  18. data/test/fixtures/jimfile +14 -7
  19. data/test/fixtures/jquery-1.4.1.js +3 -6057
  20. data/test/fixtures/jquery.color.js +1 -1
  21. data/test/fixtures/localfile.js +1 -1
  22. data/test/fixtures/mustache.js/package.json +1 -1
  23. data/test/fixtures/noversion.js +1 -1
  24. data/test/fixtures/old_jimfile +7 -0
  25. data/test/fixtures/sammy-0.5.0/examples/backend/app.rb +4 -4
  26. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/app.js +18 -18
  27. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.cloudkit.js +1 -1
  28. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.js +1 -1
  29. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/sammy.js +161 -161
  30. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task.html.erb +1 -1
  31. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task_details.html.erb +1 -1
  32. data/test/fixtures/sammy-0.5.0/examples/backend/views/app.sass +6 -6
  33. data/test/fixtures/sammy-0.5.0/examples/backend/views/index.haml +5 -5
  34. data/test/fixtures/sammy-0.5.0/examples/form_handling/index.html +16 -16
  35. data/test/fixtures/sammy-0.5.0/examples/hello_world/index.html +13 -13
  36. data/test/fixtures/sammy-0.5.0/examples/location_override/data.html +28 -28
  37. data/test/fixtures/sammy-0.5.0/examples/location_override/index.html +18 -18
  38. data/test/fixtures/sammy-0.5.0/examples/location_override/test.html +36 -36
  39. data/test/fixtures/sammy-0.5.0/lib/min/sammy-0.5.0.min.js +1 -1
  40. data/test/fixtures/sammy-0.5.0/lib/min/sammy-lastest.min.js +1 -1
  41. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.cache.js +13 -13
  42. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.haml.js +2 -2
  43. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.json.js +15 -15
  44. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.mustache.js +46 -46
  45. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.nested_params.js +29 -29
  46. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.storage.js +54 -54
  47. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.template.js +17 -17
  48. data/test/fixtures/sammy-0.5.0/lib/sammy.js +220 -220
  49. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.html +1 -1
  50. data/test/fixtures/sammy-0.5.0/test/index.html +26 -26
  51. data/test/fixtures/sammy-0.5.0/test/test_sammy_application.js +60 -60
  52. data/test/fixtures/sammy-0.5.0/test/test_sammy_event_context.js +21 -21
  53. data/test/fixtures/sammy-0.5.0/test/test_sammy_location_proxy.js +3 -3
  54. data/test/fixtures/sammy-0.5.0/test/test_sammy_plugins.js +17 -17
  55. data/test/fixtures/sammy-0.5.0/test/test_sammy_storage.js +4 -4
  56. data/test/helper.rb +15 -0
  57. data/test/test_jim_bundler.rb +114 -74
  58. data/test/test_jim_cli.rb +34 -18
  59. data/test/test_jim_index.rb +19 -19
  60. data/test/test_jim_installer.rb +13 -13
  61. data/test/test_jim_rack.rb +41 -0
  62. data/test/test_jim_version_parser.rb +4 -4
  63. metadata +204 -41
  64. data/.gitignore +0 -24
  65. data/README.rdoc +0 -105
  66. data/lib/jim/templates/commands +0 -58
@@ -4,12 +4,12 @@
4
4
 
5
5
  // Sammy.Store is an abstract adapter class that wraps the multitude of in
6
6
  // browser data storage into a single common set of methods for storing and
7
- // retreiving data. The JSON library is used (through the inclusion of the
8
- // Sammy.JSON) plugin, to automatically convert objects back and forth from
7
+ // retreiving data. The JSON library is used (through the inclusion of the
8
+ // Sammy.JSON) plugin, to automatically convert objects back and forth from
9
9
  // stored strings.
10
- //
10
+ //
11
11
  // Sammy.Store can be used directly, but within a Sammy.Application it is much
12
- // easier to use the <tt>Sammy.Storage</tt> plugin and its helper methods.
12
+ // easier to use the <tt>Sammy.Storage</tt> plugin and its helper methods.
13
13
  //
14
14
  // Sammy.Store also supports the KVO pattern, by firing DOM/jQuery Events when
15
15
  // a key is set.
@@ -28,18 +28,18 @@
28
28
  // store.keys(); //=> ['json']
29
29
  // store.clearAll();
30
30
  // store.keys(); //=> []
31
- //
31
+ //
32
32
  // === Arguments
33
33
  //
34
34
  // The constructor takes a single argument which is a Object containing these possible options.
35
- //
35
+ //
36
36
  // +name+:: The name/namespace of this store. Stores are unique by name/type. (default 'store')
37
37
  // +element+:: A selector for the element that the store is bound to. (default 'body')
38
38
  // +type+:: The type of storage/proxy to use (default 'memory')
39
- //
39
+ //
40
40
  // Extra options are passed to the storage constructor.
41
41
  // Sammy.Store supports the following methods of storage:
42
- //
42
+ //
43
43
  // +memory+:: Basic object storage
44
44
  // +data+:: jQuery.data DOM Storage
45
45
  // +cookie+:: Access to document.cookie. Limited to 2K
@@ -79,14 +79,14 @@
79
79
  },
80
80
  // Sets the value of <tt>key<tt> with <tt>value</tt>. If <tt>value<tt> is an
81
81
  // object, it is turned to and stored as a string with <tt>JSON.stringify</tt>.
82
- // It also tries to conform to the KVO pattern triggering jQuery events on the
82
+ // It also tries to conform to the KVO pattern triggering jQuery events on the
83
83
  // element that the store is bound to.
84
- //
84
+ //
85
85
  // === Example
86
86
  //
87
87
  // var store = new Sammy.Store({name: 'kvo'});
88
- // $('body').bind('set-kvo.foo', function() {
89
- // alert('foo changed!')
88
+ // $('body').bind('set-kvo.foo', function() {
89
+ // alert('foo changed!')
90
90
  // });
91
91
  // store.set('foo', 'bar'); // alerted: foo changed!
92
92
  //
@@ -94,13 +94,13 @@
94
94
  var string_value = (typeof value == 'string') ? value : JSON.stringify(value);
95
95
  key = key.toString();
96
96
  this.storage.set(key, string_value);
97
- if (key != this.meta_key) {
98
- this._addKey(key);
97
+ if (key != this.meta_key) {
98
+ this._addKey(key);
99
99
  this.$element.trigger('set-' + this.name + '.' + key, [key, value]);
100
100
  };
101
101
  return string_value;
102
102
  },
103
- // Returns the set value at <tt>key</tt>, parsing with <tt>JSON.parse</tt> and
103
+ // Returns the set value at <tt>key</tt>, parsing with <tt>JSON.parse</tt> and
104
104
  // turning into an object if possible
105
105
  get: function(key) {
106
106
  var value = this.storage.get(key);
@@ -132,9 +132,9 @@
132
132
  },
133
133
  // Returns the value at <tt>key</tt> if set, otherwise, runs the callback
134
134
  // and sets the value to the value returned in the callback.
135
- //
135
+ //
136
136
  // === Example
137
- //
137
+ //
138
138
  // var store = new Sammy.Store;
139
139
  // store.exists('foo'); //=> false
140
140
  // store.fetch('foo', function() {
@@ -144,7 +144,7 @@
144
144
  // store.fetch('foo', function() {
145
145
  // return 'baz!';
146
146
  // }); //=> 'bar!
147
- //
147
+ //
148
148
  fetch: function(key, callback) {
149
149
  if (!this.exists(key)) {
150
150
  return this.set(key, callback.apply(this));
@@ -153,20 +153,20 @@
153
153
  }
154
154
  },
155
155
  // loads the response of a request to <tt>path</tt> into <tt>key</tt>.
156
- //
156
+ //
157
157
  // === Example
158
- //
158
+ //
159
159
  // In /mytemplate.tpl:
160
- //
160
+ //
161
161
  // My Template
162
- //
162
+ //
163
163
  // In app.js:
164
- //
164
+ //
165
165
  // var store = new Sammy.Store;
166
166
  // store.load('mytemplate', '/mytemplate.tpl', function() {
167
167
  // s.get('mytemplate') //=> My Template
168
168
  // });
169
- //
169
+ //
170
170
  load: function(key, path, callback) {
171
171
  var s = this;
172
172
  $.get(path, function(response) {
@@ -186,7 +186,7 @@
186
186
  this.set(this.meta_key, keys);
187
187
  }
188
188
  });
189
-
189
+
190
190
  // Tests if the type of storage is available/works in the current browser/config.
191
191
  // Especially useful for testing the availability of the awesome, but not widely
192
192
  // supported HTML5 DOM storage
@@ -198,7 +198,7 @@
198
198
  }
199
199
  };
200
200
 
201
- // Memory ('memory') is the basic/default store. It stores data in a global
201
+ // Memory ('memory') is the basic/default store. It stores data in a global
202
202
  // JS object. Data is lost on refresh.
203
203
  Sammy.Store.Memory = function(name, element) {
204
204
  this.name = name;
@@ -252,12 +252,12 @@
252
252
  });
253
253
 
254
254
  // LocalStorage ('local') makes use of HTML5 DOM Storage, and the window.localStorage
255
- // object. The great advantage of this method is that data will persist beyond
256
- // the current request. It can be considered a pretty awesome replacement for
255
+ // object. The great advantage of this method is that data will persist beyond
256
+ // the current request. It can be considered a pretty awesome replacement for
257
257
  // cookies accessed via JS. The great disadvantage, though, is its only available
258
- // on the latest and greatest browsers.
258
+ // on the latest and greatest browsers.
259
259
  //
260
- // For more info on DOM Storage:
260
+ // For more info on DOM Storage:
261
261
  // [https://developer.mozilla.org/en/DOM/Storage]
262
262
  // [http://www.w3.org/TR/2009/WD-webstorage-20091222/]
263
263
  //
@@ -284,10 +284,10 @@
284
284
  _key: function(key) {
285
285
  return ['store', this.element, this.name, key].join('.');
286
286
  }
287
- });
287
+ });
288
288
 
289
289
  // .SessionStorage ('session') is similar to LocalStorage (part of the same API)
290
- // and shares similar browser support/availability. The difference is that
290
+ // and shares similar browser support/availability. The difference is that
291
291
  // SessionStorage is only persistant through the current 'session' which is defined
292
292
  // as the length that the current window is open. This means that data will survive
293
293
  // refreshes but not close/open or multiple windows/tabs. For more info, check out
@@ -328,7 +328,7 @@
328
328
  // +expires_in+:: Number of seconds to keep the cookie alive (default 2 weeks).
329
329
  // +path+:: The path to activate the current cookie for (default '/').
330
330
  //
331
- // For more information about document.cookie, check out the pre-eminint article
331
+ // For more information about document.cookie, check out the pre-eminint article
332
332
  // by ppk: [http://www.quirksmode.org/js/cookies.html]
333
333
  //
334
334
  Sammy.Store.Cookie = function(name, element, options) {
@@ -337,7 +337,7 @@
337
337
  this.options = options || {};
338
338
  this.path = this.options.path || '/';
339
339
  // set the expires in seconds or default 14 days
340
- this.expires_in = this.options.expires_in || (14 * 24 * 60 * 60);
340
+ this.expires_in = this.options.expires_in || (14 * 24 * 60 * 60);
341
341
  };
342
342
  $.extend(Sammy.Store.Cookie.prototype, {
343
343
  isAvailable: function() {
@@ -368,13 +368,13 @@
368
368
  var date = new Date();
369
369
  date.setTime(date.getTime() + expires);
370
370
  var set_cookie = [
371
- this._key(key), "=", value,
372
- "; expires=", date.toGMTString(),
371
+ this._key(key), "=", value,
372
+ "; expires=", date.toGMTString(),
373
373
  "; path=", this.path
374
374
  ].join('');
375
375
  document.cookie = set_cookie;
376
376
  }
377
- });
377
+ });
378
378
 
379
379
  // Sammy.Storage is a plugin that provides shortcuts for creating and using
380
380
  // Sammy.Store objects. Once included it provides the <tt>store()</tt> app level
@@ -387,26 +387,26 @@
387
387
  // <tt>store()</tt> creates and looks up existing <tt>Sammy.Store</tt> objects
388
388
  // for the current application. The first time used for a given <tt>'name'</tt>
389
389
  // initializes a <tt>Sammy.Store</tt> and also creates a helper under the store's
390
- // name.
390
+ // name.
391
391
  //
392
392
  // === Example
393
393
  //
394
394
  // var app = $.sammy(function() {
395
395
  // this.use(Sammy.Storage);
396
- //
396
+ //
397
397
  // // initializes the store on app creation.
398
398
  // this.store('mystore', {type: 'cookie'});
399
- //
399
+ //
400
400
  // this.get('#/', function() {
401
401
  // // returns the Sammy.Store object
402
- // this.store('mystore');
402
+ // this.store('mystore');
403
403
  // // sets 'foo' to 'bar' using the shortcut/helper
404
404
  // // equivilent to this.store('mystore').set('foo', 'bar');
405
- // this.mystore('foo', 'bar');
405
+ // this.mystore('foo', 'bar');
406
406
  // // returns 'bar'
407
407
  // // equivilent to this.store('mystore').get('foo');
408
408
  // this.mystore('foo');
409
- // // returns 'baz!'
409
+ // // returns 'baz!'
410
410
  // // equivilent to:
411
411
  // // this.store('mystore').fetch('foo!', function() {
412
412
  // // return 'baz!';
@@ -415,11 +415,11 @@
415
415
  // return 'baz!';
416
416
  // });
417
417
  //
418
- // this.clearMystore();
418
+ // this.clearMystore();
419
419
  // // equivilent to:
420
420
  // // this.store('mystore').clearAll()
421
421
  // });
422
- //
422
+ //
423
423
  // });
424
424
  //
425
425
  // === Arguments
@@ -429,11 +429,11 @@
429
429
  //
430
430
  this.store = function(name, options) {
431
431
  // if the store has not been initialized
432
- if (typeof this.stores[name] == 'undefined') {
432
+ if (typeof this.stores[name] == 'undefined') {
433
433
  // create initialize the store
434
434
  var clear_method_name = "clear" + name.substr(0,1).toUpperCase() + name.substr(1);
435
435
  this.stores[name] = new Sammy.Store($.extend({
436
- name: name,
436
+ name: name,
437
437
  element: this.element_selector
438
438
  }, options || {}));
439
439
  // app.name()
@@ -461,18 +461,18 @@
461
461
  }
462
462
  return this.stores[name];
463
463
  };
464
-
464
+
465
465
  this.helpers({
466
466
  store: function() {
467
467
  return this.app.store.apply(this.app, arguments);
468
468
  }
469
469
  });
470
470
  };
471
-
471
+
472
472
  // Sammy.Session is an additional plugin for creating a common 'session' store
473
473
  // for the given app. It is a very simple wrapper around <tt>Sammy.Storage</tt>
474
474
  // that provides a simple fallback mechanism for trying to provide the best
475
- // possible storage type for the session. This means, <tt>LocalStorage</tt>
475
+ // possible storage type for the session. This means, <tt>LocalStorage</tt>
476
476
  // if available, otherwise <tt>Cookie</tt>, otherwise <tt>Memory</tt>.
477
477
  // It provides the <tt>session()</tt> helper through <tt>Sammy.Storage#store()</tt>.
478
478
  //
@@ -489,8 +489,8 @@
489
489
  }
490
490
  this.store('session', $.extend({type: type}, options));
491
491
  };
492
-
493
- // Sammy.Cache provides helpers for caching data within the lifecycle of a
492
+
493
+ // Sammy.Cache provides helpers for caching data within the lifecycle of a
494
494
  // Sammy app. The plugin provides two main methods on <tt>Sammy.Application<tt>,
495
495
  // <tt>cache</tt> and <tt>clearCache</tt>. Each app has its own cache store so that
496
496
  // you dont have to worry about collisions. As of 0.5 the original Sammy.Cache module
@@ -511,5 +511,5 @@
511
511
  }
512
512
  this.store('cache', $.extend({type: type}, options));
513
513
  };
514
-
515
- })(jQuery);
514
+
515
+ })(jQuery);
@@ -1,5 +1,5 @@
1
1
  (function($) {
2
-
2
+
3
3
  // Simple JavaScript Templating
4
4
  // John Resig - http://ejohn.org/ - MIT Licensed
5
5
  // adapted from: http://ejohn.org/blog/javascript-micro-templating/
@@ -8,7 +8,7 @@
8
8
  var srender_cache = {};
9
9
  var srender = function(name, template, data) {
10
10
  // target is an optional element; if provided, the result will be inserted into it
11
- // otherwise the result will simply be returned to the caller
11
+ // otherwise the result will simply be returned to the caller
12
12
  if (srender_cache[name]) {
13
13
  fn = srender_cache[name];
14
14
  } else {
@@ -43,15 +43,15 @@
43
43
  return fn;
44
44
  }
45
45
  };
46
-
46
+
47
47
  Sammy = Sammy || {};
48
48
 
49
49
  // <tt>Sammy.Template</tt> is a simple plugin that provides a way to create
50
50
  // and render client side templates. The rendering code is based on John Resig's
51
- // quick templates and Greg Borenstien's srender plugin.
52
- // This is also a great template/boilerplate for Sammy plugins.
51
+ // quick templates and Greg Borenstien's srender plugin.
52
+ // This is also a great template/boilerplate for Sammy plugins.
53
53
  //
54
- // Templates use <% %> tags to denote embedded javascript.
54
+ // Templates use <% %> tags to denote embedded javascript.
55
55
  //
56
56
  // === Examples
57
57
  //
@@ -65,11 +65,11 @@
65
65
  // </div>
66
66
  //
67
67
  // Given that is a publicly accesible file, you would render it like:
68
- //
68
+ //
69
69
  // $.sammy(function() {
70
70
  // // include the plugin
71
71
  // this.use(Sammy.Template);
72
- //
72
+ //
73
73
  // this.get('#/', function() {
74
74
  // // the template is rendered in the current context.
75
75
  // this.user = {name: 'Aaron Quint'};
@@ -79,9 +79,9 @@
79
79
  // });
80
80
  //
81
81
  // You can also pass a second argument to use() that will alias the template
82
- // method and therefore allow you to use a different extension for template files
82
+ // method and therefore allow you to use a different extension for template files
83
83
  // in <tt>partial()</tt>
84
- //
84
+ //
85
85
  // // alias to 'tpl'
86
86
  // this.use(Sammy.Template, 'tpl');
87
87
  //
@@ -91,13 +91,13 @@
91
91
  // });
92
92
  //
93
93
  Sammy.Template = function(app, method_alias) {
94
-
94
+
95
95
  // *Helper:* Uses simple templating to parse ERB like templates.
96
96
  //
97
97
  // === Arguments
98
- //
98
+ //
99
99
  // +template+:: A String template. '<% %>' tags are evaluated as Javascript and replaced with the elements in data.
100
- // +data+:: An Object containing the replacement values for the template.
100
+ // +data+:: An Object containing the replacement values for the template.
101
101
  // data is extended with the <tt>EventContext</tt> allowing you to call its methods within the template.
102
102
  // +name+:: An optional String name to cache the template.
103
103
  //
@@ -106,12 +106,12 @@
106
106
  if (typeof name == 'undefined') name = template;
107
107
  return srender(name, template, $.extend({}, this, data));
108
108
  };
109
-
109
+
110
110
  // set the default method name/extension
111
- if (!method_alias) method_alias = 'template';
111
+ if (!method_alias) method_alias = 'template';
112
112
  // create the helper at the method alias
113
113
  app.helper(method_alias, template);
114
-
114
+
115
115
  };
116
116
 
117
- })(jQuery);
117
+ })(jQuery);
@@ -2,7 +2,7 @@
2
2
  // version: 0.5.0
3
3
 
4
4
  ;(function($) {
5
-
5
+
6
6
  var PATH_REPLACER = "([^\/]+)",
7
7
  PATH_NAME_MATCHER = /:([\w\d]+)/g,
8
8
  QUERY_STRING_MATCHER = /\?([^#]*)$/,
@@ -11,9 +11,9 @@
11
11
  return function(path, callback) { return this.route.apply(this, [verb, path, callback]); }
12
12
  },
13
13
  loggers = [];
14
-
15
-
16
- // <tt>Sammy</tt> (also aliased as $.sammy) is not only the namespace for a
14
+
15
+
16
+ // <tt>Sammy</tt> (also aliased as $.sammy) is not only the namespace for a
17
17
  // number of prototypes, its also a top level method that allows for easy
18
18
  // creation/management of <tt>Sammy.Application</tt> instances. There are a
19
19
  // number of different forms for <tt>Sammy()</tt> but each returns an instance
@@ -21,24 +21,24 @@
21
21
  // <tt>Sammy</tt> it is added to an Object called <tt>Sammy.apps</tt>. This
22
22
  // provides for an easy way to get at existing Sammy applications. Only one
23
23
  // instance is allowed per <tt>element_selector</tt> so when calling
24
- // <tt>Sammy('selector')</tt> multiple times, the first time will create
24
+ // <tt>Sammy('selector')</tt> multiple times, the first time will create
25
25
  // the application and the following times will extend the application
26
26
  // already added to that selector.
27
27
  //
28
28
  // === Example
29
29
  //
30
30
  // // returns the app at #main or a new app
31
- // Sammy('#main')
31
+ // Sammy('#main')
32
32
  //
33
33
  // // equivilent to "new Sammy.Application", except appends to apps
34
34
  // Sammy();
35
- // Sammy(function() { ... });
35
+ // Sammy(function() { ... });
36
36
  //
37
37
  // // extends the app at '#main' with function.
38
38
  // Sammy('#main', function() { ... });
39
39
  //
40
40
  Sammy = function() {
41
- var args = $.makeArray(arguments),
41
+ var args = $.makeArray(arguments),
42
42
  app, selector;
43
43
  Sammy.apps = Sammy.apps || {};
44
44
  if (args.length == 0 || args[0] && $.isFunction(args[0])) { // Sammy()
@@ -59,29 +59,29 @@
59
59
  return app;
60
60
  }
61
61
  };
62
-
62
+
63
63
  Sammy.VERSION = '0.5.0';
64
-
65
- // Add to the global logger pool. Takes a function that accepts an
64
+
65
+ // Add to the global logger pool. Takes a function that accepts an
66
66
  // unknown number of arguments and should print them or send them somewhere
67
67
  // The first argument is always a timestamp.
68
68
  Sammy.addLogger = function(logger) {
69
69
  loggers.push(logger);
70
70
  };
71
-
71
+
72
72
  // Sends a log message to each logger listed in the global
73
73
  // loggers pool. Can take any number of arguments.
74
74
  // Also prefixes the arguments with a timestamp.
75
- Sammy.log = function() {
75
+ Sammy.log = function() {
76
76
  var args = $.makeArray(arguments);
77
77
  args.unshift("[" + Date() + "]");
78
78
  $.each(loggers, function(i, logger) {
79
79
  logger.apply(Sammy, args);
80
80
  });
81
- };
82
-
83
- if (typeof window.console != 'undefined') {
84
- if ($.isFunction(console.log.apply)) {
81
+ };
82
+
83
+ if (typeof window.console != 'undefined') {
84
+ if ($.isFunction(console.log.apply)) {
85
85
  Sammy.addLogger(function() {
86
86
  window.console.log.apply(console, arguments);
87
87
  });
@@ -95,18 +95,18 @@
95
95
  console.log.apply(console, arguments);
96
96
  });
97
97
  }
98
-
99
- // Sammy.Object is the base for all other Sammy classes. It provides some useful
98
+
99
+ // Sammy.Object is the base for all other Sammy classes. It provides some useful
100
100
  // functionality, including cloning, iterating, etc.
101
101
  Sammy.Object = function(obj) { // constructor
102
102
  return $.extend(this, obj || {});
103
103
  };
104
-
105
- $.extend(Sammy.Object.prototype, {
106
-
104
+
105
+ $.extend(Sammy.Object.prototype, {
106
+
107
107
  // Returns a copy of the object with Functions removed.
108
108
  toHash: function() {
109
- var json = {};
109
+ var json = {};
110
110
  $.each(this, function(k,v) {
111
111
  if (!$.isFunction(v)) {
112
112
  json[k] = v
@@ -114,11 +114,11 @@
114
114
  });
115
115
  return json;
116
116
  },
117
-
117
+
118
118
  // Renders a simple HTML version of this Objects attributes.
119
119
  // Does not render functions.
120
120
  // For example. Given this Sammy.Object:
121
- //
121
+ //
122
122
  // var s = new Sammy.Object({first_name: 'Sammy', last_name: 'Davis Jr.'});
123
123
  // s.toHTML() //=> '<strong>first_name</strong> Sammy<br /><strong>last_name</strong> Davis Jr.<br />'
124
124
  //
@@ -131,7 +131,7 @@
131
131
  });
132
132
  return display;
133
133
  },
134
-
134
+
135
135
  // Generates a unique identifing string. Used for application namespaceing.
136
136
  uuid: function() {
137
137
  if (typeof this._uuid == 'undefined' || !this._uuid) {
@@ -139,8 +139,8 @@
139
139
  }
140
140
  return this._uuid;
141
141
  },
142
-
143
- // Returns an array of keys for this object. If <tt>attributes_only</tt>
142
+
143
+ // Returns an array of keys for this object. If <tt>attributes_only</tt>
144
144
  // is true will not return keys that map to a <tt>function()</tt>
145
145
  keys: function(attributes_only) {
146
146
  var keys = [];
@@ -151,45 +151,45 @@
151
151
  }
152
152
  return keys;
153
153
  },
154
-
154
+
155
155
  // Checks if the object has a value at <tt>key</tt> and that the value is not empty
156
156
  has: function(key) {
157
157
  return this[key] && $.trim(this[key].toString()) != '';
158
158
  },
159
-
160
- // convenience method to join as many arguments as you want
159
+
160
+ // convenience method to join as many arguments as you want
161
161
  // by the first argument - useful for making paths
162
162
  join: function() {
163
163
  var args = $.makeArray(arguments);
164
164
  var delimiter = args.shift();
165
165
  return args.join(delimiter);
166
166
  },
167
-
167
+
168
168
  // Shortcut to Sammy.log
169
169
  log: function() {
170
170
  Sammy.log.apply(Sammy, arguments);
171
171
  },
172
-
173
- // Returns a string representation of this object.
174
- // if <tt>include_functions</tt> is true, it will also toString() the
172
+
173
+ // Returns a string representation of this object.
174
+ // if <tt>include_functions</tt> is true, it will also toString() the
175
175
  // methods of this object. By default only prints the attributes.
176
176
  toString: function(include_functions) {
177
177
  var s = []
178
178
  $.each(this, function(k, v) {
179
- if (!$.isFunction(v) || include_functions) {
179
+ if (!$.isFunction(v) || include_functions) {
180
180
  s.push('"' + k + '": ' + v.toString());
181
- }
181
+ }
182
182
  });
183
- return "Sammy.Object: {" + s.join(',') + "}";
183
+ return "Sammy.Object: {" + s.join(',') + "}";
184
184
  }
185
185
  });
186
-
186
+
187
187
  // The HashLocationProxy is the default location proxy for all Sammy applications.
188
188
  // A location proxy is a prototype that conforms to a simple interface. The purpose
189
189
  // of a location proxy is to notify the Sammy.Application its bound to when the location
190
190
  // or 'external state' changes. The HashLocationProxy considers the state to be
191
191
  // changed when the 'hash' (window.location.hash / '#') changes. It does this in two
192
- // different ways depending on what browser you are using. The newest browsers
192
+ // different ways depending on what browser you are using. The newest browsers
193
193
  // (IE, Safari > 4, FF >= 3.6) support a 'onhashchange' DOM event, thats fired whenever
194
194
  // the location.hash changes. In this situation the HashLocationProxy just binds
195
195
  // to this event and delegates it to the application. In the case of older browsers
@@ -198,7 +198,7 @@
198
198
  // need for multiple pollers even when thier are multiple apps on the page.
199
199
  Sammy.HashLocationProxy = function(app, run_interval_every) {
200
200
  this.app = app;
201
-
201
+
202
202
  // check for native hash support
203
203
  if ('onhashchange' in window) {
204
204
  Sammy.log('native hash change exists, using');
@@ -209,7 +209,7 @@
209
209
  this._startPolling(run_interval_every);
210
210
  }
211
211
  };
212
-
212
+
213
213
  Sammy.HashLocationProxy.prototype = {
214
214
  // bind the proxy events to the current app.
215
215
  bind: function() {
@@ -234,7 +234,7 @@
234
234
  setLocation: function(new_location) {
235
235
  return window.location = new_location;
236
236
  },
237
-
237
+
238
238
  _startPolling: function(every) {
239
239
  // set up interval
240
240
  var proxy = this;
@@ -243,7 +243,7 @@
243
243
  var hashCheck = function() {
244
244
  current_location = proxy.getLocation();
245
245
  // Sammy.log('getLocation', current_location);
246
- if (!Sammy.HashLocationProxy._last_location ||
246
+ if (!Sammy.HashLocationProxy._last_location ||
247
247
  current_location != Sammy.HashLocationProxy._last_location) {
248
248
  setTimeout(function() {
249
249
  $(window).trigger('hashchange');
@@ -259,18 +259,18 @@
259
259
  }
260
260
  }
261
261
  };
262
-
262
+
263
263
  // The DataLocationProxy is an optional location proxy prototype. As opposed to
264
264
  // the <tt>HashLocationProxy</tt> it gets its location from a jQuery.data attribute
265
265
  // tied to the application's element. You can set the name of the attribute by
266
266
  // passing a string as the second argument to the constructor. The default attribute
267
- // name is 'sammy-location'. To read more about location proxies, check out the
267
+ // name is 'sammy-location'. To read more about location proxies, check out the
268
268
  // documentation for <tt>Sammy.HashLocationProxy</tt>
269
269
  Sammy.DataLocationProxy = function(app, data_name) {
270
270
  this.app = app;
271
271
  this.data_name = data_name || 'sammy-location';
272
272
  };
273
-
273
+
274
274
  Sammy.DataLocationProxy.prototype = {
275
275
  bind: function() {
276
276
  var proxy = this;
@@ -280,20 +280,20 @@
280
280
  }
281
281
  });
282
282
  },
283
-
283
+
284
284
  unbind: function() {
285
285
  this.app.$element().die('setData');
286
286
  },
287
-
287
+
288
288
  getLocation: function() {
289
289
  return this.app.$element().data(this.data_name);
290
290
  },
291
-
291
+
292
292
  setLocation: function(new_location) {
293
293
  return this.app.$element().data(this.data_name, new_location);
294
294
  }
295
295
  };
296
-
296
+
297
297
  // Sammy.Application is the Base prototype for defining 'applications'.
298
298
  // An 'application' is a collection of 'routes' and bound events that is
299
299
  // attached to an element when <tt>run()</tt> is called.
@@ -321,72 +321,72 @@
321
321
  });
322
322
  }
323
323
  };
324
-
324
+
325
325
  Sammy.Application.prototype = $.extend({}, Sammy.Object.prototype, {
326
-
326
+
327
327
  // the four route verbs
328
328
  ROUTE_VERBS: ['get','post','put','delete'],
329
-
330
- // An array of the default events triggered by the
329
+
330
+ // An array of the default events triggered by the
331
331
  // application during its lifecycle
332
332
  APP_EVENTS: ['run','unload','lookup-route','run-route','route-found','event-context-before','event-context-after','changed','error-404','check-form-submission','redirect'],
333
-
333
+
334
334
  _last_route: null,
335
335
  _running: false,
336
-
336
+
337
337
  // On <tt>run()</tt> the application object is stored in a <tt>$.data</tt> entry
338
338
  // assocciated with the application's <tt>$element()</tt>
339
339
  data_store_name: 'sammy-app',
340
-
341
- // Defines what element the application is bound to. Provide a selector
340
+
341
+ // Defines what element the application is bound to. Provide a selector
342
342
  // (parseable by <tt>jQuery()</tt>) and this will be used by <tt>$element()</tt>
343
343
  element_selector: 'body',
344
-
344
+
345
345
  // When set to true, logs all of the default events using <tt>log()</tt>
346
346
  debug: false,
347
-
347
+
348
348
  // When set to false, will throw a javascript error when a route is invoked
349
349
  // and can not be found.
350
350
  silence_404: true,
351
-
351
+
352
352
  // The time in milliseconds that the URL is queried for changes
353
- run_interval_every: 50,
354
-
353
+ run_interval_every: 50,
354
+
355
355
  // The location proxy for the current app. By default this is set to a new
356
356
  // <tt>Sammy.HashLocationProxy</tt> on initialization. However, you can set
357
357
  // the location_proxy inside you're app function to give youre app a custom
358
358
  // location mechanism
359
359
  location_proxy: null,
360
-
361
- // The default template engine to use when using <tt>partial()</tt> in an
362
- // <tt>EventContext</tt>. <tt>template_engine</tt> can either be a string that
360
+
361
+ // The default template engine to use when using <tt>partial()</tt> in an
362
+ // <tt>EventContext</tt>. <tt>template_engine</tt> can either be a string that
363
363
  // corresponds to the name of a method/helper on EventContext or it can be a function
364
364
  // that takes two arguments, the content of the unrendered partial and an optional
365
365
  // JS object that contains interpolation data. Template engine is only called/refered
366
366
  // to if the extension of the partial is null or unknown. See <tt>partial()</tt>
367
367
  // for more information
368
368
  template_engine: null,
369
-
369
+
370
370
  // //=> Sammy.Application: body
371
371
  toString: function() {
372
372
  return 'Sammy.Application:' + this.element_selector;
373
373
  },
374
-
374
+
375
375
  // returns a jQuery object of the Applications bound element.
376
376
  $element: function() {
377
377
  return $(this.element_selector);
378
378
  },
379
-
379
+
380
380
  // <tt>use()</tt> is the entry point for including Sammy plugins.
381
- // The first argument to use should be a function() that is evaluated
381
+ // The first argument to use should be a function() that is evaluated
382
382
  // in the context of the current application, just like the <tt>app_function</tt>
383
383
  // argument to the <tt>Sammy.Application</tt> constructor.
384
384
  //
385
385
  // Any additional arguments are passed to the app function sequentially.
386
386
  //
387
- // For much more detail about plugins, check out:
387
+ // For much more detail about plugins, check out:
388
388
  // http://code.quirkey.com/sammy/doc/plugins.html
389
- //
389
+ //
390
390
  // === Example
391
391
  //
392
392
  // var MyPlugin = function(app, prepend) {
@@ -396,15 +396,15 @@
396
396
  // alert(prepend + " " + text);
397
397
  // }
398
398
  // });
399
- //
399
+ //
400
400
  // };
401
401
  //
402
402
  // var app = $.sammy(function() {
403
- //
403
+ //
404
404
  // this.use(MyPlugin, 'This is my plugin');
405
- //
405
+ //
406
406
  // this.get('#/', function() {
407
- // this.myhelper('and dont you forget it!');
407
+ // this.myhelper('and dont you forget it!');
408
408
  // //=> Alerts: This is my plugin and dont you forget it!
409
409
  // });
410
410
  //
@@ -428,7 +428,7 @@
428
428
  }
429
429
  return this;
430
430
  },
431
-
431
+
432
432
  // <tt>route()</tt> is the main method for defining routes within an application.
433
433
  // For great detail on routes, check out: http://code.quirkey.com/sammy/doc/routes.html
434
434
  //
@@ -437,7 +437,7 @@
437
437
  // === Arguments
438
438
  //
439
439
  // +verb+:: A String in the set of ROUTE_VERBS or 'any'. 'any' will add routes for each
440
- // of the ROUTE_VERBS. If only two arguments are passed,
440
+ // of the ROUTE_VERBS. If only two arguments are passed,
441
441
  // the first argument is the path, the second is the callback and the verb
442
442
  // is assumed to be 'any'.
443
443
  // +path+:: A Regexp or a String representing the path to match to invoke this verb.
@@ -447,7 +447,7 @@
447
447
  //
448
448
  route: function(verb, path, callback) {
449
449
  var app = this, param_names = [], add_route;
450
-
450
+
451
451
  // if the method signature is just (path, callback)
452
452
  // assume the verb is 'any'
453
453
  if (!callback && $.isFunction(path)) {
@@ -455,17 +455,17 @@
455
455
  callback = path;
456
456
  verb = 'any';
457
457
  }
458
-
458
+
459
459
  verb = verb.toLowerCase(); // ensure verb is lower case
460
-
460
+
461
461
  // if path is a string turn it into a regex
462
462
  if (path.constructor == String) {
463
-
463
+
464
464
  // Needs to be explicitly set because IE will maintain the index unless NULL is returned,
465
465
  // which means that with two consecutive routes that contain params, the second set of params will not be found and end up in splat instead of params
466
- // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/RegExp/lastIndex
466
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/RegExp/lastIndex
467
467
  PATH_NAME_MATCHER.lastIndex = 0;
468
-
468
+
469
469
  // find the names
470
470
  while ((path_match = PATH_NAME_MATCHER.exec(path)) != null) {
471
471
  param_names.push(path_match[1]);
@@ -477,7 +477,7 @@
477
477
  if (typeof callback == 'string') {
478
478
  callback = app[callback];
479
479
  }
480
-
480
+
481
481
  add_route = function(with_verb) {
482
482
  var r = {verb: with_verb, path: path, callback: callback, param_names: param_names};
483
483
  // add route to routes array
@@ -485,32 +485,32 @@
485
485
  // place routes in order of definition
486
486
  app.routes[with_verb].push(r);
487
487
  }
488
-
488
+
489
489
  if (verb === 'any') {
490
490
  $.each(this.ROUTE_VERBS, function(i, v) { add_route(v) });
491
491
  } else {
492
492
  add_route(verb)
493
493
  }
494
-
494
+
495
495
  // return the app
496
496
  return this;
497
497
  },
498
-
498
+
499
499
  // Alias for route('get', ...)
500
500
  get: _routeWrapper('get'),
501
-
501
+
502
502
  // Alias for route('post', ...)
503
503
  post: _routeWrapper('post'),
504
504
 
505
505
  // Alias for route('put', ...)
506
506
  put: _routeWrapper('put'),
507
-
507
+
508
508
  // Alias for route('delete', ...)
509
509
  del: _routeWrapper('delete'),
510
-
510
+
511
511
  // Alias for route('any', ...)
512
512
  any: _routeWrapper('any'),
513
-
513
+
514
514
  // <tt>mapRoutes</tt> takes an array of arrays, each array being passed to route()
515
515
  // as arguments, this allows for mass definition of routes. Another benefit is
516
516
  // this makes it possible/easier to load routes via remote JSON.
@@ -518,7 +518,7 @@
518
518
  // === Example
519
519
  //
520
520
  // var app = $.sammy(function() {
521
- //
521
+ //
522
522
  // this.mapRoutes([
523
523
  // ['get', '#/', function() { this.log('index'); }],
524
524
  // // strings in callbacks are looked up as methods on the app
@@ -535,13 +535,13 @@
535
535
  });
536
536
  return this;
537
537
  },
538
-
538
+
539
539
  // A unique event namespace defined per application.
540
540
  // All events bound with <tt>bind()</tt> are automatically bound within this space.
541
541
  eventNamespace: function() {
542
542
  return [this.data_store_name, this.namespace].join('-');
543
543
  },
544
-
544
+
545
545
  // Works just like <tt>jQuery.fn.bind()</tt> with a couple noteable differences.
546
546
  //
547
547
  // * It binds all events to the application element
@@ -558,9 +558,9 @@
558
558
  if (typeof callback == 'undefined') callback = data;
559
559
  var listener_callback = function() {
560
560
  // pull off the context from the arguments to the callback
561
- var e, context, data;
561
+ var e, context, data;
562
562
  e = arguments[0];
563
- data = arguments[1];
563
+ data = arguments[1];
564
564
  if (data && data['context']) {
565
565
  context = data['context']
566
566
  delete data['context'];
@@ -570,7 +570,7 @@
570
570
  e.cleaned_type = e.type.replace(app.eventNamespace(), '');
571
571
  callback.apply(context, [e, data]);
572
572
  };
573
-
573
+
574
574
  // it could be that the app element doesnt exist yet
575
575
  // so attach to the listeners array and then run()
576
576
  // will actually bind the event.
@@ -583,58 +583,58 @@
583
583
  }
584
584
  return this;
585
585
  },
586
-
586
+
587
587
  // Triggers custom events defined with <tt>bind()</tt>
588
588
  //
589
589
  // === Arguments
590
- //
590
+ //
591
591
  // +name+:: The name of the event. Automatically prefixed with the <tt>eventNamespace()</tt>
592
592
  // +data+:: An optional Object that can be passed to the bound callback.
593
- // +context+:: An optional context/Object in which to execute the bound callback.
593
+ // +context+:: An optional context/Object in which to execute the bound callback.
594
594
  // If no context is supplied a the context is a new <tt>Sammy.EventContext</tt>
595
595
  //
596
596
  trigger: function(name, data) {
597
597
  this.$element().trigger([name, this.eventNamespace()].join('.'), [data]);
598
598
  return this;
599
599
  },
600
-
600
+
601
601
  // Reruns the current route
602
602
  refresh: function() {
603
603
  this.last_location = null;
604
604
  this.trigger('location-changed');
605
605
  return this;
606
606
  },
607
-
607
+
608
608
  // Takes a single callback that is pushed on to a stack.
609
- // Before any route is run, the callbacks are evaluated in order within
609
+ // Before any route is run, the callbacks are evaluated in order within
610
610
  // the current <tt>Sammy.EventContext</tt>
611
611
  //
612
- // If any of the callbacks explicitly return false, execution of any
612
+ // If any of the callbacks explicitly return false, execution of any
613
613
  // further callbacks and the route itself is halted.
614
- //
614
+ //
615
615
  // You can also provide a set of options that will define when to run this
616
- // before based on the route it proceeds.
616
+ // before based on the route it proceeds.
617
617
  //
618
618
  // === Example
619
619
  //
620
620
  // var app = $.sammy(function() {
621
- //
621
+ //
622
622
  // // will run at #/route but not at #/
623
623
  // this.before('#/route', function() {
624
624
  // //...
625
625
  // });
626
- //
626
+ //
627
627
  // // will run at #/ but not at #/route
628
628
  // this.before({except: {path: '#/route'}}, function() {
629
629
  // this.log('not before #/route');
630
630
  // });
631
- //
631
+ //
632
632
  // this.get('#/', function() {});
633
- //
633
+ //
634
634
  // this.get('#/route', function() {});
635
- //
635
+ //
636
636
  // });
637
- //
637
+ //
638
638
  // See <tt>contextMatchesOptions()</tt> for a full list of supported options
639
639
  //
640
640
  before: function(options, callback) {
@@ -645,18 +645,18 @@
645
645
  this.befores.push([options, callback]);
646
646
  return this;
647
647
  },
648
-
648
+
649
649
  // A shortcut for binding a callback to be run after a route is executed.
650
650
  // After callbacks have no guarunteed order.
651
651
  after: function(callback) {
652
652
  return this.bind('event-context-after', callback);
653
653
  },
654
-
655
-
654
+
655
+
656
656
  // Adds an around filter to the application. around filters are functions
657
- // that take a single argument <tt>callback</tt> which is the entire route
657
+ // that take a single argument <tt>callback</tt> which is the entire route
658
658
  // execution path wrapped up in a closure. This means you can decide whether
659
- // or not to proceed with execution by not invoking <tt>callback</tt> or,
659
+ // or not to proceed with execution by not invoking <tt>callback</tt> or,
660
660
  // more usefuly wrapping callback inside the result of an asynchronous execution.
661
661
  //
662
662
  // === Example
@@ -665,11 +665,11 @@
665
665
  // and executing the route within the functions callback:
666
666
  //
667
667
  // var app = $.sammy(function() {
668
- //
668
+ //
669
669
  // var current_user = false;
670
- //
670
+ //
671
671
  // function checkLoggedIn(callback) {
672
- // // /session returns a JSON representation of the logged in user
672
+ // // /session returns a JSON representation of the logged in user
673
673
  // // or an empty object
674
674
  // if (!current_user) {
675
675
  // $.getJSON('/session', function(json) {
@@ -690,74 +690,74 @@
690
690
  // callback();
691
691
  // }
692
692
  // };
693
- //
693
+ //
694
694
  // this.around(checkLoggedIn);
695
- //
695
+ //
696
696
  // });
697
697
  //
698
698
  around: function(callback) {
699
699
  this.arounds.push(callback);
700
700
  return this;
701
701
  },
702
-
702
+
703
703
  // Returns a boolean of weather the current application is running.
704
704
  isRunning: function() {
705
705
  return this._running;
706
706
  },
707
-
707
+
708
708
  // Helpers extends the EventContext prototype specific to this app.
709
709
  // This allows you to define app specific helper functions that can be used
710
710
  // whenever you're inside of an event context (templates, routes, bind).
711
- //
711
+ //
712
712
  // === Example
713
713
  //
714
714
  // var app = $.sammy(function() {
715
- //
715
+ //
716
716
  // helpers({
717
717
  // upcase: function(text) {
718
718
  // return text.toString().toUpperCase();
719
719
  // }
720
720
  // });
721
- //
721
+ //
722
722
  // get('#/', function() { with(this) {
723
723
  // // inside of this context I can use the helpers
724
724
  // $('#main').html(upcase($('#main').text());
725
725
  // }});
726
- //
726
+ //
727
727
  // });
728
728
  //
729
- //
729
+ //
730
730
  // === Arguments
731
- //
731
+ //
732
732
  // +extensions+:: An object collection of functions to extend the context.
733
- //
733
+ //
734
734
  helpers: function(extensions) {
735
735
  $.extend(this.context_prototype.prototype, extensions);
736
736
  return this;
737
737
  },
738
-
738
+
739
739
  // Helper extends the event context just like <tt>helpers()</tt> but does it
740
- // a single method at a time. This is especially useful for dynamically named
740
+ // a single method at a time. This is especially useful for dynamically named
741
741
  // helpers
742
- //
742
+ //
743
743
  // === Example
744
- //
744
+ //
745
745
  // // Trivial example that adds 3 helper methods to the context dynamically
746
746
  // var app = $.sammy(function(app) {
747
- //
747
+ //
748
748
  // $.each([1,2,3], function(i, num) {
749
749
  // app.helper('helper' + num, function() {
750
750
  // this.log("I'm helper number " + num);
751
- // });
751
+ // });
752
752
  // });
753
- //
753
+ //
754
754
  // this.get('#/', function() {
755
755
  // this.helper2(); //=> I'm helper number 2
756
756
  // });
757
757
  // });
758
- //
758
+ //
759
759
  // === Arguments
760
- //
760
+ //
761
761
  // +name+:: The name of the method
762
762
  // +method+:: The function to be added to the prototype at <tt>name</tt>
763
763
  //
@@ -765,12 +765,12 @@
765
765
  this.context_prototype.prototype[name] = method;
766
766
  return this;
767
767
  },
768
-
768
+
769
769
  // Actually starts the application's lifecycle. <tt>run()</tt> should be invoked
770
770
  // within a document.ready block to ensure the DOM exists before binding events, etc.
771
771
  //
772
772
  // === Example
773
- //
773
+ //
774
774
  // var app = $.sammy(function() { ... }); // your application
775
775
  // $(function() { // document.ready
776
776
  // app.run();
@@ -778,19 +778,19 @@
778
778
  //
779
779
  // === Arguments
780
780
  //
781
- // +start_url+:: "value", Optionally, a String can be passed which the App will redirect to
781
+ // +start_url+:: "value", Optionally, a String can be passed which the App will redirect to
782
782
  // after the events/routes have been bound.
783
783
  run: function(start_url) {
784
784
  if (this.isRunning()) return false;
785
785
  var app = this;
786
-
786
+
787
787
  // actually bind all the listeners
788
788
  $.each(this.listeners.toHash(), function(name, callbacks) {
789
789
  $.each(callbacks, function(i, listener_callback) {
790
790
  app._listen(name, listener_callback);
791
791
  });
792
792
  });
793
-
793
+
794
794
  this.trigger('run', {start_url: start_url});
795
795
  this._running = true;
796
796
  // set data for app
@@ -799,14 +799,14 @@
799
799
  this.last_location = null;
800
800
  if (this.getLocation() == '' && typeof start_url != 'undefined') {
801
801
  this.setLocation(start_url);
802
- }
802
+ }
803
803
  // check url
804
804
  this._checkLocation();
805
805
  this.location_proxy.bind();
806
806
  this.bind('location-changed', function() {
807
807
  app._checkLocation();
808
808
  });
809
-
809
+
810
810
  // bind to submit to capture post/put/delete routes
811
811
  this.bind('submit', function(e) {
812
812
  var returned = app._checkFormSubmission($(e.target).closest('form'));
@@ -817,11 +817,11 @@
817
817
  $('body').bind('onunload', function() {
818
818
  app.unload();
819
819
  });
820
-
820
+
821
821
  // trigger html changed
822
822
  return this.trigger('changed');
823
823
  },
824
-
824
+
825
825
  // The opposite of <tt>run()</tt>, un-binds all event listeners and intervals
826
826
  // <tt>run()</tt> Automaticaly binds a <tt>onunload</tt> event to run this when
827
827
  // the document is closed.
@@ -844,11 +844,11 @@
844
844
  this._running = false;
845
845
  return this;
846
846
  },
847
-
848
- // Will bind a single callback function to every event that is already
847
+
848
+ // Will bind a single callback function to every event that is already
849
849
  // being listened to in the app. This includes all the <tt>APP_EVENTS</tt>
850
850
  // as well as any custom events defined with <tt>bind()</tt>.
851
- //
851
+ //
852
852
  // Used internally for debug logging.
853
853
  bindToAllEvents: function(callback) {
854
854
  var app = this;
@@ -870,9 +870,9 @@
870
870
  routablePath: function(path) {
871
871
  return path.replace(QUERY_STRING_MATCHER, '');
872
872
  },
873
-
873
+
874
874
  // Given a verb and a String path, will return either a route object or false
875
- // if a matching route can be found within the current defined set.
875
+ // if a matching route can be found within the current defined set.
876
876
  lookupRoute: function(verb, path) {
877
877
  var app = this, routed = false;
878
878
  this.trigger('lookup-route', {verb: verb, path: path});
@@ -887,16 +887,16 @@
887
887
  return routed;
888
888
  },
889
889
 
890
- // First, invokes <tt>lookupRoute()</tt> and if a route is found, parses the
890
+ // First, invokes <tt>lookupRoute()</tt> and if a route is found, parses the
891
891
  // possible URL params and then invokes the route's callback within a new
892
- // <tt>Sammy.EventContext</tt>. If the route can not be found, it calls
892
+ // <tt>Sammy.EventContext</tt>. If the route can not be found, it calls
893
893
  // <tt>notFound()</tt> and raise an error. If <tt>silence_404</tt> is <tt>true</tt>
894
894
  // this error will be caught be the internal methods that call <tt>runRoute</tt>.
895
895
  //
896
896
  // You probably will never have to call this directly.
897
897
  //
898
898
  // === Arguments
899
- //
899
+ //
900
900
  // +verb+:: A String for the verb.
901
901
  // +path+:: A String path to lookup.
902
902
  // +params+:: An Object of Params pulled from the URI or passed directly.
@@ -911,7 +911,7 @@
911
911
  if (typeof params == 'undefined') params = {};
912
912
 
913
913
  $.extend(params, this._parseQueryString(path));
914
-
914
+
915
915
  var app = this, context, wrapped_route, arounds, around, befores, before,
916
916
  route = this.lookupRoute(verb, path);
917
917
  if (route) {
@@ -933,12 +933,12 @@
933
933
  }
934
934
  });
935
935
  }
936
-
936
+
937
937
  // set event context
938
938
  context = new this.context_prototype(this, verb, path, params);
939
939
  // ensure arrays
940
- arounds = this.arounds.slice(0);
941
- befores = this.befores.slice(0);
940
+ arounds = this.arounds.slice(0);
941
+ befores = this.befores.slice(0);
942
942
  // wrap the route up with the before filters
943
943
  wrapped_route = function() {
944
944
  var returned;
@@ -965,18 +965,18 @@
965
965
  this.notFound(verb, path);
966
966
  }
967
967
  },
968
-
968
+
969
969
  // Matches an object of options against an <tt>EventContext</tt> like object that
970
970
  // contains <tt>path</tt> and <tt>verb</tt> attributes. Internally Sammy uses this
971
- // for matching <tt>before()</tt> filters against specific options. You can set the
971
+ // for matching <tt>before()</tt> filters against specific options. You can set the
972
972
  // object to _only_ match certain paths or verbs, or match all paths or verbs _except_
973
973
  // those that match the options.
974
974
  //
975
975
  // === Example
976
- //
976
+ //
977
977
  // var app = $.sammy(),
978
978
  // context = {verb: 'get', path: '#/mypath'};
979
- //
979
+ //
980
980
  // // match against a path string
981
981
  // app.contextMatchesOptions(context, '#/mypath'); //=> true
982
982
  // app.contextMatchesOptions(context, '#/otherpath'); //=> false
@@ -995,7 +995,7 @@
995
995
  // // match all except a path
996
996
  // app.contextMatchesOptions(context, {except: {path:'#/otherpath'}}); //=> true
997
997
  // app.contextMatchesOptions(context, {except: {path:'#/mypath'}}); //=> false
998
- //
998
+ //
999
999
  contextMatchesOptions: function(context, match_options, positive) {
1000
1000
  // empty options always match
1001
1001
  var options = match_options;
@@ -1012,7 +1012,7 @@
1012
1012
  if (options.only) {
1013
1013
  return this.contextMatchesOptions(context, options.only, true);
1014
1014
  } else if (options.except) {
1015
- return this.contextMatchesOptions(context, options.except, false);
1015
+ return this.contextMatchesOptions(context, options.except, false);
1016
1016
  }
1017
1017
  var path_matched = true, verb_matched = true;
1018
1018
  if (options.path) {
@@ -1028,55 +1028,55 @@
1028
1028
  }
1029
1029
  return positive ? (verb_matched && path_matched) : !(verb_matched && path_matched);
1030
1030
  },
1031
-
1031
+
1032
1032
 
1033
1033
  // Delegates to the <tt>location_proxy</tt> to get the current location.
1034
1034
  // See <tt>Sammy.HashLocationProxy</tt> for more info on location proxies.
1035
1035
  getLocation: function() {
1036
1036
  return this.location_proxy.getLocation()
1037
1037
  },
1038
-
1038
+
1039
1039
  // Delegates to the <tt>location_proxy</tt> to set the current location.
1040
1040
  // See <tt>Sammy.HashLocationProxy</tt> for more info on location proxies.
1041
1041
  //
1042
1042
  // === Arguments
1043
- //
1043
+ //
1044
1044
  // +new_location+:: A new location string (e.g. '#/')
1045
1045
  //
1046
1046
  setLocation: function(new_location) {
1047
1047
  return this.location_proxy.setLocation(new_location);
1048
1048
  },
1049
-
1049
+
1050
1050
  // Swaps the content of <tt>$element()</tt> with <tt>content</tt>
1051
1051
  // You can override this method to provide an alternate swap behavior
1052
1052
  // for <tt>EventContext.partial()</tt>.
1053
- //
1053
+ //
1054
1054
  // === Example
1055
1055
  //
1056
1056
  // var app = $.sammy(function() {
1057
- //
1057
+ //
1058
1058
  // // implements a 'fade out'/'fade in'
1059
1059
  // this.swap = function(content) {
1060
1060
  // this.$element().hide('slow').html(content).show('slow');
1061
1061
  // }
1062
- //
1062
+ //
1063
1063
  // get('#/', function() {
1064
1064
  // this.partial('index.html.erb') // will fade out and in
1065
1065
  // });
1066
- //
1066
+ //
1067
1067
  // });
1068
1068
  //
1069
1069
  swap: function(content) {
1070
1070
  return this.$element().html(content);
1071
1071
  },
1072
-
1072
+
1073
1073
  // This thows a '404 Not Found' error. Override this method to provide custom
1074
1074
  // 404 behavior (i.e redirecting to / or showing a warning)
1075
1075
  notFound: function(verb, path) {
1076
1076
  this.trigger('error-404', {verb: verb, path: path});
1077
1077
  throw('404 Not Found ' + verb + ' ' + path);
1078
1078
  },
1079
-
1079
+
1080
1080
  _checkLocation: function() {
1081
1081
  try { // try, catch 404s
1082
1082
  // get current location
@@ -1101,7 +1101,7 @@
1101
1101
  }
1102
1102
  return returned;
1103
1103
  },
1104
-
1104
+
1105
1105
  _checkFormSubmission: function(form) {
1106
1106
  var $form, path, verb, params, returned;
1107
1107
  this.trigger('check-form-submission', {form: form});
@@ -1122,7 +1122,7 @@
1122
1122
  }
1123
1123
  return (typeof returned == 'undefined') ? false : returned;
1124
1124
  },
1125
-
1125
+
1126
1126
  _parseFormParams: function($form) {
1127
1127
  var params = {};
1128
1128
  $.each($form.serializeArray(), function(i, field) {
@@ -1138,7 +1138,7 @@
1138
1138
  });
1139
1139
  return params;
1140
1140
  },
1141
-
1141
+
1142
1142
  _parseQueryString: function(path) {
1143
1143
  var query = {}, parts, pairs, pair, i;
1144
1144
 
@@ -1153,21 +1153,21 @@
1153
1153
 
1154
1154
  return query;
1155
1155
  },
1156
-
1156
+
1157
1157
  _listen: function(name, callback) {
1158
1158
  return this.$element().bind([name, this.eventNamespace()].join('.'), callback);
1159
1159
  },
1160
-
1160
+
1161
1161
  _unlisten: function(name, callback) {
1162
1162
  return this.$element().unbind([name, this.eventNamespace()].join('.'), callback);
1163
1163
  }
1164
1164
 
1165
1165
  });
1166
-
1167
- // <tt>Sammy.EventContext</tt> objects are created every time a route is run or a
1166
+
1167
+ // <tt>Sammy.EventContext</tt> objects are created every time a route is run or a
1168
1168
  // bound event is triggered. The callbacks for these events are evaluated within a <tt>Sammy.EventContext</tt>
1169
1169
  // This within these callbacks the special methods of <tt>EventContext</tt> are available.
1170
- //
1170
+ //
1171
1171
  // === Example
1172
1172
  //
1173
1173
  // $.sammy(function() { with(this) {
@@ -1197,21 +1197,21 @@
1197
1197
  this.path = path;
1198
1198
  this.params = new Sammy.Object(params);
1199
1199
  }
1200
-
1200
+
1201
1201
  Sammy.EventContext.prototype = $.extend({}, Sammy.Object.prototype, {
1202
-
1202
+
1203
1203
  // A shortcut to the app's <tt>$element()</tt>
1204
1204
  $element: function() {
1205
1205
  return this.app.$element();
1206
1206
  },
1207
-
1207
+
1208
1208
  // Used for rendering remote templates or documents within the current application/DOM.
1209
1209
  // By default Sammy and <tt>partial()</tt> know nothing about how your templates
1210
1210
  // should be interpeted/rendered. This is easy to change, though. <tt>partial()</tt> looks
1211
1211
  // for a method in <tt>EventContext</tt> that matches the extension of the file you're
1212
1212
  // fetching (e.g. 'myfile.template' will look for a template() method, 'myfile.haml' => haml(), etc.)
1213
- // If no matching render method is found it just takes the file contents as is.
1214
- //
1213
+ // If no matching render method is found it just takes the file contents as is.
1214
+ //
1215
1215
  // If you're templates have different (or no) extensions, and you want to render them all
1216
1216
  // through the same engine, you can set the default/fallback template engine on the app level
1217
1217
  // by setting <tt>app.template_engine</tt> to the name of the engine or a <tt>function() {}</tt>
@@ -1224,38 +1224,38 @@
1224
1224
  // === Example
1225
1225
  //
1226
1226
  // There are a couple different ways to use <tt>partial()</tt>:
1227
- //
1227
+ //
1228
1228
  // partial('doc.html');
1229
1229
  // //=> Replaces $element() with the contents of doc.html
1230
1230
  //
1231
- // use(Sammy.Template);
1231
+ // use(Sammy.Template);
1232
1232
  // //=> includes the template() method
1233
- // partial('doc.template', {name: 'Sammy'});
1233
+ // partial('doc.template', {name: 'Sammy'});
1234
1234
  // //=> Replaces $element() with the contents of doc.template run through <tt>template()</tt>
1235
1235
  //
1236
1236
  // partial('doc.html', function(data) {
1237
1237
  // // data is the contents of the template.
1238
- // $('.other-selector').html(data);
1238
+ // $('.other-selector').html(data);
1239
1239
  // });
1240
1240
  //
1241
1241
  // === Iteration/Arrays
1242
1242
  //
1243
- // If the data object passed to <tt>partial()</tt> is an Array, <tt>partial()</tt>
1244
- // will itterate over each element in data calling the callback with the
1243
+ // If the data object passed to <tt>partial()</tt> is an Array, <tt>partial()</tt>
1244
+ // will itterate over each element in data calling the callback with the
1245
1245
  // results of interpolation and the index of the element in the array.
1246
- //
1246
+ //
1247
1247
  // use(Sammy.Template);
1248
1248
  // // item.template => "<li>I'm an item named <%= name %></li>"
1249
1249
  // partial('item.template', [{name: "Item 1"}, {name: "Item 2"}])
1250
- // //=> Replaces $element() with:
1250
+ // //=> Replaces $element() with:
1251
1251
  // // <li>I'm an item named Item 1</li><li>I'm an item named Item 2</li>
1252
1252
  // partial('item.template', [{name: "Item 1"}, {name: "Item 2"}], function(rendered, i) {
1253
1253
  // rendered; //=> <li>I'm an item named Item 1</li> // for each element in the Array
1254
1254
  // i; // the 0 based index of the itteration
1255
1255
  // });
1256
- //
1256
+ //
1257
1257
  partial: function(path, data, callback) {
1258
- var file_data,
1258
+ var file_data,
1259
1259
  wrapped_callback,
1260
1260
  engine,
1261
1261
  data_array,
@@ -1268,8 +1268,8 @@
1268
1268
  if ((!engine || !$.isFunction(context[engine])) && this.app.template_engine) {
1269
1269
  engine = this.app.template_engine;
1270
1270
  }
1271
- if (engine && !$.isFunction(engine) && $.isFunction(context[engine])) {
1272
- engine = context[engine];
1271
+ if (engine && !$.isFunction(engine) && $.isFunction(context[engine])) {
1272
+ engine = context[engine];
1273
1273
  }
1274
1274
  if (!callback && $.isFunction(data)) {
1275
1275
  // callback is in the data position
@@ -1282,17 +1282,17 @@
1282
1282
  all_content = "";
1283
1283
  $.each(data_array, function(i, idata) {
1284
1284
  // extend the data object with the context
1285
- $.extend(idata, context);
1285
+ $.extend(idata, context);
1286
1286
  if ($.isFunction(engine)) {
1287
1287
  new_content = engine.apply(context, [response, idata]);
1288
- }
1288
+ }
1289
1289
  // collect the content
1290
1290
  all_content += new_content;
1291
1291
  // if callback exists call it for each iteration
1292
- if (callback) {
1293
- // return the result of the callback
1292
+ if (callback) {
1293
+ // return the result of the callback
1294
1294
  // (you can bail the loop by returning false)
1295
- return callback.apply(context, [new_content, i]);
1295
+ return callback.apply(context, [new_content, i]);
1296
1296
  }
1297
1297
  });
1298
1298
  if (!callback) { context.app.swap(all_content); }
@@ -1309,8 +1309,8 @@
1309
1309
  });
1310
1310
  }
1311
1311
  },
1312
-
1313
- // Changes the location of the current window. If <tt>to</tt> begins with
1312
+
1313
+ // Changes the location of the current window. If <tt>to</tt> begins with
1314
1314
  // '#' it only changes the document's hash. If passed more than 1 argument
1315
1315
  // redirect will join them together with forward slashes.
1316
1316
  //
@@ -1321,7 +1321,7 @@
1321
1321
  // redirect('#', 'other', 'route');
1322
1322
  //
1323
1323
  redirect: function() {
1324
- var to, args = $.makeArray(arguments),
1324
+ var to, args = $.makeArray(arguments),
1325
1325
  current_location = this.app.getLocation();
1326
1326
  if (args.length > 1) {
1327
1327
  args.unshift('/');
@@ -1336,32 +1336,32 @@
1336
1336
  this.app.trigger('location-changed');
1337
1337
  }
1338
1338
  },
1339
-
1339
+
1340
1340
  // Triggers events on <tt>app</tt> within the current context.
1341
1341
  trigger: function(name, data) {
1342
- if (typeof data == 'undefined') data = {};
1342
+ if (typeof data == 'undefined') data = {};
1343
1343
  if (!data.context) data.context = this;
1344
1344
  return this.app.trigger(name, data);
1345
1345
  },
1346
-
1346
+
1347
1347
  // A shortcut to app's <tt>eventNamespace()</tt>
1348
1348
  eventNamespace: function() {
1349
1349
  return this.app.eventNamespace();
1350
1350
  },
1351
-
1351
+
1352
1352
  // Raises a possible <tt>notFound()</tt> error for the current path.
1353
1353
  notFound: function() {
1354
1354
  return this.app.notFound(this.verb, this.path);
1355
1355
  },
1356
-
1356
+
1357
1357
  // //=> Sammy.EventContext: get #/ {}
1358
1358
  toString: function() {
1359
1359
  return "Sammy.EventContext: " + [this.verb, this.path, this.params].join(' ');
1360
1360
  }
1361
-
1361
+
1362
1362
  });
1363
-
1363
+
1364
1364
  // An alias to Sammy
1365
1365
  $.sammy = Sammy;
1366
1366
 
1367
- })(jQuery);
1367
+ })(jQuery);