wiselinks-artirix 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +51 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +4 -0
  6. data/Gemfile +7 -0
  7. data/Gemfile.lock +184 -0
  8. data/LICENSE +20 -0
  9. data/README.md +479 -0
  10. data/Rakefile +10 -0
  11. data/app/views/layouts/wiselinks.html.erb +1 -0
  12. data/compiler.jar +0 -0
  13. data/lib/assets/javascripts/_dom_parser.js.coffee +50 -0
  14. data/lib/assets/javascripts/_form.js.coffee +74 -0
  15. data/lib/assets/javascripts/_link.js.coffee +44 -0
  16. data/lib/assets/javascripts/_page.js.coffee +108 -0
  17. data/lib/assets/javascripts/_request_manager.js.coffee +132 -0
  18. data/lib/assets/javascripts/_response.js.coffee +101 -0
  19. data/lib/assets/javascripts/lib/native.history.js +3337 -0
  20. data/lib/assets/javascripts/wiselinks.js.coffee +37 -0
  21. data/lib/wiselinks-artirix.rb +1 -0
  22. data/lib/wiselinks.rb +27 -0
  23. data/lib/wiselinks/controller_methods.rb +67 -0
  24. data/lib/wiselinks/helpers.rb +9 -0
  25. data/lib/wiselinks/logger.rb +11 -0
  26. data/lib/wiselinks/rails.rb +22 -0
  27. data/lib/wiselinks/rendering.rb +37 -0
  28. data/lib/wiselinks/request.rb +29 -0
  29. data/lib/wiselinks/version.rb +12 -0
  30. data/spec/cases/helpers_spec.rb +8 -0
  31. data/spec/cases/request_spec.rb +113 -0
  32. data/spec/dummy/README.rdoc +261 -0
  33. data/spec/dummy/Rakefile +7 -0
  34. data/spec/dummy/app/assets/javascripts/application.js.coffee +1 -0
  35. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  36. data/spec/dummy/app/controllers/application_controller.rb +9 -0
  37. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  38. data/spec/dummy/app/mailers/.gitkeep +0 -0
  39. data/spec/dummy/app/models/.gitkeep +0 -0
  40. data/spec/dummy/app/views/application/index.html.erb +1 -0
  41. data/spec/dummy/app/views/application/no_slash.html.erb +0 -0
  42. data/spec/dummy/app/views/application/trailing_slash.html.erb +0 -0
  43. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  44. data/spec/dummy/config.ru +4 -0
  45. data/spec/dummy/config/application.rb +59 -0
  46. data/spec/dummy/config/boot.rb +10 -0
  47. data/spec/dummy/config/database.yml +7 -0
  48. data/spec/dummy/config/environment.rb +5 -0
  49. data/spec/dummy/config/environments/development.rb +37 -0
  50. data/spec/dummy/config/environments/production.rb +67 -0
  51. data/spec/dummy/config/environments/test.rb +40 -0
  52. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  53. data/spec/dummy/config/initializers/inflections.rb +15 -0
  54. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  55. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  56. data/spec/dummy/config/initializers/session_store.rb +8 -0
  57. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  58. data/spec/dummy/config/locales/en.yml +5 -0
  59. data/spec/dummy/config/routes.rb +7 -0
  60. data/spec/dummy/lib/assets/.gitkeep +0 -0
  61. data/spec/dummy/log/.gitkeep +0 -0
  62. data/spec/dummy/log/development.log +27917 -0
  63. data/spec/dummy/public/404.html +26 -0
  64. data/spec/dummy/public/422.html +26 -0
  65. data/spec/dummy/public/500.html +25 -0
  66. data/spec/dummy/public/assets/application-a98e47eb93026a340a766faf55214702.js +2830 -0
  67. data/spec/dummy/public/assets/application-a98e47eb93026a340a766faf55214702.js.gz +0 -0
  68. data/spec/dummy/public/assets/application-ecf5beebe0b79251c8be40f0443074f2.css +14 -0
  69. data/spec/dummy/public/assets/application-ecf5beebe0b79251c8be40f0443074f2.css.gz +0 -0
  70. data/spec/dummy/public/assets/application.css +14 -0
  71. data/spec/dummy/public/assets/application.css.gz +0 -0
  72. data/spec/dummy/public/assets/application.js +2830 -0
  73. data/spec/dummy/public/assets/application.js.gz +0 -0
  74. data/spec/dummy/public/assets/manifest.yml +5 -0
  75. data/spec/dummy/public/favicon.ico +0 -0
  76. data/spec/dummy/public/javascripts/wisepdf.js +1 -0
  77. data/spec/dummy/public/stylesheets/wisepdf.css +1 -0
  78. data/spec/dummy/script/rails +6 -0
  79. data/spec/dummy/tmp/cache/assets/C26/0A0/sprockets%2F52456508a38f02f4559064b24980c87a +0 -0
  80. data/spec/dummy/tmp/cache/assets/C5E/890/sprockets%2Ffb6525457b6873e6905e2d522548091f +0 -0
  81. data/spec/dummy/tmp/cache/assets/C80/150/sprockets%2F0d3881005b0646df783d5c24683d34f5 +0 -0
  82. data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  83. data/spec/dummy/tmp/cache/assets/CF3/250/sprockets%2F7edb1809ce839a3d290508f935c89f42 +0 -0
  84. data/spec/dummy/tmp/cache/assets/D09/C40/sprockets%2Fcf317b95ed0500b7277e950a9c0c82e0 +0 -0
  85. data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  86. data/spec/dummy/tmp/cache/assets/D45/760/sprockets%2Fbc659a6e09b5025e8be539b0b68f71f2 +0 -0
  87. data/spec/dummy/tmp/cache/assets/D4E/D00/sprockets%2F1a6846f0a837ae2524e2f9ec89e6ef43 +0 -0
  88. data/spec/dummy/tmp/cache/assets/D55/090/sprockets%2F4a21bc343a4696b7603ea4cc25c3c3ba +0 -0
  89. data/spec/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  90. data/spec/dummy/tmp/cache/assets/DC2/EB0/sprockets%2F75b4716f479a2acfac51b258fba0c2bd +0 -0
  91. data/spec/dummy/tmp/cache/assets/DF1/B80/sprockets%2Fcd0ee4f742908cb7223a1e7be4a4ccbc +0 -0
  92. data/spec/dummy/tmp/cache/assets/E11/4E0/sprockets%2F86e145a39f85cceeaffdff91ebb61449 +0 -0
  93. data/spec/factories/requests.rb +30 -0
  94. data/spec/helper.rb +26 -0
  95. data/spec/requests/trailing_slash_spec.rb +17 -0
  96. data/wiselinks-artirix.gemspec +40 -0
  97. metadata +432 -0
@@ -0,0 +1,14 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+
12
+
13
+ */
14
+
@@ -0,0 +1,14 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+
12
+
13
+ */
14
+
@@ -0,0 +1,2830 @@
1
+ /**
2
+ * History.js Core
3
+ * @author Benjamin Arthur Lupton <contact@balupton.com>
4
+ * @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
5
+ * @license New BSD License <http://creativecommons.org/licenses/BSD/>
6
+ */
7
+
8
+
9
+ (function(window,undefined){
10
+ "use strict";
11
+
12
+ // ========================================================================
13
+ // Initialise
14
+
15
+ // Localise Globals
16
+ var
17
+ console = window.console||undefined, // Prevent a JSLint complain
18
+ document = window.document, // Make sure we are using the correct document
19
+ navigator = window.navigator, // Make sure we are using the correct navigator
20
+ sessionStorage = window.sessionStorage||false, // sessionStorage
21
+ setTimeout = window.setTimeout,
22
+ clearTimeout = window.clearTimeout,
23
+ setInterval = window.setInterval,
24
+ clearInterval = window.clearInterval,
25
+ JSON = window.JSON,
26
+ alert = window.alert,
27
+ History = window.History = window.History||{}, // Public History Object
28
+ history = window.history; // Old History Object
29
+
30
+ // MooTools Compatibility
31
+ JSON.stringify = JSON.stringify||JSON.encode;
32
+ JSON.parse = JSON.parse||JSON.decode;
33
+
34
+ // Check Existence
35
+ if ( typeof History.init !== 'undefined' ) {
36
+ throw new Error('History.js Core has already been loaded...');
37
+ }
38
+
39
+ // Initialise History
40
+ History.init = function(){
41
+ // Check Load Status of Adapter
42
+ if ( typeof History.Adapter === 'undefined' ) {
43
+ return false;
44
+ }
45
+
46
+ // Check Load Status of Core
47
+ if ( typeof History.initCore !== 'undefined' ) {
48
+ History.initCore();
49
+ }
50
+
51
+ // Check Load Status of HTML4 Support
52
+ if ( typeof History.initHtml4 !== 'undefined' ) {
53
+ History.initHtml4();
54
+ }
55
+
56
+ // Return true
57
+ return true;
58
+ };
59
+
60
+
61
+ // ========================================================================
62
+ // Initialise Core
63
+
64
+ // Initialise Core
65
+ History.initCore = function(){
66
+ // Initialise
67
+ if ( typeof History.initCore.initialized !== 'undefined' ) {
68
+ // Already Loaded
69
+ return false;
70
+ }
71
+ else {
72
+ History.initCore.initialized = true;
73
+ }
74
+
75
+
76
+ // ====================================================================
77
+ // Options
78
+
79
+ /**
80
+ * History.options
81
+ * Configurable options
82
+ */
83
+ History.options = History.options||{};
84
+
85
+ /**
86
+ * History.options.hashChangeInterval
87
+ * How long should the interval be before hashchange checks
88
+ */
89
+ History.options.hashChangeInterval = History.options.hashChangeInterval || 100;
90
+
91
+ /**
92
+ * History.options.safariPollInterval
93
+ * How long should the interval be before safari poll checks
94
+ */
95
+ History.options.safariPollInterval = History.options.safariPollInterval || 500;
96
+
97
+ /**
98
+ * History.options.doubleCheckInterval
99
+ * How long should the interval be before we perform a double check
100
+ */
101
+ History.options.doubleCheckInterval = History.options.doubleCheckInterval || 500;
102
+
103
+ /**
104
+ * History.options.storeInterval
105
+ * How long should we wait between store calls
106
+ */
107
+ History.options.storeInterval = History.options.storeInterval || 1000;
108
+
109
+ /**
110
+ * History.options.busyDelay
111
+ * How long should we wait between busy events
112
+ */
113
+ History.options.busyDelay = History.options.busyDelay || 250;
114
+
115
+ /**
116
+ * History.options.debug
117
+ * If true will enable debug messages to be logged
118
+ */
119
+ History.options.debug = History.options.debug || false;
120
+
121
+ /**
122
+ * History.options.initialTitle
123
+ * What is the title of the initial state
124
+ */
125
+ History.options.initialTitle = History.options.initialTitle || document.title;
126
+
127
+
128
+ // ====================================================================
129
+ // Interval record
130
+
131
+ /**
132
+ * History.intervalList
133
+ * List of intervals set, to be cleared when document is unloaded.
134
+ */
135
+ History.intervalList = [];
136
+
137
+ /**
138
+ * History.clearAllIntervals
139
+ * Clears all setInterval instances.
140
+ */
141
+ History.clearAllIntervals = function(){
142
+ var i, il = History.intervalList;
143
+ if (typeof il !== "undefined" && il !== null) {
144
+ for (i = 0; i < il.length; i++) {
145
+ clearInterval(il[i]);
146
+ }
147
+ History.intervalList = null;
148
+ }
149
+ };
150
+
151
+
152
+ // ====================================================================
153
+ // Debug
154
+
155
+ /**
156
+ * History.debug(message,...)
157
+ * Logs the passed arguments if debug enabled
158
+ */
159
+ History.debug = function(){
160
+ if ( (History.options.debug||false) ) {
161
+ History.log.apply(History,arguments);
162
+ }
163
+ };
164
+
165
+ /**
166
+ * History.log(message,...)
167
+ * Logs the passed arguments
168
+ */
169
+ History.log = function(){
170
+ // Prepare
171
+ var
172
+ consoleExists = !(typeof console === 'undefined' || typeof console.log === 'undefined' || typeof console.log.apply === 'undefined'),
173
+ textarea = document.getElementById('log'),
174
+ message,
175
+ i,n,
176
+ args,arg
177
+ ;
178
+
179
+ // Write to Console
180
+ if ( consoleExists ) {
181
+ args = Array.prototype.slice.call(arguments);
182
+ message = args.shift();
183
+ if ( typeof console.debug !== 'undefined' ) {
184
+ console.debug.apply(console,[message,args]);
185
+ }
186
+ else {
187
+ console.log.apply(console,[message,args]);
188
+ }
189
+ }
190
+ else {
191
+ message = ("\n"+arguments[0]+"\n");
192
+ }
193
+
194
+ // Write to log
195
+ for ( i=1,n=arguments.length; i<n; ++i ) {
196
+ arg = arguments[i];
197
+ if ( typeof arg === 'object' && typeof JSON !== 'undefined' ) {
198
+ try {
199
+ arg = JSON.stringify(arg);
200
+ }
201
+ catch ( Exception ) {
202
+ // Recursive Object
203
+ }
204
+ }
205
+ message += "\n"+arg+"\n";
206
+ }
207
+
208
+ // Textarea
209
+ if ( textarea ) {
210
+ textarea.value += message+"\n-----\n";
211
+ textarea.scrollTop = textarea.scrollHeight - textarea.clientHeight;
212
+ }
213
+ // No Textarea, No Console
214
+ else if ( !consoleExists ) {
215
+ alert(message);
216
+ }
217
+
218
+ // Return true
219
+ return true;
220
+ };
221
+
222
+
223
+ // ====================================================================
224
+ // Emulated Status
225
+
226
+ /**
227
+ * History.getInternetExplorerMajorVersion()
228
+ * Get's the major version of Internet Explorer
229
+ * @return {integer}
230
+ * @license Public Domain
231
+ * @author Benjamin Arthur Lupton <contact@balupton.com>
232
+ * @author James Padolsey <https://gist.github.com/527683>
233
+ */
234
+ History.getInternetExplorerMajorVersion = function(){
235
+ var result = History.getInternetExplorerMajorVersion.cached =
236
+ (typeof History.getInternetExplorerMajorVersion.cached !== 'undefined')
237
+ ? History.getInternetExplorerMajorVersion.cached
238
+ : (function(){
239
+ var v = 3,
240
+ div = document.createElement('div'),
241
+ all = div.getElementsByTagName('i');
242
+ while ( (div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->') && all[0] ) {}
243
+ return (v > 4) ? v : false;
244
+ })()
245
+ ;
246
+ return result;
247
+ };
248
+
249
+ /**
250
+ * History.isInternetExplorer()
251
+ * Are we using Internet Explorer?
252
+ * @return {boolean}
253
+ * @license Public Domain
254
+ * @author Benjamin Arthur Lupton <contact@balupton.com>
255
+ */
256
+ History.isInternetExplorer = function(){
257
+ var result =
258
+ History.isInternetExplorer.cached =
259
+ (typeof History.isInternetExplorer.cached !== 'undefined')
260
+ ? History.isInternetExplorer.cached
261
+ : Boolean(History.getInternetExplorerMajorVersion())
262
+ ;
263
+ return result;
264
+ };
265
+
266
+ /**
267
+ * History.emulated
268
+ * Which features require emulating?
269
+ */
270
+ History.emulated = {
271
+ pushState: !Boolean(
272
+ window.history && window.history.pushState && window.history.replaceState
273
+ && !(
274
+ (/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent) /* disable for versions of iOS before version 4.3 (8F190) */
275
+ || (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent) /* disable for the mercury iOS browser, or at least older versions of the webkit engine */
276
+ )
277
+ ),
278
+ hashChange: Boolean(
279
+ !(('onhashchange' in window) || ('onhashchange' in document))
280
+ ||
281
+ (History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8)
282
+ )
283
+ };
284
+
285
+ /**
286
+ * History.enabled
287
+ * Is History enabled?
288
+ */
289
+ History.enabled = !History.emulated.pushState;
290
+
291
+ /**
292
+ * History.bugs
293
+ * Which bugs are present
294
+ */
295
+ History.bugs = {
296
+ /**
297
+ * Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call
298
+ * https://bugs.webkit.org/show_bug.cgi?id=56249
299
+ */
300
+ setHash: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)),
301
+
302
+ /**
303
+ * Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions
304
+ * https://bugs.webkit.org/show_bug.cgi?id=42940
305
+ */
306
+ safariPoll: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)),
307
+
308
+ /**
309
+ * MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function)
310
+ */
311
+ ieDoubleCheck: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8),
312
+
313
+ /**
314
+ * MSIE 6 requires the entire hash to be encoded for the hashes to trigger the onHashChange event
315
+ */
316
+ hashEscape: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 7)
317
+ };
318
+
319
+ /**
320
+ * History.isEmptyObject(obj)
321
+ * Checks to see if the Object is Empty
322
+ * @param {Object} obj
323
+ * @return {boolean}
324
+ */
325
+ History.isEmptyObject = function(obj) {
326
+ for ( var name in obj ) {
327
+ return false;
328
+ }
329
+ return true;
330
+ };
331
+
332
+ /**
333
+ * History.cloneObject(obj)
334
+ * Clones a object and eliminate all references to the original contexts
335
+ * @param {Object} obj
336
+ * @return {Object}
337
+ */
338
+ History.cloneObject = function(obj) {
339
+ var hash,newObj;
340
+ if ( obj ) {
341
+ hash = JSON.stringify(obj);
342
+ newObj = JSON.parse(hash);
343
+ }
344
+ else {
345
+ newObj = {};
346
+ }
347
+ return newObj;
348
+ };
349
+
350
+
351
+ // ====================================================================
352
+ // URL Helpers
353
+
354
+ /**
355
+ * History.getRootUrl()
356
+ * Turns "http://mysite.com/dir/page.html?asd" into "http://mysite.com"
357
+ * @return {String} rootUrl
358
+ */
359
+ History.getRootUrl = function(){
360
+ // Create
361
+ var rootUrl = document.location.protocol+'//'+(document.location.hostname||document.location.host);
362
+ if ( document.location.port||false ) {
363
+ rootUrl += ':'+document.location.port;
364
+ }
365
+ rootUrl += '/';
366
+
367
+ // Return
368
+ return rootUrl;
369
+ };
370
+
371
+ /**
372
+ * History.getBaseHref()
373
+ * Fetches the `href` attribute of the `<base href="...">` element if it exists
374
+ * @return {String} baseHref
375
+ */
376
+ History.getBaseHref = function(){
377
+ // Create
378
+ var
379
+ baseElements = document.getElementsByTagName('base'),
380
+ baseElement = null,
381
+ baseHref = '';
382
+
383
+ // Test for Base Element
384
+ if ( baseElements.length === 1 ) {
385
+ // Prepare for Base Element
386
+ baseElement = baseElements[0];
387
+ baseHref = baseElement.href.replace(/[^\/]+$/,'');
388
+ }
389
+
390
+ // Adjust trailing slash
391
+ baseHref = baseHref.replace(/\/+$/,'');
392
+ if ( baseHref ) baseHref += '/';
393
+
394
+ // Return
395
+ return baseHref;
396
+ };
397
+
398
+ /**
399
+ * History.getBaseUrl()
400
+ * Fetches the baseHref or basePageUrl or rootUrl (whichever one exists first)
401
+ * @return {String} baseUrl
402
+ */
403
+ History.getBaseUrl = function(){
404
+ // Create
405
+ var baseUrl = History.getBaseHref()||History.getBasePageUrl()||History.getRootUrl();
406
+
407
+ // Return
408
+ return baseUrl;
409
+ };
410
+
411
+ /**
412
+ * History.getPageUrl()
413
+ * Fetches the URL of the current page
414
+ * @return {String} pageUrl
415
+ */
416
+ History.getPageUrl = function(){
417
+ // Fetch
418
+ var
419
+ State = History.getState(false,false),
420
+ stateUrl = (State||{}).url||document.location.href,
421
+ pageUrl;
422
+
423
+ // Create
424
+ pageUrl = stateUrl.replace(/\/+$/,'').replace(/[^\/]+$/,function(part,index,string){
425
+ return (/\!/).test(part) ? part : part+'/';
426
+ });
427
+
428
+ // Return
429
+ return pageUrl;
430
+ };
431
+
432
+ /**
433
+ * History.getBasePageUrl()
434
+ * Fetches the Url of the directory of the current page
435
+ * @return {String} basePageUrl
436
+ */
437
+ History.getBasePageUrl = function(){
438
+ // Create
439
+ var basePageUrl = document.location.href.replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){
440
+ return (/[^\/]$/).test(part) ? '' : part;
441
+ }).replace(/\/+$/,'')+'/';
442
+
443
+ // Return
444
+ return basePageUrl;
445
+ };
446
+
447
+ /**
448
+ * History.getFullUrl(url)
449
+ * Ensures that we have an absolute URL and not a relative URL
450
+ * @param {string} url
451
+ * @param {Boolean} allowBaseHref
452
+ * @return {string} fullUrl
453
+ */
454
+ History.getFullUrl = function(url,allowBaseHref){
455
+ // Prepare
456
+ var fullUrl = url, firstChar = url.substring(0,1);
457
+ allowBaseHref = (typeof allowBaseHref === 'undefined') ? true : allowBaseHref;
458
+
459
+ // Check
460
+ if ( /[a-z]+\:\/\//.test(url) ) {
461
+ // Full URL
462
+ }
463
+ else if ( firstChar === '/' ) {
464
+ // Root URL
465
+ fullUrl = History.getRootUrl()+url.replace(/^\/+/,'');
466
+ }
467
+ else if ( firstChar === '#' ) {
468
+ // Anchor URL
469
+ fullUrl = History.getPageUrl().replace(/#!*/,'')+url;
470
+ }
471
+ else if ( firstChar === '?' ) {
472
+ // Query URL
473
+ fullUrl = History.getPageUrl().replace(/[\?#]!*/,'')+url;
474
+ }
475
+ else {
476
+ // Relative URL
477
+ if ( allowBaseHref ) {
478
+ fullUrl = History.getBaseUrl()+url.replace(/^(\!\/)+/,'');
479
+ } else {
480
+ fullUrl = History.getBasePageUrl()+url.replace(/^(\!\/)+/,'');
481
+ }
482
+ // We have an if condition above as we do not want hashes
483
+ // which are relative to the baseHref in our URLs
484
+ // as if the baseHref changes, then all our bookmarks
485
+ // would now point to different locations
486
+ // whereas the basePageUrl will always stay the same
487
+ }
488
+
489
+ // Return
490
+ return fullUrl.replace(/\#$/,'');
491
+ };
492
+
493
+ /**
494
+ * History.getShortUrl(url)
495
+ * Ensures that we have a relative URL and not a absolute URL
496
+ * @param {string} url
497
+ * @return {string} url
498
+ */
499
+ History.getShortUrl = function(url){
500
+ // Prepare
501
+ var shortUrl = url, baseUrl = History.getBaseUrl(), rootUrl = History.getRootUrl();
502
+
503
+ // Trim baseUrl
504
+ if ( History.emulated.pushState ) {
505
+ // We are in a if statement as when pushState is not emulated
506
+ // The actual url these short urls are relative to can change
507
+ // So within the same session, we the url may end up somewhere different
508
+ shortUrl = shortUrl.replace(baseUrl,'');
509
+ }
510
+
511
+ // Trim rootUrl
512
+ shortUrl = shortUrl.replace(rootUrl,'/');
513
+
514
+ // Ensure we can still detect it as a state
515
+ // if ( History.isTraditionalAnchor(shortUrl) ) {
516
+ // shortUrl = './'+shortUrl;
517
+ // // shortUrl = '/'+shortUrl;
518
+ // }
519
+
520
+ shortUrl = '!/'+shortUrl;
521
+
522
+ // Clean It
523
+ shortUrl = shortUrl.replace(/^(\!\/)+/g,'!/').replace(/\#$/,'');
524
+
525
+ // Return
526
+ return shortUrl;
527
+ };
528
+
529
+
530
+ // ====================================================================
531
+ // State Storage
532
+
533
+ /**
534
+ * History.store
535
+ * The store for all session specific data
536
+ */
537
+ History.store = {};
538
+
539
+ /**
540
+ * History.idToState
541
+ * 1-1: State ID to State Object
542
+ */
543
+ History.idToState = History.idToState||{};
544
+
545
+ /**
546
+ * History.stateToId
547
+ * 1-1: State String to State ID
548
+ */
549
+ History.stateToId = History.stateToId||{};
550
+
551
+ /**
552
+ * History.urlToId
553
+ * 1-1: State URL to State ID
554
+ */
555
+ History.urlToId = History.urlToId||{};
556
+
557
+ /**
558
+ * History.storedStates
559
+ * Store the states in an array
560
+ */
561
+ History.storedStates = History.storedStates||[];
562
+
563
+ /**
564
+ * History.savedStates
565
+ * Saved the states in an array
566
+ */
567
+ History.savedStates = History.savedStates||[];
568
+
569
+ /**
570
+ * History.noramlizeStore()
571
+ * Noramlize the store by adding necessary values
572
+ */
573
+ History.normalizeStore = function(){
574
+ History.store.idToState = History.store.idToState||{};
575
+ History.store.urlToId = History.store.urlToId||{};
576
+ History.store.stateToId = History.store.stateToId||{};
577
+ };
578
+
579
+ /**
580
+ * History.getState()
581
+ * Get an object containing the data, title and url of the current state
582
+ * @param {Boolean} friendly
583
+ * @param {Boolean} create
584
+ * @return {Object} State
585
+ */
586
+ History.getState = function(friendly,create){
587
+ // Prepare
588
+ if ( typeof friendly === 'undefined' ) { friendly = true; }
589
+ if ( typeof create === 'undefined' ) { create = true; }
590
+
591
+ // Fetch
592
+ var State = History.getLastSavedState();
593
+
594
+ // Create
595
+ if ( !State && create ) {
596
+ State = History.createStateObject();
597
+ }
598
+
599
+ // Adjust
600
+ if ( friendly ) {
601
+ State = History.cloneObject(State);
602
+ State.url = State.cleanUrl||State.url;
603
+ }
604
+
605
+ // Return
606
+ return State;
607
+ };
608
+
609
+ /**
610
+ * History.getIdByState(State)
611
+ * Gets a ID for a State
612
+ * @param {State} newState
613
+ * @return {String} id
614
+ */
615
+ History.getIdByState = function(newState){
616
+
617
+ // Fetch ID
618
+ var id = History.extractId(newState.url),
619
+ str;
620
+
621
+ if ( !id ) {
622
+ // Find ID via State String
623
+ str = History.getStateString(newState);
624
+ if ( typeof History.stateToId[str] !== 'undefined' ) {
625
+ id = History.stateToId[str];
626
+ }
627
+ else if ( typeof History.store.stateToId[str] !== 'undefined' ) {
628
+ id = History.store.stateToId[str];
629
+ }
630
+ else {
631
+ // Generate a new ID
632
+ while ( true ) {
633
+ id = (new Date()).getTime() + String(Math.random()).replace(/\D/g,'');
634
+ if ( typeof History.idToState[id] === 'undefined' && typeof History.store.idToState[id] === 'undefined' ) {
635
+ break;
636
+ }
637
+ }
638
+
639
+ // Apply the new State to the ID
640
+ History.stateToId[str] = id;
641
+ History.idToState[id] = newState;
642
+ }
643
+ }
644
+
645
+ // Return ID
646
+ return id;
647
+ };
648
+
649
+ /**
650
+ * History.normalizeState(State)
651
+ * Expands a State Object
652
+ * @param {object} State
653
+ * @return {object}
654
+ */
655
+ History.normalizeState = function(oldState){
656
+ // Variables
657
+ var newState, dataNotEmpty;
658
+
659
+ // Prepare
660
+ if ( !oldState || (typeof oldState !== 'object') ) {
661
+ oldState = {};
662
+ }
663
+
664
+ // Check
665
+ if ( typeof oldState.normalized !== 'undefined' ) {
666
+ return oldState;
667
+ }
668
+
669
+ // Adjust
670
+ if ( !oldState.data || (typeof oldState.data !== 'object') ) {
671
+ oldState.data = {};
672
+ }
673
+
674
+ // ----------------------------------------------------------------
675
+
676
+ // Create
677
+ newState = {};
678
+ newState.normalized = true;
679
+ newState.title = oldState.title||'';
680
+ newState.url = History.getFullUrl(History.unescapeString(oldState.url||document.location.href));
681
+ newState.hash = History.getShortUrl(newState.url);
682
+ newState.data = History.cloneObject(oldState.data);
683
+
684
+ // Fetch ID
685
+ newState.id = History.getIdByState(newState);
686
+
687
+ // ----------------------------------------------------------------
688
+
689
+ // Clean the URL
690
+ newState.cleanUrl = newState.url.replace(/\??\&_suid.*/,'');
691
+ newState.url = newState.cleanUrl;
692
+
693
+ // Check to see if we have more than just a url
694
+ dataNotEmpty = !History.isEmptyObject(newState.data);
695
+
696
+ // Apply
697
+ if ( newState.title || dataNotEmpty ) {
698
+ // Add ID to Hash
699
+ newState.hash = History.getShortUrl(newState.url).replace(/\??\&_suid.*/,'');
700
+ if ( !/\?/.test(newState.hash) ) {
701
+ newState.hash += '?';
702
+ }
703
+ newState.hash += '&_suid='+newState.id;
704
+ }
705
+
706
+ // Create the Hashed URL
707
+ newState.hashedUrl = History.getFullUrl(newState.hash);
708
+
709
+ // ----------------------------------------------------------------
710
+
711
+ // Update the URL if we have a duplicate
712
+ if ( (History.emulated.pushState || History.bugs.safariPoll) && History.hasUrlDuplicate(newState) ) {
713
+ newState.url = newState.hashedUrl;
714
+ }
715
+
716
+ // ----------------------------------------------------------------
717
+
718
+ // Return
719
+ return newState;
720
+ };
721
+
722
+ /**
723
+ * History.createStateObject(data,title,url)
724
+ * Creates a object based on the data, title and url state params
725
+ * @param {object} data
726
+ * @param {string} title
727
+ * @param {string} url
728
+ * @return {object}
729
+ */
730
+ History.createStateObject = function(data,title,url){
731
+ // Hashify
732
+ var State = {
733
+ 'data': data,
734
+ 'title': title,
735
+ 'url': url
736
+ };
737
+
738
+ // Expand the State
739
+ State = History.normalizeState(State);
740
+
741
+ // Return object
742
+ return State;
743
+ };
744
+
745
+ /**
746
+ * History.getStateById(id)
747
+ * Get a state by it's UID
748
+ * @param {String} id
749
+ */
750
+ History.getStateById = function(id){
751
+ // Prepare
752
+ id = String(id);
753
+
754
+ // Retrieve
755
+ var State = History.idToState[id] || History.store.idToState[id] || undefined;
756
+
757
+ // Return State
758
+ return State;
759
+ };
760
+
761
+ /**
762
+ * Get a State's String
763
+ * @param {State} passedState
764
+ */
765
+ History.getStateString = function(passedState){
766
+ // Prepare
767
+ var State, cleanedState, str;
768
+
769
+ // Fetch
770
+ State = History.normalizeState(passedState);
771
+
772
+ // Clean
773
+ cleanedState = {
774
+ data: State.data,
775
+ title: passedState.title,
776
+ url: passedState.url
777
+ };
778
+
779
+ // Fetch
780
+ str = JSON.stringify(cleanedState);
781
+
782
+ // Return
783
+ return str;
784
+ };
785
+
786
+ /**
787
+ * Get a State's ID
788
+ * @param {State} passedState
789
+ * @return {String} id
790
+ */
791
+ History.getStateId = function(passedState){
792
+ // Prepare
793
+ var State, id;
794
+
795
+ // Fetch
796
+ State = History.normalizeState(passedState);
797
+
798
+ // Fetch
799
+ id = State.id;
800
+
801
+ // Return
802
+ return id;
803
+ };
804
+
805
+ /**
806
+ * History.getHashByState(State)
807
+ * Creates a Hash for the State Object
808
+ * @param {State} passedState
809
+ * @return {String} hash
810
+ */
811
+ History.getHashByState = function(passedState){
812
+ // Prepare
813
+ var State, hash;
814
+
815
+ // Fetch
816
+ State = History.normalizeState(passedState);
817
+
818
+ // Hash
819
+ hash = State.hash;
820
+
821
+ // Return
822
+ return hash;
823
+ };
824
+
825
+ /**
826
+ * History.extractId(url_or_hash)
827
+ * Get a State ID by it's URL or Hash
828
+ * @param {string} url_or_hash
829
+ * @return {string} id
830
+ */
831
+ History.extractId = function ( url_or_hash ) {
832
+ // Prepare
833
+ var id,parts,url;
834
+
835
+ // Extract
836
+ parts = /(.*)\&_suid=([0-9]+)$/.exec(url_or_hash);
837
+ url = parts ? (parts[1]||url_or_hash) : url_or_hash;
838
+ id = parts ? String(parts[2]||'') : '';
839
+
840
+ // Return
841
+ return id||false;
842
+ };
843
+
844
+ /**
845
+ * History.isTraditionalAnchor
846
+ * Checks to see if the url is a traditional anchor or not
847
+ * @param {String} url_or_hash
848
+ * @return {Boolean}
849
+ */
850
+ History.isTraditionalAnchor = function(url_or_hash){
851
+ // Check
852
+ var isTraditional = !(/[\/\?\.]/.test(url_or_hash));
853
+
854
+ // Return
855
+ return isTraditional;
856
+ };
857
+
858
+ /**
859
+ * History.extractState
860
+ * Get a State by it's URL or Hash
861
+ * @param {String} url_or_hash
862
+ * @return {State|null}
863
+ */
864
+ History.extractState = function(url_or_hash,create){
865
+ // Prepare
866
+ var State = null, id, url;
867
+ create = create||false;
868
+
869
+ // Fetch SUID
870
+ id = History.extractId(url_or_hash);
871
+ if ( id ) {
872
+ State = History.getStateById(id);
873
+ }
874
+
875
+ // Fetch SUID returned no State
876
+ if ( !State ) {
877
+ // Fetch URL
878
+ url = History.getFullUrl(url_or_hash);
879
+
880
+ // Check URL
881
+ id = History.getIdByUrl(url)||false;
882
+ if ( id ) {
883
+ State = History.getStateById(id);
884
+ }
885
+
886
+ // Create State
887
+ if ( !State && create && !History.isTraditionalAnchor(url_or_hash) ) {
888
+ State = History.createStateObject(null,null,url);
889
+ }
890
+ }
891
+
892
+ // Return
893
+ return State;
894
+ };
895
+
896
+ /**
897
+ * History.getIdByUrl()
898
+ * Get a State ID by a State URL
899
+ */
900
+ History.getIdByUrl = function(url){
901
+ // Fetch
902
+ var id = History.urlToId[url] || History.store.urlToId[url] || undefined;
903
+
904
+ // Return
905
+ return id;
906
+ };
907
+
908
+ /**
909
+ * History.getLastSavedState()
910
+ * Get an object containing the data, title and url of the current state
911
+ * @return {Object} State
912
+ */
913
+ History.getLastSavedState = function(){
914
+ return History.savedStates[History.savedStates.length-1]||undefined;
915
+ };
916
+
917
+ /**
918
+ * History.getLastStoredState()
919
+ * Get an object containing the data, title and url of the current state
920
+ * @return {Object} State
921
+ */
922
+ History.getLastStoredState = function(){
923
+ return History.storedStates[History.storedStates.length-1]||undefined;
924
+ };
925
+
926
+ /**
927
+ * History.hasUrlDuplicate
928
+ * Checks if a Url will have a url conflict
929
+ * @param {Object} newState
930
+ * @return {Boolean} hasDuplicate
931
+ */
932
+ History.hasUrlDuplicate = function(newState) {
933
+ // Prepare
934
+ var hasDuplicate = false,
935
+ oldState;
936
+
937
+ // Fetch
938
+ oldState = History.extractState(newState.url);
939
+
940
+ // Check
941
+ hasDuplicate = oldState && oldState.id !== newState.id;
942
+
943
+ // Return
944
+ return hasDuplicate;
945
+ };
946
+
947
+ /**
948
+ * History.storeState
949
+ * Store a State
950
+ * @param {Object} newState
951
+ * @return {Object} newState
952
+ */
953
+ History.storeState = function(newState){
954
+ // Store the State
955
+ History.urlToId[newState.url] = newState.id;
956
+
957
+ // Push the State
958
+ History.storedStates.push(History.cloneObject(newState));
959
+
960
+ // Return newState
961
+ return newState;
962
+ };
963
+
964
+ /**
965
+ * History.isLastSavedState(newState)
966
+ * Tests to see if the state is the last state
967
+ * @param {Object} newState
968
+ * @return {boolean} isLast
969
+ */
970
+ History.isLastSavedState = function(newState){
971
+ // Prepare
972
+ var isLast = false,
973
+ newId, oldState, oldId;
974
+
975
+ // Check
976
+ if ( History.savedStates.length ) {
977
+ newId = newState.id;
978
+ oldState = History.getLastSavedState();
979
+ oldId = oldState.id;
980
+
981
+ // Check
982
+ isLast = (newId === oldId);
983
+ }
984
+
985
+ // Return
986
+ return isLast;
987
+ };
988
+
989
+ /**
990
+ * History.saveState
991
+ * Push a State
992
+ * @param {Object} newState
993
+ * @return {boolean} changed
994
+ */
995
+ History.saveState = function(newState){
996
+ // Check Hash
997
+ if ( History.isLastSavedState(newState) ) {
998
+ return false;
999
+ }
1000
+
1001
+ // Push the State
1002
+ History.savedStates.push(History.cloneObject(newState));
1003
+
1004
+ // Return true
1005
+ return true;
1006
+ };
1007
+
1008
+ /**
1009
+ * History.getStateByIndex()
1010
+ * Gets a state by the index
1011
+ * @param {integer} index
1012
+ * @return {Object}
1013
+ */
1014
+ History.getStateByIndex = function(index){
1015
+ // Prepare
1016
+ var State = null;
1017
+
1018
+ // Handle
1019
+ if ( typeof index === 'undefined' ) {
1020
+ // Get the last inserted
1021
+ State = History.savedStates[History.savedStates.length-1];
1022
+ }
1023
+ else if ( index < 0 ) {
1024
+ // Get from the end
1025
+ State = History.savedStates[History.savedStates.length+index];
1026
+ }
1027
+ else {
1028
+ // Get from the beginning
1029
+ State = History.savedStates[index];
1030
+ }
1031
+
1032
+ // Return State
1033
+ return State;
1034
+ };
1035
+
1036
+
1037
+ // ====================================================================
1038
+ // Hash Helpers
1039
+
1040
+ /**
1041
+ * History.getHash()
1042
+ * Gets the current document hash
1043
+ * @return {string}
1044
+ */
1045
+ History.getHash = function(){
1046
+ var hash = History.unescapeHash(document.location.hash);
1047
+ return hash;
1048
+ };
1049
+
1050
+ /**
1051
+ * History.unescapeString()
1052
+ * Unescape a string
1053
+ * @param {String} str
1054
+ * @return {string}
1055
+ */
1056
+ History.unescapeString = function(str){
1057
+ // Prepare
1058
+ var result = str,
1059
+ tmp;
1060
+
1061
+ // Unescape hash
1062
+ while ( true ) {
1063
+ tmp = window.decodeURI(result);
1064
+ if ( tmp === result ) {
1065
+ break;
1066
+ }
1067
+ result = tmp;
1068
+ }
1069
+
1070
+ // Return result
1071
+ return result;
1072
+ };
1073
+
1074
+ /**
1075
+ * History.unescapeHash()
1076
+ * normalize and Unescape a Hash
1077
+ * @param {String} hash
1078
+ * @return {string}
1079
+ */
1080
+ History.unescapeHash = function(hash){
1081
+ // Prepare
1082
+ var result = History.normalizeHash(hash);
1083
+
1084
+ // Unescape hash
1085
+ result = History.unescapeString(result);
1086
+
1087
+ // Return result
1088
+ return result;
1089
+ };
1090
+
1091
+ /**
1092
+ * History.normalizeHash()
1093
+ * normalize a hash across browsers
1094
+ * @return {string}
1095
+ */
1096
+ History.normalizeHash = function(hash){
1097
+ // Prepare
1098
+ var result = hash.replace(/[^#]*#/,'').replace(/#!*/, '');
1099
+
1100
+ // Return result
1101
+ return result;
1102
+ };
1103
+
1104
+ /**
1105
+ * History.setHash(hash)
1106
+ * Sets the document hash
1107
+ * @param {string} hash
1108
+ * @return {History}
1109
+ */
1110
+ History.setHash = function(hash,queue){
1111
+ // Prepare
1112
+ var adjustedHash, State, pageUrl;
1113
+
1114
+ // Handle Queueing
1115
+ if ( queue !== false && History.busy() ) {
1116
+ // Wait + Push to Queue
1117
+ //History.debug('History.setHash: we must wait', arguments);
1118
+ History.pushQueue({
1119
+ scope: History,
1120
+ callback: History.setHash,
1121
+ args: arguments,
1122
+ queue: queue
1123
+ });
1124
+ return false;
1125
+ }
1126
+
1127
+ // Log
1128
+ //History.debug('History.setHash: called',hash);
1129
+
1130
+ // Prepare
1131
+ adjustedHash = History.escapeHash(hash);
1132
+
1133
+ // Make Busy + Continue
1134
+ History.busy(true);
1135
+
1136
+ // Check if hash is a state
1137
+ State = History.extractState(hash,true);
1138
+ if ( State && !History.emulated.pushState ) {
1139
+ // Hash is a state so skip the setHash
1140
+ //History.debug('History.setHash: Hash is a state so skipping the hash set with a direct pushState call',arguments);
1141
+
1142
+ // PushState
1143
+ History.pushState(State.data,State.title,State.url,false);
1144
+ }
1145
+ else if ( document.location.hash !== adjustedHash ) {
1146
+ // Hash is a proper hash, so apply it
1147
+
1148
+ // Handle browser bugs
1149
+ if ( History.bugs.setHash ) {
1150
+ // Fix Safari Bug https://bugs.webkit.org/show_bug.cgi?id=56249
1151
+
1152
+ // Fetch the base page
1153
+ pageUrl = History.getPageUrl();
1154
+
1155
+ // Safari hash apply
1156
+ History.pushState(null,null,pageUrl+'#'+adjustedHash,false);
1157
+ }
1158
+ else {
1159
+ // Normal hash apply
1160
+ document.location.hash = adjustedHash;
1161
+ }
1162
+ }
1163
+
1164
+ // Chain
1165
+ return History;
1166
+ };
1167
+
1168
+ /**
1169
+ * History.escape()
1170
+ * normalize and Escape a Hash
1171
+ * @return {string}
1172
+ */
1173
+ History.escapeHash = function(hash){
1174
+ // Prepare
1175
+ var result = History.normalizeHash(hash);
1176
+
1177
+ // Escape hash
1178
+ result = window.encodeURI(result);
1179
+
1180
+ // IE6 Escape Bug
1181
+ if ( !History.bugs.hashEscape ) {
1182
+ // Restore common parts
1183
+ result = result
1184
+ .replace(/\%21/g,'!')
1185
+ .replace(/\%26/g,'&')
1186
+ .replace(/\%3D/g,'=')
1187
+ .replace(/\%3F/g,'?');
1188
+ }
1189
+
1190
+ // Return result
1191
+ return result;
1192
+ };
1193
+
1194
+ /**
1195
+ * History.getHashByUrl(url)
1196
+ * Extracts the Hash from a URL
1197
+ * @param {string} url
1198
+ * @return {string} url
1199
+ */
1200
+ History.getHashByUrl = function(url){
1201
+ // Extract the hash
1202
+ var hash = String(url)
1203
+ .replace(/([^#]*)#?([^#]*)#?(.*)/, '$2')
1204
+ ;
1205
+
1206
+ // Unescape hash
1207
+ hash = History.unescapeHash(hash);
1208
+
1209
+ // Return hash
1210
+ return hash;
1211
+ };
1212
+
1213
+ /**
1214
+ * History.setTitle(title)
1215
+ * Applies the title to the document
1216
+ * @param {State} newState
1217
+ * @return {Boolean}
1218
+ */
1219
+ History.setTitle = function(newState){
1220
+ // Prepare
1221
+ var title = newState.title,
1222
+ firstState;
1223
+
1224
+ // Initial
1225
+ if ( !title ) {
1226
+ firstState = History.getStateByIndex(0);
1227
+ if ( firstState && firstState.url === newState.url ) {
1228
+ title = firstState.title||History.options.initialTitle;
1229
+ }
1230
+ }
1231
+
1232
+ // Apply
1233
+ try {
1234
+ document.getElementsByTagName('title')[0].innerHTML = title.replace('<','&lt;').replace('>','&gt;').replace(' & ',' &amp; ');
1235
+ }
1236
+ catch ( Exception ) { }
1237
+ document.title = title;
1238
+
1239
+ // Chain
1240
+ return History;
1241
+ };
1242
+
1243
+
1244
+ // ====================================================================
1245
+ // Queueing
1246
+
1247
+ /**
1248
+ * History.queues
1249
+ * The list of queues to use
1250
+ * First In, First Out
1251
+ */
1252
+ History.queues = [];
1253
+
1254
+ /**
1255
+ * History.busy(value)
1256
+ * @param {boolean} value [optional]
1257
+ * @return {boolean} busy
1258
+ */
1259
+ History.busy = function(value){
1260
+ // Apply
1261
+ if ( typeof value !== 'undefined' ) {
1262
+ //History.debug('History.busy: changing ['+(History.busy.flag||false)+'] to ['+(value||false)+']', History.queues.length);
1263
+ History.busy.flag = value;
1264
+ }
1265
+ // Default
1266
+ else if ( typeof History.busy.flag === 'undefined' ) {
1267
+ History.busy.flag = false;
1268
+ }
1269
+
1270
+ // Queue
1271
+ if ( !History.busy.flag ) {
1272
+ // Execute the next item in the queue
1273
+ clearTimeout(History.busy.timeout);
1274
+ var fireNext = function(){
1275
+ var i, queue, item;
1276
+ if ( History.busy.flag ) return;
1277
+ for ( i=History.queues.length-1; i >= 0; --i ) {
1278
+ queue = History.queues[i];
1279
+ if ( queue.length === 0 ) continue;
1280
+ item = queue.shift();
1281
+ History.fireQueueItem(item);
1282
+ History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);
1283
+ }
1284
+ };
1285
+ History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);
1286
+ }
1287
+
1288
+ // Return
1289
+ return History.busy.flag;
1290
+ };
1291
+
1292
+ /**
1293
+ * History.busy.flag
1294
+ */
1295
+ History.busy.flag = false;
1296
+
1297
+ /**
1298
+ * History.fireQueueItem(item)
1299
+ * Fire a Queue Item
1300
+ * @param {Object} item
1301
+ * @return {Mixed} result
1302
+ */
1303
+ History.fireQueueItem = function(item){
1304
+ return item.callback.apply(item.scope||History,item.args||[]);
1305
+ };
1306
+
1307
+ /**
1308
+ * History.pushQueue(callback,args)
1309
+ * Add an item to the queue
1310
+ * @param {Object} item [scope,callback,args,queue]
1311
+ */
1312
+ History.pushQueue = function(item){
1313
+ // Prepare the queue
1314
+ History.queues[item.queue||0] = History.queues[item.queue||0]||[];
1315
+
1316
+ // Add to the queue
1317
+ History.queues[item.queue||0].push(item);
1318
+
1319
+ // Chain
1320
+ return History;
1321
+ };
1322
+
1323
+ /**
1324
+ * History.queue (item,queue), (func,queue), (func), (item)
1325
+ * Either firs the item now if not busy, or adds it to the queue
1326
+ */
1327
+ History.queue = function(item,queue){
1328
+ // Prepare
1329
+ if ( typeof item === 'function' ) {
1330
+ item = {
1331
+ callback: item
1332
+ };
1333
+ }
1334
+ if ( typeof queue !== 'undefined' ) {
1335
+ item.queue = queue;
1336
+ }
1337
+
1338
+ // Handle
1339
+ if ( History.busy() ) {
1340
+ History.pushQueue(item);
1341
+ } else {
1342
+ History.fireQueueItem(item);
1343
+ }
1344
+
1345
+ // Chain
1346
+ return History;
1347
+ };
1348
+
1349
+ /**
1350
+ * History.clearQueue()
1351
+ * Clears the Queue
1352
+ */
1353
+ History.clearQueue = function(){
1354
+ History.busy.flag = false;
1355
+ History.queues = [];
1356
+ return History;
1357
+ };
1358
+
1359
+
1360
+ // ====================================================================
1361
+ // IE Bug Fix
1362
+
1363
+ /**
1364
+ * History.stateChanged
1365
+ * States whether or not the state has changed since the last double check was initialised
1366
+ */
1367
+ History.stateChanged = false;
1368
+
1369
+ /**
1370
+ * History.doubleChecker
1371
+ * Contains the timeout used for the double checks
1372
+ */
1373
+ History.doubleChecker = false;
1374
+
1375
+ /**
1376
+ * History.doubleCheckComplete()
1377
+ * Complete a double check
1378
+ * @return {History}
1379
+ */
1380
+ History.doubleCheckComplete = function(){
1381
+ // Update
1382
+ History.stateChanged = true;
1383
+
1384
+ // Clear
1385
+ History.doubleCheckClear();
1386
+
1387
+ // Chain
1388
+ return History;
1389
+ };
1390
+
1391
+ /**
1392
+ * History.doubleCheckClear()
1393
+ * Clear a double check
1394
+ * @return {History}
1395
+ */
1396
+ History.doubleCheckClear = function(){
1397
+ // Clear
1398
+ if ( History.doubleChecker ) {
1399
+ clearTimeout(History.doubleChecker);
1400
+ History.doubleChecker = false;
1401
+ }
1402
+
1403
+ // Chain
1404
+ return History;
1405
+ };
1406
+
1407
+ /**
1408
+ * History.doubleCheck()
1409
+ * Create a double check
1410
+ * @return {History}
1411
+ */
1412
+ History.doubleCheck = function(tryAgain){
1413
+ // Reset
1414
+ History.stateChanged = false;
1415
+ History.doubleCheckClear();
1416
+
1417
+ // Fix IE6,IE7 bug where calling history.back or history.forward does not actually change the hash (whereas doing it manually does)
1418
+ // Fix Safari 5 bug where sometimes the state does not change: https://bugs.webkit.org/show_bug.cgi?id=42940
1419
+ if ( History.bugs.ieDoubleCheck ) {
1420
+ // Apply Check
1421
+ History.doubleChecker = setTimeout(
1422
+ function(){
1423
+ History.doubleCheckClear();
1424
+ if ( !History.stateChanged ) {
1425
+ //History.debug('History.doubleCheck: State has not yet changed, trying again', arguments);
1426
+ // Re-Attempt
1427
+ tryAgain();
1428
+ }
1429
+ return true;
1430
+ },
1431
+ History.options.doubleCheckInterval
1432
+ );
1433
+ }
1434
+
1435
+ // Chain
1436
+ return History;
1437
+ };
1438
+
1439
+
1440
+ // ====================================================================
1441
+ // Safari Bug Fix
1442
+
1443
+ /**
1444
+ * History.safariStatePoll()
1445
+ * Poll the current state
1446
+ * @return {History}
1447
+ */
1448
+ History.safariStatePoll = function(){
1449
+ // Poll the URL
1450
+
1451
+ // Get the Last State which has the new URL
1452
+ var
1453
+ urlState = History.extractState(document.location.href),
1454
+ newState;
1455
+
1456
+ // Check for a difference
1457
+ if ( !History.isLastSavedState(urlState) ) {
1458
+ newState = urlState;
1459
+ }
1460
+ else {
1461
+ return;
1462
+ }
1463
+
1464
+ // Check if we have a state with that url
1465
+ // If not create it
1466
+ if ( !newState ) {
1467
+ //History.debug('History.safariStatePoll: new');
1468
+ newState = History.createStateObject();
1469
+ }
1470
+
1471
+ // Apply the New State
1472
+ //History.debug('History.safariStatePoll: trigger');
1473
+ History.Adapter.trigger(window,'popstate');
1474
+
1475
+ // Chain
1476
+ return History;
1477
+ };
1478
+
1479
+
1480
+ // ====================================================================
1481
+ // State Aliases
1482
+
1483
+ /**
1484
+ * History.back(queue)
1485
+ * Send the browser history back one item
1486
+ * @param {Integer} queue [optional]
1487
+ */
1488
+ History.back = function(queue){
1489
+ //History.debug('History.back: called', arguments);
1490
+
1491
+ // Handle Queueing
1492
+ if ( queue !== false && History.busy() ) {
1493
+ // Wait + Push to Queue
1494
+ //History.debug('History.back: we must wait', arguments);
1495
+ History.pushQueue({
1496
+ scope: History,
1497
+ callback: History.back,
1498
+ args: arguments,
1499
+ queue: queue
1500
+ });
1501
+ return false;
1502
+ }
1503
+
1504
+ // Make Busy + Continue
1505
+ History.busy(true);
1506
+
1507
+ // Fix certain browser bugs that prevent the state from changing
1508
+ History.doubleCheck(function(){
1509
+ History.back(false);
1510
+ });
1511
+
1512
+ // Go back
1513
+ history.go(-1);
1514
+
1515
+ // End back closure
1516
+ return true;
1517
+ };
1518
+
1519
+ /**
1520
+ * History.forward(queue)
1521
+ * Send the browser history forward one item
1522
+ * @param {Integer} queue [optional]
1523
+ */
1524
+ History.forward = function(queue){
1525
+ //History.debug('History.forward: called', arguments);
1526
+
1527
+ // Handle Queueing
1528
+ if ( queue !== false && History.busy() ) {
1529
+ // Wait + Push to Queue
1530
+ //History.debug('History.forward: we must wait', arguments);
1531
+ History.pushQueue({
1532
+ scope: History,
1533
+ callback: History.forward,
1534
+ args: arguments,
1535
+ queue: queue
1536
+ });
1537
+ return false;
1538
+ }
1539
+
1540
+ // Make Busy + Continue
1541
+ History.busy(true);
1542
+
1543
+ // Fix certain browser bugs that prevent the state from changing
1544
+ History.doubleCheck(function(){
1545
+ History.forward(false);
1546
+ });
1547
+
1548
+ // Go forward
1549
+ history.go(1);
1550
+
1551
+ // End forward closure
1552
+ return true;
1553
+ };
1554
+
1555
+ /**
1556
+ * History.go(index,queue)
1557
+ * Send the browser history back or forward index times
1558
+ * @param {Integer} queue [optional]
1559
+ */
1560
+ History.go = function(index,queue){
1561
+ //History.debug('History.go: called', arguments);
1562
+
1563
+ // Prepare
1564
+ var i;
1565
+
1566
+ // Handle
1567
+ if ( index > 0 ) {
1568
+ // Forward
1569
+ for ( i=1; i<=index; ++i ) {
1570
+ History.forward(queue);
1571
+ }
1572
+ }
1573
+ else if ( index < 0 ) {
1574
+ // Backward
1575
+ for ( i=-1; i>=index; --i ) {
1576
+ History.back(queue);
1577
+ }
1578
+ }
1579
+ else {
1580
+ throw new Error('History.go: History.go requires a positive or negative integer passed.');
1581
+ }
1582
+
1583
+ // Chain
1584
+ return History;
1585
+ };
1586
+
1587
+
1588
+ // ====================================================================
1589
+ // HTML5 State Support
1590
+
1591
+ // Non-Native pushState Implementation
1592
+ if ( History.emulated.pushState ) {
1593
+ /*
1594
+ * Provide Skeleton for HTML4 Browsers
1595
+ */
1596
+
1597
+ // Prepare
1598
+ var emptyFunction = function(){};
1599
+ History.pushState = History.pushState||emptyFunction;
1600
+ History.replaceState = History.replaceState||emptyFunction;
1601
+ } // History.emulated.pushState
1602
+
1603
+ // Native pushState Implementation
1604
+ else {
1605
+ /*
1606
+ * Use native HTML5 History API Implementation
1607
+ */
1608
+
1609
+ /**
1610
+ * History.onPopState(event,extra)
1611
+ * Refresh the Current State
1612
+ */
1613
+ History.onPopState = function(event,extra){
1614
+ // Prepare
1615
+ var stateId = false, newState = false, currentHash, currentState;
1616
+
1617
+ // Reset the double check
1618
+ History.doubleCheckComplete();
1619
+
1620
+ // Check for a Hash, and handle apporiatly
1621
+ currentHash = History.getHash();
1622
+ if ( currentHash ) {
1623
+ // Expand Hash
1624
+ currentState = History.extractState(currentHash||document.location.href,true);
1625
+ if ( currentState ) {
1626
+ // We were able to parse it, it must be a State!
1627
+ // Let's forward to replaceState
1628
+ //History.debug('History.onPopState: state anchor', currentHash, currentState);
1629
+ History.replaceState(currentState.data, currentState.title, currentState.url, false);
1630
+ }
1631
+ else {
1632
+ // Traditional Anchor
1633
+ //History.debug('History.onPopState: traditional anchor', currentHash);
1634
+ History.Adapter.trigger(window,'anchorchange');
1635
+ History.busy(false);
1636
+ }
1637
+
1638
+ // We don't care for hashes
1639
+ History.expectedStateId = false;
1640
+ return false;
1641
+ }
1642
+
1643
+ // Ensure
1644
+ stateId = History.Adapter.extractEventData('state',event,extra) || false;
1645
+
1646
+ // Fetch State
1647
+ if ( stateId ) {
1648
+ // Vanilla: Back/forward button was used
1649
+ newState = History.getStateById(stateId);
1650
+ }
1651
+ else if ( History.expectedStateId ) {
1652
+ // Vanilla: A new state was pushed, and popstate was called manually
1653
+ newState = History.getStateById(History.expectedStateId);
1654
+ }
1655
+ else {
1656
+ // Initial State
1657
+ newState = History.extractState(document.location.href);
1658
+ }
1659
+
1660
+ // The State did not exist in our store
1661
+ if ( !newState ) {
1662
+ // Regenerate the State
1663
+ newState = History.createStateObject(null,null,document.location.href);
1664
+ }
1665
+
1666
+ // Clean
1667
+ History.expectedStateId = false;
1668
+
1669
+ // Check if we are the same state
1670
+ if ( History.isLastSavedState(newState) ) {
1671
+ // There has been no change (just the page's hash has finally propagated)
1672
+ //History.debug('History.onPopState: no change', newState, History.savedStates);
1673
+ History.busy(false);
1674
+ return false;
1675
+ }
1676
+
1677
+ // Store the State
1678
+ History.storeState(newState);
1679
+ History.saveState(newState);
1680
+
1681
+ // Force update of the title
1682
+ History.setTitle(newState);
1683
+
1684
+ // Fire Our Event
1685
+ History.Adapter.trigger(window,'statechange');
1686
+ History.busy(false);
1687
+
1688
+ // Return true
1689
+ return true;
1690
+ };
1691
+ History.Adapter.bind(window,'popstate',History.onPopState);
1692
+
1693
+ /**
1694
+ * History.pushState(data,title,url)
1695
+ * Add a new State to the history object, become it, and trigger onpopstate
1696
+ * We have to trigger for HTML4 compatibility
1697
+ * @param {object} data
1698
+ * @param {string} title
1699
+ * @param {string} url
1700
+ * @return {true}
1701
+ */
1702
+ History.pushState = function(data,title,url,queue){
1703
+ //History.debug('History.pushState: called', arguments);
1704
+
1705
+ // Check the State
1706
+ if ( History.getHashByUrl(url) && History.emulated.pushState ) {
1707
+ throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
1708
+ }
1709
+
1710
+ // Handle Queueing
1711
+ if ( queue !== false && History.busy() ) {
1712
+ // Wait + Push to Queue
1713
+ //History.debug('History.pushState: we must wait', arguments);
1714
+ History.pushQueue({
1715
+ scope: History,
1716
+ callback: History.pushState,
1717
+ args: arguments,
1718
+ queue: queue
1719
+ });
1720
+ return false;
1721
+ }
1722
+
1723
+ // Make Busy + Continue
1724
+ History.busy(true);
1725
+
1726
+ // Create the newState
1727
+ var newState = History.createStateObject(data,title,url);
1728
+
1729
+ // Check it
1730
+ if ( History.isLastSavedState(newState) ) {
1731
+ // Won't be a change
1732
+ History.busy(false);
1733
+ }
1734
+ else {
1735
+ // Store the newState
1736
+ History.storeState(newState);
1737
+ History.expectedStateId = newState.id;
1738
+
1739
+ // Push the newState
1740
+ history.pushState(newState.id,newState.title,newState.url);
1741
+
1742
+ // Fire HTML5 Event
1743
+ History.Adapter.trigger(window,'popstate');
1744
+ }
1745
+
1746
+ // End pushState closure
1747
+ return true;
1748
+ };
1749
+
1750
+ /**
1751
+ * History.replaceState(data,title,url)
1752
+ * Replace the State and trigger onpopstate
1753
+ * We have to trigger for HTML4 compatibility
1754
+ * @param {object} data
1755
+ * @param {string} title
1756
+ * @param {string} url
1757
+ * @return {true}
1758
+ */
1759
+ History.replaceState = function(data,title,url,queue){
1760
+ //History.debug('History.replaceState: called', arguments);
1761
+
1762
+ // Check the State
1763
+ if ( History.getHashByUrl(url) && History.emulated.pushState ) {
1764
+ throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
1765
+ }
1766
+
1767
+ // Handle Queueing
1768
+ if ( queue !== false && History.busy() ) {
1769
+ // Wait + Push to Queue
1770
+ //History.debug('History.replaceState: we must wait', arguments);
1771
+ History.pushQueue({
1772
+ scope: History,
1773
+ callback: History.replaceState,
1774
+ args: arguments,
1775
+ queue: queue
1776
+ });
1777
+ return false;
1778
+ }
1779
+
1780
+ // Make Busy + Continue
1781
+ History.busy(true);
1782
+
1783
+ // Create the newState
1784
+ var newState = History.createStateObject(data,title,url);
1785
+
1786
+ // Check it
1787
+ if ( History.isLastSavedState(newState) ) {
1788
+ // Won't be a change
1789
+ History.busy(false);
1790
+ }
1791
+ else {
1792
+ // Store the newState
1793
+ History.storeState(newState);
1794
+ History.expectedStateId = newState.id;
1795
+
1796
+ // Push the newState
1797
+ history.replaceState(newState.id,newState.title,newState.url);
1798
+
1799
+ // Fire HTML5 Event
1800
+ History.Adapter.trigger(window,'popstate');
1801
+ }
1802
+
1803
+ // End replaceState closure
1804
+ return true;
1805
+ };
1806
+
1807
+ } // !History.emulated.pushState
1808
+
1809
+
1810
+ // ====================================================================
1811
+ // Initialise
1812
+
1813
+ /**
1814
+ * Load the Store
1815
+ */
1816
+ if ( sessionStorage ) {
1817
+ // Fetch
1818
+ try {
1819
+ History.store = JSON.parse(sessionStorage.getItem('History.store'))||{};
1820
+ }
1821
+ catch ( err ) {
1822
+ History.store = {};
1823
+ }
1824
+
1825
+ // Normalize
1826
+ History.normalizeStore();
1827
+ }
1828
+ else {
1829
+ // Default Load
1830
+ History.store = {};
1831
+ History.normalizeStore();
1832
+ }
1833
+
1834
+ /**
1835
+ * Clear Intervals on exit to prevent memory leaks
1836
+ */
1837
+ History.Adapter.bind(window,"beforeunload",History.clearAllIntervals);
1838
+ History.Adapter.bind(window,"unload",History.clearAllIntervals);
1839
+
1840
+ /**
1841
+ * Create the initial State
1842
+ */
1843
+ History.saveState(History.storeState(History.extractState(document.location.href,true)));
1844
+
1845
+ /**
1846
+ * Bind for Saving Store
1847
+ */
1848
+ if ( sessionStorage ) {
1849
+ // When the page is closed
1850
+ History.onUnload = function(){
1851
+ // Prepare
1852
+ var currentStore, item;
1853
+
1854
+ // Fetch
1855
+ try {
1856
+ currentStore = JSON.parse(sessionStorage.getItem('History.store'))||{};
1857
+ }
1858
+ catch ( err ) {
1859
+ currentStore = {};
1860
+ }
1861
+
1862
+ // Ensure
1863
+ currentStore.idToState = currentStore.idToState || {};
1864
+ currentStore.urlToId = currentStore.urlToId || {};
1865
+ currentStore.stateToId = currentStore.stateToId || {};
1866
+
1867
+ // Sync
1868
+ for ( item in History.idToState ) {
1869
+ if ( !History.idToState.hasOwnProperty(item) ) {
1870
+ continue;
1871
+ }
1872
+ currentStore.idToState[item] = History.idToState[item];
1873
+ }
1874
+ for ( item in History.urlToId ) {
1875
+ if ( !History.urlToId.hasOwnProperty(item) ) {
1876
+ continue;
1877
+ }
1878
+ currentStore.urlToId[item] = History.urlToId[item];
1879
+ }
1880
+ for ( item in History.stateToId ) {
1881
+ if ( !History.stateToId.hasOwnProperty(item) ) {
1882
+ continue;
1883
+ }
1884
+ currentStore.stateToId[item] = History.stateToId[item];
1885
+ }
1886
+
1887
+ // Update
1888
+ History.store = currentStore;
1889
+ History.normalizeStore();
1890
+
1891
+ // Store
1892
+ sessionStorage.setItem('History.store',JSON.stringify(currentStore));
1893
+ };
1894
+
1895
+ // For Internet Explorer
1896
+ History.intervalList.push(setInterval(History.onUnload,History.options.storeInterval));
1897
+
1898
+ // For Other Browsers
1899
+ History.Adapter.bind(window,'beforeunload',History.onUnload);
1900
+ History.Adapter.bind(window,'unload',History.onUnload);
1901
+
1902
+ // Both are enabled for consistency
1903
+ }
1904
+
1905
+ // Non-Native pushState Implementation
1906
+ if ( !History.emulated.pushState ) {
1907
+ // Be aware, the following is only for native pushState implementations
1908
+ // If you are wanting to include something for all browsers
1909
+ // Then include it above this if block
1910
+
1911
+ /**
1912
+ * Setup Safari Fix
1913
+ */
1914
+ if ( History.bugs.safariPoll ) {
1915
+ History.intervalList.push(setInterval(History.safariStatePoll, History.options.safariPollInterval));
1916
+ }
1917
+
1918
+ /**
1919
+ * Ensure Cross Browser Compatibility
1920
+ */
1921
+ if ( navigator.vendor === 'Apple Computer, Inc.' || (navigator.appCodeName||'') === 'Mozilla' ) {
1922
+ /**
1923
+ * Fix Safari HashChange Issue
1924
+ */
1925
+
1926
+ // Setup Alias
1927
+ History.Adapter.bind(window,'hashchange',function(){
1928
+ History.Adapter.trigger(window,'popstate');
1929
+ });
1930
+
1931
+ // Initialise Alias
1932
+ if ( History.getHash() ) {
1933
+ History.Adapter.onDomLoad(function(){
1934
+ History.Adapter.trigger(window,'hashchange');
1935
+ });
1936
+ }
1937
+ }
1938
+
1939
+ } // !History.emulated.pushState
1940
+
1941
+
1942
+ }; // History.initCore
1943
+
1944
+ // Try and Initialise History
1945
+ History.init();
1946
+
1947
+ })(window);
1948
+ /**
1949
+ * History.js HTML4 Support
1950
+ * Depends on the HTML5 Support
1951
+ * @author Benjamin Arthur Lupton <contact@balupton.com>
1952
+ * @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
1953
+ * @license New BSD License <http://creativecommons.org/licenses/BSD/>
1954
+ */
1955
+
1956
+
1957
+ (function(window,undefined){
1958
+ "use strict";
1959
+
1960
+ // ========================================================================
1961
+ // Initialise
1962
+
1963
+ // Localise Globals
1964
+ var
1965
+ document = window.document, // Make sure we are using the correct document
1966
+ setTimeout = window.setTimeout||setTimeout,
1967
+ clearTimeout = window.clearTimeout||clearTimeout,
1968
+ setInterval = window.setInterval||setInterval,
1969
+ History = window.History = window.History||{}; // Public History Object
1970
+
1971
+ // Check Existence
1972
+ if ( typeof History.initHtml4 !== 'undefined' ) {
1973
+ throw new Error('History.js HTML4 Support has already been loaded...');
1974
+ }
1975
+
1976
+
1977
+ // ========================================================================
1978
+ // Initialise HTML4 Support
1979
+
1980
+ // Initialise HTML4 Support
1981
+ History.initHtml4 = function(){
1982
+ // Initialise
1983
+ if ( typeof History.initHtml4.initialized !== 'undefined' ) {
1984
+ // Already Loaded
1985
+ return false;
1986
+ }
1987
+ else {
1988
+ History.initHtml4.initialized = true;
1989
+ }
1990
+
1991
+
1992
+ // ====================================================================
1993
+ // Properties
1994
+
1995
+ /**
1996
+ * History.enabled
1997
+ * Is History enabled?
1998
+ */
1999
+ History.enabled = true;
2000
+
2001
+
2002
+ // ====================================================================
2003
+ // Hash Storage
2004
+
2005
+ /**
2006
+ * History.savedHashes
2007
+ * Store the hashes in an array
2008
+ */
2009
+ History.savedHashes = [];
2010
+
2011
+ /**
2012
+ * History.isLastHash(newHash)
2013
+ * Checks if the hash is the last hash
2014
+ * @param {string} newHash
2015
+ * @return {boolean} true
2016
+ */
2017
+ History.isLastHash = function(newHash){
2018
+ // Prepare
2019
+ var oldHash = History.getHashByIndex(),
2020
+ isLast;
2021
+
2022
+ // Check
2023
+ isLast = newHash === oldHash;
2024
+
2025
+ // Return isLast
2026
+ return isLast;
2027
+ };
2028
+
2029
+ /**
2030
+ * History.saveHash(newHash)
2031
+ * Push a Hash
2032
+ * @param {string} newHash
2033
+ * @return {boolean} true
2034
+ */
2035
+ History.saveHash = function(newHash){
2036
+ // Check Hash
2037
+ if ( History.isLastHash(newHash) ) {
2038
+ return false;
2039
+ }
2040
+
2041
+ // Push the Hash
2042
+ History.savedHashes.push(newHash);
2043
+
2044
+ // Return true
2045
+ return true;
2046
+ };
2047
+
2048
+ /**
2049
+ * History.getHashByIndex()
2050
+ * Gets a hash by the index
2051
+ * @param {integer} index
2052
+ * @return {string}
2053
+ */
2054
+ History.getHashByIndex = function(index){
2055
+ // Prepare
2056
+ var hash = null;
2057
+
2058
+ // Handle
2059
+ if ( typeof index === 'undefined' ) {
2060
+ // Get the last inserted
2061
+ hash = History.savedHashes[History.savedHashes.length-1];
2062
+ }
2063
+ else if ( index < 0 ) {
2064
+ // Get from the end
2065
+ hash = History.savedHashes[History.savedHashes.length+index];
2066
+ }
2067
+ else {
2068
+ // Get from the beginning
2069
+ hash = History.savedHashes[index];
2070
+ }
2071
+
2072
+ // Return hash
2073
+ return hash;
2074
+ };
2075
+
2076
+
2077
+ // ====================================================================
2078
+ // Discarded States
2079
+
2080
+ /**
2081
+ * History.discardedHashes
2082
+ * A hashed array of discarded hashes
2083
+ */
2084
+ History.discardedHashes = {};
2085
+
2086
+ /**
2087
+ * History.discardedStates
2088
+ * A hashed array of discarded states
2089
+ */
2090
+ History.discardedStates = {};
2091
+
2092
+ /**
2093
+ * History.discardState(State)
2094
+ * Discards the state by ignoring it through History
2095
+ * @param {object} State
2096
+ * @return {true}
2097
+ */
2098
+ History.discardState = function(discardedState,forwardState,backState){
2099
+ //History.debug('History.discardState', arguments);
2100
+ // Prepare
2101
+ var discardedStateHash = History.getHashByState(discardedState),
2102
+ discardObject;
2103
+
2104
+ // Create Discard Object
2105
+ discardObject = {
2106
+ 'discardedState': discardedState,
2107
+ 'backState': backState,
2108
+ 'forwardState': forwardState
2109
+ };
2110
+
2111
+ // Add to DiscardedStates
2112
+ History.discardedStates[discardedStateHash] = discardObject;
2113
+
2114
+ // Return true
2115
+ return true;
2116
+ };
2117
+
2118
+ /**
2119
+ * History.discardHash(hash)
2120
+ * Discards the hash by ignoring it through History
2121
+ * @param {string} hash
2122
+ * @return {true}
2123
+ */
2124
+ History.discardHash = function(discardedHash,forwardState,backState){
2125
+ //History.debug('History.discardState', arguments);
2126
+ // Create Discard Object
2127
+ var discardObject = {
2128
+ 'discardedHash': discardedHash,
2129
+ 'backState': backState,
2130
+ 'forwardState': forwardState
2131
+ };
2132
+
2133
+ // Add to discardedHash
2134
+ History.discardedHashes[discardedHash] = discardObject;
2135
+
2136
+ // Return true
2137
+ return true;
2138
+ };
2139
+
2140
+ /**
2141
+ * History.discardState(State)
2142
+ * Checks to see if the state is discarded
2143
+ * @param {object} State
2144
+ * @return {bool}
2145
+ */
2146
+ History.discardedState = function(State){
2147
+ // Prepare
2148
+ var StateHash = History.getHashByState(State),
2149
+ discarded;
2150
+
2151
+ // Check
2152
+ discarded = History.discardedStates[StateHash]||false;
2153
+
2154
+ // Return true
2155
+ return discarded;
2156
+ };
2157
+
2158
+ /**
2159
+ * History.discardedHash(hash)
2160
+ * Checks to see if the state is discarded
2161
+ * @param {string} State
2162
+ * @return {bool}
2163
+ */
2164
+ History.discardedHash = function(hash){
2165
+ // Check
2166
+ var discarded = History.discardedHashes[hash]||false;
2167
+
2168
+ // Return true
2169
+ return discarded;
2170
+ };
2171
+
2172
+ /**
2173
+ * History.recycleState(State)
2174
+ * Allows a discarded state to be used again
2175
+ * @param {object} data
2176
+ * @param {string} title
2177
+ * @param {string} url
2178
+ * @return {true}
2179
+ */
2180
+ History.recycleState = function(State){
2181
+ //History.debug('History.recycleState', arguments);
2182
+ // Prepare
2183
+ var StateHash = History.getHashByState(State);
2184
+
2185
+ // Remove from DiscardedStates
2186
+ if ( History.discardedState(State) ) {
2187
+ delete History.discardedStates[StateHash];
2188
+ }
2189
+
2190
+ // Return true
2191
+ return true;
2192
+ };
2193
+
2194
+
2195
+ // ====================================================================
2196
+ // HTML4 HashChange Support
2197
+
2198
+ if ( History.emulated.hashChange ) {
2199
+ /*
2200
+ * We must emulate the HTML4 HashChange Support by manually checking for hash changes
2201
+ */
2202
+
2203
+ /**
2204
+ * History.hashChangeInit()
2205
+ * Init the HashChange Emulation
2206
+ */
2207
+ History.hashChangeInit = function(){
2208
+ // Define our Checker Function
2209
+ History.checkerFunction = null;
2210
+
2211
+ // Define some variables that will help in our checker function
2212
+ var lastDocumentHash = '',
2213
+ iframeId, iframe,
2214
+ lastIframeHash, checkerRunning;
2215
+
2216
+ // Handle depending on the browser
2217
+ if ( History.isInternetExplorer() ) {
2218
+ // IE6 and IE7
2219
+ // We need to use an iframe to emulate the back and forward buttons
2220
+
2221
+ // Create iFrame
2222
+ iframeId = 'historyjs-iframe';
2223
+ iframe = document.createElement('iframe');
2224
+
2225
+ // Adjust iFarme
2226
+ iframe.setAttribute('id', iframeId);
2227
+ iframe.style.display = 'none';
2228
+
2229
+ // Append iFrame
2230
+ document.body.appendChild(iframe);
2231
+
2232
+ // Create initial history entry
2233
+ iframe.contentWindow.document.open();
2234
+ iframe.contentWindow.document.close();
2235
+
2236
+ // Define some variables that will help in our checker function
2237
+ lastIframeHash = '';
2238
+ checkerRunning = false;
2239
+
2240
+ // Define the checker function
2241
+ History.checkerFunction = function(){
2242
+ // Check Running
2243
+ if ( checkerRunning ) {
2244
+ return false;
2245
+ }
2246
+
2247
+ // Update Running
2248
+ checkerRunning = true;
2249
+
2250
+ // Fetch
2251
+ var documentHash = History.getHash()||'',
2252
+ iframeHash = History.unescapeHash(iframe.contentWindow.document.location.hash)||'';
2253
+
2254
+ // The Document Hash has changed (application caused)
2255
+ if ( documentHash !== lastDocumentHash ) {
2256
+ // Equalise
2257
+ lastDocumentHash = documentHash;
2258
+
2259
+ // Create a history entry in the iframe
2260
+ if ( iframeHash !== documentHash ) {
2261
+ //History.debug('hashchange.checker: iframe hash change', 'documentHash (new):', documentHash, 'iframeHash (old):', iframeHash);
2262
+
2263
+ // Equalise
2264
+ lastIframeHash = iframeHash = documentHash;
2265
+
2266
+ // Create History Entry
2267
+ iframe.contentWindow.document.open();
2268
+ iframe.contentWindow.document.close();
2269
+
2270
+ // Update the iframe's hash
2271
+ iframe.contentWindow.document.location.hash = History.escapeHash(documentHash);
2272
+ }
2273
+
2274
+ // Trigger Hashchange Event
2275
+ History.Adapter.trigger(window,'hashchange');
2276
+ }
2277
+
2278
+ // The iFrame Hash has changed (back button caused)
2279
+ else if ( iframeHash !== lastIframeHash ) {
2280
+ //History.debug('hashchange.checker: iframe hash out of sync', 'iframeHash (new):', iframeHash, 'documentHash (old):', documentHash);
2281
+
2282
+ // Equalise
2283
+ lastIframeHash = iframeHash;
2284
+
2285
+ // Update the Hash
2286
+ History.setHash(iframeHash,false);
2287
+ }
2288
+
2289
+ // Reset Running
2290
+ checkerRunning = false;
2291
+
2292
+ // Return true
2293
+ return true;
2294
+ };
2295
+ }
2296
+ else {
2297
+ // We are not IE
2298
+ // Firefox 1 or 2, Opera
2299
+
2300
+ // Define the checker function
2301
+ History.checkerFunction = function(){
2302
+ // Prepare
2303
+ var documentHash = History.getHash();
2304
+
2305
+ // The Document Hash has changed (application caused)
2306
+ if ( documentHash !== lastDocumentHash ) {
2307
+ // Equalise
2308
+ lastDocumentHash = documentHash;
2309
+
2310
+ // Trigger Hashchange Event
2311
+ History.Adapter.trigger(window,'hashchange');
2312
+ }
2313
+
2314
+ // Return true
2315
+ return true;
2316
+ };
2317
+ }
2318
+
2319
+ // Apply the checker function
2320
+ History.intervalList.push(setInterval(History.checkerFunction, History.options.hashChangeInterval));
2321
+
2322
+ // Done
2323
+ return true;
2324
+ }; // History.hashChangeInit
2325
+
2326
+ // Bind hashChangeInit
2327
+ History.Adapter.onDomLoad(History.hashChangeInit);
2328
+
2329
+ } // History.emulated.hashChange
2330
+
2331
+
2332
+ // ====================================================================
2333
+ // HTML5 State Support
2334
+
2335
+ // Non-Native pushState Implementation
2336
+ if ( History.emulated.pushState ) {
2337
+ /*
2338
+ * We must emulate the HTML5 State Management by using HTML4 HashChange
2339
+ */
2340
+
2341
+ /**
2342
+ * History.onHashChange(event)
2343
+ * Trigger HTML5's window.onpopstate via HTML4 HashChange Support
2344
+ */
2345
+ History.onHashChange = function(event){
2346
+ //History.debug('History.onHashChange', arguments);
2347
+
2348
+ // Prepare
2349
+ var currentUrl = ((event && event.newURL) || document.location.href),
2350
+ currentHash = History.getHashByUrl(currentUrl),
2351
+ currentState = null,
2352
+ currentStateHash = null,
2353
+ currentStateHashExits = null,
2354
+ discardObject;
2355
+
2356
+ // Check if we are the same state
2357
+ if ( History.isLastHash(currentHash) ) {
2358
+ // There has been no change (just the page's hash has finally propagated)
2359
+ //History.debug('History.onHashChange: no change');
2360
+ History.busy(false);
2361
+ return false;
2362
+ }
2363
+
2364
+ // Reset the double check
2365
+ History.doubleCheckComplete();
2366
+
2367
+ // Store our location for use in detecting back/forward direction
2368
+ History.saveHash(currentHash);
2369
+
2370
+ // Expand Hash
2371
+ if ( currentHash && History.isTraditionalAnchor(currentHash) ) {
2372
+ //History.debug('History.onHashChange: traditional anchor', currentHash);
2373
+ // Traditional Anchor Hash
2374
+ History.Adapter.trigger(window,'anchorchange');
2375
+ History.busy(false);
2376
+ return false;
2377
+ }
2378
+
2379
+ // Create State
2380
+ currentState = History.extractState(History.getFullUrl(currentHash||document.location.href,false),true);
2381
+
2382
+ // Check if we are the same state
2383
+ if ( History.isLastSavedState(currentState) ) {
2384
+ //History.debug('History.onHashChange: no change');
2385
+ // There has been no change (just the page's hash has finally propagated)
2386
+ History.busy(false);
2387
+ return false;
2388
+ }
2389
+
2390
+ // Create the state Hash
2391
+ currentStateHash = History.getHashByState(currentState);
2392
+
2393
+ // Check if we are DiscardedState
2394
+ discardObject = History.discardedState(currentState);
2395
+ if ( discardObject ) {
2396
+ // Ignore this state as it has been discarded and go back to the state before it
2397
+ if ( History.getHashByIndex(-2) === History.getHashByState(discardObject.forwardState) ) {
2398
+ // We are going backwards
2399
+ //History.debug('History.onHashChange: go backwards');
2400
+ History.back(false);
2401
+ } else {
2402
+ // We are going forwards
2403
+ //History.debug('History.onHashChange: go forwards');
2404
+ History.forward(false);
2405
+ }
2406
+ return false;
2407
+ }
2408
+
2409
+ // Push the new HTML5 State
2410
+ //History.debug('History.onHashChange: success hashchange');
2411
+ History.pushState(currentState.data,currentState.title,currentState.url,false);
2412
+
2413
+ // End onHashChange closure
2414
+ return true;
2415
+ };
2416
+ History.Adapter.bind(window,'hashchange',History.onHashChange);
2417
+
2418
+ /**
2419
+ * History.pushState(data,title,url)
2420
+ * Add a new State to the history object, become it, and trigger onpopstate
2421
+ * We have to trigger for HTML4 compatibility
2422
+ * @param {object} data
2423
+ * @param {string} title
2424
+ * @param {string} url
2425
+ * @return {true}
2426
+ */
2427
+ History.pushState = function(data,title,url,queue){
2428
+ //History.debug('History.pushState: called', arguments);
2429
+
2430
+ // Check the State
2431
+ if ( History.getHashByUrl(url) ) {
2432
+ throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
2433
+ }
2434
+
2435
+ // Handle Queueing
2436
+ if ( queue !== false && History.busy() ) {
2437
+ // Wait + Push to Queue
2438
+ //History.debug('History.pushState: we must wait', arguments);
2439
+ History.pushQueue({
2440
+ scope: History,
2441
+ callback: History.pushState,
2442
+ args: arguments,
2443
+ queue: queue
2444
+ });
2445
+ return false;
2446
+ }
2447
+
2448
+ // Make Busy
2449
+ History.busy(true);
2450
+
2451
+ // Fetch the State Object
2452
+ var newState = History.createStateObject(data,title,url),
2453
+ newStateHash = History.getHashByState(newState),
2454
+ oldState = History.getState(false),
2455
+ oldStateHash = History.getHashByState(oldState),
2456
+ html4Hash = History.getHash();
2457
+
2458
+ // Store the newState
2459
+ History.storeState(newState);
2460
+ History.expectedStateId = newState.id;
2461
+
2462
+ // Recycle the State
2463
+ History.recycleState(newState);
2464
+
2465
+ // Force update of the title
2466
+ // History.setTitle(newState);
2467
+
2468
+ // Check if we are the same State
2469
+ if ( newStateHash === oldStateHash ) {
2470
+ //History.debug('History.pushState: no change', newStateHash);
2471
+ History.busy(false);
2472
+ return false;
2473
+ }
2474
+
2475
+ // Update HTML4 Hash
2476
+ if ( newStateHash !== html4Hash && newStateHash !== History.getShortUrl(document.location.href) ) {
2477
+ //History.debug('History.pushState: update hash', newStateHash, html4Hash);
2478
+ History.setHash(newStateHash,false);
2479
+ return false;
2480
+ }
2481
+
2482
+ // Update HTML5 State
2483
+ History.saveState(newState);
2484
+
2485
+ // Fire HTML5 Event
2486
+ //History.debug('History.pushState: trigger popstate');
2487
+ History.Adapter.trigger(window,'statechange');
2488
+ History.busy(false);
2489
+
2490
+ // End pushState closure
2491
+ return true;
2492
+ };
2493
+
2494
+ /**
2495
+ * History.replaceState(data,title,url)
2496
+ * Replace the State and trigger onpopstate
2497
+ * We have to trigger for HTML4 compatibility
2498
+ * @param {object} data
2499
+ * @param {string} title
2500
+ * @param {string} url
2501
+ * @return {true}
2502
+ */
2503
+ History.replaceState = function(data,title,url,queue){
2504
+ //History.debug('History.replaceState: called', arguments);
2505
+
2506
+ // Check the State
2507
+ if ( History.getHashByUrl(url) ) {
2508
+ throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
2509
+ }
2510
+
2511
+ // Handle Queueing
2512
+ if ( queue !== false && History.busy() ) {
2513
+ // Wait + Push to Queue
2514
+ //History.debug('History.replaceState: we must wait', arguments);
2515
+ History.pushQueue({
2516
+ scope: History,
2517
+ callback: History.replaceState,
2518
+ args: arguments,
2519
+ queue: queue
2520
+ });
2521
+ return false;
2522
+ }
2523
+
2524
+ // Make Busy
2525
+ History.busy(true);
2526
+
2527
+ // Fetch the State Objects
2528
+ var newState = History.createStateObject(data,title,url),
2529
+ oldState = History.getState(false),
2530
+ previousState = History.getStateByIndex(-2);
2531
+
2532
+ // Discard Old State
2533
+ History.discardState(oldState,newState,previousState);
2534
+
2535
+ // Alias to PushState
2536
+ History.pushState(newState.data,newState.title,newState.url,false);
2537
+
2538
+ // End replaceState closure
2539
+ return true;
2540
+ };
2541
+
2542
+ } // History.emulated.pushState
2543
+
2544
+
2545
+
2546
+ // ====================================================================
2547
+ // Initialise
2548
+
2549
+ // Non-Native pushState Implementation
2550
+ if ( History.emulated.pushState ) {
2551
+ /**
2552
+ * Ensure initial state is handled correctly
2553
+ */
2554
+ if ( History.getHash() && !History.emulated.hashChange ) {
2555
+ History.Adapter.onDomLoad(function(){
2556
+ History.Adapter.trigger(window,'hashchange');
2557
+ });
2558
+ }
2559
+
2560
+ } // History.emulated.pushState
2561
+
2562
+ }; // History.initHtml4
2563
+
2564
+ // Try and Initialise History
2565
+ if ( typeof History.init !== 'undefined' ) {
2566
+ History.init();
2567
+ }
2568
+
2569
+ })(window);
2570
+ /**
2571
+ * History.js jQuery Adapter
2572
+ * @author Benjamin Arthur Lupton <contact@balupton.com>
2573
+ * @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
2574
+ * @license New BSD License <http://creativecommons.org/licenses/BSD/>
2575
+ */
2576
+
2577
+ // Closure
2578
+ (function(window,undefined){
2579
+ "use strict";
2580
+
2581
+ // Localise Globals
2582
+ var
2583
+ History = window.History = window.History||{},
2584
+ jQuery = window.jQuery;
2585
+
2586
+ // Check Existence
2587
+ if ( typeof History.Adapter !== 'undefined' ) {
2588
+ throw new Error('History.js Adapter has already been loaded...');
2589
+ }
2590
+
2591
+ // Add the Adapter
2592
+ History.Adapter = {
2593
+ /**
2594
+ * History.Adapter.bind(el,event,callback)
2595
+ * @param {Element|string} el
2596
+ * @param {string} event - custom and standard events
2597
+ * @param {function} callback
2598
+ * @return {void}
2599
+ */
2600
+ bind: function(el,event,callback){
2601
+ jQuery(el).bind(event,callback);
2602
+ },
2603
+
2604
+ /**
2605
+ * History.Adapter.trigger(el,event)
2606
+ * @param {Element|string} el
2607
+ * @param {string} event - custom and standard events
2608
+ * @param {Object=} extra - a object of extra event data (optional)
2609
+ * @return {void}
2610
+ */
2611
+ trigger: function(el,event,extra){
2612
+ jQuery(el).trigger(event,extra);
2613
+ },
2614
+
2615
+ /**
2616
+ * History.Adapter.extractEventData(key,event,extra)
2617
+ * @param {string} key - key for the event data to extract
2618
+ * @param {string} event - custom and standard events
2619
+ * @param {Object=} extra - a object of extra event data (optional)
2620
+ * @return {mixed}
2621
+ */
2622
+ extractEventData: function(key,event,extra){
2623
+ // jQuery Native then jQuery Custom
2624
+ var result = (event && event.originalEvent && event.originalEvent[key]) || (extra && extra[key]) || undefined;
2625
+
2626
+ // Return
2627
+ return result;
2628
+ },
2629
+
2630
+ /**
2631
+ * History.Adapter.onDomLoad(callback)
2632
+ * @param {function} callback
2633
+ * @return {void}
2634
+ */
2635
+ onDomLoad: function(callback) {
2636
+ jQuery(callback);
2637
+ }
2638
+ };
2639
+
2640
+ // Try and Initialise History
2641
+ if ( typeof History.init !== 'undefined' ) {
2642
+ History.init();
2643
+ }
2644
+
2645
+ })(window);
2646
+ (function() {
2647
+ var Wiselinks;
2648
+
2649
+ String.prototype.ends_with = function(suffix) {
2650
+ return this.indexOf(suffix, this.length - suffix.length) !== -1;
2651
+ };
2652
+
2653
+ Wiselinks = (function() {
2654
+
2655
+ function Wiselinks($target, options) {
2656
+ var self;
2657
+ this.$target = $target != null ? $target : $('body');
2658
+ this.options = options != null ? options : {};
2659
+ if (window.jQuery == null) {
2660
+ throw "Load jQuery to use Wiselinks";
2661
+ }
2662
+ self = this;
2663
+ this.options = jQuery.extend(self._defaults(), this.options);
2664
+ if (self.enabled()) {
2665
+ this.assets_digest = $("meta[name='assets-digest']").attr("content");
2666
+ if (History.emulated.pushState && this.options.html4 === true) {
2667
+ if (window.location.href.indexOf('#!') === -1 && window.location.pathname !== '/') {
2668
+ window.location.href = "" + window.location.protocol + "//" + window.location.host + "/#!" + window.location.pathname;
2669
+ }
2670
+ if (window.location.hash.indexOf('#!') !== -1) {
2671
+ self._call(window.location.hash.substring(2));
2672
+ }
2673
+ }
2674
+ History.Adapter.bind(window, "statechange", function(event, data) {
2675
+ var state;
2676
+ if (!History.ready) {
2677
+ return false;
2678
+ }
2679
+ state = History.getState();
2680
+ return self._call(state.url, state.data.target, state.data.render);
2681
+ });
2682
+ $(document).on("submit", "form[data-push], form[data-replace]", function(event) {
2683
+ self._process_form($(this));
2684
+ event.preventDefault();
2685
+ return false;
2686
+ });
2687
+ $(document).on("click", "a[data-push], a[data-replace]", function(event) {
2688
+ if (self._cross_origin_link(event.target) || self._non_standard_click(event)) {
2689
+ return true;
2690
+ }
2691
+ self._process_link($(this));
2692
+ event.preventDefault();
2693
+ return false;
2694
+ });
2695
+ }
2696
+ }
2697
+
2698
+ Wiselinks.prototype.enabled = function() {
2699
+ return !History.emulated.pushState || this.options.html4 === true;
2700
+ };
2701
+
2702
+ Wiselinks.prototype.load = function(url, target, render) {
2703
+ if (render == null) {
2704
+ render = 'template';
2705
+ }
2706
+ History.ready = true;
2707
+ return History.pushState({
2708
+ timestamp: new Date().getTime(),
2709
+ render: render,
2710
+ target: target
2711
+ }, document.title, url);
2712
+ };
2713
+
2714
+ Wiselinks.prototype.reload = function() {
2715
+ History.ready = true;
2716
+ return History.replaceState({
2717
+ timestamp: new Date().getTime(),
2718
+ render: 'template'
2719
+ }, document.title, History.getState().url);
2720
+ };
2721
+
2722
+ Wiselinks.prototype._defaults = function() {
2723
+ return {
2724
+ html4: true
2725
+ };
2726
+ };
2727
+
2728
+ Wiselinks.prototype._call = function(url, target, render) {
2729
+ var $document, $target, self;
2730
+ if (render == null) {
2731
+ render = 'template';
2732
+ }
2733
+ self = this;
2734
+ $target = target != null ? $(target) : self.$target;
2735
+ $document = $(document).trigger('page:loading', [url, $target.selector, render]);
2736
+ return $.ajax({
2737
+ url: url,
2738
+ headers: {
2739
+ 'X-Render': render
2740
+ },
2741
+ complete: function(xhr, status) {
2742
+ return $document.trigger('page:complete', [xhr, status]);
2743
+ },
2744
+ success: function(data, status, xhr) {
2745
+ if (self._assets_changed(xhr.getResponseHeader('X-Assets-Digest'))) {
2746
+ return window.location.reload(true);
2747
+ } else {
2748
+ self._set_title(xhr);
2749
+ $target.html(data);
2750
+ return $document.trigger('page:success', [data, status]);
2751
+ }
2752
+ },
2753
+ error: function(xhr, status, error) {
2754
+ return $document.trigger('page:error', [status, error]);
2755
+ },
2756
+ dataType: "html"
2757
+ });
2758
+ };
2759
+
2760
+ Wiselinks.prototype._process_form = function($form) {
2761
+ var $disable, item, key, name, params, self, serialized, type, url, _i, _len, _ref;
2762
+ self = this;
2763
+ $disable = $form.find(':input[value=""]');
2764
+ $disable.attr('disabled', true);
2765
+ params = {};
2766
+ _ref = $form.serializeArray();
2767
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
2768
+ item = _ref[_i];
2769
+ if (item.name !== 'utf8') {
2770
+ name = item.name.ends_with('[]') ? item.name.substr(0, item.name.length - 2) : item.name;
2771
+ if (params[name] != null) {
2772
+ params[name] = params[name] + ("," + item.value);
2773
+ } else {
2774
+ params[name] = item.value;
2775
+ }
2776
+ }
2777
+ }
2778
+ serialized = [];
2779
+ for (key in params) {
2780
+ serialized.push("" + key + "=" + params[key]);
2781
+ }
2782
+ serialized = serialized.join('&').replace(/%|!/g, '');
2783
+ url = $form.attr("action");
2784
+ if (serialized.length > 0) {
2785
+ url += "?" + serialized;
2786
+ }
2787
+ $disable.attr('disabled', false);
2788
+ type = $form.attr("data-push") === 'partial' ? 'partial' : 'template';
2789
+ return self.load(url, $form.attr("data-target"), type);
2790
+ };
2791
+
2792
+ Wiselinks.prototype._process_link = function($link) {
2793
+ var self, type;
2794
+ self = this;
2795
+ type = $link.attr("data-push") === 'partial' ? 'partial' : 'template';
2796
+ return self.load($link.attr("href"), $link.attr("data-target"), type);
2797
+ };
2798
+
2799
+ Wiselinks.prototype._cross_origin_link = function(link) {
2800
+ return (location.protocol !== link.protocol) || (location.host.split(':')[0] !== link.host.split(':')[0]);
2801
+ };
2802
+
2803
+ Wiselinks.prototype._non_standard_click = function(event) {
2804
+ return event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
2805
+ };
2806
+
2807
+ Wiselinks.prototype._assets_changed = function(digest) {
2808
+ return (this.assets_digest != null) && this.assets_digest !== digest;
2809
+ };
2810
+
2811
+ Wiselinks.prototype._set_title = function(xhr) {
2812
+ var value;
2813
+ value = xhr.getResponseHeader('X-Title');
2814
+ if (value != null) {
2815
+ return document.title = decodeURI(value);
2816
+ }
2817
+ };
2818
+
2819
+ return Wiselinks;
2820
+
2821
+ })();
2822
+
2823
+ window.Wiselinks = Wiselinks;
2824
+
2825
+ }).call(this);
2826
+ (function() {
2827
+
2828
+
2829
+
2830
+ }).call(this);