jim 0.1.2 → 0.2.0

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 (72) hide show
  1. data/HISTORY +28 -0
  2. data/README.rdoc +1 -1
  3. data/Rakefile +2 -1
  4. data/jim.gemspec +67 -9
  5. data/lib/jim/bundler.rb +14 -11
  6. data/lib/jim/cli.rb +51 -9
  7. data/lib/jim/index.rb +3 -7
  8. data/lib/jim/installer.rb +140 -22
  9. data/lib/jim/templates/commands +21 -6
  10. data/lib/jim/version_parser.rb +2 -3
  11. data/lib/jim.rb +19 -2
  12. data/test/fixtures/jimfile +3 -3
  13. data/test/fixtures/sammy-0.5.0/HISTORY.md +135 -0
  14. data/test/fixtures/sammy-0.5.0/LICENSE +22 -0
  15. data/test/fixtures/sammy-0.5.0/README.md +81 -0
  16. data/test/fixtures/sammy-0.5.0/Rakefile +174 -0
  17. data/test/fixtures/sammy-0.5.0/examples/backend/README.md +23 -0
  18. data/test/fixtures/sammy-0.5.0/examples/backend/Rakefile +15 -0
  19. data/test/fixtures/sammy-0.5.0/examples/backend/app.rb +17 -0
  20. data/test/fixtures/sammy-0.5.0/examples/backend/app.ru +3 -0
  21. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/app.js +106 -0
  22. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.cloudkit.js +840 -0
  23. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.js +19 -0
  24. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/sammy.js +1013 -0
  25. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/index.html.erb +11 -0
  26. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task.html.erb +4 -0
  27. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task_details.html.erb +4 -0
  28. data/test/fixtures/sammy-0.5.0/examples/backend/views/app.sass +63 -0
  29. data/test/fixtures/sammy-0.5.0/examples/backend/views/index.haml +18 -0
  30. data/test/fixtures/sammy-0.5.0/examples/form_handling/files/form.html +12 -0
  31. data/test/fixtures/sammy-0.5.0/examples/form_handling/index.html +65 -0
  32. data/test/fixtures/sammy-0.5.0/examples/hello_world/index.html +50 -0
  33. data/test/fixtures/sammy-0.5.0/examples/location_override/README.md +15 -0
  34. data/test/fixtures/sammy-0.5.0/examples/location_override/data.html +110 -0
  35. data/test/fixtures/sammy-0.5.0/examples/location_override/index.html +79 -0
  36. data/test/fixtures/sammy-0.5.0/examples/location_override/test.html +121 -0
  37. data/test/fixtures/sammy-0.5.0/lib/min/sammy-0.5.0.min.js +5 -0
  38. data/test/fixtures/sammy-0.5.0/lib/min/sammy-lastest.min.js +5 -0
  39. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.cache.js +117 -0
  40. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.haml.js +539 -0
  41. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.json.js +362 -0
  42. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.mustache.js +415 -0
  43. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.nested_params.js +118 -0
  44. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.storage.js +515 -0
  45. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.template.js +117 -0
  46. data/test/fixtures/sammy-0.5.0/lib/sammy.js +1367 -0
  47. data/test/fixtures/sammy-0.5.0/test/fixtures/partial +1 -0
  48. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.html +1 -0
  49. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.noengine +1 -0
  50. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.template +1 -0
  51. data/test/fixtures/sammy-0.5.0/test/index.html +84 -0
  52. data/test/fixtures/sammy-0.5.0/test/test_sammy_application.js +953 -0
  53. data/test/fixtures/sammy-0.5.0/test/test_sammy_event_context.js +252 -0
  54. data/test/fixtures/sammy-0.5.0/test/test_sammy_location_proxy.js +91 -0
  55. data/test/fixtures/sammy-0.5.0/test/test_sammy_plugins.js +296 -0
  56. data/test/fixtures/sammy-0.5.0/test/test_sammy_storage.js +175 -0
  57. data/test/fixtures/sammy-0.5.0/test/test_server +27 -0
  58. data/test/fixtures/sammy-0.5.0/vendor/jquery-1.4.1.js +6078 -0
  59. data/test/fixtures/sammy-0.5.0/vendor/jquery-1.4.1.min.js +152 -0
  60. data/test/fixtures/sammy-0.5.0/vendor/jsdoc/doc.haml +58 -0
  61. data/test/fixtures/sammy-0.5.0/vendor/jsdoc/jsdoc.rb +143 -0
  62. data/test/fixtures/sammy-0.5.0/vendor/jslitmus.js +670 -0
  63. data/test/fixtures/sammy-0.5.0/vendor/qunit/qunit.css +119 -0
  64. data/test/fixtures/sammy-0.5.0/vendor/qunit/qunit.js +1043 -0
  65. data/test/fixtures/sammy-0.5.0/vendor/qunit-spec.js +127 -0
  66. data/test/helper.rb +23 -3
  67. data/test/test_jim_bundler.rb +9 -8
  68. data/test/test_jim_cli.rb +21 -12
  69. data/test/test_jim_installer.rb +152 -35
  70. data/test/test_jim_version_parser.rb +4 -0
  71. metadata +117 -27
  72. data/.document +0 -5
@@ -0,0 +1,11 @@
1
+ <ul id="tasks"></ul>
2
+ <div id="task_entry">
3
+ <form action="#/tasks" method="post">
4
+ <p>
5
+ <input class="entry" name="entry" type="text" />
6
+ </p>
7
+ <p>
8
+ <input type="submit" value="Create" />
9
+ </p>
10
+ </form>
11
+ </div>
@@ -0,0 +1,4 @@
1
+ <li class="task <%= (task.attr('completed') ? 'completed' : '') %>" id="<%= task.attr('id') %>">
2
+ <input type="checkbox" <%= (task.attr('completed') ? 'checked="checked"' : '') %>" />
3
+ <a href="#/tasks/<%= task.attr('id') %>" class="entry"><%= task.attr('entry') %></a>
4
+ </li>
@@ -0,0 +1,4 @@
1
+ <%= console.log('template task', task) %>
2
+ <div id="task_<%= task.__id__ %>">
3
+ <h3><%= task.entry %></h3>
4
+ </div>
@@ -0,0 +1,63 @@
1
+ !font = "'Lucida Grande', Helvetica, Arial, sans-serif"
2
+
3
+ body
4
+ :font-family = !font
5
+ :color #333
6
+ :margin 0px
7
+ :background #F3F3F3
8
+
9
+
10
+ a:link, a:visited
11
+ :text-decoration none
12
+ :color #5588CA
13
+ a:hover
14
+ :color #333
15
+ :background #E8E8E8
16
+ :-moz-border-radius 2px
17
+
18
+ h1
19
+ :color #000
20
+ :margin 0px
21
+ :font-weight normal
22
+
23
+ a:link, a:visited
24
+ :color #000
25
+ a:hover
26
+ :color #5588CA
27
+ :background none
28
+
29
+ #header
30
+ :padding 5px 20px
31
+ :background #D7D7D7
32
+ :border-bottom 4px solid #C0C0C0
33
+ #main
34
+ :padding 15px
35
+ #tasks
36
+ :list-style-type none
37
+ :margin 5px 0px
38
+ :padding 0px
39
+
40
+ li
41
+ :margin 5px 0px
42
+ :padding 4px
43
+ a
44
+ :padding 2px
45
+ :font-size 18px
46
+ &.completed a
47
+ :text-decoration line-through
48
+ :color #999
49
+
50
+ #task_entry
51
+ input[type=text]
52
+ :width 100%
53
+ :font-size 18px
54
+ :padding 4px
55
+ :-moz-border-radius 4px
56
+ :border 1px solid #CCC
57
+ input[type=submit]
58
+ :-moz-border-radius 4px
59
+ :font-size 16px
60
+ :padding 4px 20px
61
+ :color #333
62
+ :background #ECECEC
63
+ :border 1px solid #CCC
@@ -0,0 +1,18 @@
1
+ %html{:xmlns=> "http://www.w3.org/1999/xhtml", 'xml:lang' => "en", :lang => "en"}
2
+ %head
3
+ %meta{'http-equiv' => "Content-Type", 'content' => "text/html; charset=utf-8"}
4
+ %title Backended
5
+
6
+ %link{:rel => 'stylesheet', :href => '/stylesheets/app.css', :media => 'screen'}
7
+
8
+ - ['jquery', 'jquery.cloudkit', 'sammy', 'app'].each do |js|
9
+ %script{:src => "/javascripts/#{js}.js", :type => 'text/javascript', :charset => 'utf-8'}
10
+ %body
11
+ #container
12
+ #header
13
+ %h1
14
+ %a{:href => '#/', :title => 'Home'} Sammy Todo
15
+ #error{:style => 'display:none'}
16
+ %span.close x
17
+ #main
18
+ #debug
@@ -0,0 +1,12 @@
1
+ <form action="#/pretend/post/url" method="post">
2
+ <p><label for="name">Name:</label><input type="text" name="name" /></p>
3
+ <p><label for="email">Email:</label><input type="text" name="email" /></p>
4
+ <p><label for="role_admin">Admin?</label><input type="checkbox" name="roles[]" value="admin" id="role_admin"/></p>
5
+ <p><label for="role_author">Author?</label><input type="checkbox" name="roles[]" value="author" id="role_author"/></p>
6
+ <p><input type="submit" value="Post!" /></p>
7
+ </form>
8
+
9
+ <h3>Plain old form</h3>
10
+ <form method="post" action="/i_should_submit">
11
+ <p><input type="submit" value="Dont press me!" /></p>
12
+ </form>
@@ -0,0 +1,65 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
+
8
+ <title>Form Handling</title>
9
+
10
+ <style type="text/css" media="screen">
11
+
12
+ </style>
13
+
14
+ <script src="../../vendor/jquery-1.4.1.min.js" type="text/javascript" charset="utf-8"></script>
15
+ <script src="../../lib/sammy.js" type="text/javascript" charset="utf-8"></script>
16
+ <script type="text/javascript" charset="utf-8">
17
+ // ;(function($) {
18
+ var app = new Sammy.Application(function() { with(this) {
19
+ debug = true;
20
+ element_selector = '#main';
21
+ form_fields = null;
22
+
23
+ get('#/', function() { with(this) {
24
+ $element().text('Click form!');
25
+ }});
26
+
27
+ get('#/form', function() { with(this) {
28
+ partial('files/form.html');
29
+ }});
30
+
31
+ post('#/pretend/post/url', function() { with(this) {
32
+ form_fields = params;
33
+ redirect('#/display');
34
+ }});
35
+
36
+ get('#/display', function() { with(this) {
37
+ if (form_fields) {
38
+ $element().html(form_fields.toHTML());
39
+ } else {
40
+ redirect('#/form')
41
+ }
42
+ }});
43
+
44
+ }});
45
+
46
+ $(function() {
47
+ app.run('#/');
48
+ });
49
+
50
+ // })(jQuery);
51
+ </script>
52
+
53
+ </head>
54
+
55
+ <body>
56
+ <div id="container">
57
+ <div id="main">
58
+ </div>
59
+ <ul id="link">
60
+ <li><a href="#/form">Form!</a></li>
61
+ <li><a href="#/">Back</a></li>
62
+ </ul>
63
+ </div>
64
+ </body>
65
+ </html>
@@ -0,0 +1,50 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
+
8
+ <title>Hello World</title>
9
+
10
+ <style type="text/css" media="screen">
11
+
12
+ </style>
13
+
14
+ <script src="../../vendor/jquery-1.3.2.min.js" type="text/javascript" charset="utf-8"></script>
15
+ <script src="../../lib/sammy.js" type="text/javascript" charset="utf-8"></script>
16
+ <script type="text/javascript" charset="utf-8">
17
+ ;(function($) {
18
+ var app = new Sammy.Application(function() {
19
+ with(this) {
20
+
21
+ get('#/', function() { with(this) {
22
+ $('#main').text('');
23
+ }});
24
+
25
+ get('#/test', function() { with(this) {
26
+ $('#main').text('Hello World');
27
+ }});
28
+
29
+ }
30
+ });
31
+
32
+ $(function() {
33
+ app.run()
34
+ });
35
+ })(jQuery);
36
+ </script>
37
+
38
+ </head>
39
+
40
+ <body>
41
+ <div id="container">
42
+ <div id="main">
43
+ </div>
44
+ <ul id="link">
45
+ <li><a href="#/test">Click me!</a></li>
46
+ <li><a href="#/">Back</a></li>
47
+ </div>
48
+ </div>
49
+ </body>
50
+ </html>
@@ -0,0 +1,15 @@
1
+ # Sammy
2
+
3
+ ## Location Override Example
4
+
5
+ These two examples represent ways of overriding the default location ability to get and set the location from somewhere other then
6
+
7
+ window.location.hash
8
+
9
+ ### index.html
10
+
11
+ Uses a text input as a 'location bar'.
12
+
13
+ ### data.html
14
+
15
+ Uses jQuery's $.data() accessor to get/set the location from within the applications element. (Submitted by CodeOfficer)
@@ -0,0 +1,110 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
+ <title>Location Demo</title>
8
+ <style type="text/css" media="screen">
9
+ #main { background-color: #CCCCCC; }
10
+ </style>
11
+
12
+ <script src="../../vendor/jquery-1.3.2.min.js" type="text/javascript" charset="utf-8"></script>
13
+ <script src="../../lib/sammy.js" type="text/javascript" charset="utf-8"></script>
14
+
15
+ <script type="text/javascript" charset="utf-8">
16
+ ;(function($) {
17
+ var app = new Sammy.Application(function() { with(this) {
18
+ debug = true;
19
+ element_selector = '#main';
20
+
21
+ // overide getLocation
22
+ this.getLocation = function() {
23
+ if (this.$element().data('location') == undefined) {
24
+ this.$element().data('location', '');
25
+ };
26
+ return this.$element().data('location');
27
+ };
28
+
29
+ // overide setLocation
30
+ this.setLocation = function(new_location) {
31
+ return this.$element().data('location', new_location);
32
+ };
33
+
34
+ get('#/', function() { with(this) {
35
+ $("#output").text("matched: #/");
36
+ }});
37
+
38
+ get('#/link/:id', function() { with(this) {
39
+ $("#output").text("matched: #/link/:" + params['id']);
40
+ }});
41
+
42
+ post('#/form', function() { with(this) {
43
+ $("#output").text("post matched: #/form - params[field] = " + params['field']);
44
+ return false;
45
+ }});
46
+
47
+ put('#/form', function() { with(this) {
48
+ $("#output").text("put matched: #/form - params[field] = " + params['field']);
49
+ return false;
50
+ }});
51
+
52
+ bind('run', function() { with(this) {
53
+ var context = this;
54
+ var element = context.$element();
55
+
56
+ // intercept click events manually
57
+ // we dont want the url to change for matched routes
58
+ $('a', element).bind('click', function(e) {
59
+ var path = $(this).attr('href');
60
+ if (path.match(/^#/)) {
61
+ context.redirect(path);
62
+ return false;
63
+ } else {
64
+ return true;
65
+ }
66
+ });
67
+
68
+ }});
69
+
70
+ }});
71
+
72
+ $(function() {
73
+ app.run('#/');
74
+ });
75
+
76
+ })(jQuery);
77
+ </script>
78
+
79
+ </head>
80
+
81
+ <body>
82
+ <div id="container">
83
+
84
+ <div id="main">
85
+ <ul>
86
+ <li><a href="data.html">reset</a></li>
87
+ <li><a href="#/">#/</a></li>
88
+ <li><a href="#/link/id">#/link/id</a></li>
89
+ </ul>
90
+
91
+ <form action="#/form" method="put">
92
+ <p><input type="text" name="field" value="WAS PUT" id="field"/></p>
93
+ <p><input type="submit" value="Continue &rarr;"/></p>
94
+ </form>
95
+
96
+ <form action="#/form" method="post">
97
+ <p><input type="text" name="field" value="WAS POSTED" id="field"/></p>
98
+ <p><input type="submit" value="Continue &rarr;"/></p>
99
+ </form>
100
+ </div>
101
+
102
+ <h1>Results</h1>
103
+
104
+ <div id="output">
105
+ </div>
106
+
107
+ </div>
108
+
109
+ </body>
110
+ </html>
@@ -0,0 +1,79 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
+
8
+ <title>Form Handling</title>
9
+
10
+ <style type="text/css" media="screen">
11
+
12
+ </style>
13
+
14
+ <script src="../../vendor/jquery-1.3.2.min.js" type="text/javascript" charset="utf-8"></script>
15
+ <script src="../../lib/sammy.js" type="text/javascript" charset="utf-8"></script>
16
+ <script type="text/javascript" charset="utf-8">
17
+ ;(function($) {
18
+ var app = new Sammy.Application(function() { with(this) {
19
+ debug = true;
20
+ element_selector = '#main';
21
+ // form_fields = null;
22
+
23
+ this.getLocation = function() {
24
+ return $('#location').val().toString();
25
+ };
26
+
27
+ this.setLocation = function(new_location) {
28
+ return $('#location').val(new_location);
29
+ }
30
+
31
+ get('/', function() { with(this) {
32
+ $element().html('Enter a URL in the field above! Try /user/...');
33
+ }});
34
+
35
+ get('/user/:name', function() { with(this) {
36
+ $element().html('Youre at ' + params['name'] + "'s page. <a href='/' class='back'>Go Back</a>.");
37
+ }});
38
+
39
+ bind('back', function() { with(this) {
40
+ log('back!');
41
+ redirect('/');
42
+ }});
43
+
44
+ bind('run', function() {
45
+ var context = this;
46
+ $('a').live('click', function() {
47
+ var href = $(this).attr('href');
48
+ if (href.match(/^\//)) { // local link
49
+ context.redirect(href);
50
+ return false;
51
+ } else {
52
+ return true; // execute actual href
53
+ }
54
+ });
55
+ });
56
+
57
+ }});
58
+
59
+ $(function() {
60
+ app.run('/');
61
+ });
62
+
63
+ })(jQuery);
64
+ </script>
65
+
66
+ </head>
67
+
68
+ <body>
69
+ <div id="container">
70
+ <input id="location" type="text" />
71
+ <div id="main">
72
+
73
+ </div>
74
+ <ul>
75
+ <li><a href="/">Go Home</a></li>
76
+ <li><a href="/user/blah">Check out this user</a></li>
77
+ </div>
78
+ </body>
79
+ </html>
@@ -0,0 +1,121 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
+ <title>Location Demo</title>
8
+ <style type="text/css" media="screen">
9
+ #main { background-color: #CCCCCC; }
10
+ #output { background-color: #FF6666; }
11
+ </style>
12
+
13
+ <script src="../../vendor/jquery-1.3.2.min.js" type="text/javascript" charset="utf-8"></script>
14
+ <script src="../../lib/sammy.js" type="text/javascript" charset="utf-8"></script>
15
+
16
+ <script type="text/javascript" charset="utf-8">
17
+ ;(function($) {
18
+
19
+ // ----------------------------------------------------------------
20
+
21
+ Sammy.Application.prototype.getLocation = function() {
22
+ if (this.$element().data('appState') == undefined) {
23
+ this.$element().data('appState', '');
24
+ };
25
+ return this.$element().data('appState');
26
+ };
27
+
28
+ Sammy.Application.prototype.setLocation = function(newState) {
29
+ console.log('setLocation called with:', newState);
30
+ return this.$element().data('appState', newState);
31
+ };
32
+
33
+ // ----------------------------------------------------------------
34
+
35
+ var app = new Sammy.Application(function() { with(this) {
36
+ element_selector = '#main';
37
+
38
+ get('#/link', function() { with(this) {
39
+ $("#output").text("matched: #/link");
40
+ redirect('#/test_route');
41
+ }});
42
+
43
+ post('#/form', function() { with(this) {
44
+ $("#output").text("post matched: #/form (REDIRECT UNSUCCESSFUL)");
45
+ redirect('#/test_route');
46
+ }});
47
+
48
+ get('#/test_route', function() { with(this) {
49
+ $("#output").text("matched: #/test_route (REDIRECT SUCCESSFUL)");
50
+ }});
51
+
52
+ bind('run', function() { with(this) {
53
+ var context = this;
54
+ var element = context.$element();
55
+
56
+ // intercept click events manually
57
+ // we dont want the url to change for matched routes
58
+ $('a', element).bind('click', function(e) {
59
+ var path = $(this).attr('href');
60
+ if (path.match(/^#/)) {
61
+ context.redirect(path);
62
+ return false;
63
+ } else {
64
+ return true;
65
+ }
66
+ });
67
+
68
+ }});
69
+ }});
70
+
71
+ // ----------------------------------------------------------------
72
+
73
+ $(function() {
74
+ app.run();
75
+ });
76
+
77
+ })(jQuery);
78
+ </script>
79
+
80
+ </head>
81
+
82
+ <body>
83
+ <div id="container">
84
+
85
+ <h2>Using <strong>redirects</strong> with the new location storage.</h2>
86
+
87
+ <p>This example defines 2 routes, <strong>#/link</strong> and <strong>#/form</strong> ... both of which execute a redirect to <strong>#/test_route</strong></p>
88
+
89
+ <p><u>When #/link route triggers the redirect</u>, the behavior is as expected every time. And when I look in console I can see setLocation being called <strong>twice</strong> as I'd expect.</p>
90
+
91
+ <p><u>When #/form route triggers the redirect</u>, the behavior seems inconsistent.</p>
92
+
93
+ <p>The first form submit is successful, the redirect occurs and the body of the #/test_route executes. BUT! looking in console, we see setLocation only being called <strong>once</strong> for the #/test_route/ and not at all for the #/form route preceeding it.</p>
94
+
95
+ <p>Because #/test_route was the last location set, and because the #/form route never did a setLocation anyway, repeated clicks to submit the form will not be heard.</p>
96
+
97
+ <p>I kind of expect that when a form submission is caught it will trigger a Setlocation ... but looking in _checkFormSubmission, i see that the form routes are manually run here via runRoute, bypassing setLocation entirely!</p>
98
+
99
+ <p>Any thoughts on this? I know that recording app state via data attributes isn't a core feature of sammy, but I'm curious to hear if you think caught form submits should still bypass setLocation etc.</p>
100
+
101
+ <div id="main">
102
+ <ul>
103
+ <li><a href="quirkey.html">reset</a></li>
104
+ <li><a href="#/link">#/link</a></li>
105
+ </ul>
106
+
107
+ <form action="#/form" method="post">
108
+ <p><input type="text" name="field" value="WAS POSTED" id="field"/></p>
109
+ <p><input type="submit" value="Continue &rarr;"/></p>
110
+ </form>
111
+ </div>
112
+
113
+ <h1>Results</h1>
114
+
115
+ <div id="output">
116
+ </div>
117
+
118
+ </div>
119
+
120
+ </body>
121
+ </html>
@@ -0,0 +1,5 @@
1
+ // -- Sammy -- /sammy.js
2
+ // http://code.quirkey.com/sammy
3
+ // Version: 0.5.0
4
+ // Built: Mon Feb 15 14:13:25 -0500 2010
5
+ (function(g){var d="([^/]+)",f=/:([\w\d]+)/g,c=/\?([^#]*)$/,a=decodeURIComponent,b=function(h){return function(i,j){return this.route.apply(this,[h,i,j])}},e=[];Sammy=function(){var i=g.makeArray(arguments),j,h;Sammy.apps=Sammy.apps||{};if(i.length==0||i[0]&&g.isFunction(i[0])){return Sammy.apply(Sammy,["body"].concat(i))}else{if(typeof(h=i.shift())=="string"){j=Sammy.apps[h]||new Sammy.Application();j.element_selector=h;if(i.length>0){g.each(i,function(k,l){j.use(l)})}if(j.element_selector!=h){delete Sammy.apps[h]}Sammy.apps[j.element_selector]=j;return j}}};Sammy.VERSION="0.5.0";Sammy.addLogger=function(h){e.push(h)};Sammy.log=function(){var h=g.makeArray(arguments);h.unshift("["+Date()+"]");g.each(e,function(k,j){j.apply(Sammy,h)})};if(typeof window.console!="undefined"){if(g.isFunction(console.log.apply)){Sammy.addLogger(function(){window.console.log.apply(console,arguments)})}else{Sammy.addLogger(function(){window.console.log(arguments)})}}else{if(typeof console!="undefined"){Sammy.addLogger(function(){console.log.apply(console,arguments)})}}Sammy.Object=function(h){return g.extend(this,h||{})};g.extend(Sammy.Object.prototype,{toHash:function(){var h={};g.each(this,function(j,i){if(!g.isFunction(i)){h[j]=i}});return h},toHTML:function(){var h="";g.each(this,function(j,i){if(!g.isFunction(i)){h+="<strong>"+j+"</strong> "+i+"<br />"}});return h},uuid:function(){if(typeof this._uuid=="undefined"||!this._uuid){this._uuid=(new Date()).getTime()+"-"+parseInt(Math.random()*1000)}return this._uuid},keys:function(h){var i=[];for(var j in this){if(!g.isFunction(this[j])||!h){i.push(j)}}return i},has:function(h){return this[h]&&g.trim(this[h].toString())!=""},join:function(){var i=g.makeArray(arguments);var h=i.shift();return i.join(h)},log:function(){Sammy.log.apply(Sammy,arguments)},toString:function(h){var i=[];g.each(this,function(l,j){if(!g.isFunction(j)||h){i.push('"'+l+'": '+j.toString())}});return"Sammy.Object: {"+i.join(",")+"}"}});Sammy.HashLocationProxy=function(i,h){this.app=i;if("onhashchange" in window){Sammy.log("native hash change exists, using");this.is_native=true}else{Sammy.log("no native hash change, falling back to polling");this.is_native=false;this._startPolling(h)}};Sammy.HashLocationProxy.prototype={bind:function(){var h=this.app;g(window).bind("hashchange."+this.app.eventNamespace(),function(){h.trigger("location-changed")})},unbind:function(){g(window).die("hashchange."+this.app.eventNamespace())},getLocation:function(){var h=window.location.toString().match(/^[^#]*(#.+)$/);return h?h[1]:""},setLocation:function(h){return window.location=h},_startPolling:function(j){var i=this;if(!Sammy.HashLocationProxy._interval){if(!j){j=10}var h=function(){current_location=i.getLocation();if(!Sammy.HashLocationProxy._last_location||current_location!=Sammy.HashLocationProxy._last_location){setTimeout(function(){g(window).trigger("hashchange")},1)}Sammy.HashLocationProxy._last_location=current_location};h();Sammy.HashLocationProxy._interval=setInterval(h,j);g(window).bind("unload",function(){clearInterval(Sammy.HashLocationProxy._interval)})}}};Sammy.DataLocationProxy=function(i,h){this.app=i;this.data_name=h||"sammy-location"};Sammy.DataLocationProxy.prototype={bind:function(){var h=this;this.app.$element().bind("setData",function(j,i){if(i==h.data_name){h.app.trigger("location-changed")}})},unbind:function(){this.app.$element().die("setData")},getLocation:function(){return this.app.$element().data(this.data_name)},setLocation:function(h){return this.app.$element().data(this.data_name,h)}};Sammy.Application=function(h){var i=this;this.routes={};this.listeners=new Sammy.Object({});this.arounds=[];this.befores=[];this.namespace=this.uuid();this.context_prototype=function(){Sammy.EventContext.apply(this,arguments)};this.context_prototype.prototype=new Sammy.EventContext();if(g.isFunction(h)){h.apply(this,[this])}if(!this.location_proxy){this.location_proxy=new Sammy.HashLocationProxy(i,this.run_interval_every)}if(this.debug){this.bindToAllEvents(function(k,j){i.log(i.toString(),k.cleaned_type,j||{})})}};Sammy.Application.prototype=g.extend({},Sammy.Object.prototype,{ROUTE_VERBS:["get","post","put","delete"],APP_EVENTS:["run","unload","lookup-route","run-route","route-found","event-context-before","event-context-after","changed","error-404","check-form-submission","redirect"],_last_route:null,_running:false,data_store_name:"sammy-app",element_selector:"body",debug:false,silence_404:true,run_interval_every:50,location_proxy:null,template_engine:null,toString:function(){return"Sammy.Application:"+this.element_selector},$element:function(){return g(this.element_selector)},use:function(){var h=g.makeArray(arguments);var i=h.shift();try{h.unshift(this);i.apply(this,h)}catch(j){if(typeof i=="undefined"){throw ("Error: called use() but plugin is not defined")}else{if(!g.isFunction(i)){throw ("Error: called use() but '"+i.toString()+"' is not a function")}else{throw (j)}}}return this},route:function(k,i,m){var j=this,l=[],h;if(!m&&g.isFunction(i)){i=k;m=i;k="any"}k=k.toLowerCase();if(i.constructor==String){f.lastIndex=0;while((path_match=f.exec(i))!=null){l.push(path_match[1])}i=new RegExp("^"+i.replace(f,d)+"$")}if(typeof m=="string"){m=j[m]}h=function(n){var o={verb:n,path:i,callback:m,param_names:l};j.routes[n]=j.routes[n]||[];j.routes[n].push(o)};if(k==="any"){g.each(this.ROUTE_VERBS,function(o,n){h(n)})}else{h(k)}return this},get:b("get"),post:b("post"),put:b("put"),del:b("delete"),any:b("any"),mapRoutes:function(i){var h=this;g.each(i,function(j,k){h.route.apply(h,k)});return this},eventNamespace:function(){return[this.data_store_name,this.namespace].join("-")},bind:function(h,j,l){var k=this;if(typeof l=="undefined"){l=j}var i=function(){var o,m,n;o=arguments[0];n=arguments[1];if(n&&n.context){m=n.context;delete n.context}else{m=new k.context_prototype(k,"bind",o.type,n)}o.cleaned_type=o.type.replace(k.eventNamespace(),"");l.apply(m,[o,n])};if(!this.listeners[h]){this.listeners[h]=[]}this.listeners[h].push(i);if(this.isRunning()){this._listen(h,i)}return this},trigger:function(h,i){this.$element().trigger([h,this.eventNamespace()].join("."),[i]);return this},refresh:function(){this.last_location=null;this.trigger("location-changed");return this},before:function(h,i){if(g.isFunction(h)){i=h;h={}}this.befores.push([h,i]);return this},after:function(h){return this.bind("event-context-after",h)},around:function(h){this.arounds.push(h);return this},isRunning:function(){return this._running},helpers:function(h){g.extend(this.context_prototype.prototype,h);return this},helper:function(h,i){this.context_prototype.prototype[h]=i;return this},run:function(h){if(this.isRunning()){return false}var i=this;g.each(this.listeners.toHash(),function(j,k){g.each(k,function(m,l){i._listen(j,l)})});this.trigger("run",{start_url:h});this._running=true;this.$element().data(this.data_store_name,this);this.last_location=null;if(this.getLocation()==""&&typeof h!="undefined"){this.setLocation(h)}this._checkLocation();this.location_proxy.bind();this.bind("location-changed",function(){i._checkLocation()});this.bind("submit",function(k){var j=i._checkFormSubmission(g(k.target).closest("form"));return(j===false)?k.preventDefault():false});g("body").bind("onunload",function(){i.unload()});return this.trigger("changed")},unload:function(){if(!this.isRunning()){return false}var h=this;this.trigger("unload");this.location_proxy.unbind();this.$element().unbind("submit").removeClass(h.eventNamespace());this.$element().removeData(this.data_store_name);g.each(this.listeners.toHash(),function(i,j){g.each(j,function(l,k){h._unlisten(i,k)})});this._running=false;return this},bindToAllEvents:function(i){var h=this;g.each(this.APP_EVENTS,function(j,k){h.bind(k,i)});g.each(this.listeners.keys(true),function(k,j){if(h.APP_EVENTS.indexOf(j)==-1){h.bind(j,i)}});return this},routablePath:function(h){return h.replace(c,"")},lookupRoute:function(k,i){var j=this,h=false;this.trigger("lookup-route",{verb:k,path:i});if(typeof this.routes[k]!="undefined"){g.each(this.routes[k],function(m,l){if(j.routablePath(i).match(l.path)){h=l;return false}})}return h},runRoute:function(i,r,k){this.log("runRoute",[i,r].join(" "));this.trigger("run-route",{verb:i,path:r,params:k});if(typeof k=="undefined"){k={}}g.extend(k,this._parseQueryString(r));var j=this,h,n,l,m,q,o,p=this.lookupRoute(i,r);if(p){this.trigger("route-found",{route:p});if((path_params=p.path.exec(this.routablePath(r)))!=null){path_params.shift();g.each(path_params,function(s,t){if(p.param_names[s]){k[p.param_names[s]]=a(t)}else{if(!k.splat){k.splat=[]}k.splat.push(a(t))}})}h=new this.context_prototype(this,i,r,k);l=this.arounds.slice(0);q=this.befores.slice(0);n=function(){var s;while(q.length>0){o=q.shift();if(j.contextMatchesOptions(h,o[0])){s=o[1].apply(h,[h]);if(s===false){return false}}}j.last_route=p;h.trigger("event-context-before",{context:h});s=p.callback.apply(h,[h]);h.trigger("event-context-after",{context:h});return s};g.each(l.reverse(),function(s,t){var u=n;n=function(){return t.apply(h,[u])}});return n()}else{this.notFound(i,r)}},contextMatchesOptions:function(k,m,i){var j=m;if(typeof j==="undefined"||j=={}){return true}if(typeof i==="undefined"){i=true}if(typeof j==="string"||g.isFunction(j.test)){j={path:j}}if(j.only){return this.contextMatchesOptions(k,j.only,true)}else{if(j.except){return this.contextMatchesOptions(k,j.except,false)}}var h=true,l=true;if(j.path){if(g.isFunction(j.path.test)){h=j.path.test(k.path)}else{h=(j.path.toString()===k.path)}}if(j.verb){l=j.verb===k.verb}return i?(l&&h):!(l&&h)},getLocation:function(){return this.location_proxy.getLocation()},setLocation:function(h){return this.location_proxy.setLocation(h)},swap:function(h){return this.$element().html(h)},notFound:function(i,h){this.trigger("error-404",{verb:i,path:h});throw ("404 Not Found "+i+" "+h)},_checkLocation:function(){try{var h,i;h=this.getLocation();if(h!=this.last_location){i=this.runRoute("get",h)}this.last_location=h}catch(j){this.last_location=h;if(j.toString().match(/^404/)&&this.silence_404){return i}else{throw (j)}}return i},_checkFormSubmission:function(j){var h,l,n,m,i;this.trigger("check-form-submission",{form:j});h=g(j);l=h.attr("action");n=g.trim(h.attr("method").toString().toLowerCase());if(!n||n==""){n="get"}this.log("_checkFormSubmission",h,l,n);m=g.extend({},this._parseFormParams(h),{"$form":h});try{i=this.runRoute(n,l,m)}catch(k){if(k.toString().match(/^404/)&&this.silence_404){return true}else{throw (k)}}return(typeof i=="undefined")?false:i},_parseFormParams:function(h){var i={};g.each(h.serializeArray(),function(j,k){if(i[k.name]){if(g.isArray(i[k.name])){i[k.name].push(k.value)}else{i[k.name]=[i[k.name],k.value]}}else{i[k.name]=k.value}});return i},_parseQueryString:function(m){var k={},l,j,n,h;l=m.match(c);if(l){j=l[1].split("&");for(h=0;h<j.length;h+=1){n=j[h].split("=");k[n[0]]=a(n[1])}}return k},_listen:function(h,i){return this.$element().bind([h,this.eventNamespace()].join("."),i)},_unlisten:function(h,i){return this.$element().unbind([h,this.eventNamespace()].join("."),i)}});Sammy.EventContext=function(k,j,h,i){this.app=k;this.verb=j;this.path=h;this.params=new Sammy.Object(i)};Sammy.EventContext.prototype=g.extend({},Sammy.Object.prototype,{$element:function(){return this.app.$element()},partial:function(p,l,o){var h,k,n,m,j="partial:"+p,i=this;if((n=p.match(/\.([^\.]+)$/))){n=n[1]}if((!n||!g.isFunction(i[n]))&&this.app.template_engine){n=this.app.template_engine}if(n&&!g.isFunction(n)&&g.isFunction(i[n])){n=i[n]}if(!o&&g.isFunction(l)){o=l;l={}}m=(g.isArray(l)?l:[l||{}]),k=function(q){var r=q,s="";g.each(m,function(t,u){g.extend(u,i);if(g.isFunction(n)){r=n.apply(i,[q,u])}s+=r;if(o){return o.apply(i,[r,t])}});if(!o){i.app.swap(s)}i.trigger("changed")};if(this.app.cache_partials&&this.cache(j)){k.apply(i,[this.cache(j)])}else{g.get(p,function(q){if(i.app.cache_partials){i.cache(j,q)}k.apply(i,[q])})}},redirect:function(){var j,i=g.makeArray(arguments),h=this.app.getLocation();if(i.length>1){i.unshift("/");j=this.join.apply(this,i)}else{j=i[0]}this.trigger("redirect",{to:j});this.app.last_location=this.path;this.app.setLocation(j);if(h==j){this.app.trigger("location-changed")}},trigger:function(h,i){if(typeof i=="undefined"){i={}}if(!i.context){i.context=this}return this.app.trigger(h,i)},eventNamespace:function(){return this.app.eventNamespace()},notFound:function(){return this.app.notFound(this.verb,this.path)},toString:function(){return"Sammy.EventContext: "+[this.verb,this.path,this.params].join(" ")}});g.sammy=Sammy})(jQuery);
@@ -0,0 +1,5 @@
1
+ // -- Sammy -- /sammy.js
2
+ // http://code.quirkey.com/sammy
3
+ // Version: 0.5.0
4
+ // Built: Mon Feb 15 14:13:25 -0500 2010
5
+ (function(g){var d="([^/]+)",f=/:([\w\d]+)/g,c=/\?([^#]*)$/,a=decodeURIComponent,b=function(h){return function(i,j){return this.route.apply(this,[h,i,j])}},e=[];Sammy=function(){var i=g.makeArray(arguments),j,h;Sammy.apps=Sammy.apps||{};if(i.length==0||i[0]&&g.isFunction(i[0])){return Sammy.apply(Sammy,["body"].concat(i))}else{if(typeof(h=i.shift())=="string"){j=Sammy.apps[h]||new Sammy.Application();j.element_selector=h;if(i.length>0){g.each(i,function(k,l){j.use(l)})}if(j.element_selector!=h){delete Sammy.apps[h]}Sammy.apps[j.element_selector]=j;return j}}};Sammy.VERSION="0.5.0";Sammy.addLogger=function(h){e.push(h)};Sammy.log=function(){var h=g.makeArray(arguments);h.unshift("["+Date()+"]");g.each(e,function(k,j){j.apply(Sammy,h)})};if(typeof window.console!="undefined"){if(g.isFunction(console.log.apply)){Sammy.addLogger(function(){window.console.log.apply(console,arguments)})}else{Sammy.addLogger(function(){window.console.log(arguments)})}}else{if(typeof console!="undefined"){Sammy.addLogger(function(){console.log.apply(console,arguments)})}}Sammy.Object=function(h){return g.extend(this,h||{})};g.extend(Sammy.Object.prototype,{toHash:function(){var h={};g.each(this,function(j,i){if(!g.isFunction(i)){h[j]=i}});return h},toHTML:function(){var h="";g.each(this,function(j,i){if(!g.isFunction(i)){h+="<strong>"+j+"</strong> "+i+"<br />"}});return h},uuid:function(){if(typeof this._uuid=="undefined"||!this._uuid){this._uuid=(new Date()).getTime()+"-"+parseInt(Math.random()*1000)}return this._uuid},keys:function(h){var i=[];for(var j in this){if(!g.isFunction(this[j])||!h){i.push(j)}}return i},has:function(h){return this[h]&&g.trim(this[h].toString())!=""},join:function(){var i=g.makeArray(arguments);var h=i.shift();return i.join(h)},log:function(){Sammy.log.apply(Sammy,arguments)},toString:function(h){var i=[];g.each(this,function(l,j){if(!g.isFunction(j)||h){i.push('"'+l+'": '+j.toString())}});return"Sammy.Object: {"+i.join(",")+"}"}});Sammy.HashLocationProxy=function(i,h){this.app=i;if("onhashchange" in window){Sammy.log("native hash change exists, using");this.is_native=true}else{Sammy.log("no native hash change, falling back to polling");this.is_native=false;this._startPolling(h)}};Sammy.HashLocationProxy.prototype={bind:function(){var h=this.app;g(window).bind("hashchange."+this.app.eventNamespace(),function(){h.trigger("location-changed")})},unbind:function(){g(window).die("hashchange."+this.app.eventNamespace())},getLocation:function(){var h=window.location.toString().match(/^[^#]*(#.+)$/);return h?h[1]:""},setLocation:function(h){return window.location=h},_startPolling:function(j){var i=this;if(!Sammy.HashLocationProxy._interval){if(!j){j=10}var h=function(){current_location=i.getLocation();if(!Sammy.HashLocationProxy._last_location||current_location!=Sammy.HashLocationProxy._last_location){setTimeout(function(){g(window).trigger("hashchange")},1)}Sammy.HashLocationProxy._last_location=current_location};h();Sammy.HashLocationProxy._interval=setInterval(h,j);g(window).bind("unload",function(){clearInterval(Sammy.HashLocationProxy._interval)})}}};Sammy.DataLocationProxy=function(i,h){this.app=i;this.data_name=h||"sammy-location"};Sammy.DataLocationProxy.prototype={bind:function(){var h=this;this.app.$element().bind("setData",function(j,i){if(i==h.data_name){h.app.trigger("location-changed")}})},unbind:function(){this.app.$element().die("setData")},getLocation:function(){return this.app.$element().data(this.data_name)},setLocation:function(h){return this.app.$element().data(this.data_name,h)}};Sammy.Application=function(h){var i=this;this.routes={};this.listeners=new Sammy.Object({});this.arounds=[];this.befores=[];this.namespace=this.uuid();this.context_prototype=function(){Sammy.EventContext.apply(this,arguments)};this.context_prototype.prototype=new Sammy.EventContext();if(g.isFunction(h)){h.apply(this,[this])}if(!this.location_proxy){this.location_proxy=new Sammy.HashLocationProxy(i,this.run_interval_every)}if(this.debug){this.bindToAllEvents(function(k,j){i.log(i.toString(),k.cleaned_type,j||{})})}};Sammy.Application.prototype=g.extend({},Sammy.Object.prototype,{ROUTE_VERBS:["get","post","put","delete"],APP_EVENTS:["run","unload","lookup-route","run-route","route-found","event-context-before","event-context-after","changed","error-404","check-form-submission","redirect"],_last_route:null,_running:false,data_store_name:"sammy-app",element_selector:"body",debug:false,silence_404:true,run_interval_every:50,location_proxy:null,template_engine:null,toString:function(){return"Sammy.Application:"+this.element_selector},$element:function(){return g(this.element_selector)},use:function(){var h=g.makeArray(arguments);var i=h.shift();try{h.unshift(this);i.apply(this,h)}catch(j){if(typeof i=="undefined"){throw ("Error: called use() but plugin is not defined")}else{if(!g.isFunction(i)){throw ("Error: called use() but '"+i.toString()+"' is not a function")}else{throw (j)}}}return this},route:function(k,i,m){var j=this,l=[],h;if(!m&&g.isFunction(i)){i=k;m=i;k="any"}k=k.toLowerCase();if(i.constructor==String){f.lastIndex=0;while((path_match=f.exec(i))!=null){l.push(path_match[1])}i=new RegExp("^"+i.replace(f,d)+"$")}if(typeof m=="string"){m=j[m]}h=function(n){var o={verb:n,path:i,callback:m,param_names:l};j.routes[n]=j.routes[n]||[];j.routes[n].push(o)};if(k==="any"){g.each(this.ROUTE_VERBS,function(o,n){h(n)})}else{h(k)}return this},get:b("get"),post:b("post"),put:b("put"),del:b("delete"),any:b("any"),mapRoutes:function(i){var h=this;g.each(i,function(j,k){h.route.apply(h,k)});return this},eventNamespace:function(){return[this.data_store_name,this.namespace].join("-")},bind:function(h,j,l){var k=this;if(typeof l=="undefined"){l=j}var i=function(){var o,m,n;o=arguments[0];n=arguments[1];if(n&&n.context){m=n.context;delete n.context}else{m=new k.context_prototype(k,"bind",o.type,n)}o.cleaned_type=o.type.replace(k.eventNamespace(),"");l.apply(m,[o,n])};if(!this.listeners[h]){this.listeners[h]=[]}this.listeners[h].push(i);if(this.isRunning()){this._listen(h,i)}return this},trigger:function(h,i){this.$element().trigger([h,this.eventNamespace()].join("."),[i]);return this},refresh:function(){this.last_location=null;this.trigger("location-changed");return this},before:function(h,i){if(g.isFunction(h)){i=h;h={}}this.befores.push([h,i]);return this},after:function(h){return this.bind("event-context-after",h)},around:function(h){this.arounds.push(h);return this},isRunning:function(){return this._running},helpers:function(h){g.extend(this.context_prototype.prototype,h);return this},helper:function(h,i){this.context_prototype.prototype[h]=i;return this},run:function(h){if(this.isRunning()){return false}var i=this;g.each(this.listeners.toHash(),function(j,k){g.each(k,function(m,l){i._listen(j,l)})});this.trigger("run",{start_url:h});this._running=true;this.$element().data(this.data_store_name,this);this.last_location=null;if(this.getLocation()==""&&typeof h!="undefined"){this.setLocation(h)}this._checkLocation();this.location_proxy.bind();this.bind("location-changed",function(){i._checkLocation()});this.bind("submit",function(k){var j=i._checkFormSubmission(g(k.target).closest("form"));return(j===false)?k.preventDefault():false});g("body").bind("onunload",function(){i.unload()});return this.trigger("changed")},unload:function(){if(!this.isRunning()){return false}var h=this;this.trigger("unload");this.location_proxy.unbind();this.$element().unbind("submit").removeClass(h.eventNamespace());this.$element().removeData(this.data_store_name);g.each(this.listeners.toHash(),function(i,j){g.each(j,function(l,k){h._unlisten(i,k)})});this._running=false;return this},bindToAllEvents:function(i){var h=this;g.each(this.APP_EVENTS,function(j,k){h.bind(k,i)});g.each(this.listeners.keys(true),function(k,j){if(h.APP_EVENTS.indexOf(j)==-1){h.bind(j,i)}});return this},routablePath:function(h){return h.replace(c,"")},lookupRoute:function(k,i){var j=this,h=false;this.trigger("lookup-route",{verb:k,path:i});if(typeof this.routes[k]!="undefined"){g.each(this.routes[k],function(m,l){if(j.routablePath(i).match(l.path)){h=l;return false}})}return h},runRoute:function(i,r,k){this.log("runRoute",[i,r].join(" "));this.trigger("run-route",{verb:i,path:r,params:k});if(typeof k=="undefined"){k={}}g.extend(k,this._parseQueryString(r));var j=this,h,n,l,m,q,o,p=this.lookupRoute(i,r);if(p){this.trigger("route-found",{route:p});if((path_params=p.path.exec(this.routablePath(r)))!=null){path_params.shift();g.each(path_params,function(s,t){if(p.param_names[s]){k[p.param_names[s]]=a(t)}else{if(!k.splat){k.splat=[]}k.splat.push(a(t))}})}h=new this.context_prototype(this,i,r,k);l=this.arounds.slice(0);q=this.befores.slice(0);n=function(){var s;while(q.length>0){o=q.shift();if(j.contextMatchesOptions(h,o[0])){s=o[1].apply(h,[h]);if(s===false){return false}}}j.last_route=p;h.trigger("event-context-before",{context:h});s=p.callback.apply(h,[h]);h.trigger("event-context-after",{context:h});return s};g.each(l.reverse(),function(s,t){var u=n;n=function(){return t.apply(h,[u])}});return n()}else{this.notFound(i,r)}},contextMatchesOptions:function(k,m,i){var j=m;if(typeof j==="undefined"||j=={}){return true}if(typeof i==="undefined"){i=true}if(typeof j==="string"||g.isFunction(j.test)){j={path:j}}if(j.only){return this.contextMatchesOptions(k,j.only,true)}else{if(j.except){return this.contextMatchesOptions(k,j.except,false)}}var h=true,l=true;if(j.path){if(g.isFunction(j.path.test)){h=j.path.test(k.path)}else{h=(j.path.toString()===k.path)}}if(j.verb){l=j.verb===k.verb}return i?(l&&h):!(l&&h)},getLocation:function(){return this.location_proxy.getLocation()},setLocation:function(h){return this.location_proxy.setLocation(h)},swap:function(h){return this.$element().html(h)},notFound:function(i,h){this.trigger("error-404",{verb:i,path:h});throw ("404 Not Found "+i+" "+h)},_checkLocation:function(){try{var h,i;h=this.getLocation();if(h!=this.last_location){i=this.runRoute("get",h)}this.last_location=h}catch(j){this.last_location=h;if(j.toString().match(/^404/)&&this.silence_404){return i}else{throw (j)}}return i},_checkFormSubmission:function(j){var h,l,n,m,i;this.trigger("check-form-submission",{form:j});h=g(j);l=h.attr("action");n=g.trim(h.attr("method").toString().toLowerCase());if(!n||n==""){n="get"}this.log("_checkFormSubmission",h,l,n);m=g.extend({},this._parseFormParams(h),{"$form":h});try{i=this.runRoute(n,l,m)}catch(k){if(k.toString().match(/^404/)&&this.silence_404){return true}else{throw (k)}}return(typeof i=="undefined")?false:i},_parseFormParams:function(h){var i={};g.each(h.serializeArray(),function(j,k){if(i[k.name]){if(g.isArray(i[k.name])){i[k.name].push(k.value)}else{i[k.name]=[i[k.name],k.value]}}else{i[k.name]=k.value}});return i},_parseQueryString:function(m){var k={},l,j,n,h;l=m.match(c);if(l){j=l[1].split("&");for(h=0;h<j.length;h+=1){n=j[h].split("=");k[n[0]]=a(n[1])}}return k},_listen:function(h,i){return this.$element().bind([h,this.eventNamespace()].join("."),i)},_unlisten:function(h,i){return this.$element().unbind([h,this.eventNamespace()].join("."),i)}});Sammy.EventContext=function(k,j,h,i){this.app=k;this.verb=j;this.path=h;this.params=new Sammy.Object(i)};Sammy.EventContext.prototype=g.extend({},Sammy.Object.prototype,{$element:function(){return this.app.$element()},partial:function(p,l,o){var h,k,n,m,j="partial:"+p,i=this;if((n=p.match(/\.([^\.]+)$/))){n=n[1]}if((!n||!g.isFunction(i[n]))&&this.app.template_engine){n=this.app.template_engine}if(n&&!g.isFunction(n)&&g.isFunction(i[n])){n=i[n]}if(!o&&g.isFunction(l)){o=l;l={}}m=(g.isArray(l)?l:[l||{}]),k=function(q){var r=q,s="";g.each(m,function(t,u){g.extend(u,i);if(g.isFunction(n)){r=n.apply(i,[q,u])}s+=r;if(o){return o.apply(i,[r,t])}});if(!o){i.app.swap(s)}i.trigger("changed")};if(this.app.cache_partials&&this.cache(j)){k.apply(i,[this.cache(j)])}else{g.get(p,function(q){if(i.app.cache_partials){i.cache(j,q)}k.apply(i,[q])})}},redirect:function(){var j,i=g.makeArray(arguments),h=this.app.getLocation();if(i.length>1){i.unshift("/");j=this.join.apply(this,i)}else{j=i[0]}this.trigger("redirect",{to:j});this.app.last_location=this.path;this.app.setLocation(j);if(h==j){this.app.trigger("location-changed")}},trigger:function(h,i){if(typeof i=="undefined"){i={}}if(!i.context){i.context=this}return this.app.trigger(h,i)},eventNamespace:function(){return this.app.eventNamespace()},notFound:function(){return this.app.notFound(this.verb,this.path)},toString:function(){return"Sammy.EventContext: "+[this.verb,this.path,this.params].join(" ")}});g.sammy=Sammy})(jQuery);