@ms-atlas/datastudio 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @ms-atlas/datastudio might be problematic. Click here for more details.

Files changed (38) hide show
  1. package/ExternalLibraries/Monaco/vs/loader.js +2166 -0
  2. package/ExternalLibraries/URI.min.js +1901 -0
  3. package/ExternalLibraries/crossroads.min.js +453 -0
  4. package/ExternalLibraries/css.js +165 -0
  5. package/ExternalLibraries/d3.min.js +10857 -0
  6. package/ExternalLibraries/es6-promise.min.js +363 -0
  7. package/ExternalLibraries/hammer.js +2224 -0
  8. package/ExternalLibraries/hull.js +444 -0
  9. package/ExternalLibraries/i18n.min.js +115 -0
  10. package/ExternalLibraries/jquery-ui-timepicker-addon.min.css +76 -0
  11. package/ExternalLibraries/jquery-ui-timepicker-addon.min.js +1918 -0
  12. package/ExternalLibraries/jquery-ui.js +17201 -0
  13. package/ExternalLibraries/jquery-ui.min.css +1454 -0
  14. package/ExternalLibraries/jquery.history.js +2173 -0
  15. package/ExternalLibraries/jquery.min.js +5168 -0
  16. package/ExternalLibraries/jquery.mockjax.min.js +445 -0
  17. package/ExternalLibraries/jquery.modal.js +173 -0
  18. package/ExternalLibraries/jstree.js +10086 -0
  19. package/ExternalLibraries/jstree.style.css +1048 -0
  20. package/ExternalLibraries/jwt-decode.min.js +142 -0
  21. package/ExternalLibraries/knockout-latest.debug.js +7375 -0
  22. package/ExternalLibraries/knockout.mapping.min.js +534 -0
  23. package/ExternalLibraries/moment.js +3389 -0
  24. package/ExternalLibraries/q.js +1974 -0
  25. package/ExternalLibraries/require.js +2230 -0
  26. package/ExternalLibraries/signals.min.js +179 -0
  27. package/ExternalLibraries/text.js +445 -0
  28. package/ExternalLibraries/uuid.js +274 -0
  29. package/datastudio.application.mainpage.js +1502 -0
  30. package/datastudio.application.shared.js +626 -0
  31. package/datastudio.bootstrapper.js +517 -0
  32. package/fonts.css +14 -0
  33. package/nls/resx.js +1 -0
  34. package/nls/root/resx.js +22 -0
  35. package/package.json +22 -0
  36. package/scripts/application/sourceMapper.js +15 -0
  37. package/scripts/libs/adal/adal.js +720 -0
  38. package/stylesheets/main.css +8879 -0
@@ -0,0 +1,2173 @@
1
+ /**
2
+ * History.js jQuery Adapter
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
+ // Closure
9
+ (function (window, undefined) {
10
+ "use strict";
11
+
12
+ // Localise Globals
13
+ var History = (window.History = window.History || {}),
14
+ jQuery = window.jQuery;
15
+
16
+ // Check Existence
17
+ if (typeof History.Adapter !== "undefined") {
18
+ throw new Error("History.js Adapter has already been loaded...");
19
+ }
20
+
21
+ // Add the Adapter
22
+ History.Adapter = {
23
+ /**
24
+ * History.Adapter.bind(el,event,callback)
25
+ * @param {Element|string} el
26
+ * @param {string} event - custom and standard events
27
+ * @param {function} callback
28
+ * @return {void}
29
+ */
30
+ bind: function (el, event, callback) {
31
+ jQuery(el).bind(event, callback);
32
+ },
33
+
34
+ /**
35
+ * History.Adapter.trigger(el,event)
36
+ * @param {Element|string} el
37
+ * @param {string} event - custom and standard events
38
+ * @param {Object=} extra - a object of extra event data (optional)
39
+ * @return {void}
40
+ */
41
+ trigger: function (el, event, extra) {
42
+ jQuery(el).trigger(event, extra);
43
+ },
44
+
45
+ /**
46
+ * History.Adapter.extractEventData(key,event,extra)
47
+ * @param {string} key - key for the event data to extract
48
+ * @param {string} event - custom and standard events
49
+ * @param {Object=} extra - a object of extra event data (optional)
50
+ * @return {mixed}
51
+ */
52
+ extractEventData: function (key, event, extra) {
53
+ // jQuery Native then jQuery Custom
54
+ var result =
55
+ (event && event.originalEvent && event.originalEvent[key]) ||
56
+ (extra && extra[key]) ||
57
+ undefined;
58
+
59
+ // Return
60
+ return result;
61
+ },
62
+
63
+ /**
64
+ * History.Adapter.onDomLoad(callback)
65
+ * @param {function} callback
66
+ * @return {void}
67
+ */
68
+ onDomLoad: function (callback) {
69
+ jQuery(callback);
70
+ },
71
+ };
72
+
73
+ // Try and Initialise History
74
+ if (typeof History.init !== "undefined") {
75
+ History.init();
76
+ }
77
+ })(window);
78
+
79
+ /**
80
+ * History.js Core
81
+ * @author Benjamin Arthur Lupton <contact@balupton.com>
82
+ * @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
83
+ * @license New BSD License <http://creativecommons.org/licenses/BSD/>
84
+ */
85
+
86
+ (function (window, undefined) {
87
+ "use strict";
88
+
89
+ // ========================================================================
90
+ // Initialise
91
+
92
+ // Localise Globals
93
+ var console = window.console || undefined, // Prevent a JSLint complain
94
+ document = window.document, // Make sure we are using the correct document
95
+ navigator = window.navigator, // Make sure we are using the correct navigator
96
+ sessionStorage = false, // sessionStorage
97
+ setTimeout = window.setTimeout,
98
+ clearTimeout = window.clearTimeout,
99
+ setInterval = window.setInterval,
100
+ clearInterval = window.clearInterval,
101
+ JSON = window.JSON,
102
+ alert = window.alert,
103
+ History = (window.History = window.History || {}), // Public History Object
104
+ history = window.history; // Old History Object
105
+
106
+ try {
107
+ sessionStorage = window.sessionStorage; // This will throw an exception in some browsers when cookies/localStorage are explicitly disabled (i.e. Chrome)
108
+ sessionStorage.setItem("TEST", "1");
109
+ sessionStorage.removeItem("TEST");
110
+ } catch (e) {
111
+ sessionStorage = false;
112
+ }
113
+
114
+ // MooTools Compatibility
115
+ JSON.stringify = JSON.stringify || JSON.encode;
116
+ JSON.parse = JSON.parse || JSON.decode;
117
+
118
+ // Check Existence
119
+ if (typeof History.init !== "undefined") {
120
+ throw new Error("History.js Core has already been loaded...");
121
+ }
122
+
123
+ // Initialise History
124
+ History.init = function (options) {
125
+ // Check Load Status of Adapter
126
+ if (typeof History.Adapter === "undefined") {
127
+ return false;
128
+ }
129
+
130
+ // Check Load Status of Core
131
+ if (typeof History.initCore !== "undefined") {
132
+ History.initCore();
133
+ }
134
+
135
+ // Check Load Status of HTML4 Support
136
+ if (typeof History.initHtml4 !== "undefined") {
137
+ History.initHtml4();
138
+ }
139
+
140
+ // Return true
141
+ return true;
142
+ };
143
+
144
+ // ========================================================================
145
+ // Initialise Core
146
+
147
+ // Initialise Core
148
+ History.initCore = function (options) {
149
+ // Initialise
150
+ if (typeof History.initCore.initialized !== "undefined") {
151
+ // Already Loaded
152
+ return false;
153
+ } else {
154
+ History.initCore.initialized = true;
155
+ }
156
+
157
+ // ====================================================================
158
+ // Options
159
+
160
+ /**
161
+ * History.options
162
+ * Configurable options
163
+ */
164
+ History.options = History.options || {};
165
+
166
+ /**
167
+ * History.options.hashChangeInterval
168
+ * How long should the interval be before hashchange checks
169
+ */
170
+ History.options.hashChangeInterval =
171
+ History.options.hashChangeInterval || 100;
172
+
173
+ /**
174
+ * History.options.safariPollInterval
175
+ * How long should the interval be before safari poll checks
176
+ */
177
+ History.options.safariPollInterval =
178
+ History.options.safariPollInterval || 500;
179
+
180
+ /**
181
+ * History.options.doubleCheckInterval
182
+ * How long should the interval be before we perform a double check
183
+ */
184
+ History.options.doubleCheckInterval =
185
+ History.options.doubleCheckInterval || 500;
186
+
187
+ /**
188
+ * History.options.disableSuid
189
+ * Force History not to append suid
190
+ */
191
+ History.options.disableSuid = History.options.disableSuid || false;
192
+
193
+ /**
194
+ * History.options.storeInterval
195
+ * How long should we wait between store calls
196
+ */
197
+ History.options.storeInterval = History.options.storeInterval || 1000;
198
+
199
+ /**
200
+ * History.options.busyDelay
201
+ * How long should we wait between busy events
202
+ */
203
+ History.options.busyDelay = History.options.busyDelay || 250;
204
+
205
+ /**
206
+ * History.options.debug
207
+ * If true will enable debug messages to be logged
208
+ */
209
+ History.options.debug = History.options.debug || false;
210
+
211
+ /**
212
+ * History.options.initialTitle
213
+ * What is the title of the initial state
214
+ */
215
+ History.options.initialTitle =
216
+ History.options.initialTitle || document.title;
217
+
218
+ /**
219
+ * History.options.html4Mode
220
+ * If true, will force HTMl4 mode (hashtags)
221
+ */
222
+ History.options.html4Mode = History.options.html4Mode || false;
223
+
224
+ /**
225
+ * History.options.delayInit
226
+ * Want to override default options and call init manually.
227
+ */
228
+ History.options.delayInit = History.options.delayInit || false;
229
+
230
+ // ====================================================================
231
+ // Interval record
232
+
233
+ /**
234
+ * History.intervalList
235
+ * List of intervals set, to be cleared when document is unloaded.
236
+ */
237
+ History.intervalList = [];
238
+
239
+ /**
240
+ * History.clearAllIntervals
241
+ * Clears all setInterval instances.
242
+ */
243
+ History.clearAllIntervals = function () {
244
+ var i,
245
+ il = History.intervalList;
246
+ if (typeof il !== "undefined" && il !== null) {
247
+ for (i = 0; i < il.length; i++) {
248
+ clearInterval(il[i]);
249
+ }
250
+ History.intervalList = null;
251
+ }
252
+ };
253
+
254
+ // ====================================================================
255
+ // Debug
256
+
257
+ /**
258
+ * History.debug(message,...)
259
+ * Logs the passed arguments if debug enabled
260
+ */
261
+ History.debug = function () {
262
+ if (History.options.debug || false) {
263
+ History.log.apply(History, arguments);
264
+ }
265
+ };
266
+
267
+ /**
268
+ * History.log(message,...)
269
+ * Logs the passed arguments
270
+ */
271
+ History.log = function () {
272
+ // Prepare
273
+ var consoleExists = !(
274
+ typeof console === "undefined" ||
275
+ typeof console.log === "undefined" ||
276
+ typeof console.log.apply === "undefined"
277
+ ),
278
+ textarea = document.getElementById("log"),
279
+ message,
280
+ i,
281
+ n,
282
+ args,
283
+ arg;
284
+
285
+ // Write to Console
286
+ if (consoleExists) {
287
+ args = Array.prototype.slice.call(arguments);
288
+ message = args.shift();
289
+ if (typeof console.debug !== "undefined") {
290
+ console.debug.apply(console, [message, args]);
291
+ } else {
292
+ console.log.apply(console, [message, args]);
293
+ }
294
+ } else {
295
+ message = "\n" + arguments[0] + "\n";
296
+ }
297
+
298
+ // Write to log
299
+ for (i = 1, n = arguments.length; i < n; ++i) {
300
+ arg = arguments[i];
301
+ if (typeof arg === "object" && typeof JSON !== "undefined") {
302
+ try {
303
+ arg = JSON.stringify(arg);
304
+ } catch (Exception) {
305
+ // Recursive Object
306
+ }
307
+ }
308
+ message += "\n" + arg + "\n";
309
+ }
310
+
311
+ // Textarea
312
+ if (textarea) {
313
+ textarea.value += message + "\n-----\n";
314
+ textarea.scrollTop = textarea.scrollHeight - textarea.clientHeight;
315
+ }
316
+ // No Textarea, No Console
317
+ else if (!consoleExists) {
318
+ alert(message);
319
+ }
320
+
321
+ // Return true
322
+ return true;
323
+ };
324
+
325
+ // ====================================================================
326
+ // Emulated Status
327
+
328
+ /**
329
+ * History.getInternetExplorerMajorVersion()
330
+ * Get's the major version of Internet Explorer
331
+ * @return {integer}
332
+ * @license Public Domain
333
+ * @author Benjamin Arthur Lupton <contact@balupton.com>
334
+ * @author James Padolsey <https://gist.github.com/527683>
335
+ */
336
+ History.getInternetExplorerMajorVersion = function () {
337
+ var result = (History.getInternetExplorerMajorVersion.cached =
338
+ typeof History.getInternetExplorerMajorVersion.cached !== "undefined"
339
+ ? History.getInternetExplorerMajorVersion.cached
340
+ : (function () {
341
+ var v = 3,
342
+ div = document.createElement("div"),
343
+ all = div.getElementsByTagName("i");
344
+ while (
345
+ (div.innerHTML =
346
+ "<!--[if gt IE " + ++v + "]><i></i><![endif]-->") &&
347
+ all[0]
348
+ ) {}
349
+ return v > 4 ? v : false;
350
+ })());
351
+ return result;
352
+ };
353
+
354
+ /**
355
+ * History.isInternetExplorer()
356
+ * Are we using Internet Explorer?
357
+ * @return {boolean}
358
+ * @license Public Domain
359
+ * @author Benjamin Arthur Lupton <contact@balupton.com>
360
+ */
361
+ History.isInternetExplorer = function () {
362
+ var result = (History.isInternetExplorer.cached =
363
+ typeof History.isInternetExplorer.cached !== "undefined"
364
+ ? History.isInternetExplorer.cached
365
+ : Boolean(History.getInternetExplorerMajorVersion()));
366
+ return result;
367
+ };
368
+
369
+ /**
370
+ * History.emulated
371
+ * Which features require emulating?
372
+ */
373
+
374
+ if (History.options.html4Mode) {
375
+ History.emulated = {
376
+ pushState: true,
377
+ hashChange: true,
378
+ };
379
+ } else {
380
+ History.emulated = {
381
+ pushState: !Boolean(
382
+ window.history &&
383
+ window.history.pushState &&
384
+ window.history.replaceState &&
385
+ !(
386
+ (
387
+ / Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i.test(
388
+ navigator.userAgent
389
+ ) /* disable for versions of iOS before version 4.3 (8F190) */ ||
390
+ /AppleWebKit\/5([0-2]|3[0-2])/i.test(navigator.userAgent)
391
+ ) /* disable for the mercury iOS browser, or at least older versions of the webkit engine */
392
+ )
393
+ ),
394
+ hashChange: Boolean(
395
+ !("onhashchange" in window || "onhashchange" in document) ||
396
+ (History.isInternetExplorer() &&
397
+ History.getInternetExplorerMajorVersion() < 8)
398
+ ),
399
+ };
400
+ }
401
+
402
+ /**
403
+ * History.enabled
404
+ * Is History enabled?
405
+ */
406
+ History.enabled = !History.emulated.pushState;
407
+
408
+ /**
409
+ * History.bugs
410
+ * Which bugs are present
411
+ */
412
+ History.bugs = {
413
+ /**
414
+ * Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call
415
+ * https://bugs.webkit.org/show_bug.cgi?id=56249
416
+ */
417
+ setHash: Boolean(
418
+ !History.emulated.pushState &&
419
+ navigator.vendor === "Apple Computer, Inc." &&
420
+ /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)
421
+ ),
422
+
423
+ /**
424
+ * Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions
425
+ * https://bugs.webkit.org/show_bug.cgi?id=42940
426
+ */
427
+ safariPoll: Boolean(
428
+ !History.emulated.pushState &&
429
+ navigator.vendor === "Apple Computer, Inc." &&
430
+ /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)
431
+ ),
432
+
433
+ /**
434
+ * MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function)
435
+ */
436
+ ieDoubleCheck: Boolean(
437
+ History.isInternetExplorer() &&
438
+ History.getInternetExplorerMajorVersion() < 8
439
+ ),
440
+
441
+ /**
442
+ * MSIE 6 requires the entire hash to be encoded for the hashes to trigger the onHashChange event
443
+ */
444
+ hashEscape: Boolean(
445
+ History.isInternetExplorer() &&
446
+ History.getInternetExplorerMajorVersion() < 7
447
+ ),
448
+ };
449
+
450
+ /**
451
+ * History.isEmptyObject(obj)
452
+ * Checks to see if the Object is Empty
453
+ * @param {Object} obj
454
+ * @return {boolean}
455
+ */
456
+ History.isEmptyObject = function (obj) {
457
+ for (var name in obj) {
458
+ if (obj.hasOwnProperty(name)) {
459
+ return false;
460
+ }
461
+ }
462
+ return true;
463
+ };
464
+
465
+ /**
466
+ * History.cloneObject(obj)
467
+ * Clones a object and eliminate all references to the original contexts
468
+ * @param {Object} obj
469
+ * @return {Object}
470
+ */
471
+ History.cloneObject = function (obj) {
472
+ var hash, newObj;
473
+ if (obj) {
474
+ hash = JSON.stringify(obj);
475
+ newObj = JSON.parse(hash);
476
+ } else {
477
+ newObj = {};
478
+ }
479
+ return newObj;
480
+ };
481
+
482
+ // ====================================================================
483
+ // URL Helpers
484
+
485
+ /**
486
+ * History.getRootUrl()
487
+ * Turns "http://mysite.com/dir/page.html?asd" into "http://mysite.com"
488
+ * @return {String} rootUrl
489
+ */
490
+ History.getRootUrl = function () {
491
+ // Create
492
+ var rootUrl =
493
+ document.location.protocol +
494
+ "//" +
495
+ (document.location.hostname || document.location.host);
496
+ if (document.location.port || false) {
497
+ rootUrl += ":" + document.location.port;
498
+ }
499
+ rootUrl += "/";
500
+
501
+ // Return
502
+ return rootUrl;
503
+ };
504
+
505
+ /**
506
+ * History.getBaseHref()
507
+ * Fetches the `href` attribute of the `<base href="...">` element if it exists
508
+ * @return {String} baseHref
509
+ */
510
+ History.getBaseHref = function () {
511
+ // Create
512
+ var baseElements = document.getElementsByTagName("base"),
513
+ baseElement = null,
514
+ baseHref = "";
515
+
516
+ // Test for Base Element
517
+ if (baseElements.length === 1) {
518
+ // Prepare for Base Element
519
+ baseElement = baseElements[0];
520
+ baseHref = baseElement.href.replace(/[^\/]+$/, "");
521
+ }
522
+
523
+ // Adjust trailing slash
524
+ baseHref = baseHref.replace(/\/+$/, "");
525
+ if (baseHref) baseHref += "/";
526
+
527
+ // Return
528
+ return baseHref;
529
+ };
530
+
531
+ /**
532
+ * History.getBaseUrl()
533
+ * Fetches the baseHref or basePageUrl or rootUrl (whichever one exists first)
534
+ * @return {String} baseUrl
535
+ */
536
+ History.getBaseUrl = function () {
537
+ // Create
538
+ var baseUrl =
539
+ History.getBaseHref() ||
540
+ History.getBasePageUrl() ||
541
+ History.getRootUrl();
542
+
543
+ // Return
544
+ return baseUrl;
545
+ };
546
+
547
+ /**
548
+ * History.getPageUrl()
549
+ * Fetches the URL of the current page
550
+ * @return {String} pageUrl
551
+ */
552
+ History.getPageUrl = function () {
553
+ // Fetch
554
+ var State = History.getState(false, false),
555
+ stateUrl = (State || {}).url || History.getLocationHref(),
556
+ pageUrl;
557
+
558
+ // Create
559
+ pageUrl = stateUrl
560
+ .replace(/\/+$/, "")
561
+ .replace(/[^\/]+$/, function (part, index, string) {
562
+ return /\./.test(part) ? part : part + "/";
563
+ });
564
+
565
+ // Return
566
+ return pageUrl;
567
+ };
568
+
569
+ /**
570
+ * History.getBasePageUrl()
571
+ * Fetches the Url of the directory of the current page
572
+ * @return {String} basePageUrl
573
+ */
574
+ History.getBasePageUrl = function () {
575
+ // Create
576
+ var basePageUrl =
577
+ History.getLocationHref()
578
+ .replace(/[#\?].*/, "")
579
+ .replace(/[^\/]+$/, function (part, index, string) {
580
+ return /[^\/]$/.test(part) ? "" : part;
581
+ })
582
+ .replace(/\/+$/, "") + "/";
583
+
584
+ // Return
585
+ return basePageUrl;
586
+ };
587
+
588
+ /**
589
+ * History.getFullUrl(url)
590
+ * Ensures that we have an absolute URL and not a relative URL
591
+ * @param {string} url
592
+ * @param {Boolean} allowBaseHref
593
+ * @return {string} fullUrl
594
+ */
595
+ History.getFullUrl = function (url, allowBaseHref) {
596
+ // Prepare
597
+ var fullUrl = url,
598
+ firstChar = url.substring(0, 1);
599
+ allowBaseHref =
600
+ typeof allowBaseHref === "undefined" ? true : allowBaseHref;
601
+
602
+ // Check
603
+ if (/[a-z]+\:\/\//.test(url)) {
604
+ // Full URL
605
+ } else if (firstChar === "/") {
606
+ // Root URL
607
+ fullUrl = History.getRootUrl() + url.replace(/^\/+/, "");
608
+ } else if (firstChar === "#") {
609
+ // Anchor URL
610
+ fullUrl = History.getPageUrl().replace(/#.*/, "") + url;
611
+ } else if (firstChar === "?") {
612
+ // Query URL
613
+ fullUrl = History.getPageUrl().replace(/[\?#].*/, "") + url;
614
+ } else {
615
+ // Relative URL
616
+ if (allowBaseHref) {
617
+ fullUrl = History.getBaseUrl() + url.replace(/^(\.\/)+/, "");
618
+ } else {
619
+ fullUrl = History.getBasePageUrl() + url.replace(/^(\.\/)+/, "");
620
+ }
621
+ // We have an if condition above as we do not want hashes
622
+ // which are relative to the baseHref in our URLs
623
+ // as if the baseHref changes, then all our bookmarks
624
+ // would now point to different locations
625
+ // whereas the basePageUrl will always stay the same
626
+ }
627
+
628
+ // Return
629
+ return fullUrl.replace(/\#$/, "");
630
+ };
631
+
632
+ /**
633
+ * History.getShortUrl(url)
634
+ * Ensures that we have a relative URL and not a absolute URL
635
+ * @param {string} url
636
+ * @return {string} url
637
+ */
638
+ History.getShortUrl = function (url) {
639
+ // Prepare
640
+ var shortUrl = url,
641
+ baseUrl = History.getBaseUrl(),
642
+ rootUrl = History.getRootUrl();
643
+
644
+ // Trim baseUrl
645
+ if (History.emulated.pushState) {
646
+ // We are in a if statement as when pushState is not emulated
647
+ // The actual url these short urls are relative to can change
648
+ // So within the same session, we the url may end up somewhere different
649
+ shortUrl = shortUrl.replace(baseUrl, "");
650
+ }
651
+
652
+ // Trim rootUrl
653
+ shortUrl = shortUrl.replace(rootUrl, "/");
654
+
655
+ // Ensure we can still detect it as a state
656
+ if (History.isTraditionalAnchor(shortUrl)) {
657
+ shortUrl = "./" + shortUrl;
658
+ }
659
+
660
+ // Clean It
661
+ shortUrl = shortUrl.replace(/^(\.\/)+/g, "./").replace(/\#$/, "");
662
+
663
+ // Return
664
+ return shortUrl;
665
+ };
666
+
667
+ /**
668
+ * History.getLocationHref(document)
669
+ * Returns a normalized version of document.location.href
670
+ * accounting for browser inconsistencies, etc.
671
+ *
672
+ * This URL will be URI-encoded and will include the hash
673
+ *
674
+ * @param {object} document
675
+ * @return {string} url
676
+ */
677
+ History.getLocationHref = function (doc) {
678
+ doc = doc || document;
679
+
680
+ // most of the time, this will be true
681
+ if (doc.URL === doc.location.href) return doc.location.href;
682
+
683
+ // some versions of webkit URI-decode document.location.href
684
+ // but they leave document.URL in an encoded state
685
+ if (doc.location.href === decodeURIComponent(doc.URL)) return doc.URL;
686
+
687
+ // FF 3.6 only updates document.URL when a page is reloaded
688
+ // document.location.href is updated correctly
689
+ if (
690
+ doc.location.hash &&
691
+ decodeURIComponent(doc.location.href.replace(/^[^#]+/, "")) ===
692
+ doc.location.hash
693
+ )
694
+ return doc.location.href;
695
+
696
+ if (doc.URL.indexOf("#") == -1 && doc.location.href.indexOf("#") != -1)
697
+ return doc.location.href;
698
+
699
+ return doc.URL || doc.location.href;
700
+ };
701
+
702
+ // ====================================================================
703
+ // State Storage
704
+
705
+ /**
706
+ * History.store
707
+ * The store for all session specific data
708
+ */
709
+ History.store = {};
710
+
711
+ /**
712
+ * History.idToState
713
+ * 1-1: State ID to State Object
714
+ */
715
+ History.idToState = History.idToState || {};
716
+
717
+ /**
718
+ * History.stateToId
719
+ * 1-1: State String to State ID
720
+ */
721
+ History.stateToId = History.stateToId || {};
722
+
723
+ /**
724
+ * History.urlToId
725
+ * 1-1: State URL to State ID
726
+ */
727
+ History.urlToId = History.urlToId || {};
728
+
729
+ /**
730
+ * History.storedStates
731
+ * Store the states in an array
732
+ */
733
+ History.storedStates = History.storedStates || [];
734
+
735
+ /**
736
+ * History.savedStates
737
+ * Saved the states in an array
738
+ */
739
+ History.savedStates = History.savedStates || [];
740
+
741
+ /**
742
+ * History.noramlizeStore()
743
+ * Noramlize the store by adding necessary values
744
+ */
745
+ History.normalizeStore = function () {
746
+ History.store.idToState = History.store.idToState || {};
747
+ History.store.urlToId = History.store.urlToId || {};
748
+ History.store.stateToId = History.store.stateToId || {};
749
+ };
750
+
751
+ /**
752
+ * History.getState()
753
+ * Get an object containing the data, title and url of the current state
754
+ * @param {Boolean} friendly
755
+ * @param {Boolean} create
756
+ * @return {Object} State
757
+ */
758
+ History.getState = function (friendly, create) {
759
+ // Prepare
760
+ if (typeof friendly === "undefined") {
761
+ friendly = true;
762
+ }
763
+ if (typeof create === "undefined") {
764
+ create = true;
765
+ }
766
+
767
+ // Fetch
768
+ var State = History.getLastSavedState();
769
+
770
+ // Create
771
+ if (!State && create) {
772
+ State = History.createStateObject();
773
+ }
774
+
775
+ // Adjust
776
+ if (friendly) {
777
+ State = History.cloneObject(State);
778
+ State.url = State.cleanUrl || State.url;
779
+ }
780
+
781
+ // Return
782
+ return State;
783
+ };
784
+
785
+ /**
786
+ * History.getIdByState(State)
787
+ * Gets a ID for a State
788
+ * @param {State} newState
789
+ * @return {String} id
790
+ */
791
+ History.getIdByState = function (newState) {
792
+ // Fetch ID
793
+ var id = History.extractId(newState.url),
794
+ str;
795
+
796
+ if (!id) {
797
+ // Find ID via State String
798
+ str = History.getStateString(newState);
799
+ if (typeof History.stateToId[str] !== "undefined") {
800
+ id = History.stateToId[str];
801
+ } else if (typeof History.store.stateToId[str] !== "undefined") {
802
+ id = History.store.stateToId[str];
803
+ } else {
804
+ // Generate a new ID
805
+ while (true) {
806
+ id =
807
+ new Date().getTime() + String(Math.random()).replace(/\D/g, "");
808
+ if (
809
+ typeof History.idToState[id] === "undefined" &&
810
+ typeof History.store.idToState[id] === "undefined"
811
+ ) {
812
+ break;
813
+ }
814
+ }
815
+
816
+ // Apply the new State to the ID
817
+ History.stateToId[str] = id;
818
+ History.idToState[id] = newState;
819
+ }
820
+ }
821
+
822
+ // Return ID
823
+ return id;
824
+ };
825
+
826
+ /**
827
+ * History.normalizeState(State)
828
+ * Expands a State Object
829
+ * @param {object} State
830
+ * @return {object}
831
+ */
832
+ History.normalizeState = function (oldState) {
833
+ // Variables
834
+ var newState, dataNotEmpty;
835
+
836
+ // Prepare
837
+ if (!oldState || typeof oldState !== "object") {
838
+ oldState = {};
839
+ }
840
+
841
+ // Check
842
+ if (typeof oldState.normalized !== "undefined") {
843
+ return oldState;
844
+ }
845
+
846
+ // Adjust
847
+ if (!oldState.data || typeof oldState.data !== "object") {
848
+ oldState.data = {};
849
+ }
850
+
851
+ // ----------------------------------------------------------------
852
+
853
+ // Create
854
+ newState = {};
855
+ newState.normalized = true;
856
+ newState.title = oldState.title || "";
857
+ newState.url = History.getFullUrl(
858
+ oldState.url ? oldState.url : History.getLocationHref()
859
+ );
860
+ newState.hash = History.getShortUrl(newState.url);
861
+ newState.data = History.cloneObject(oldState.data);
862
+
863
+ // Fetch ID
864
+ newState.id = History.getIdByState(newState);
865
+
866
+ // ----------------------------------------------------------------
867
+
868
+ // Clean the URL
869
+ newState.cleanUrl = newState.url.replace(/\??\&_suid.*/, "");
870
+ newState.url = newState.cleanUrl;
871
+
872
+ // Check to see if we have more than just a url
873
+ dataNotEmpty = !History.isEmptyObject(newState.data);
874
+
875
+ // Apply
876
+ if (
877
+ (newState.title || dataNotEmpty) &&
878
+ History.options.disableSuid !== true
879
+ ) {
880
+ // Add ID to Hash
881
+ newState.hash = History.getShortUrl(newState.url).replace(
882
+ /\??\&_suid.*/,
883
+ ""
884
+ );
885
+ if (!/\?/.test(newState.hash)) {
886
+ newState.hash += "?";
887
+ }
888
+ newState.hash += "&_suid=" + newState.id;
889
+ }
890
+
891
+ // Create the Hashed URL
892
+ newState.hashedUrl = History.getFullUrl(newState.hash);
893
+
894
+ // ----------------------------------------------------------------
895
+
896
+ // Update the URL if we have a duplicate
897
+ if (
898
+ (History.emulated.pushState || History.bugs.safariPoll) &&
899
+ History.hasUrlDuplicate(newState)
900
+ ) {
901
+ newState.url = newState.hashedUrl;
902
+ }
903
+
904
+ // ----------------------------------------------------------------
905
+
906
+ // Return
907
+ return newState;
908
+ };
909
+
910
+ /**
911
+ * History.createStateObject(data,title,url)
912
+ * Creates a object based on the data, title and url state params
913
+ * @param {object} data
914
+ * @param {string} title
915
+ * @param {string} url
916
+ * @return {object}
917
+ */
918
+ History.createStateObject = function (data, title, url) {
919
+ // Hashify
920
+ var State = {
921
+ data: data,
922
+ title: title,
923
+ url: url,
924
+ };
925
+
926
+ // Expand the State
927
+ State = History.normalizeState(State);
928
+
929
+ // Return object
930
+ return State;
931
+ };
932
+
933
+ /**
934
+ * History.getStateById(id)
935
+ * Get a state by it's UID
936
+ * @param {String} id
937
+ */
938
+ History.getStateById = function (id) {
939
+ // Prepare
940
+ id = String(id);
941
+
942
+ // Retrieve
943
+ var State =
944
+ History.idToState[id] || History.store.idToState[id] || undefined;
945
+
946
+ // Return State
947
+ return State;
948
+ };
949
+
950
+ /**
951
+ * Get a State's String
952
+ * @param {State} passedState
953
+ */
954
+ History.getStateString = function (passedState) {
955
+ // Prepare
956
+ var State, cleanedState, str;
957
+
958
+ // Fetch
959
+ State = History.normalizeState(passedState);
960
+
961
+ // Clean
962
+ cleanedState = {
963
+ data: State.data,
964
+ title: passedState.title,
965
+ url: passedState.url,
966
+ };
967
+
968
+ // Fetch
969
+ str = JSON.stringify(cleanedState);
970
+
971
+ // Return
972
+ return str;
973
+ };
974
+
975
+ /**
976
+ * Get a State's ID
977
+ * @param {State} passedState
978
+ * @return {String} id
979
+ */
980
+ History.getStateId = function (passedState) {
981
+ // Prepare
982
+ var State, id;
983
+
984
+ // Fetch
985
+ State = History.normalizeState(passedState);
986
+
987
+ // Fetch
988
+ id = State.id;
989
+
990
+ // Return
991
+ return id;
992
+ };
993
+
994
+ /**
995
+ * History.getHashByState(State)
996
+ * Creates a Hash for the State Object
997
+ * @param {State} passedState
998
+ * @return {String} hash
999
+ */
1000
+ History.getHashByState = function (passedState) {
1001
+ // Prepare
1002
+ var State, hash;
1003
+
1004
+ // Fetch
1005
+ State = History.normalizeState(passedState);
1006
+
1007
+ // Hash
1008
+ hash = State.hash;
1009
+
1010
+ // Return
1011
+ return hash;
1012
+ };
1013
+
1014
+ /**
1015
+ * History.extractId(url_or_hash)
1016
+ * Get a State ID by it's URL or Hash
1017
+ * @param {string} url_or_hash
1018
+ * @return {string} id
1019
+ */
1020
+ History.extractId = function (url_or_hash) {
1021
+ // Prepare
1022
+ var id, parts, url, tmp;
1023
+
1024
+ // Extract
1025
+
1026
+ // If the URL has a #, use the id from before the #
1027
+ if (url_or_hash.indexOf("#") != -1) {
1028
+ tmp = url_or_hash.split("#")[0];
1029
+ } else {
1030
+ tmp = url_or_hash;
1031
+ }
1032
+
1033
+ parts = /(.*)\&_suid=([0-9]+)$/.exec(tmp);
1034
+ url = parts ? parts[1] || url_or_hash : url_or_hash;
1035
+ id = parts ? String(parts[2] || "") : "";
1036
+
1037
+ // Return
1038
+ return id || false;
1039
+ };
1040
+
1041
+ /**
1042
+ * History.isTraditionalAnchor
1043
+ * Checks to see if the url is a traditional anchor or not
1044
+ * @param {String} url_or_hash
1045
+ * @return {Boolean}
1046
+ */
1047
+ History.isTraditionalAnchor = function (url_or_hash) {
1048
+ // Check
1049
+ var isTraditional = !/[\/\?\.]/.test(url_or_hash);
1050
+
1051
+ // Return
1052
+ return isTraditional;
1053
+ };
1054
+
1055
+ /**
1056
+ * History.extractState
1057
+ * Get a State by it's URL or Hash
1058
+ * @param {String} url_or_hash
1059
+ * @return {State|null}
1060
+ */
1061
+ History.extractState = function (url_or_hash, create) {
1062
+ // Prepare
1063
+ var State = null,
1064
+ id,
1065
+ url;
1066
+ create = create || false;
1067
+
1068
+ // Fetch SUID
1069
+ id = History.extractId(url_or_hash);
1070
+ if (id) {
1071
+ State = History.getStateById(id);
1072
+ }
1073
+
1074
+ // Fetch SUID returned no State
1075
+ if (!State) {
1076
+ // Fetch URL
1077
+ url = History.getFullUrl(url_or_hash);
1078
+
1079
+ // Check URL
1080
+ id = History.getIdByUrl(url) || false;
1081
+ if (id) {
1082
+ State = History.getStateById(id);
1083
+ }
1084
+
1085
+ // Create State
1086
+ if (!State && create && !History.isTraditionalAnchor(url_or_hash)) {
1087
+ State = History.createStateObject(null, null, url);
1088
+ }
1089
+ }
1090
+
1091
+ // Return
1092
+ return State;
1093
+ };
1094
+
1095
+ /**
1096
+ * History.getIdByUrl()
1097
+ * Get a State ID by a State URL
1098
+ */
1099
+ History.getIdByUrl = function (url) {
1100
+ // Fetch
1101
+ var id = History.urlToId[url] || History.store.urlToId[url] || undefined;
1102
+
1103
+ // Return
1104
+ return id;
1105
+ };
1106
+
1107
+ /**
1108
+ * History.getLastSavedState()
1109
+ * Get an object containing the data, title and url of the current state
1110
+ * @return {Object} State
1111
+ */
1112
+ History.getLastSavedState = function () {
1113
+ return History.savedStates[History.savedStates.length - 1] || undefined;
1114
+ };
1115
+
1116
+ /**
1117
+ * History.getLastStoredState()
1118
+ * Get an object containing the data, title and url of the current state
1119
+ * @return {Object} State
1120
+ */
1121
+ History.getLastStoredState = function () {
1122
+ return History.storedStates[History.storedStates.length - 1] || undefined;
1123
+ };
1124
+
1125
+ /**
1126
+ * History.hasUrlDuplicate
1127
+ * Checks if a Url will have a url conflict
1128
+ * @param {Object} newState
1129
+ * @return {Boolean} hasDuplicate
1130
+ */
1131
+ History.hasUrlDuplicate = function (newState) {
1132
+ // Prepare
1133
+ var hasDuplicate = false,
1134
+ oldState;
1135
+
1136
+ // Fetch
1137
+ oldState = History.extractState(newState.url);
1138
+
1139
+ // Check
1140
+ hasDuplicate = oldState && oldState.id !== newState.id;
1141
+
1142
+ // Return
1143
+ return hasDuplicate;
1144
+ };
1145
+
1146
+ /**
1147
+ * History.storeState
1148
+ * Store a State
1149
+ * @param {Object} newState
1150
+ * @return {Object} newState
1151
+ */
1152
+ History.storeState = function (newState) {
1153
+ // Store the State
1154
+ History.urlToId[newState.url] = newState.id;
1155
+
1156
+ // Push the State
1157
+ History.storedStates.push(History.cloneObject(newState));
1158
+
1159
+ // Return newState
1160
+ return newState;
1161
+ };
1162
+
1163
+ /**
1164
+ * History.isLastSavedState(newState)
1165
+ * Tests to see if the state is the last state
1166
+ * @param {Object} newState
1167
+ * @return {boolean} isLast
1168
+ */
1169
+ History.isLastSavedState = function (newState) {
1170
+ // Prepare
1171
+ var isLast = false,
1172
+ newId,
1173
+ oldState,
1174
+ oldId;
1175
+
1176
+ // Check
1177
+ if (History.savedStates.length) {
1178
+ newId = newState.id;
1179
+ oldState = History.getLastSavedState();
1180
+ oldId = oldState.id;
1181
+
1182
+ // Check
1183
+ isLast = newId === oldId;
1184
+ }
1185
+
1186
+ // Return
1187
+ return isLast;
1188
+ };
1189
+
1190
+ /**
1191
+ * History.saveState
1192
+ * Push a State
1193
+ * @param {Object} newState
1194
+ * @return {boolean} changed
1195
+ */
1196
+ History.saveState = function (newState) {
1197
+ // Check Hash
1198
+ if (History.isLastSavedState(newState)) {
1199
+ return false;
1200
+ }
1201
+
1202
+ // Push the State
1203
+ History.savedStates.push(History.cloneObject(newState));
1204
+
1205
+ // Return true
1206
+ return true;
1207
+ };
1208
+
1209
+ /**
1210
+ * History.getStateByIndex()
1211
+ * Gets a state by the index
1212
+ * @param {integer} index
1213
+ * @return {Object}
1214
+ */
1215
+ History.getStateByIndex = function (index) {
1216
+ // Prepare
1217
+ var State = null;
1218
+
1219
+ // Handle
1220
+ if (typeof index === "undefined") {
1221
+ // Get the last inserted
1222
+ State = History.savedStates[History.savedStates.length - 1];
1223
+ } else if (index < 0) {
1224
+ // Get from the end
1225
+ State = History.savedStates[History.savedStates.length + index];
1226
+ } else {
1227
+ // Get from the beginning
1228
+ State = History.savedStates[index];
1229
+ }
1230
+
1231
+ // Return State
1232
+ return State;
1233
+ };
1234
+
1235
+ /**
1236
+ * History.getCurrentIndex()
1237
+ * Gets the current index
1238
+ * @return (integer)
1239
+ */
1240
+ History.getCurrentIndex = function () {
1241
+ // Prepare
1242
+ var index = null;
1243
+
1244
+ // No states saved
1245
+ if (History.savedStates.length < 1) {
1246
+ index = 0;
1247
+ } else {
1248
+ index = History.savedStates.length - 1;
1249
+ }
1250
+ return index;
1251
+ };
1252
+
1253
+ // ====================================================================
1254
+ // Hash Helpers
1255
+
1256
+ /**
1257
+ * History.getHash()
1258
+ * @param {Location=} location
1259
+ * Gets the current document hash
1260
+ * Note: unlike location.hash, this is guaranteed to return the escaped hash in all browsers
1261
+ * @return {string}
1262
+ */
1263
+ History.getHash = function (doc) {
1264
+ var url = History.getLocationHref(doc),
1265
+ hash;
1266
+ hash = History.getHashByUrl(url);
1267
+ return hash;
1268
+ };
1269
+
1270
+ /**
1271
+ * History.unescapeHash()
1272
+ * normalize and Unescape a Hash
1273
+ * @param {String} hash
1274
+ * @return {string}
1275
+ */
1276
+ History.unescapeHash = function (hash) {
1277
+ // Prepare
1278
+ var result = History.normalizeHash(hash);
1279
+
1280
+ // Unescape hash
1281
+ result = decodeURIComponent(result);
1282
+
1283
+ // Return result
1284
+ return result;
1285
+ };
1286
+
1287
+ /**
1288
+ * History.normalizeHash()
1289
+ * normalize a hash across browsers
1290
+ * @return {string}
1291
+ */
1292
+ History.normalizeHash = function (hash) {
1293
+ // Prepare
1294
+ var result = hash.replace(/[^#]*#/, "").replace(/#.*/, "");
1295
+
1296
+ // Return result
1297
+ return result;
1298
+ };
1299
+
1300
+ /**
1301
+ * History.setHash(hash)
1302
+ * Sets the document hash
1303
+ * @param {string} hash
1304
+ * @return {History}
1305
+ */
1306
+ History.setHash = function (hash, queue) {
1307
+ // Prepare
1308
+ var State, pageUrl;
1309
+
1310
+ // Handle Queueing
1311
+ if (queue !== false && History.busy()) {
1312
+ // Wait + Push to Queue
1313
+ //History.debug('History.setHash: we must wait', arguments);
1314
+ History.pushQueue({
1315
+ scope: History,
1316
+ callback: History.setHash,
1317
+ args: arguments,
1318
+ queue: queue,
1319
+ });
1320
+ return false;
1321
+ }
1322
+
1323
+ // Log
1324
+ //History.debug('History.setHash: called',hash);
1325
+
1326
+ // Make Busy + Continue
1327
+ History.busy(true);
1328
+
1329
+ // Check if hash is a state
1330
+ State = History.extractState(hash, true);
1331
+ if (State && !History.emulated.pushState) {
1332
+ // Hash is a state so skip the setHash
1333
+ //History.debug('History.setHash: Hash is a state so skipping the hash set with a direct pushState call',arguments);
1334
+
1335
+ // PushState
1336
+ History.pushState(State.data, State.title, State.url, false);
1337
+ } else if (History.getHash() !== hash) {
1338
+ // Hash is a proper hash, so apply it
1339
+
1340
+ // Handle browser bugs
1341
+ if (History.bugs.setHash) {
1342
+ // Fix Safari Bug https://bugs.webkit.org/show_bug.cgi?id=56249
1343
+
1344
+ // Fetch the base page
1345
+ pageUrl = History.getPageUrl();
1346
+
1347
+ // Safari hash apply
1348
+ History.pushState(null, null, pageUrl + "#" + hash, false);
1349
+ } else {
1350
+ // Normal hash apply
1351
+ document.location.hash = hash;
1352
+ }
1353
+ }
1354
+
1355
+ // Chain
1356
+ return History;
1357
+ };
1358
+
1359
+ /**
1360
+ * History.escape()
1361
+ * normalize and Escape a Hash
1362
+ * @return {string}
1363
+ */
1364
+ History.escapeHash = function (hash) {
1365
+ // Prepare
1366
+ var result = History.normalizeHash(hash);
1367
+
1368
+ // Escape hash
1369
+ result = window.encodeURIComponent(result);
1370
+
1371
+ // IE6 Escape Bug
1372
+ if (!History.bugs.hashEscape) {
1373
+ // Restore common parts
1374
+ result = result
1375
+ .replace(/\%21/g, "!")
1376
+ .replace(/\%26/g, "&")
1377
+ .replace(/\%3D/g, "=")
1378
+ .replace(/\%3F/g, "?");
1379
+ }
1380
+
1381
+ // Return result
1382
+ return result;
1383
+ };
1384
+
1385
+ /**
1386
+ * History.getHashByUrl(url)
1387
+ * Extracts the Hash from a URL
1388
+ * @param {string} url
1389
+ * @return {string} url
1390
+ */
1391
+ History.getHashByUrl = function (url) {
1392
+ // Extract the hash
1393
+ var hash = String(url).replace(/([^#]*)#?([^#]*)#?(.*)/, "$2");
1394
+ // Unescape hash
1395
+ hash = History.unescapeHash(hash);
1396
+
1397
+ // Return hash
1398
+ return hash;
1399
+ };
1400
+
1401
+ /**
1402
+ * History.setTitle(title)
1403
+ * Applies the title to the document
1404
+ * @param {State} newState
1405
+ * @return {Boolean}
1406
+ */
1407
+ History.setTitle = function (newState) {
1408
+ // Prepare
1409
+ var title = newState.title,
1410
+ firstState;
1411
+
1412
+ // Initial
1413
+ if (!title) {
1414
+ firstState = History.getStateByIndex(0);
1415
+ if (firstState && firstState.url === newState.url) {
1416
+ title = firstState.title || History.options.initialTitle;
1417
+ }
1418
+ }
1419
+
1420
+ // Apply
1421
+ try {
1422
+ document.getElementsByTagName("title")[0].innerHTML = title
1423
+ .replace("<", "&lt;")
1424
+ .replace(">", "&gt;")
1425
+ .replace(" & ", " &amp; ");
1426
+ } catch (Exception) {}
1427
+ document.title = title;
1428
+
1429
+ // Chain
1430
+ return History;
1431
+ };
1432
+
1433
+ // ====================================================================
1434
+ // Queueing
1435
+
1436
+ /**
1437
+ * History.queues
1438
+ * The list of queues to use
1439
+ * First In, First Out
1440
+ */
1441
+ History.queues = [];
1442
+
1443
+ /**
1444
+ * History.busy(value)
1445
+ * @param {boolean} value [optional]
1446
+ * @return {boolean} busy
1447
+ */
1448
+ History.busy = function (value) {
1449
+ // Apply
1450
+ if (typeof value !== "undefined") {
1451
+ //History.debug('History.busy: changing ['+(History.busy.flag||false)+'] to ['+(value||false)+']', History.queues.length);
1452
+ History.busy.flag = value;
1453
+ }
1454
+ // Default
1455
+ else if (typeof History.busy.flag === "undefined") {
1456
+ History.busy.flag = false;
1457
+ }
1458
+
1459
+ // Queue
1460
+ if (!History.busy.flag) {
1461
+ // Execute the next item in the queue
1462
+ clearTimeout(History.busy.timeout);
1463
+ var fireNext = function () {
1464
+ var i, queue, item;
1465
+ if (History.busy.flag) return;
1466
+ for (i = History.queues.length - 1; i >= 0; --i) {
1467
+ queue = History.queues[i];
1468
+ if (queue.length === 0) continue;
1469
+ item = queue.shift();
1470
+ History.fireQueueItem(item);
1471
+ History.busy.timeout = setTimeout(
1472
+ fireNext,
1473
+ History.options.busyDelay
1474
+ );
1475
+ }
1476
+ };
1477
+ History.busy.timeout = setTimeout(fireNext, History.options.busyDelay);
1478
+ }
1479
+
1480
+ // Return
1481
+ return History.busy.flag;
1482
+ };
1483
+
1484
+ /**
1485
+ * History.busy.flag
1486
+ */
1487
+ History.busy.flag = false;
1488
+
1489
+ /**
1490
+ * History.fireQueueItem(item)
1491
+ * Fire a Queue Item
1492
+ * @param {Object} item
1493
+ * @return {Mixed} result
1494
+ */
1495
+ History.fireQueueItem = function (item) {
1496
+ return item.callback.apply(item.scope || History, item.args || []);
1497
+ };
1498
+
1499
+ /**
1500
+ * History.pushQueue(callback,args)
1501
+ * Add an item to the queue
1502
+ * @param {Object} item [scope,callback,args,queue]
1503
+ */
1504
+ History.pushQueue = function (item) {
1505
+ // Prepare the queue
1506
+ History.queues[item.queue || 0] = History.queues[item.queue || 0] || [];
1507
+
1508
+ // Add to the queue
1509
+ History.queues[item.queue || 0].push(item);
1510
+
1511
+ // Chain
1512
+ return History;
1513
+ };
1514
+
1515
+ /**
1516
+ * History.queue (item,queue), (func,queue), (func), (item)
1517
+ * Either firs the item now if not busy, or adds it to the queue
1518
+ */
1519
+ History.queue = function (item, queue) {
1520
+ // Prepare
1521
+ if (typeof item === "function") {
1522
+ item = {
1523
+ callback: item,
1524
+ };
1525
+ }
1526
+ if (typeof queue !== "undefined") {
1527
+ item.queue = queue;
1528
+ }
1529
+
1530
+ // Handle
1531
+ if (History.busy()) {
1532
+ History.pushQueue(item);
1533
+ } else {
1534
+ History.fireQueueItem(item);
1535
+ }
1536
+
1537
+ // Chain
1538
+ return History;
1539
+ };
1540
+
1541
+ /**
1542
+ * History.clearQueue()
1543
+ * Clears the Queue
1544
+ */
1545
+ History.clearQueue = function () {
1546
+ History.busy.flag = false;
1547
+ History.queues = [];
1548
+ return History;
1549
+ };
1550
+
1551
+ // ====================================================================
1552
+ // IE Bug Fix
1553
+
1554
+ /**
1555
+ * History.stateChanged
1556
+ * States whether or not the state has changed since the last double check was initialised
1557
+ */
1558
+ History.stateChanged = false;
1559
+
1560
+ /**
1561
+ * History.doubleChecker
1562
+ * Contains the timeout used for the double checks
1563
+ */
1564
+ History.doubleChecker = false;
1565
+
1566
+ /**
1567
+ * History.doubleCheckComplete()
1568
+ * Complete a double check
1569
+ * @return {History}
1570
+ */
1571
+ History.doubleCheckComplete = function () {
1572
+ // Update
1573
+ History.stateChanged = true;
1574
+
1575
+ // Clear
1576
+ History.doubleCheckClear();
1577
+
1578
+ // Chain
1579
+ return History;
1580
+ };
1581
+
1582
+ /**
1583
+ * History.doubleCheckClear()
1584
+ * Clear a double check
1585
+ * @return {History}
1586
+ */
1587
+ History.doubleCheckClear = function () {
1588
+ // Clear
1589
+ if (History.doubleChecker) {
1590
+ clearTimeout(History.doubleChecker);
1591
+ History.doubleChecker = false;
1592
+ }
1593
+
1594
+ // Chain
1595
+ return History;
1596
+ };
1597
+
1598
+ /**
1599
+ * History.doubleCheck()
1600
+ * Create a double check
1601
+ * @return {History}
1602
+ */
1603
+ History.doubleCheck = function (tryAgain) {
1604
+ // Reset
1605
+ History.stateChanged = false;
1606
+ History.doubleCheckClear();
1607
+
1608
+ // Fix IE6,IE7 bug where calling history.back or history.forward does not actually change the hash (whereas doing it manually does)
1609
+ // Fix Safari 5 bug where sometimes the state does not change: https://bugs.webkit.org/show_bug.cgi?id=42940
1610
+ if (History.bugs.ieDoubleCheck) {
1611
+ // Apply Check
1612
+ History.doubleChecker = setTimeout(function () {
1613
+ History.doubleCheckClear();
1614
+ if (!History.stateChanged) {
1615
+ //History.debug('History.doubleCheck: State has not yet changed, trying again', arguments);
1616
+ // Re-Attempt
1617
+ tryAgain();
1618
+ }
1619
+ return true;
1620
+ }, History.options.doubleCheckInterval);
1621
+ }
1622
+
1623
+ // Chain
1624
+ return History;
1625
+ };
1626
+
1627
+ // ====================================================================
1628
+ // Safari Bug Fix
1629
+
1630
+ /**
1631
+ * History.safariStatePoll()
1632
+ * Poll the current state
1633
+ * @return {History}
1634
+ */
1635
+ History.safariStatePoll = function () {
1636
+ // Poll the URL
1637
+
1638
+ // Get the Last State which has the new URL
1639
+ var urlState = History.extractState(History.getLocationHref()),
1640
+ newState;
1641
+
1642
+ // Check for a difference
1643
+ if (!History.isLastSavedState(urlState)) {
1644
+ newState = urlState;
1645
+ } else {
1646
+ return;
1647
+ }
1648
+
1649
+ // Check if we have a state with that url
1650
+ // If not create it
1651
+ if (!newState) {
1652
+ //History.debug('History.safariStatePoll: new');
1653
+ newState = History.createStateObject();
1654
+ }
1655
+
1656
+ // Apply the New State
1657
+ //History.debug('History.safariStatePoll: trigger');
1658
+ History.Adapter.trigger(window, "popstate");
1659
+
1660
+ // Chain
1661
+ return History;
1662
+ };
1663
+
1664
+ // ====================================================================
1665
+ // State Aliases
1666
+
1667
+ /**
1668
+ * History.back(queue)
1669
+ * Send the browser history back one item
1670
+ * @param {Integer} queue [optional]
1671
+ */
1672
+ History.back = function (queue) {
1673
+ //History.debug('History.back: called', arguments);
1674
+
1675
+ // Handle Queueing
1676
+ if (queue !== false && History.busy()) {
1677
+ // Wait + Push to Queue
1678
+ //History.debug('History.back: we must wait', arguments);
1679
+ History.pushQueue({
1680
+ scope: History,
1681
+ callback: History.back,
1682
+ args: arguments,
1683
+ queue: queue,
1684
+ });
1685
+ return false;
1686
+ }
1687
+
1688
+ // Make Busy + Continue
1689
+ History.busy(true);
1690
+
1691
+ // Fix certain browser bugs that prevent the state from changing
1692
+ History.doubleCheck(function () {
1693
+ History.back(false);
1694
+ });
1695
+
1696
+ // Go back
1697
+ history.go(-1);
1698
+
1699
+ // End back closure
1700
+ return true;
1701
+ };
1702
+
1703
+ /**
1704
+ * History.forward(queue)
1705
+ * Send the browser history forward one item
1706
+ * @param {Integer} queue [optional]
1707
+ */
1708
+ History.forward = function (queue) {
1709
+ //History.debug('History.forward: called', arguments);
1710
+
1711
+ // Handle Queueing
1712
+ if (queue !== false && History.busy()) {
1713
+ // Wait + Push to Queue
1714
+ //History.debug('History.forward: we must wait', arguments);
1715
+ History.pushQueue({
1716
+ scope: History,
1717
+ callback: History.forward,
1718
+ args: arguments,
1719
+ queue: queue,
1720
+ });
1721
+ return false;
1722
+ }
1723
+
1724
+ // Make Busy + Continue
1725
+ History.busy(true);
1726
+
1727
+ // Fix certain browser bugs that prevent the state from changing
1728
+ History.doubleCheck(function () {
1729
+ History.forward(false);
1730
+ });
1731
+
1732
+ // Go forward
1733
+ history.go(1);
1734
+
1735
+ // End forward closure
1736
+ return true;
1737
+ };
1738
+
1739
+ /**
1740
+ * History.go(index,queue)
1741
+ * Send the browser history back or forward index times
1742
+ * @param {Integer} queue [optional]
1743
+ */
1744
+ History.go = function (index, queue) {
1745
+ //History.debug('History.go: called', arguments);
1746
+
1747
+ // Prepare
1748
+ var i;
1749
+
1750
+ // Handle
1751
+ if (index > 0) {
1752
+ // Forward
1753
+ for (i = 1; i <= index; ++i) {
1754
+ History.forward(queue);
1755
+ }
1756
+ } else if (index < 0) {
1757
+ // Backward
1758
+ for (i = -1; i >= index; --i) {
1759
+ History.back(queue);
1760
+ }
1761
+ } else {
1762
+ throw new Error(
1763
+ "History.go: History.go requires a positive or negative integer passed."
1764
+ );
1765
+ }
1766
+
1767
+ // Chain
1768
+ return History;
1769
+ };
1770
+
1771
+ // ====================================================================
1772
+ // HTML5 State Support
1773
+
1774
+ // Non-Native pushState Implementation
1775
+ if (History.emulated.pushState) {
1776
+ /*
1777
+ * Provide Skeleton for HTML4 Browsers
1778
+ */
1779
+
1780
+ // Prepare
1781
+ var emptyFunction = function () {};
1782
+ History.pushState = History.pushState || emptyFunction;
1783
+ History.replaceState = History.replaceState || emptyFunction;
1784
+ } // History.emulated.pushState
1785
+
1786
+ // Native pushState Implementation
1787
+ else {
1788
+ /*
1789
+ * Use native HTML5 History API Implementation
1790
+ */
1791
+
1792
+ /**
1793
+ * History.onPopState(event,extra)
1794
+ * Refresh the Current State
1795
+ */
1796
+ History.onPopState = function (event, extra) {
1797
+ // Prepare
1798
+ var stateId = false,
1799
+ newState = false,
1800
+ currentHash,
1801
+ currentState;
1802
+
1803
+ // Reset the double check
1804
+ History.doubleCheckComplete();
1805
+
1806
+ // Check for a Hash, and handle apporiatly
1807
+ currentHash = History.getHash();
1808
+ if (currentHash) {
1809
+ // Expand Hash
1810
+ currentState = History.extractState(
1811
+ currentHash || History.getLocationHref(),
1812
+ true
1813
+ );
1814
+ if (currentState) {
1815
+ // We were able to parse it, it must be a State!
1816
+ // Let's forward to replaceState
1817
+ //History.debug('History.onPopState: state anchor', currentHash, currentState);
1818
+ History.replaceState(
1819
+ currentState.data,
1820
+ currentState.title,
1821
+ currentState.url,
1822
+ false
1823
+ );
1824
+ } else {
1825
+ // Traditional Anchor
1826
+ //History.debug('History.onPopState: traditional anchor', currentHash);
1827
+ History.Adapter.trigger(window, "anchorchange");
1828
+ History.busy(false);
1829
+ }
1830
+
1831
+ // We don't care for hashes
1832
+ History.expectedStateId = false;
1833
+ return false;
1834
+ }
1835
+
1836
+ // Ensure
1837
+ stateId =
1838
+ History.Adapter.extractEventData("state", event, extra) || false;
1839
+
1840
+ // Fetch State
1841
+ if (stateId) {
1842
+ // Vanilla: Back/forward button was used
1843
+ newState = History.getStateById(stateId);
1844
+ } else if (History.expectedStateId) {
1845
+ // Vanilla: A new state was pushed, and popstate was called manually
1846
+ newState = History.getStateById(History.expectedStateId);
1847
+ } else {
1848
+ // Initial State
1849
+ newState = History.extractState(History.getLocationHref());
1850
+ }
1851
+
1852
+ // The State did not exist in our store
1853
+ if (!newState) {
1854
+ // Regenerate the State
1855
+ newState = History.createStateObject(
1856
+ null,
1857
+ null,
1858
+ History.getLocationHref()
1859
+ );
1860
+ }
1861
+
1862
+ // Clean
1863
+ History.expectedStateId = false;
1864
+
1865
+ // Check if we are the same state
1866
+ if (History.isLastSavedState(newState)) {
1867
+ // There has been no change (just the page's hash has finally propagated)
1868
+ //History.debug('History.onPopState: no change', newState, History.savedStates);
1869
+ History.busy(false);
1870
+ return false;
1871
+ }
1872
+
1873
+ // Store the State
1874
+ History.storeState(newState);
1875
+ History.saveState(newState);
1876
+
1877
+ // Force update of the title
1878
+ History.setTitle(newState);
1879
+
1880
+ // Fire Our Event
1881
+ History.Adapter.trigger(window, "statechange");
1882
+ History.busy(false);
1883
+
1884
+ // Return true
1885
+ return true;
1886
+ };
1887
+ History.Adapter.bind(window, "popstate", History.onPopState);
1888
+
1889
+ /**
1890
+ * History.pushState(data,title,url)
1891
+ * Add a new State to the history object, become it, and trigger onpopstate
1892
+ * We have to trigger for HTML4 compatibility
1893
+ * @param {object} data
1894
+ * @param {string} title
1895
+ * @param {string} url
1896
+ * @return {true}
1897
+ */
1898
+ History.pushState = function (data, title, url, queue) {
1899
+ //History.debug('History.pushState: called', arguments);
1900
+
1901
+ // Check the State
1902
+ if (History.getHashByUrl(url) && History.emulated.pushState) {
1903
+ throw new Error(
1904
+ "History.js does not support states with fragement-identifiers (hashes/anchors)."
1905
+ );
1906
+ }
1907
+
1908
+ // Handle Queueing
1909
+ if (queue !== false && History.busy()) {
1910
+ // Wait + Push to Queue
1911
+ //History.debug('History.pushState: we must wait', arguments);
1912
+ History.pushQueue({
1913
+ scope: History,
1914
+ callback: History.pushState,
1915
+ args: arguments,
1916
+ queue: queue,
1917
+ });
1918
+ return false;
1919
+ }
1920
+
1921
+ // Make Busy + Continue
1922
+ History.busy(true);
1923
+
1924
+ // Create the newState
1925
+ var newState = History.createStateObject(data, title, url);
1926
+
1927
+ // Check it
1928
+ if (History.isLastSavedState(newState)) {
1929
+ // Won't be a change
1930
+ History.busy(false);
1931
+ } else {
1932
+ // Store the newState
1933
+ History.storeState(newState);
1934
+ History.expectedStateId = newState.id;
1935
+
1936
+ // Push the newState
1937
+ history.pushState(newState.id, newState.title, newState.url);
1938
+
1939
+ // Fire HTML5 Event
1940
+ History.Adapter.trigger(window, "popstate");
1941
+ }
1942
+
1943
+ // End pushState closure
1944
+ return true;
1945
+ };
1946
+
1947
+ /**
1948
+ * History.replaceState(data,title,url)
1949
+ * Replace the State and trigger onpopstate
1950
+ * We have to trigger for HTML4 compatibility
1951
+ * @param {object} data
1952
+ * @param {string} title
1953
+ * @param {string} url
1954
+ * @return {true}
1955
+ */
1956
+ History.replaceState = function (data, title, url, queue) {
1957
+ //History.debug('History.replaceState: called', arguments);
1958
+
1959
+ // Check the State
1960
+ if (History.getHashByUrl(url) && History.emulated.pushState) {
1961
+ throw new Error(
1962
+ "History.js does not support states with fragement-identifiers (hashes/anchors)."
1963
+ );
1964
+ }
1965
+
1966
+ // Handle Queueing
1967
+ if (queue !== false && History.busy()) {
1968
+ // Wait + Push to Queue
1969
+ //History.debug('History.replaceState: we must wait', arguments);
1970
+ History.pushQueue({
1971
+ scope: History,
1972
+ callback: History.replaceState,
1973
+ args: arguments,
1974
+ queue: queue,
1975
+ });
1976
+ return false;
1977
+ }
1978
+
1979
+ // Make Busy + Continue
1980
+ History.busy(true);
1981
+
1982
+ // Create the newState
1983
+ var newState = History.createStateObject(data, title, url);
1984
+
1985
+ // Check it
1986
+ if (History.isLastSavedState(newState)) {
1987
+ // Won't be a change
1988
+ History.busy(false);
1989
+ } else {
1990
+ // Store the newState
1991
+ History.storeState(newState);
1992
+ History.expectedStateId = newState.id;
1993
+
1994
+ // Push the newState
1995
+ history.replaceState(newState.id, newState.title, newState.url);
1996
+
1997
+ // Fire HTML5 Event
1998
+ History.Adapter.trigger(window, "popstate");
1999
+ }
2000
+
2001
+ // End replaceState closure
2002
+ return true;
2003
+ };
2004
+ } // !History.emulated.pushState
2005
+
2006
+ // ====================================================================
2007
+ // Initialise
2008
+
2009
+ /**
2010
+ * Load the Store
2011
+ */
2012
+ if (sessionStorage) {
2013
+ // Fetch
2014
+ try {
2015
+ History.store =
2016
+ JSON.parse(sessionStorage.getItem("History.store")) || {};
2017
+ } catch (err) {
2018
+ History.store = {};
2019
+ }
2020
+
2021
+ // Normalize
2022
+ History.normalizeStore();
2023
+ } else {
2024
+ // Default Load
2025
+ History.store = {};
2026
+ History.normalizeStore();
2027
+ }
2028
+
2029
+ /**
2030
+ * Clear Intervals on exit to prevent memory leaks
2031
+ */
2032
+ History.Adapter.bind(window, "unload", History.clearAllIntervals);
2033
+
2034
+ /**
2035
+ * Create the initial State
2036
+ */
2037
+ History.saveState(
2038
+ History.storeState(History.extractState(History.getLocationHref(), true))
2039
+ );
2040
+
2041
+ /**
2042
+ * Bind for Saving Store
2043
+ */
2044
+ if (sessionStorage) {
2045
+ // When the page is closed
2046
+ History.onUnload = function () {
2047
+ // Prepare
2048
+ var currentStore, item, currentStoreString;
2049
+
2050
+ // Fetch
2051
+ try {
2052
+ currentStore =
2053
+ JSON.parse(sessionStorage.getItem("History.store")) || {};
2054
+ } catch (err) {
2055
+ currentStore = {};
2056
+ }
2057
+
2058
+ // Ensure
2059
+ currentStore.idToState = currentStore.idToState || {};
2060
+ currentStore.urlToId = currentStore.urlToId || {};
2061
+ currentStore.stateToId = currentStore.stateToId || {};
2062
+
2063
+ // Sync
2064
+ for (item in History.idToState) {
2065
+ if (!History.idToState.hasOwnProperty(item)) {
2066
+ continue;
2067
+ }
2068
+ currentStore.idToState[item] = History.idToState[item];
2069
+ }
2070
+ for (item in History.urlToId) {
2071
+ if (!History.urlToId.hasOwnProperty(item)) {
2072
+ continue;
2073
+ }
2074
+ currentStore.urlToId[item] = History.urlToId[item];
2075
+ }
2076
+ for (item in History.stateToId) {
2077
+ if (!History.stateToId.hasOwnProperty(item)) {
2078
+ continue;
2079
+ }
2080
+ currentStore.stateToId[item] = History.stateToId[item];
2081
+ }
2082
+
2083
+ // Update
2084
+ History.store = currentStore;
2085
+ History.normalizeStore();
2086
+
2087
+ // In Safari, going into Private Browsing mode causes the
2088
+ // Session Storage object to still exist but if you try and use
2089
+ // or set any property/function of it it throws the exception
2090
+ // "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to
2091
+ // add something to storage that exceeded the quota." infinitely
2092
+ // every second.
2093
+ currentStoreString = JSON.stringify(currentStore);
2094
+ try {
2095
+ // Store
2096
+ sessionStorage.setItem("History.store", currentStoreString);
2097
+ } catch (e) {
2098
+ if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
2099
+ if (sessionStorage.length) {
2100
+ // Workaround for a bug seen on iPads. Sometimes the quota exceeded error comes up and simply
2101
+ // removing/resetting the storage can work.
2102
+ sessionStorage.removeItem("History.store");
2103
+ sessionStorage.setItem("History.store", currentStoreString);
2104
+ } else {
2105
+ // Otherwise, we're probably private browsing in Safari, so we'll ignore the exception.
2106
+ }
2107
+ } else {
2108
+ throw e;
2109
+ }
2110
+ }
2111
+ };
2112
+
2113
+ // For Internet Explorer
2114
+ History.intervalList.push(
2115
+ setInterval(History.onUnload, History.options.storeInterval)
2116
+ );
2117
+
2118
+ // For Other Browsers
2119
+ History.Adapter.bind(window, "beforeunload", History.onUnload);
2120
+ History.Adapter.bind(window, "unload", History.onUnload);
2121
+
2122
+ // Both are enabled for consistency
2123
+ }
2124
+
2125
+ // Non-Native pushState Implementation
2126
+ if (!History.emulated.pushState) {
2127
+ // Be aware, the following is only for native pushState implementations
2128
+ // If you are wanting to include something for all browsers
2129
+ // Then include it above this if block
2130
+
2131
+ /**
2132
+ * Setup Safari Fix
2133
+ */
2134
+ if (History.bugs.safariPoll) {
2135
+ History.intervalList.push(
2136
+ setInterval(
2137
+ History.safariStatePoll,
2138
+ History.options.safariPollInterval
2139
+ )
2140
+ );
2141
+ }
2142
+
2143
+ /**
2144
+ * Ensure Cross Browser Compatibility
2145
+ */
2146
+ if (
2147
+ navigator.vendor === "Apple Computer, Inc." ||
2148
+ (navigator.appCodeName || "") === "Mozilla"
2149
+ ) {
2150
+ /**
2151
+ * Fix Safari HashChange Issue
2152
+ */
2153
+
2154
+ // Setup Alias
2155
+ History.Adapter.bind(window, "hashchange", function () {
2156
+ History.Adapter.trigger(window, "popstate");
2157
+ });
2158
+
2159
+ // Initialise Alias
2160
+ if (History.getHash()) {
2161
+ History.Adapter.onDomLoad(function () {
2162
+ History.Adapter.trigger(window, "hashchange");
2163
+ });
2164
+ }
2165
+ }
2166
+ } // !History.emulated.pushState
2167
+ }; // History.initCore
2168
+
2169
+ // Try to Initialise History
2170
+ if (!History.options || !History.options.delayInit) {
2171
+ History.init();
2172
+ }
2173
+ })(window);