twigg-app 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. checksums.yaml +7 -0
  2. data/data/quips.yml +45 -0
  3. data/lib/twigg-app/app/quips.rb +13 -0
  4. data/lib/twigg-app/app/routes.rb +43 -0
  5. data/lib/twigg-app/app/server.rb +146 -0
  6. data/lib/twigg-app/app/version.rb +5 -0
  7. data/lib/twigg-app/app.rb +14 -0
  8. data/lib/twigg-app.rb +5 -0
  9. data/public/application.js +106 -0
  10. data/public/favicon.ico +0 -0
  11. data/public/favicon.png +0 -0
  12. data/public/vendor/bootstrap/CNAME +1 -0
  13. data/public/vendor/bootstrap/CONTRIBUTING.md +66 -0
  14. data/public/vendor/bootstrap/Gruntfile.js +195 -0
  15. data/public/vendor/bootstrap/LICENSE +176 -0
  16. data/public/vendor/bootstrap/README.md +139 -0
  17. data/public/vendor/bootstrap/_config.yml +28 -0
  18. data/public/vendor/bootstrap/_includes/ads.html +1 -0
  19. data/public/vendor/bootstrap/_includes/footer.html +33 -0
  20. data/public/vendor/bootstrap/_includes/header.html +43 -0
  21. data/public/vendor/bootstrap/_includes/nav-components.html +135 -0
  22. data/public/vendor/bootstrap/_includes/nav-css.html +77 -0
  23. data/public/vendor/bootstrap/_includes/nav-customize.html +40 -0
  24. data/public/vendor/bootstrap/_includes/nav-getting-started.html +28 -0
  25. data/public/vendor/bootstrap/_includes/nav-javascript.html +88 -0
  26. data/public/vendor/bootstrap/_includes/nav-main.html +32 -0
  27. data/public/vendor/bootstrap/_includes/old-bs-docs.html +8 -0
  28. data/public/vendor/bootstrap/_includes/social-buttons.html +16 -0
  29. data/public/vendor/bootstrap/_layouts/customize.html +52 -0
  30. data/public/vendor/bootstrap/_layouts/default.html +72 -0
  31. data/public/vendor/bootstrap/_layouts/home.html +43 -0
  32. data/public/vendor/bootstrap/assets/css/docs.css +896 -0
  33. data/public/vendor/bootstrap/assets/css/pygments-manni.css +66 -0
  34. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-114-precomposed.png +0 -0
  35. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-144-precomposed.png +0 -0
  36. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-57-precomposed.png +0 -0
  37. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-72-precomposed.png +0 -0
  38. data/public/vendor/bootstrap/assets/ico/favicon.png +0 -0
  39. data/public/vendor/bootstrap/assets/js/application.js +82 -0
  40. data/public/vendor/bootstrap/assets/js/customizer.js +175 -0
  41. data/public/vendor/bootstrap/assets/js/holder.js +419 -0
  42. data/public/vendor/bootstrap/assets/js/html5shiv.js +8 -0
  43. data/public/vendor/bootstrap/assets/js/jquery.bbq.min.js +1287 -0
  44. data/public/vendor/bootstrap/assets/js/jquery.js +5 -0
  45. data/public/vendor/bootstrap/assets/js/jszip.js +1425 -0
  46. data/public/vendor/bootstrap/assets/js/less.js +9 -0
  47. data/public/vendor/bootstrap/assets/js/respond.min.js +6 -0
  48. data/public/vendor/bootstrap/assets/js/uglify.js +14 -0
  49. data/public/vendor/bootstrap/bower.json +11 -0
  50. data/public/vendor/bootstrap/browserstack.json +37 -0
  51. data/public/vendor/bootstrap/components.html +2555 -0
  52. data/public/vendor/bootstrap/composer.json +20 -0
  53. data/public/vendor/bootstrap/css.html +2276 -0
  54. data/public/vendor/bootstrap/customize.html +1480 -0
  55. data/public/vendor/bootstrap/dist/css/bootstrap.css +5579 -0
  56. data/public/vendor/bootstrap/dist/css/bootstrap.min.css +9 -0
  57. data/public/vendor/bootstrap/dist/js/bootstrap.js +1993 -0
  58. data/public/vendor/bootstrap/dist/js/bootstrap.min.js +6 -0
  59. data/public/vendor/bootstrap/getting-started.html +375 -0
  60. data/public/vendor/bootstrap/index.html +16 -0
  61. data/public/vendor/bootstrap/javascript.html +1904 -0
  62. data/public/vendor/bootstrap/js/affix.js +126 -0
  63. data/public/vendor/bootstrap/js/alert.js +98 -0
  64. data/public/vendor/bootstrap/js/button.js +109 -0
  65. data/public/vendor/bootstrap/js/carousel.js +217 -0
  66. data/public/vendor/bootstrap/js/collapse.js +179 -0
  67. data/public/vendor/bootstrap/js/dropdown.js +154 -0
  68. data/public/vendor/bootstrap/js/modal.js +244 -0
  69. data/public/vendor/bootstrap/js/popover.js +117 -0
  70. data/public/vendor/bootstrap/js/scrollspy.js +158 -0
  71. data/public/vendor/bootstrap/js/tab.js +135 -0
  72. data/public/vendor/bootstrap/js/tests/index.html +52 -0
  73. data/public/vendor/bootstrap/js/tests/phantom.js +63 -0
  74. data/public/vendor/bootstrap/js/tests/server.js +14 -0
  75. data/public/vendor/bootstrap/js/tests/unit/affix.js +25 -0
  76. data/public/vendor/bootstrap/js/tests/unit/alert.js +62 -0
  77. data/public/vendor/bootstrap/js/tests/unit/button.js +116 -0
  78. data/public/vendor/bootstrap/js/tests/unit/carousel.js +87 -0
  79. data/public/vendor/bootstrap/js/tests/unit/collapse.js +164 -0
  80. data/public/vendor/bootstrap/js/tests/unit/dropdown.js +219 -0
  81. data/public/vendor/bootstrap/js/tests/unit/modal.js +177 -0
  82. data/public/vendor/bootstrap/js/tests/unit/phantom.js +69 -0
  83. data/public/vendor/bootstrap/js/tests/unit/popover.js +133 -0
  84. data/public/vendor/bootstrap/js/tests/unit/scrollspy.js +37 -0
  85. data/public/vendor/bootstrap/js/tests/unit/tab.js +86 -0
  86. data/public/vendor/bootstrap/js/tests/unit/tooltip.js +437 -0
  87. data/public/vendor/bootstrap/js/tests/unit/transition.js +13 -0
  88. data/public/vendor/bootstrap/js/tests/vendor/jquery.js +5 -0
  89. data/public/vendor/bootstrap/js/tests/vendor/qunit.css +232 -0
  90. data/public/vendor/bootstrap/js/tests/vendor/qunit.js +1510 -0
  91. data/public/vendor/bootstrap/js/tooltip.js +382 -0
  92. data/public/vendor/bootstrap/js/transition.js +56 -0
  93. data/public/vendor/bootstrap/less/alerts.less +71 -0
  94. data/public/vendor/bootstrap/less/badges.less +51 -0
  95. data/public/vendor/bootstrap/less/bootstrap.less +63 -0
  96. data/public/vendor/bootstrap/less/breadcrumbs.less +23 -0
  97. data/public/vendor/bootstrap/less/button-groups.less +244 -0
  98. data/public/vendor/bootstrap/less/buttons.less +159 -0
  99. data/public/vendor/bootstrap/less/carousel.less +204 -0
  100. data/public/vendor/bootstrap/less/close.less +33 -0
  101. data/public/vendor/bootstrap/less/code.less +56 -0
  102. data/public/vendor/bootstrap/less/component-animations.less +29 -0
  103. data/public/vendor/bootstrap/less/dropdowns.less +176 -0
  104. data/public/vendor/bootstrap/less/forms.less +332 -0
  105. data/public/vendor/bootstrap/less/grid.less +340 -0
  106. data/public/vendor/bootstrap/less/input-groups.less +127 -0
  107. data/public/vendor/bootstrap/less/jumbotron.less +29 -0
  108. data/public/vendor/bootstrap/less/labels.less +54 -0
  109. data/public/vendor/bootstrap/less/list-group.less +88 -0
  110. data/public/vendor/bootstrap/less/media.less +56 -0
  111. data/public/vendor/bootstrap/less/mixins.less +693 -0
  112. data/public/vendor/bootstrap/less/modals.less +133 -0
  113. data/public/vendor/bootstrap/less/navbar.less +559 -0
  114. data/public/vendor/bootstrap/less/navs.less +228 -0
  115. data/public/vendor/bootstrap/less/normalize.less +396 -0
  116. data/public/vendor/bootstrap/less/pager.less +55 -0
  117. data/public/vendor/bootstrap/less/pagination.less +72 -0
  118. data/public/vendor/bootstrap/less/panels.less +128 -0
  119. data/public/vendor/bootstrap/less/popovers.less +133 -0
  120. data/public/vendor/bootstrap/less/print.less +100 -0
  121. data/public/vendor/bootstrap/less/progress-bars.less +99 -0
  122. data/public/vendor/bootstrap/less/responsive-utilities.less +149 -0
  123. data/public/vendor/bootstrap/less/scaffolding.less +111 -0
  124. data/public/vendor/bootstrap/less/tables.less +211 -0
  125. data/public/vendor/bootstrap/less/thumbnails.less +42 -0
  126. data/public/vendor/bootstrap/less/tooltip.less +95 -0
  127. data/public/vendor/bootstrap/less/type.less +238 -0
  128. data/public/vendor/bootstrap/less/utilities.less +42 -0
  129. data/public/vendor/bootstrap/less/variables.less +607 -0
  130. data/public/vendor/bootstrap/less/wells.less +29 -0
  131. data/public/vendor/bootstrap/package.json +33 -0
  132. data/public/vendor/bootstrap-glyphicons/CHANGELOG.md +3 -0
  133. data/public/vendor/bootstrap-glyphicons/CNAME +1 -0
  134. data/public/vendor/bootstrap-glyphicons/CONTRIBUTING.md +54 -0
  135. data/public/vendor/bootstrap-glyphicons/LICENSE +19 -0
  136. data/public/vendor/bootstrap-glyphicons/README.md +61 -0
  137. data/public/vendor/bootstrap-glyphicons/_config.yml +12 -0
  138. data/public/vendor/bootstrap-glyphicons/composer.json +9 -0
  139. data/public/vendor/bootstrap-glyphicons/css/bootstrap-glyphicons.css +2 -0
  140. data/public/vendor/bootstrap-glyphicons/css/bootstrap.css +9 -0
  141. data/public/vendor/bootstrap-glyphicons/css/docs.css +160 -0
  142. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.eot +0 -0
  143. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.otf +0 -0
  144. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.svg +175 -0
  145. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.ttf +0 -0
  146. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.woff +0 -0
  147. data/public/vendor/bootstrap-glyphicons/index.html +255 -0
  148. data/public/vendor/bootstrap-glyphicons/less/bootstrap-glyphicons.less +201 -0
  149. data/public/vendor/bootstrap-glyphicons/package.json +18 -0
  150. data/public/vendor/d3/LICENSE +26 -0
  151. data/public/vendor/d3/README.md +7 -0
  152. data/public/vendor/d3/bower.json +25 -0
  153. data/public/vendor/d3/d3.js +8810 -0
  154. data/public/vendor/d3/d3.min.js +5 -0
  155. data/public/vendor/jquery/README.md +11 -0
  156. data/public/vendor/jquery/bower.json +11 -0
  157. data/public/vendor/jquery/component.json +15 -0
  158. data/public/vendor/jquery/composer.json +35 -0
  159. data/public/vendor/jquery/jquery-migrate.js +511 -0
  160. data/public/vendor/jquery/jquery-migrate.min.js +3 -0
  161. data/public/vendor/jquery/jquery.js +8829 -0
  162. data/public/vendor/jquery/jquery.min.js +6 -0
  163. data/public/vendor/jquery/jquery.min.map +1 -0
  164. data/public/vendor/jquery/package.json +7 -0
  165. data/public/vendor/replacejs/CHANGELOG.md +3 -0
  166. data/public/vendor/replacejs/MIT-LICENSE.txt +20 -0
  167. data/public/vendor/replacejs/README.md +123 -0
  168. data/public/vendor/replacejs/bower.json +24 -0
  169. data/public/vendor/replacejs/primer.js +17 -0
  170. data/public/vendor/replacejs/primer.min.js +1 -0
  171. data/public/vendor/replacejs/replace.js +182 -0
  172. data/public/vendor/stupidtable.js +158 -0
  173. data/views/dashboard.haml +17 -0
  174. data/views/layout.haml +60 -0
  175. metadata +330 -0
@@ -0,0 +1,1287 @@
1
+ /*!
2
+ * jQuery BBQ: Back Button & Query Library - v1.3pre - 8/26/2010
3
+ * http://benalman.com/projects/jquery-bbq-plugin/
4
+ *
5
+ * Copyright (c) 2010 "Cowboy" Ben Alman
6
+ * Dual licensed under the MIT and GPL licenses.
7
+ * http://benalman.com/about/license/
8
+ */
9
+
10
+ // Script: jQuery BBQ: Back Button & Query Library
11
+ //
12
+ // *Version: 1.3pre, Last updated: 8/26/2010*
13
+ //
14
+ // Project Home - http://benalman.com/projects/jquery-bbq-plugin/
15
+ // GitHub - http://github.com/cowboy/jquery-bbq/
16
+ // Source - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.js
17
+ // (Minified) - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (2.2kb gzipped)
18
+ //
19
+ // About: License
20
+ //
21
+ // Copyright (c) 2010 "Cowboy" Ben Alman,
22
+ // Dual licensed under the MIT and GPL licenses.
23
+ // http://benalman.com/about/license/
24
+ //
25
+ // About: Examples
26
+ //
27
+ // These working examples, complete with fully commented code, illustrate a few
28
+ // ways in which this plugin can be used.
29
+ //
30
+ // Basic AJAX - http://benalman.com/code/projects/jquery-bbq/examples/fragment-basic/
31
+ // Advanced AJAX - http://benalman.com/code/projects/jquery-bbq/examples/fragment-advanced/
32
+ // jQuery UI Tabs - http://benalman.com/code/projects/jquery-bbq/examples/fragment-jquery-ui-tabs/
33
+ // Deparam - http://benalman.com/code/projects/jquery-bbq/examples/deparam/
34
+ //
35
+ // About: Support and Testing
36
+ //
37
+ // Information about what version or versions of jQuery this plugin has been
38
+ // tested with, what browsers it has been tested in, and where the unit tests
39
+ // reside (so you can test it yourself).
40
+ //
41
+ // jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
42
+ // Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
43
+ // Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
44
+ // Unit Tests - http://benalman.com/code/projects/jquery-bbq/unit/
45
+ //
46
+ // About: Release History
47
+ //
48
+ // 1.3pre - (8/26/2010) Integrated <jQuery hashchange event> v1.3, which adds
49
+ // document.title and document.domain support in IE6/7, BlackBerry
50
+ // support, better Iframe hiding for accessibility reasons, and the new
51
+ // <jQuery.fn.hashchange> "shortcut" method. Added the
52
+ // <jQuery.param.sorted> method which reduces the possibility of
53
+ // extraneous hashchange event triggering. Added the
54
+ // <jQuery.param.fragment.ajaxCrawlable> method which can be used to
55
+ // enable Google "AJAX Crawlable mode."
56
+ // 1.2.1 - (2/17/2010) Actually fixed the stale window.location Safari bug from
57
+ // <jQuery hashchange event> in BBQ, which was the main reason for the
58
+ // previous release!
59
+ // 1.2 - (2/16/2010) Integrated <jQuery hashchange event> v1.2, which fixes a
60
+ // Safari bug, the event can now be bound before DOM ready, and IE6/7
61
+ // page should no longer scroll when the event is first bound. Also
62
+ // added the <jQuery.param.fragment.noEscape> method, and reworked the
63
+ // <hashchange event (BBQ)> internal "add" method to be compatible with
64
+ // changes made to the jQuery 1.4.2 special events API.
65
+ // 1.1.1 - (1/22/2010) Integrated <jQuery hashchange event> v1.1, which fixes an
66
+ // obscure IE8 EmulateIE7 meta tag compatibility mode bug.
67
+ // 1.1 - (1/9/2010) Broke out the jQuery BBQ event.special <hashchange event>
68
+ // functionality into a separate plugin for users who want just the
69
+ // basic event & back button support, without all the extra awesomeness
70
+ // that BBQ provides. This plugin will be included as part of jQuery BBQ,
71
+ // but also be available separately. See <jQuery hashchange event>
72
+ // plugin for more information. Also added the <jQuery.bbq.removeState>
73
+ // method and added additional <jQuery.deparam> examples.
74
+ // 1.0.3 - (12/2/2009) Fixed an issue in IE 6 where location.search and
75
+ // location.hash would report incorrectly if the hash contained the ?
76
+ // character. Also <jQuery.param.querystring> and <jQuery.param.fragment>
77
+ // will no longer parse params out of a URL that doesn't contain ? or #,
78
+ // respectively.
79
+ // 1.0.2 - (10/10/2009) Fixed an issue in IE 6/7 where the hidden IFRAME caused
80
+ // a "This page contains both secure and nonsecure items." warning when
81
+ // used on an https:// page.
82
+ // 1.0.1 - (10/7/2009) Fixed an issue in IE 8. Since both "IE7" and "IE8
83
+ // Compatibility View" modes erroneously report that the browser
84
+ // supports the native window.onhashchange event, a slightly more
85
+ // robust test needed to be added.
86
+ // 1.0 - (10/2/2009) Initial release
87
+
88
+ (function($,window){
89
+ '$:nomunge'; // Used by YUI compressor.
90
+
91
+ // Some convenient shortcuts.
92
+ var undefined,
93
+ aps = Array.prototype.slice,
94
+ decode = decodeURIComponent,
95
+
96
+ // Method / object references.
97
+ jq_param = $.param,
98
+ jq_param_sorted,
99
+ jq_param_fragment,
100
+ jq_deparam,
101
+ jq_deparam_fragment,
102
+ jq_bbq = $.bbq = $.bbq || {},
103
+ jq_bbq_pushState,
104
+ jq_bbq_getState,
105
+ jq_elemUrlAttr,
106
+ special = $.event.special,
107
+
108
+ // Reused strings.
109
+ str_hashchange = 'hashchange',
110
+ str_querystring = 'querystring',
111
+ str_fragment = 'fragment',
112
+ str_elemUrlAttr = 'elemUrlAttr',
113
+ str_href = 'href',
114
+ str_src = 'src',
115
+
116
+ // Reused RegExp.
117
+ re_params_querystring = /^.*\?|#.*$/g,
118
+ re_params_fragment,
119
+ re_fragment,
120
+ re_no_escape,
121
+
122
+ ajax_crawlable,
123
+ fragment_prefix,
124
+
125
+ // Used by jQuery.elemUrlAttr.
126
+ elemUrlAttr_cache = {};
127
+
128
+ // A few commonly used bits, broken out to help reduce minified file size.
129
+
130
+ function is_string( arg ) {
131
+ return typeof arg === 'string';
132
+ };
133
+
134
+ // Why write the same function twice? Let's curry! Mmmm, curry..
135
+
136
+ function curry( func ) {
137
+ var args = aps.call( arguments, 1 );
138
+
139
+ return function() {
140
+ return func.apply( this, args.concat( aps.call( arguments ) ) );
141
+ };
142
+ };
143
+
144
+ // Get location.hash (or what you'd expect location.hash to be) sans any
145
+ // leading #. Thanks for making this necessary, Firefox!
146
+ function get_fragment( url ) {
147
+ return url.replace( re_fragment, '$2' );
148
+ };
149
+
150
+ // Get location.search (or what you'd expect location.search to be) sans any
151
+ // leading #. Thanks for making this necessary, IE6!
152
+ function get_querystring( url ) {
153
+ return url.replace( /(?:^[^?#]*\?([^#]*).*$)?.*/, '$1' );
154
+ };
155
+
156
+ // Section: Param (to string)
157
+ //
158
+ // Method: jQuery.param.querystring
159
+ //
160
+ // Retrieve the query string from a URL or if no arguments are passed, the
161
+ // current window.location.href.
162
+ //
163
+ // Usage:
164
+ //
165
+ // > jQuery.param.querystring( [ url ] );
166
+ //
167
+ // Arguments:
168
+ //
169
+ // url - (String) A URL containing query string params to be parsed. If url
170
+ // is not passed, the current window.location.href is used.
171
+ //
172
+ // Returns:
173
+ //
174
+ // (String) The parsed query string, with any leading "?" removed.
175
+ //
176
+
177
+ // Method: jQuery.param.querystring (build url)
178
+ //
179
+ // Merge a URL, with or without pre-existing query string params, plus any
180
+ // object, params string or URL containing query string params into a new URL.
181
+ //
182
+ // Usage:
183
+ //
184
+ // > jQuery.param.querystring( url, params [, merge_mode ] );
185
+ //
186
+ // Arguments:
187
+ //
188
+ // url - (String) A valid URL for params to be merged into. This URL may
189
+ // contain a query string and/or fragment (hash).
190
+ // params - (String) A params string or URL containing query string params to
191
+ // be merged into url.
192
+ // params - (Object) A params object to be merged into url.
193
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
194
+ // specified, and is as-follows:
195
+ //
196
+ // * 0: params in the params argument will override any query string
197
+ // params in url.
198
+ // * 1: any query string params in url will override params in the params
199
+ // argument.
200
+ // * 2: params argument will completely replace any query string in url.
201
+ //
202
+ // Returns:
203
+ //
204
+ // (String) A URL with a urlencoded query string in the format '?a=b&c=d&e=f'.
205
+
206
+ // Method: jQuery.param.fragment
207
+ //
208
+ // Retrieve the fragment (hash) from a URL or if no arguments are passed, the
209
+ // current window.location.href.
210
+ //
211
+ // Usage:
212
+ //
213
+ // > jQuery.param.fragment( [ url ] );
214
+ //
215
+ // Arguments:
216
+ //
217
+ // url - (String) A URL containing fragment (hash) params to be parsed. If
218
+ // url is not passed, the current window.location.href is used.
219
+ //
220
+ // Returns:
221
+ //
222
+ // (String) The parsed fragment (hash) string, with any leading "#" removed.
223
+
224
+ // Method: jQuery.param.fragment (build url)
225
+ //
226
+ // Merge a URL, with or without pre-existing fragment (hash) params, plus any
227
+ // object, params string or URL containing fragment (hash) params into a new
228
+ // URL.
229
+ //
230
+ // Usage:
231
+ //
232
+ // > jQuery.param.fragment( url, params [, merge_mode ] );
233
+ //
234
+ // Arguments:
235
+ //
236
+ // url - (String) A valid URL for params to be merged into. This URL may
237
+ // contain a query string and/or fragment (hash).
238
+ // params - (String) A params string or URL containing fragment (hash) params
239
+ // to be merged into url.
240
+ // params - (Object) A params object to be merged into url.
241
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
242
+ // specified, and is as-follows:
243
+ //
244
+ // * 0: params in the params argument will override any fragment (hash)
245
+ // params in url.
246
+ // * 1: any fragment (hash) params in url will override params in the
247
+ // params argument.
248
+ // * 2: params argument will completely replace any query string in url.
249
+ //
250
+ // Returns:
251
+ //
252
+ // (String) A URL with a urlencoded fragment (hash) in the format '#a=b&c=d&e=f'.
253
+
254
+ function jq_param_sub( is_fragment, get_func, url, params, merge_mode ) {
255
+ var result,
256
+ qs,
257
+ matches,
258
+ url_params,
259
+ hash;
260
+
261
+ if ( params !== undefined ) {
262
+ // Build URL by merging params into url string.
263
+
264
+ // matches[1] = url part that precedes params, not including trailing ?/#
265
+ // matches[2] = params, not including leading ?/#
266
+ // matches[3] = if in 'querystring' mode, hash including leading #, otherwise ''
267
+ matches = url.match( is_fragment ? re_fragment : /^([^#?]*)\??([^#]*)(#?.*)/ );
268
+
269
+ // Get the hash if in 'querystring' mode, and it exists.
270
+ hash = matches[3] || '';
271
+
272
+ if ( merge_mode === 2 && is_string( params ) ) {
273
+ // If merge_mode is 2 and params is a string, merge the fragment / query
274
+ // string into the URL wholesale, without converting it into an object.
275
+ qs = params.replace( is_fragment ? re_params_fragment : re_params_querystring, '' );
276
+
277
+ } else {
278
+ // Convert relevant params in url to object.
279
+ url_params = jq_deparam( matches[2] );
280
+
281
+ params = is_string( params )
282
+
283
+ // Convert passed params string into object.
284
+ ? jq_deparam[ is_fragment ? str_fragment : str_querystring ]( params )
285
+
286
+ // Passed params object.
287
+ : params;
288
+
289
+ qs = merge_mode === 2 ? params // passed params replace url params
290
+ : merge_mode === 1 ? $.extend( {}, params, url_params ) // url params override passed params
291
+ : $.extend( {}, url_params, params ); // passed params override url params
292
+
293
+ // Convert params object into a sorted params string.
294
+ qs = jq_param_sorted( qs );
295
+
296
+ // Unescape characters specified via $.param.noEscape. Since only hash-
297
+ // history users have requested this feature, it's only enabled for
298
+ // fragment-related params strings.
299
+ if ( is_fragment ) {
300
+ qs = qs.replace( re_no_escape, decode );
301
+ }
302
+ }
303
+
304
+ // Build URL from the base url, querystring and hash. In 'querystring'
305
+ // mode, ? is only added if a query string exists. In 'fragment' mode, #
306
+ // is always added.
307
+ result = matches[1] + ( is_fragment ? fragment_prefix : qs || !matches[1] ? '?' : '' ) + qs + hash;
308
+
309
+ } else {
310
+ // If URL was passed in, parse params from URL string, otherwise parse
311
+ // params from window.location.href.
312
+ result = get_func( url !== undefined ? url : location.href );
313
+ }
314
+
315
+ return result;
316
+ };
317
+
318
+ jq_param[ str_querystring ] = curry( jq_param_sub, 0, get_querystring );
319
+ jq_param[ str_fragment ] = jq_param_fragment = curry( jq_param_sub, 1, get_fragment );
320
+
321
+ // Method: jQuery.param.sorted
322
+ //
323
+ // Returns a params string equivalent to that returned by the internal
324
+ // jQuery.param method, but sorted, which makes it suitable for use as a
325
+ // cache key.
326
+ //
327
+ // For example, in most browsers jQuery.param({z:1,a:2}) returns "z=1&a=2"
328
+ // and jQuery.param({a:2,z:1}) returns "a=2&z=1". Even though both the
329
+ // objects being serialized and the resulting params strings are equivalent,
330
+ // if these params strings were set into the location.hash fragment
331
+ // sequentially, the hashchange event would be triggered unnecessarily, since
332
+ // the strings are different (even though the data described by them is the
333
+ // same). By sorting the params string, unecessary hashchange event triggering
334
+ // can be avoided.
335
+ //
336
+ // Usage:
337
+ //
338
+ // > jQuery.param.sorted( obj [, traditional ] );
339
+ //
340
+ // Arguments:
341
+ //
342
+ // obj - (Object) An object to be serialized.
343
+ // traditional - (Boolean) Params deep/shallow serialization mode. See the
344
+ // documentation at http://api.jquery.com/jQuery.param/ for more detail.
345
+ //
346
+ // Returns:
347
+ //
348
+ // (String) A sorted params string.
349
+
350
+ jq_param.sorted = jq_param_sorted = function( a, traditional ) {
351
+ var arr = [],
352
+ obj = {};
353
+
354
+ $.each( jq_param( a, traditional ).split( '&' ), function(i,v){
355
+ var key = v.replace( /(?:%5B|=).*$/, '' ),
356
+ key_obj = obj[ key ];
357
+
358
+ if ( !key_obj ) {
359
+ key_obj = obj[ key ] = [];
360
+ arr.push( key );
361
+ }
362
+
363
+ key_obj.push( v );
364
+ });
365
+
366
+ return $.map( arr.sort(), function(v){
367
+ return obj[ v ];
368
+ }).join( '&' );
369
+ };
370
+
371
+ // Method: jQuery.param.fragment.noEscape
372
+ //
373
+ // Specify characters that will be left unescaped when fragments are created
374
+ // or merged using <jQuery.param.fragment>, or when the fragment is modified
375
+ // using <jQuery.bbq.pushState>. This option only applies to serialized data
376
+ // object fragments, and not set-as-string fragments. Does not affect the
377
+ // query string. Defaults to ",/" (comma, forward slash).
378
+ //
379
+ // Note that this is considered a purely aesthetic option, and will help to
380
+ // create URLs that "look pretty" in the address bar or bookmarks, without
381
+ // affecting functionality in any way. That being said, be careful to not
382
+ // unescape characters that are used as delimiters or serve a special
383
+ // purpose, such as the "#?&=+" (octothorpe, question mark, ampersand,
384
+ // equals, plus) characters.
385
+ //
386
+ // Usage:
387
+ //
388
+ // > jQuery.param.fragment.noEscape( [ chars ] );
389
+ //
390
+ // Arguments:
391
+ //
392
+ // chars - (String) The characters to not escape in the fragment. If
393
+ // unspecified, defaults to empty string (escape all characters).
394
+ //
395
+ // Returns:
396
+ //
397
+ // Nothing.
398
+
399
+ jq_param_fragment.noEscape = function( chars ) {
400
+ chars = chars || '';
401
+ var arr = $.map( chars.split(''), encodeURIComponent );
402
+ re_no_escape = new RegExp( arr.join('|'), 'g' );
403
+ };
404
+
405
+ // A sensible default. These are the characters people seem to complain about
406
+ // "uglifying up the URL" the most.
407
+ jq_param_fragment.noEscape( ',/' );
408
+
409
+ // Method: jQuery.param.fragment.ajaxCrawlable
410
+ //
411
+ // TODO: DESCRIBE
412
+ //
413
+ // Usage:
414
+ //
415
+ // > jQuery.param.fragment.ajaxCrawlable( [ state ] );
416
+ //
417
+ // Arguments:
418
+ //
419
+ // state - (Boolean) TODO: DESCRIBE
420
+ //
421
+ // Returns:
422
+ //
423
+ // (Boolean) The current ajaxCrawlable state.
424
+
425
+ jq_param_fragment.ajaxCrawlable = function( state ) {
426
+ if ( state !== undefined ) {
427
+ if ( state ) {
428
+ re_params_fragment = /^.*(?:#!|#)/;
429
+ re_fragment = /^([^#]*)(?:#!|#)?(.*)$/;
430
+ fragment_prefix = '#!';
431
+ } else {
432
+ re_params_fragment = /^.*#/;
433
+ re_fragment = /^([^#]*)#?(.*)$/;
434
+ fragment_prefix = '#';
435
+ }
436
+ ajax_crawlable = !!state;
437
+ }
438
+
439
+ return ajax_crawlable;
440
+ };
441
+
442
+ jq_param_fragment.ajaxCrawlable( 0 );
443
+
444
+ // Section: Deparam (from string)
445
+ //
446
+ // Method: jQuery.deparam
447
+ //
448
+ // Deserialize a params string into an object, optionally coercing numbers,
449
+ // booleans, null and undefined values; this method is the counterpart to the
450
+ // internal jQuery.param method.
451
+ //
452
+ // Usage:
453
+ //
454
+ // > jQuery.deparam( params [, coerce ] );
455
+ //
456
+ // Arguments:
457
+ //
458
+ // params - (String) A params string to be parsed.
459
+ // coerce - (Boolean) If true, coerces any numbers or true, false, null, and
460
+ // undefined to their actual value. Defaults to false if omitted.
461
+ //
462
+ // Returns:
463
+ //
464
+ // (Object) An object representing the deserialized params string.
465
+
466
+ $.deparam = jq_deparam = function( params, coerce ) {
467
+ var obj = {},
468
+ coerce_types = { 'true': !0, 'false': !1, 'null': null };
469
+
470
+ // Iterate over all name=value pairs.
471
+ $.each( params.replace( /\+/g, ' ' ).split( '&' ), function(j,v){
472
+ var param = v.split( '=' ),
473
+ key = decode( param[0] ),
474
+ val,
475
+ cur = obj,
476
+ i = 0,
477
+
478
+ // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it
479
+ // into its component parts.
480
+ keys = key.split( '][' ),
481
+ keys_last = keys.length - 1;
482
+
483
+ // If the first keys part contains [ and the last ends with ], then []
484
+ // are correctly balanced.
485
+ if ( /\[/.test( keys[0] ) && /\]$/.test( keys[ keys_last ] ) ) {
486
+ // Remove the trailing ] from the last keys part.
487
+ keys[ keys_last ] = keys[ keys_last ].replace( /\]$/, '' );
488
+
489
+ // Split first keys part into two parts on the [ and add them back onto
490
+ // the beginning of the keys array.
491
+ keys = keys.shift().split('[').concat( keys );
492
+
493
+ keys_last = keys.length - 1;
494
+ } else {
495
+ // Basic 'foo' style key.
496
+ keys_last = 0;
497
+ }
498
+
499
+ // Are we dealing with a name=value pair, or just a name?
500
+ if ( param.length === 2 ) {
501
+ val = decode( param[1] );
502
+
503
+ // Coerce values.
504
+ if ( coerce ) {
505
+ val = val && !isNaN(val) ? +val // number
506
+ : val === 'undefined' ? undefined // undefined
507
+ : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null
508
+ : val; // string
509
+ }
510
+
511
+ if ( keys_last ) {
512
+ // Complex key, build deep object structure based on a few rules:
513
+ // * The 'cur' pointer starts at the object top-level.
514
+ // * [] = array push (n is set to array length), [n] = array if n is
515
+ // numeric, otherwise object.
516
+ // * If at the last keys part, set the value.
517
+ // * For each keys part, if the current level is undefined create an
518
+ // object or array based on the type of the next keys part.
519
+ // * Move the 'cur' pointer to the next level.
520
+ // * Rinse & repeat.
521
+ for ( ; i <= keys_last; i++ ) {
522
+ key = keys[i] === '' ? cur.length : keys[i];
523
+ cur = cur[key] = i < keys_last
524
+ ? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
525
+ : val;
526
+ }
527
+
528
+ } else {
529
+ // Simple key, even simpler rules, since only scalars and shallow
530
+ // arrays are allowed.
531
+
532
+ if ( $.isArray( obj[key] ) ) {
533
+ // val is already an array, so push on the next value.
534
+ obj[key].push( val );
535
+
536
+ } else if ( obj[key] !== undefined ) {
537
+ // val isn't an array, but since a second value has been specified,
538
+ // convert val into an array.
539
+ obj[key] = [ obj[key], val ];
540
+
541
+ } else {
542
+ // val is a scalar.
543
+ obj[key] = val;
544
+ }
545
+ }
546
+
547
+ } else if ( key ) {
548
+ // No value was defined, so set something meaningful.
549
+ obj[key] = coerce
550
+ ? undefined
551
+ : '';
552
+ }
553
+ });
554
+
555
+ return obj;
556
+ };
557
+
558
+ // Method: jQuery.deparam.querystring
559
+ //
560
+ // Parse the query string from a URL or the current window.location.href,
561
+ // deserializing it into an object, optionally coercing numbers, booleans,
562
+ // null and undefined values.
563
+ //
564
+ // Usage:
565
+ //
566
+ // > jQuery.deparam.querystring( [ url ] [, coerce ] );
567
+ //
568
+ // Arguments:
569
+ //
570
+ // url - (String) An optional params string or URL containing query string
571
+ // params to be parsed. If url is omitted, the current
572
+ // window.location.href is used.
573
+ // coerce - (Boolean) If true, coerces any numbers or true, false, null, and
574
+ // undefined to their actual value. Defaults to false if omitted.
575
+ //
576
+ // Returns:
577
+ //
578
+ // (Object) An object representing the deserialized params string.
579
+
580
+ // Method: jQuery.deparam.fragment
581
+ //
582
+ // Parse the fragment (hash) from a URL or the current window.location.href,
583
+ // deserializing it into an object, optionally coercing numbers, booleans,
584
+ // null and undefined values.
585
+ //
586
+ // Usage:
587
+ //
588
+ // > jQuery.deparam.fragment( [ url ] [, coerce ] );
589
+ //
590
+ // Arguments:
591
+ //
592
+ // url - (String) An optional params string or URL containing fragment (hash)
593
+ // params to be parsed. If url is omitted, the current window.location.href
594
+ // is used.
595
+ // coerce - (Boolean) If true, coerces any numbers or true, false, null, and
596
+ // undefined to their actual value. Defaults to false if omitted.
597
+ //
598
+ // Returns:
599
+ //
600
+ // (Object) An object representing the deserialized params string.
601
+
602
+ function jq_deparam_sub( is_fragment, url_or_params, coerce ) {
603
+ if ( url_or_params === undefined || typeof url_or_params === 'boolean' ) {
604
+ // url_or_params not specified.
605
+ coerce = url_or_params;
606
+ url_or_params = jq_param[ is_fragment ? str_fragment : str_querystring ]();
607
+ } else {
608
+ url_or_params = is_string( url_or_params )
609
+ ? url_or_params.replace( is_fragment ? re_params_fragment : re_params_querystring, '' )
610
+ : url_or_params;
611
+ }
612
+
613
+ return jq_deparam( url_or_params, coerce );
614
+ };
615
+
616
+ jq_deparam[ str_querystring ] = curry( jq_deparam_sub, 0 );
617
+ jq_deparam[ str_fragment ] = jq_deparam_fragment = curry( jq_deparam_sub, 1 );
618
+
619
+ // Section: Element manipulation
620
+ //
621
+ // Method: jQuery.elemUrlAttr
622
+ //
623
+ // Get the internal "Default URL attribute per tag" list, or augment the list
624
+ // with additional tag-attribute pairs, in case the defaults are insufficient.
625
+ //
626
+ // In the <jQuery.fn.querystring> and <jQuery.fn.fragment> methods, this list
627
+ // is used to determine which attribute contains the URL to be modified, if
628
+ // an "attr" param is not specified.
629
+ //
630
+ // Default Tag-Attribute List:
631
+ //
632
+ // a - href
633
+ // base - href
634
+ // iframe - src
635
+ // img - src
636
+ // input - src
637
+ // form - action
638
+ // link - href
639
+ // script - src
640
+ //
641
+ // Usage:
642
+ //
643
+ // > jQuery.elemUrlAttr( [ tag_attr ] );
644
+ //
645
+ // Arguments:
646
+ //
647
+ // tag_attr - (Object) An object containing a list of tag names and their
648
+ // associated default attribute names in the format { tag: 'attr', ... } to
649
+ // be merged into the internal tag-attribute list.
650
+ //
651
+ // Returns:
652
+ //
653
+ // (Object) An object containing all stored tag-attribute values.
654
+
655
+ // Only define function and set defaults if function doesn't already exist, as
656
+ // the urlInternal plugin will provide this method as well.
657
+ $[ str_elemUrlAttr ] || ($[ str_elemUrlAttr ] = function( obj ) {
658
+ return $.extend( elemUrlAttr_cache, obj );
659
+ })({
660
+ a: str_href,
661
+ base: str_href,
662
+ iframe: str_src,
663
+ img: str_src,
664
+ input: str_src,
665
+ form: 'action',
666
+ link: str_href,
667
+ script: str_src
668
+ });
669
+
670
+ jq_elemUrlAttr = $[ str_elemUrlAttr ];
671
+
672
+ // Method: jQuery.fn.querystring
673
+ //
674
+ // Update URL attribute in one or more elements, merging the current URL (with
675
+ // or without pre-existing query string params) plus any params object or
676
+ // string into a new URL, which is then set into that attribute. Like
677
+ // <jQuery.param.querystring (build url)>, but for all elements in a jQuery
678
+ // collection.
679
+ //
680
+ // Usage:
681
+ //
682
+ // > jQuery('selector').querystring( [ attr, ] params [, merge_mode ] );
683
+ //
684
+ // Arguments:
685
+ //
686
+ // attr - (String) Optional name of an attribute that will contain a URL to
687
+ // merge params or url into. See <jQuery.elemUrlAttr> for a list of default
688
+ // attributes.
689
+ // params - (Object) A params object to be merged into the URL attribute.
690
+ // params - (String) A URL containing query string params, or params string
691
+ // to be merged into the URL attribute.
692
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
693
+ // specified, and is as-follows:
694
+ //
695
+ // * 0: params in the params argument will override any params in attr URL.
696
+ // * 1: any params in attr URL will override params in the params argument.
697
+ // * 2: params argument will completely replace any query string in attr
698
+ // URL.
699
+ //
700
+ // Returns:
701
+ //
702
+ // (jQuery) The initial jQuery collection of elements, but with modified URL
703
+ // attribute values.
704
+
705
+ // Method: jQuery.fn.fragment
706
+ //
707
+ // Update URL attribute in one or more elements, merging the current URL (with
708
+ // or without pre-existing fragment/hash params) plus any params object or
709
+ // string into a new URL, which is then set into that attribute. Like
710
+ // <jQuery.param.fragment (build url)>, but for all elements in a jQuery
711
+ // collection.
712
+ //
713
+ // Usage:
714
+ //
715
+ // > jQuery('selector').fragment( [ attr, ] params [, merge_mode ] );
716
+ //
717
+ // Arguments:
718
+ //
719
+ // attr - (String) Optional name of an attribute that will contain a URL to
720
+ // merge params into. See <jQuery.elemUrlAttr> for a list of default
721
+ // attributes.
722
+ // params - (Object) A params object to be merged into the URL attribute.
723
+ // params - (String) A URL containing fragment (hash) params, or params
724
+ // string to be merged into the URL attribute.
725
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
726
+ // specified, and is as-follows:
727
+ //
728
+ // * 0: params in the params argument will override any params in attr URL.
729
+ // * 1: any params in attr URL will override params in the params argument.
730
+ // * 2: params argument will completely replace any fragment (hash) in attr
731
+ // URL.
732
+ //
733
+ // Returns:
734
+ //
735
+ // (jQuery) The initial jQuery collection of elements, but with modified URL
736
+ // attribute values.
737
+
738
+ function jq_fn_sub( mode, force_attr, params, merge_mode ) {
739
+ if ( !is_string( params ) && typeof params !== 'object' ) {
740
+ // force_attr not specified.
741
+ merge_mode = params;
742
+ params = force_attr;
743
+ force_attr = undefined;
744
+ }
745
+
746
+ return this.each(function(){
747
+ var that = $(this),
748
+
749
+ // Get attribute specified, or default specified via $.elemUrlAttr.
750
+ attr = force_attr || jq_elemUrlAttr()[ ( this.nodeName || '' ).toLowerCase() ] || '',
751
+
752
+ // Get URL value.
753
+ url = attr && that.attr( attr ) || '';
754
+
755
+ // Update attribute with new URL.
756
+ that.attr( attr, jq_param[ mode ]( url, params, merge_mode ) );
757
+ });
758
+
759
+ };
760
+
761
+ $.fn[ str_querystring ] = curry( jq_fn_sub, str_querystring );
762
+ $.fn[ str_fragment ] = curry( jq_fn_sub, str_fragment );
763
+
764
+ // Section: History, hashchange event
765
+ //
766
+ // Method: jQuery.bbq.pushState
767
+ //
768
+ // Adds a 'state' into the browser history at the current position, setting
769
+ // location.hash and triggering any bound <hashchange event> callbacks
770
+ // (provided the new state is different than the previous state).
771
+ //
772
+ // If no arguments are passed, an empty state is created, which is just a
773
+ // shortcut for jQuery.bbq.pushState( {}, 2 ).
774
+ //
775
+ // Usage:
776
+ //
777
+ // > jQuery.bbq.pushState( [ params [, merge_mode ] ] );
778
+ //
779
+ // Arguments:
780
+ //
781
+ // params - (String) A serialized params string or a hash string beginning
782
+ // with # to merge into location.hash.
783
+ // params - (Object) A params object to merge into location.hash.
784
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
785
+ // specified (unless a hash string beginning with # is specified, in which
786
+ // case merge behavior defaults to 2), and is as-follows:
787
+ //
788
+ // * 0: params in the params argument will override any params in the
789
+ // current state.
790
+ // * 1: any params in the current state will override params in the params
791
+ // argument.
792
+ // * 2: params argument will completely replace current state.
793
+ //
794
+ // Returns:
795
+ //
796
+ // Nothing.
797
+ //
798
+ // Additional Notes:
799
+ //
800
+ // * Setting an empty state may cause the browser to scroll.
801
+ // * Unlike the fragment and querystring methods, if a hash string beginning
802
+ // with # is specified as the params agrument, merge_mode defaults to 2.
803
+
804
+ jq_bbq.pushState = jq_bbq_pushState = function( params, merge_mode ) {
805
+ if ( is_string( params ) && /^#/.test( params ) && merge_mode === undefined ) {
806
+ // Params string begins with # and merge_mode not specified, so completely
807
+ // overwrite window.location.hash.
808
+ merge_mode = 2;
809
+ }
810
+
811
+ var has_args = params !== undefined,
812
+ // Merge params into window.location using $.param.fragment.
813
+ url = jq_param_fragment( location.href,
814
+ has_args ? params : {}, has_args ? merge_mode : 2 );
815
+
816
+ // Set new window.location.href. Note that Safari 3 & Chrome barf on
817
+ // location.hash = '#' so the entire URL is set.
818
+ location.href = url;
819
+ };
820
+
821
+ // Method: jQuery.bbq.getState
822
+ //
823
+ // Retrieves the current 'state' from the browser history, parsing
824
+ // location.hash for a specific key or returning an object containing the
825
+ // entire state, optionally coercing numbers, booleans, null and undefined
826
+ // values.
827
+ //
828
+ // Usage:
829
+ //
830
+ // > jQuery.bbq.getState( [ key ] [, coerce ] );
831
+ //
832
+ // Arguments:
833
+ //
834
+ // key - (String) An optional state key for which to return a value.
835
+ // coerce - (Boolean) If true, coerces any numbers or true, false, null, and
836
+ // undefined to their actual value. Defaults to false.
837
+ //
838
+ // Returns:
839
+ //
840
+ // (Anything) If key is passed, returns the value corresponding with that key
841
+ // in the location.hash 'state', or undefined. If not, an object
842
+ // representing the entire 'state' is returned.
843
+
844
+ jq_bbq.getState = jq_bbq_getState = function( key, coerce ) {
845
+ return key === undefined || typeof key === 'boolean'
846
+ ? jq_deparam_fragment( key ) // 'key' really means 'coerce' here
847
+ : jq_deparam_fragment( coerce )[ key ];
848
+ };
849
+
850
+ // Method: jQuery.bbq.removeState
851
+ //
852
+ // Remove one or more keys from the current browser history 'state', creating
853
+ // a new state, setting location.hash and triggering any bound
854
+ // <hashchange event> callbacks (provided the new state is different than
855
+ // the previous state).
856
+ //
857
+ // If no arguments are passed, an empty state is created, which is just a
858
+ // shortcut for jQuery.bbq.pushState( {}, 2 ).
859
+ //
860
+ // Usage:
861
+ //
862
+ // > jQuery.bbq.removeState( [ key [, key ... ] ] );
863
+ //
864
+ // Arguments:
865
+ //
866
+ // key - (String) One or more key values to remove from the current state,
867
+ // passed as individual arguments.
868
+ // key - (Array) A single array argument that contains a list of key values
869
+ // to remove from the current state.
870
+ //
871
+ // Returns:
872
+ //
873
+ // Nothing.
874
+ //
875
+ // Additional Notes:
876
+ //
877
+ // * Setting an empty state may cause the browser to scroll.
878
+
879
+ jq_bbq.removeState = function( arr ) {
880
+ var state = {};
881
+
882
+ // If one or more arguments is passed..
883
+ if ( arr !== undefined ) {
884
+
885
+ // Get the current state.
886
+ state = jq_bbq_getState();
887
+
888
+ // For each passed key, delete the corresponding property from the current
889
+ // state.
890
+ $.each( $.isArray( arr ) ? arr : arguments, function(i,v){
891
+ delete state[ v ];
892
+ });
893
+ }
894
+
895
+ // Set the state, completely overriding any existing state.
896
+ jq_bbq_pushState( state, 2 );
897
+ };
898
+
899
+ // Event: hashchange event (BBQ)
900
+ //
901
+ // Usage in jQuery 1.4 and newer:
902
+ //
903
+ // In jQuery 1.4 and newer, the event object passed into any hashchange event
904
+ // callback is augmented with a copy of the location.hash fragment at the time
905
+ // the event was triggered as its event.fragment property. In addition, the
906
+ // event.getState method operates on this property (instead of location.hash)
907
+ // which allows this fragment-as-a-state to be referenced later, even after
908
+ // window.location may have changed.
909
+ //
910
+ // Note that event.fragment and event.getState are not defined according to
911
+ // W3C (or any other) specification, but will still be available whether or
912
+ // not the hashchange event exists natively in the browser, because of the
913
+ // utility they provide.
914
+ //
915
+ // The event.fragment property contains the output of <jQuery.param.fragment>
916
+ // and the event.getState method is equivalent to the <jQuery.bbq.getState>
917
+ // method.
918
+ //
919
+ // > $(window).bind( 'hashchange', function( event ) {
920
+ // > var hash_str = event.fragment,
921
+ // > param_obj = event.getState(),
922
+ // > param_val = event.getState( 'param_name' ),
923
+ // > param_val_coerced = event.getState( 'param_name', true );
924
+ // > ...
925
+ // > });
926
+ //
927
+ // Usage in jQuery 1.3.2:
928
+ //
929
+ // In jQuery 1.3.2, the event object cannot to be augmented as in jQuery 1.4+,
930
+ // so the fragment state isn't bound to the event object and must instead be
931
+ // parsed using the <jQuery.param.fragment> and <jQuery.bbq.getState> methods.
932
+ //
933
+ // > $(window).bind( 'hashchange', function( event ) {
934
+ // > var hash_str = $.param.fragment(),
935
+ // > param_obj = $.bbq.getState(),
936
+ // > param_val = $.bbq.getState( 'param_name' ),
937
+ // > param_val_coerced = $.bbq.getState( 'param_name', true );
938
+ // > ...
939
+ // > });
940
+ //
941
+ // Additional Notes:
942
+ //
943
+ // * Due to changes in the special events API, jQuery BBQ v1.2 or newer is
944
+ // required to enable the augmented event object in jQuery 1.4.2 and newer.
945
+ // * See <jQuery hashchange event> for more detailed information.
946
+
947
+ special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
948
+
949
+ // Augmenting the event object with the .fragment property and .getState
950
+ // method requires jQuery 1.4 or newer. Note: with 1.3.2, everything will
951
+ // work, but the event won't be augmented)
952
+ add: function( handleObj ) {
953
+ var old_handler;
954
+
955
+ function new_handler(e) {
956
+ // e.fragment is set to the value of location.hash (with any leading #
957
+ // removed) at the time the event is triggered.
958
+ var hash = e[ str_fragment ] = jq_param_fragment();
959
+
960
+ // e.getState() works just like $.bbq.getState(), but uses the
961
+ // e.fragment property stored on the event object.
962
+ e.getState = function( key, coerce ) {
963
+ return key === undefined || typeof key === 'boolean'
964
+ ? jq_deparam( hash, key ) // 'key' really means 'coerce' here
965
+ : jq_deparam( hash, coerce )[ key ];
966
+ };
967
+
968
+ old_handler.apply( this, arguments );
969
+ };
970
+
971
+ // This may seem a little complicated, but it normalizes the special event
972
+ // .add method between jQuery 1.4/1.4.1 and 1.4.2+
973
+ if ( $.isFunction( handleObj ) ) {
974
+ // 1.4, 1.4.1
975
+ old_handler = handleObj;
976
+ return new_handler;
977
+ } else {
978
+ // 1.4.2+
979
+ old_handler = handleObj.handler;
980
+ handleObj.handler = new_handler;
981
+ }
982
+ }
983
+
984
+ });
985
+
986
+ })(jQuery,this);
987
+
988
+ /*!
989
+ * jQuery hashchange event - v1.3 - 7/21/2010
990
+ * http://benalman.com/projects/jquery-hashchange-plugin/
991
+ *
992
+ * Copyright (c) 2010 "Cowboy" Ben Alman
993
+ * Dual licensed under the MIT and GPL licenses.
994
+ * http://benalman.com/about/license/
995
+ */
996
+
997
+ // Script: jQuery hashchange event
998
+ //
999
+ // *Version: 1.3, Last updated: 7/21/2010*
1000
+ //
1001
+ // Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
1002
+ // GitHub - http://github.com/cowboy/jquery-hashchange/
1003
+ // Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
1004
+ // (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
1005
+ //
1006
+ // About: License
1007
+ //
1008
+ // Copyright (c) 2010 "Cowboy" Ben Alman,
1009
+ // Dual licensed under the MIT and GPL licenses.
1010
+ // http://benalman.com/about/license/
1011
+ //
1012
+ // About: Examples
1013
+ //
1014
+ // These working examples, complete with fully commented code, illustrate a few
1015
+ // ways in which this plugin can be used.
1016
+ //
1017
+ // hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
1018
+ // document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
1019
+ //
1020
+ // About: Support and Testing
1021
+ //
1022
+ // Information about what version or versions of jQuery this plugin has been
1023
+ // tested with, what browsers it has been tested in, and where the unit tests
1024
+ // reside (so you can test it yourself).
1025
+ //
1026
+ // jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
1027
+ // Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
1028
+ // Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
1029
+ // Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
1030
+ //
1031
+ // About: Known issues
1032
+ //
1033
+ // While this jQuery hashchange event implementation is quite stable and
1034
+ // robust, there are a few unfortunate browser bugs surrounding expected
1035
+ // hashchange event-based behaviors, independent of any JavaScript
1036
+ // window.onhashchange abstraction. See the following examples for more
1037
+ // information:
1038
+ //
1039
+ // Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
1040
+ // Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
1041
+ // WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
1042
+ // Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
1043
+ //
1044
+ // Also note that should a browser natively support the window.onhashchange
1045
+ // event, but not report that it does, the fallback polling loop will be used.
1046
+ //
1047
+ // About: Release History
1048
+ //
1049
+ // 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
1050
+ // "removable" for mobile-only development. Added IE6/7 document.title
1051
+ // support. Attempted to make Iframe as hidden as possible by using
1052
+ // techniques from http://www.paciellogroup.com/blog/?p=604. Added
1053
+ // support for the "shortcut" format $(window).hashchange( fn ) and
1054
+ // $(window).hashchange() like jQuery provides for built-in events.
1055
+ // Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
1056
+ // lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
1057
+ // and <jQuery.fn.hashchange.src> properties plus document-domain.html
1058
+ // file to address access denied issues when setting document.domain in
1059
+ // IE6/7.
1060
+ // 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
1061
+ // from a page on another domain would cause an error in Safari 4. Also,
1062
+ // IE6/7 Iframe is now inserted after the body (this actually works),
1063
+ // which prevents the page from scrolling when the event is first bound.
1064
+ // Event can also now be bound before DOM ready, but it won't be usable
1065
+ // before then in IE6/7.
1066
+ // 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
1067
+ // where browser version is incorrectly reported as 8.0, despite
1068
+ // inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
1069
+ // 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
1070
+ // window.onhashchange functionality into a separate plugin for users
1071
+ // who want just the basic event & back button support, without all the
1072
+ // extra awesomeness that BBQ provides. This plugin will be included as
1073
+ // part of jQuery BBQ, but also be available separately.
1074
+
1075
+ (function($,window,undefined){
1076
+ '$:nomunge'; // Used by YUI compressor.
1077
+
1078
+ // Reused string.
1079
+ var str_hashchange = 'hashchange',
1080
+
1081
+ // Method / object references.
1082
+ doc = document,
1083
+ fake_onhashchange,
1084
+ special = $.event.special,
1085
+
1086
+ // Does the browser support window.onhashchange? Note that IE8 running in
1087
+ // IE7 compatibility mode reports true for 'onhashchange' in window, even
1088
+ // though the event isn't supported, so also test document.documentMode.
1089
+ doc_mode = doc.documentMode,
1090
+ supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
1091
+
1092
+ // Get location.hash (or what you'd expect location.hash to be) sans any
1093
+ // leading #. Thanks for making this necessary, Firefox!
1094
+ function get_fragment( url ) {
1095
+ url = url || location.href;
1096
+ return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
1097
+ };
1098
+
1099
+ // Method: jQuery.fn.hashchange
1100
+ //
1101
+ // Bind a handler to the window.onhashchange event or trigger all bound
1102
+ // window.onhashchange event handlers. This behavior is consistent with
1103
+ // jQuery's built-in event handlers.
1104
+ //
1105
+ // Usage:
1106
+ //
1107
+ // > jQuery(window).hashchange( [ handler ] );
1108
+ //
1109
+ // Arguments:
1110
+ //
1111
+ // handler - (Function) Optional handler to be bound to the hashchange
1112
+ // event. This is a "shortcut" for the more verbose form:
1113
+ // jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
1114
+ // all bound window.onhashchange event handlers will be triggered. This
1115
+ // is a shortcut for the more verbose
1116
+ // jQuery(window).trigger( 'hashchange' ). These forms are described in
1117
+ // the <hashchange event> section.
1118
+ //
1119
+ // Returns:
1120
+ //
1121
+ // (jQuery) The initial jQuery collection of elements.
1122
+
1123
+ // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
1124
+ // $(elem).hashchange() for triggering, like jQuery does for built-in events.
1125
+ $.fn[ str_hashchange ] = function( fn ) {
1126
+ return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
1127
+ };
1128
+
1129
+ // Property: jQuery.fn.hashchange.delay
1130
+ //
1131
+ // The numeric interval (in milliseconds) at which the <hashchange event>
1132
+ // polling loop executes. Defaults to 50.
1133
+
1134
+ // Property: jQuery.fn.hashchange.domain
1135
+ //
1136
+ // If you're setting document.domain in your JavaScript, and you want hash
1137
+ // history to work in IE6/7, not only must this property be set, but you must
1138
+ // also set document.domain BEFORE jQuery is loaded into the page. This
1139
+ // property is only applicable if you are supporting IE6/7 (or IE8 operating
1140
+ // in "IE7 compatibility" mode).
1141
+ //
1142
+ // In addition, the <jQuery.fn.hashchange.src> property must be set to the
1143
+ // path of the included "document-domain.html" file, which can be renamed or
1144
+ // modified if necessary (note that the document.domain specified must be the
1145
+ // same in both your main JavaScript as well as in this file).
1146
+ //
1147
+ // Usage:
1148
+ //
1149
+ // jQuery.fn.hashchange.domain = document.domain;
1150
+
1151
+ // Property: jQuery.fn.hashchange.src
1152
+ //
1153
+ // If, for some reason, you need to specify an Iframe src file (for example,
1154
+ // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
1155
+ // do so using this property. Note that when using this property, history
1156
+ // won't be recorded in IE6/7 until the Iframe src file loads. This property
1157
+ // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
1158
+ // compatibility" mode).
1159
+ //
1160
+ // Usage:
1161
+ //
1162
+ // jQuery.fn.hashchange.src = 'path/to/file.html';
1163
+
1164
+ $.fn[ str_hashchange ].delay = 50;
1165
+ /*
1166
+ $.fn[ str_hashchange ].domain = null;
1167
+ $.fn[ str_hashchange ].src = null;
1168
+ */
1169
+
1170
+ // Event: hashchange event
1171
+ //
1172
+ // Fired when location.hash changes. In browsers that support it, the native
1173
+ // HTML5 window.onhashchange event is used, otherwise a polling loop is
1174
+ // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
1175
+ // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
1176
+ // compatibility" mode), a hidden Iframe is created to allow the back button
1177
+ // and hash-based history to work.
1178
+ //
1179
+ // Usage as described in <jQuery.fn.hashchange>:
1180
+ //
1181
+ // > // Bind an event handler.
1182
+ // > jQuery(window).hashchange( function(e) {
1183
+ // > var hash = location.hash;
1184
+ // > ...
1185
+ // > });
1186
+ // >
1187
+ // > // Manually trigger the event handler.
1188
+ // > jQuery(window).hashchange();
1189
+ //
1190
+ // A more verbose usage that allows for event namespacing:
1191
+ //
1192
+ // > // Bind an event handler.
1193
+ // > jQuery(window).bind( 'hashchange', function(e) {
1194
+ // > var hash = location.hash;
1195
+ // > ...
1196
+ // > });
1197
+ // >
1198
+ // > // Manually trigger the event handler.
1199
+ // > jQuery(window).trigger( 'hashchange' );
1200
+ //
1201
+ // Additional Notes:
1202
+ //
1203
+ // * The polling loop and Iframe are not created until at least one handler
1204
+ // is actually bound to the 'hashchange' event.
1205
+ // * If you need the bound handler(s) to execute immediately, in cases where
1206
+ // a location.hash exists on page load, via bookmark or page refresh for
1207
+ // example, use jQuery(window).hashchange() or the more verbose
1208
+ // jQuery(window).trigger( 'hashchange' ).
1209
+ // * The event can be bound before DOM ready, but since it won't be usable
1210
+ // before then in IE6/7 (due to the necessary Iframe), recommended usage is
1211
+ // to bind it inside a DOM ready handler.
1212
+
1213
+ // Override existing $.event.special.hashchange methods (allowing this plugin
1214
+ // to be defined after jQuery BBQ in BBQ's source code).
1215
+ special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
1216
+
1217
+ // Called only when the first 'hashchange' event is bound to window.
1218
+ setup: function() {
1219
+ // If window.onhashchange is supported natively, there's nothing to do..
1220
+ if ( supports_onhashchange ) { return false; }
1221
+
1222
+ // Otherwise, we need to create our own. And we don't want to call this
1223
+ // until the user binds to the event, just in case they never do, since it
1224
+ // will create a polling loop and possibly even a hidden Iframe.
1225
+ $( fake_onhashchange.start );
1226
+ },
1227
+
1228
+ // Called only when the last 'hashchange' event is unbound from window.
1229
+ teardown: function() {
1230
+ // If window.onhashchange is supported natively, there's nothing to do..
1231
+ if ( supports_onhashchange ) { return false; }
1232
+
1233
+ // Otherwise, we need to stop ours (if possible).
1234
+ $( fake_onhashchange.stop );
1235
+ }
1236
+
1237
+ });
1238
+
1239
+ // fake_onhashchange does all the work of triggering the window.onhashchange
1240
+ // event for browsers that don't natively support it, including creating a
1241
+ // polling loop to watch for hash changes and in IE 6/7 creating a hidden
1242
+ // Iframe to enable back and forward.
1243
+ fake_onhashchange = (function(){
1244
+ var self = {},
1245
+ timeout_id,
1246
+
1247
+ // Remember the initial hash so it doesn't get triggered immediately.
1248
+ last_hash = get_fragment(),
1249
+
1250
+ fn_retval = function(val){ return val; },
1251
+ history_set = fn_retval,
1252
+ history_get = fn_retval;
1253
+
1254
+ // Start the polling loop.
1255
+ self.start = function() {
1256
+ timeout_id || poll();
1257
+ };
1258
+
1259
+ // Stop the polling loop.
1260
+ self.stop = function() {
1261
+ timeout_id && clearTimeout( timeout_id );
1262
+ timeout_id = undefined;
1263
+ };
1264
+
1265
+ // This polling loop checks every $.fn.hashchange.delay milliseconds to see
1266
+ // if location.hash has changed, and triggers the 'hashchange' event on
1267
+ // window when necessary.
1268
+ function poll() {
1269
+ var hash = get_fragment(),
1270
+ history_hash = history_get( last_hash );
1271
+
1272
+ if ( hash !== last_hash ) {
1273
+ history_set( last_hash = hash, history_hash );
1274
+
1275
+ $(window).trigger( str_hashchange );
1276
+
1277
+ } else if ( history_hash !== last_hash ) {
1278
+ location.href = location.href.replace( /#.*/, '' ) + history_hash;
1279
+ }
1280
+
1281
+ timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
1282
+ };
1283
+
1284
+ return self;
1285
+ })();
1286
+
1287
+ })(jQuery,this);