jquery-historyjs 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f4534c2578530802db05295b2e2499f6c3260d8e
4
+ data.tar.gz: f6703c4de9968fd01c78ea774582b0179cb7e261
5
+ SHA512:
6
+ metadata.gz: 922e0f0c1f36c8ffd03152abad7a9241296fa318566e7e1471cd84ceb4e565676dca8924353e1906172501243ff1164e7f271845bbfe5f8943de69134ebe0e6e
7
+ data.tar.gz: c98fec73c3879ad64d8a9669535a0a4c8501e0dab76ae4a06ee5bb7c1c323036d5b71db9885a33b990999b04558a642176a410f2316ab03289f40c9e4c741582
@@ -1,7 +1,7 @@
1
1
  module Historyjs
2
2
  module Rails
3
- VERSION = "0.2.3"
4
- HISTORYJS_VERSION = "1.7.1-r2"
5
- JSON2_VERSION = "47a9882cdd"
3
+ VERSION = "0.3.0"
4
+ HISTORYJS_VERSION = "1.8.0-b2"
5
+ JSON2_VERSION = "e39db4b7e6"
6
6
  end
7
7
  end
@@ -26,6 +26,13 @@
26
26
  History = window.History = window.History||{}, // Public History Object
27
27
  history = window.history; // Old History Object
28
28
 
29
+ try {
30
+ sessionStorage.setItem('TEST', '1');
31
+ sessionStorage.removeItem('TEST');
32
+ } catch(e) {
33
+ sessionStorage = false;
34
+ }
35
+
29
36
  // MooTools Compatibility
30
37
  JSON.stringify = JSON.stringify||JSON.encode;
31
38
  JSON.parse = JSON.parse||JSON.decode;
@@ -36,7 +43,7 @@
36
43
  }
37
44
 
38
45
  // Initialise History
39
- History.init = function(){
46
+ History.init = function(options){
40
47
  // Check Load Status of Adapter
41
48
  if ( typeof History.Adapter === 'undefined' ) {
42
49
  return false;
@@ -61,7 +68,7 @@
61
68
  // Initialise Core
62
69
 
63
70
  // Initialise Core
64
- History.initCore = function(){
71
+ History.initCore = function(options){
65
72
  // Initialise
66
73
  if ( typeof History.initCore.initialized !== 'undefined' ) {
67
74
  // Already Loaded
@@ -99,6 +106,12 @@
99
106
  */
100
107
  History.options.doubleCheckInterval = History.options.doubleCheckInterval || 500;
101
108
 
109
+ /**
110
+ * History.options.disableSuid
111
+ * Force History not to append suid
112
+ */
113
+ History.options.disableSuid = History.options.disableSuid || false;
114
+
102
115
  /**
103
116
  * History.options.storeInterval
104
117
  * How long should we wait between store calls
@@ -123,6 +136,18 @@
123
136
  */
124
137
  History.options.initialTitle = History.options.initialTitle || document.title;
125
138
 
139
+ /**
140
+ * History.options.html4Mode
141
+ * If true, will force HTMl4 mode (hashtags)
142
+ */
143
+ History.options.html4Mode = History.options.html4Mode || false;
144
+
145
+ /**
146
+ * History.options.delayInit
147
+ * Want to override default options and call init manually.
148
+ */
149
+ History.options.delayInit = History.options.delayInit || false;
150
+
126
151
 
127
152
  // ====================================================================
128
153
  // Interval record
@@ -266,20 +291,31 @@
266
291
  * History.emulated
267
292
  * Which features require emulating?
268
293
  */
269
- History.emulated = {
270
- pushState: !Boolean(
271
- window.history && window.history.pushState && window.history.replaceState
272
- && !(
273
- (/ 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) */
274
- || (/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 */
294
+
295
+ if (History.options.html4Mode) {
296
+ History.emulated = {
297
+ pushState : true,
298
+ hashChange: true
299
+ };
300
+ }
301
+
302
+ else {
303
+
304
+ History.emulated = {
305
+ pushState: !Boolean(
306
+ window.history && window.history.pushState && window.history.replaceState
307
+ && !(
308
+ (/ 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) */
309
+ || (/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 */
310
+ )
311
+ ),
312
+ hashChange: Boolean(
313
+ !(('onhashchange' in window) || ('onhashchange' in document))
314
+ ||
315
+ (History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8)
275
316
  )
276
- ),
277
- hashChange: Boolean(
278
- !(('onhashchange' in window) || ('onhashchange' in document))
279
- ||
280
- (History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8)
281
- )
282
- };
317
+ };
318
+ }
283
319
 
284
320
  /**
285
321
  * History.enabled
@@ -323,7 +359,9 @@
323
359
  */
324
360
  History.isEmptyObject = function(obj) {
325
361
  for ( var name in obj ) {
326
- return false;
362
+ if ( obj.hasOwnProperty(name) ) {
363
+ return false;
364
+ }
327
365
  }
328
366
  return true;
329
367
  };
@@ -416,7 +454,7 @@
416
454
  // Fetch
417
455
  var
418
456
  State = History.getState(false,false),
419
- stateUrl = (State||{}).url||document.location.href,
457
+ stateUrl = (State||{}).url||History.getLocationHref(),
420
458
  pageUrl;
421
459
 
422
460
  // Create
@@ -435,7 +473,7 @@
435
473
  */
436
474
  History.getBasePageUrl = function(){
437
475
  // Create
438
- var basePageUrl = document.location.href.replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){
476
+ var basePageUrl = (History.getLocationHref()).replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){
439
477
  return (/[^\/]$/).test(part) ? '' : part;
440
478
  }).replace(/\/+$/,'')+'/';
441
479
 
@@ -522,6 +560,39 @@
522
560
  return shortUrl;
523
561
  };
524
562
 
563
+ /**
564
+ * History.getLocationHref(document)
565
+ * Returns a normalized version of document.location.href
566
+ * accounting for browser inconsistencies, etc.
567
+ *
568
+ * This URL will be URI-encoded and will include the hash
569
+ *
570
+ * @param {object} document
571
+ * @return {string} url
572
+ */
573
+ History.getLocationHref = function(doc) {
574
+ doc = doc || document;
575
+
576
+ // most of the time, this will be true
577
+ if (doc.URL === doc.location.href)
578
+ return doc.location.href;
579
+
580
+ // some versions of webkit URI-decode document.location.href
581
+ // but they leave document.URL in an encoded state
582
+ if (doc.location.href === decodeURIComponent(doc.URL))
583
+ return doc.URL;
584
+
585
+ // FF 3.6 only updates document.URL when a page is reloaded
586
+ // document.location.href is updated correctly
587
+ if (doc.location.hash && decodeURIComponent(doc.location.href.replace(/^[^#]+/, "")) === doc.location.hash)
588
+ return doc.location.href;
589
+
590
+ if (doc.URL.indexOf('#') == -1 && doc.location.href.indexOf('#') != -1)
591
+ return doc.location.href;
592
+
593
+ return doc.URL || doc.location.href;
594
+ };
595
+
525
596
 
526
597
  // ====================================================================
527
598
  // State Storage
@@ -613,7 +684,7 @@
613
684
  // Fetch ID
614
685
  var id = History.extractId(newState.url),
615
686
  str;
616
-
687
+
617
688
  if ( !id ) {
618
689
  // Find ID via State String
619
690
  str = History.getStateString(newState);
@@ -673,7 +744,7 @@
673
744
  newState = {};
674
745
  newState.normalized = true;
675
746
  newState.title = oldState.title||'';
676
- newState.url = History.getFullUrl(History.unescapeString(oldState.url||document.location.href));
747
+ newState.url = History.getFullUrl(oldState.url?oldState.url:(History.getLocationHref()));
677
748
  newState.hash = History.getShortUrl(newState.url);
678
749
  newState.data = History.cloneObject(oldState.data);
679
750
 
@@ -690,7 +761,7 @@
690
761
  dataNotEmpty = !History.isEmptyObject(newState.data);
691
762
 
692
763
  // Apply
693
- if ( newState.title || dataNotEmpty ) {
764
+ if ( (newState.title || dataNotEmpty) && History.options.disableSuid !== true ) {
694
765
  // Add ID to Hash
695
766
  newState.hash = History.getShortUrl(newState.url).replace(/\??\&_suid.*/,'');
696
767
  if ( !/\?/.test(newState.hash) ) {
@@ -787,7 +858,7 @@
787
858
  History.getStateId = function(passedState){
788
859
  // Prepare
789
860
  var State, id;
790
-
861
+
791
862
  // Fetch
792
863
  State = History.normalizeState(passedState);
793
864
 
@@ -807,7 +878,7 @@
807
878
  History.getHashByState = function(passedState){
808
879
  // Prepare
809
880
  var State, hash;
810
-
881
+
811
882
  // Fetch
812
883
  State = History.normalizeState(passedState);
813
884
 
@@ -826,10 +897,21 @@
826
897
  */
827
898
  History.extractId = function ( url_or_hash ) {
828
899
  // Prepare
829
- var id,parts,url;
900
+ var id,parts,url, tmp;
830
901
 
831
902
  // Extract
832
- parts = /(.*)\&_suid=([0-9]+)$/.exec(url_or_hash);
903
+
904
+ // If the URL has a #, use the id from before the #
905
+ if (url_or_hash.indexOf('#') != -1)
906
+ {
907
+ tmp = url_or_hash.split("#")[0];
908
+ }
909
+ else
910
+ {
911
+ tmp = url_or_hash;
912
+ }
913
+
914
+ parts = /(.*)\&_suid=([0-9]+)$/.exec(tmp);
833
915
  url = parts ? (parts[1]||url_or_hash) : url_or_hash;
834
916
  id = parts ? String(parts[2]||'') : '';
835
917
 
@@ -1029,44 +1111,42 @@
1029
1111
  return State;
1030
1112
  };
1031
1113
 
1114
+ /**
1115
+ * History.getCurrentIndex()
1116
+ * Gets the current index
1117
+ * @return (integer)
1118
+ */
1119
+ History.getCurrentIndex = function(){
1120
+ // Prepare
1121
+ var index = null;
1122
+
1123
+ // No states saved
1124
+ if(History.savedStates.length < 1) {
1125
+ index = 0;
1126
+ }
1127
+ else {
1128
+ index = History.savedStates.length-1;
1129
+ }
1130
+ return index;
1131
+ };
1032
1132
 
1033
1133
  // ====================================================================
1034
1134
  // Hash Helpers
1035
1135
 
1036
1136
  /**
1037
1137
  * History.getHash()
1138
+ * @param {Location=} location
1038
1139
  * Gets the current document hash
1140
+ * Note: unlike location.hash, this is guaranteed to return the escaped hash in all browsers
1039
1141
  * @return {string}
1040
1142
  */
1041
- History.getHash = function(){
1042
- var hash = History.unescapeHash(document.location.hash);
1143
+ History.getHash = function(doc){
1144
+ var url = History.getLocationHref(doc),
1145
+ hash;
1146
+ hash = History.getHashByUrl(url);
1043
1147
  return hash;
1044
1148
  };
1045
1149
 
1046
- /**
1047
- * History.unescapeString()
1048
- * Unescape a string
1049
- * @param {String} str
1050
- * @return {string}
1051
- */
1052
- History.unescapeString = function(str){
1053
- // Prepare
1054
- var result = str,
1055
- tmp;
1056
-
1057
- // Unescape hash
1058
- while ( true ) {
1059
- tmp = window.unescape(result);
1060
- if ( tmp === result ) {
1061
- break;
1062
- }
1063
- result = tmp;
1064
- }
1065
-
1066
- // Return result
1067
- return result;
1068
- };
1069
-
1070
1150
  /**
1071
1151
  * History.unescapeHash()
1072
1152
  * normalize and Unescape a Hash
@@ -1078,7 +1158,7 @@
1078
1158
  var result = History.normalizeHash(hash);
1079
1159
 
1080
1160
  // Unescape hash
1081
- result = History.unescapeString(result);
1161
+ result = decodeURIComponent(result);
1082
1162
 
1083
1163
  // Return result
1084
1164
  return result;
@@ -1105,7 +1185,7 @@
1105
1185
  */
1106
1186
  History.setHash = function(hash,queue){
1107
1187
  // Prepare
1108
- var adjustedHash, State, pageUrl;
1188
+ var State, pageUrl;
1109
1189
 
1110
1190
  // Handle Queueing
1111
1191
  if ( queue !== false && History.busy() ) {
@@ -1123,9 +1203,6 @@
1123
1203
  // Log
1124
1204
  //History.debug('History.setHash: called',hash);
1125
1205
 
1126
- // Prepare
1127
- adjustedHash = History.escapeHash(hash);
1128
-
1129
1206
  // Make Busy + Continue
1130
1207
  History.busy(true);
1131
1208
 
@@ -1138,7 +1215,7 @@
1138
1215
  // PushState
1139
1216
  History.pushState(State.data,State.title,State.url,false);
1140
1217
  }
1141
- else if ( document.location.hash !== adjustedHash ) {
1218
+ else if ( History.getHash() !== hash ) {
1142
1219
  // Hash is a proper hash, so apply it
1143
1220
 
1144
1221
  // Handle browser bugs
@@ -1149,11 +1226,11 @@
1149
1226
  pageUrl = History.getPageUrl();
1150
1227
 
1151
1228
  // Safari hash apply
1152
- History.pushState(null,null,pageUrl+'#'+adjustedHash,false);
1229
+ History.pushState(null,null,pageUrl+'#'+hash,false);
1153
1230
  }
1154
1231
  else {
1155
1232
  // Normal hash apply
1156
- document.location.hash = adjustedHash;
1233
+ document.location.hash = hash;
1157
1234
  }
1158
1235
  }
1159
1236
 
@@ -1171,7 +1248,7 @@
1171
1248
  var result = History.normalizeHash(hash);
1172
1249
 
1173
1250
  // Escape hash
1174
- result = window.escape(result);
1251
+ result = window.encodeURIComponent(result);
1175
1252
 
1176
1253
  // IE6 Escape Bug
1177
1254
  if ( !History.bugs.hashEscape ) {
@@ -1446,7 +1523,7 @@
1446
1523
 
1447
1524
  // Get the Last State which has the new URL
1448
1525
  var
1449
- urlState = History.extractState(document.location.href),
1526
+ urlState = History.extractState(History.getLocationHref()),
1450
1527
  newState;
1451
1528
 
1452
1529
  // Check for a difference
@@ -1614,10 +1691,10 @@
1614
1691
  History.doubleCheckComplete();
1615
1692
 
1616
1693
  // Check for a Hash, and handle apporiatly
1617
- currentHash = History.getHash();
1694
+ currentHash = History.getHash();
1618
1695
  if ( currentHash ) {
1619
1696
  // Expand Hash
1620
- currentState = History.extractState(currentHash||document.location.href,true);
1697
+ currentState = History.extractState(currentHash||History.getLocationHref(),true);
1621
1698
  if ( currentState ) {
1622
1699
  // We were able to parse it, it must be a State!
1623
1700
  // Let's forward to replaceState
@@ -1650,13 +1727,13 @@
1650
1727
  }
1651
1728
  else {
1652
1729
  // Initial State
1653
- newState = History.extractState(document.location.href);
1730
+ newState = History.extractState(History.getLocationHref());
1654
1731
  }
1655
1732
 
1656
1733
  // The State did not exist in our store
1657
1734
  if ( !newState ) {
1658
1735
  // Regenerate the State
1659
- newState = History.createStateObject(null,null,document.location.href);
1736
+ newState = History.createStateObject(null,null,History.getLocationHref());
1660
1737
  }
1661
1738
 
1662
1739
  // Clean
@@ -1830,13 +1907,12 @@
1830
1907
  /**
1831
1908
  * Clear Intervals on exit to prevent memory leaks
1832
1909
  */
1833
- History.Adapter.bind(window,"beforeunload",History.clearAllIntervals);
1834
1910
  History.Adapter.bind(window,"unload",History.clearAllIntervals);
1835
1911
 
1836
1912
  /**
1837
1913
  * Create the initial State
1838
1914
  */
1839
- History.saveState(History.storeState(History.extractState(document.location.href,true)));
1915
+ History.saveState(History.storeState(History.extractState(History.getLocationHref(),true)));
1840
1916
 
1841
1917
  /**
1842
1918
  * Bind for Saving Store
@@ -1845,7 +1921,7 @@
1845
1921
  // When the page is closed
1846
1922
  History.onUnload = function(){
1847
1923
  // Prepare
1848
- var currentStore, item;
1924
+ var currentStore, item, currentStoreString;
1849
1925
 
1850
1926
  // Fetch
1851
1927
  try {
@@ -1884,17 +1960,40 @@
1884
1960
  History.store = currentStore;
1885
1961
  History.normalizeStore();
1886
1962
 
1887
- // Store
1888
- sessionStorage.setItem('History.store',JSON.stringify(currentStore));
1963
+ // In Safari, going into Private Browsing mode causes the
1964
+ // Session Storage object to still exist but if you try and use
1965
+ // or set any property/function of it it throws the exception
1966
+ // "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to
1967
+ // add something to storage that exceeded the quota." infinitely
1968
+ // every second.
1969
+ currentStoreString = JSON.stringify(currentStore);
1970
+ try {
1971
+ // Store
1972
+ sessionStorage.setItem('History.store', currentStoreString);
1973
+ }
1974
+ catch (e) {
1975
+ if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
1976
+ if (sessionStorage.length) {
1977
+ // Workaround for a bug seen on iPads. Sometimes the quota exceeded error comes up and simply
1978
+ // removing/resetting the storage can work.
1979
+ sessionStorage.removeItem('History.store');
1980
+ sessionStorage.setItem('History.store', currentStoreString);
1981
+ } else {
1982
+ // Otherwise, we're probably private browsing in Safari, so we'll ignore the exception.
1983
+ }
1984
+ } else {
1985
+ throw e;
1986
+ }
1987
+ }
1889
1988
  };
1890
1989
 
1891
1990
  // For Internet Explorer
1892
1991
  History.intervalList.push(setInterval(History.onUnload,History.options.storeInterval));
1893
-
1992
+
1894
1993
  // For Other Browsers
1895
1994
  History.Adapter.bind(window,'beforeunload',History.onUnload);
1896
1995
  History.Adapter.bind(window,'unload',History.onUnload);
1897
-
1996
+
1898
1997
  // Both are enabled for consistency
1899
1998
  }
1900
1999
 
@@ -1937,7 +2036,9 @@
1937
2036
 
1938
2037
  }; // History.initCore
1939
2038
 
1940
- // Try and Initialise History
1941
- History.init();
2039
+ // Try to Initialise History
2040
+ if (!History.options || !History.options.delayInit) {
2041
+ History.init();
2042
+ }
1942
2043
 
1943
- })(window);
2044
+ })(window);
@@ -78,6 +78,19 @@
78
78
  return isLast;
79
79
  };
80
80
 
81
+ /**
82
+ * History.isHashEqual(newHash, oldHash)
83
+ * Checks to see if two hashes are functionally equal
84
+ * @param {string} newHash
85
+ * @param {string} oldHash
86
+ * @return {boolean} true
87
+ */
88
+ History.isHashEqual = function(newHash, oldHash){
89
+ newHash = encodeURIComponent(newHash).replace(/%25/g, "%");
90
+ oldHash = encodeURIComponent(oldHash).replace(/%25/g, "%");
91
+ return newHash === oldHash;
92
+ };
93
+
81
94
  /**
82
95
  * History.saveHash(newHash)
83
96
  * Push a Hash
@@ -190,7 +203,7 @@
190
203
  };
191
204
 
192
205
  /**
193
- * History.discardState(State)
206
+ * History.discardedState(State)
194
207
  * Checks to see if the state is discarded
195
208
  * @param {object} State
196
209
  * @return {bool}
@@ -263,7 +276,8 @@
263
276
  // Define some variables that will help in our checker function
264
277
  var lastDocumentHash = '',
265
278
  iframeId, iframe,
266
- lastIframeHash, checkerRunning;
279
+ lastIframeHash, checkerRunning,
280
+ startedWithHash = Boolean(History.getHash());
267
281
 
268
282
  // Handle depending on the browser
269
283
  if ( History.isInternetExplorer() ) {
@@ -275,7 +289,10 @@
275
289
  iframe = document.createElement('iframe');
276
290
 
277
291
  // Adjust iFarme
292
+ // IE 6 requires iframe to have a src on HTTPS pages, otherwise it will throw a
293
+ // "This page contains both secure and nonsecure items" warning.
278
294
  iframe.setAttribute('id', iframeId);
295
+ iframe.setAttribute('src', '#');
279
296
  iframe.style.display = 'none';
280
297
 
281
298
  // Append iFrame
@@ -300,8 +317,9 @@
300
317
  checkerRunning = true;
301
318
 
302
319
  // Fetch
303
- var documentHash = History.getHash()||'',
304
- iframeHash = History.unescapeHash(iframe.contentWindow.document.location.hash)||'';
320
+ var
321
+ documentHash = History.getHash(),
322
+ iframeHash = History.getHash(iframe.contentWindow.document);
305
323
 
306
324
  // The Document Hash has changed (application caused)
307
325
  if ( documentHash !== lastDocumentHash ) {
@@ -334,8 +352,18 @@
334
352
  // Equalise
335
353
  lastIframeHash = iframeHash;
336
354
 
337
- // Update the Hash
338
- History.setHash(iframeHash,false);
355
+ // If there is no iframe hash that means we're at the original
356
+ // iframe state.
357
+ // And if there was a hash on the original request, the original
358
+ // iframe state was replaced instantly, so skip this state and take
359
+ // the user back to where they came from.
360
+ if (startedWithHash && iframeHash === '') {
361
+ History.back();
362
+ }
363
+ else {
364
+ // Update the Hash
365
+ History.setHash(iframeHash,false);
366
+ }
339
367
  }
340
368
 
341
369
  // Reset Running
@@ -352,7 +380,7 @@
352
380
  // Define the checker function
353
381
  History.checkerFunction = function(){
354
382
  // Prepare
355
- var documentHash = History.getHash();
383
+ var documentHash = History.getHash()||'';
356
384
 
357
385
  // The Document Hash has changed (application caused)
358
386
  if ( documentHash !== lastDocumentHash ) {
@@ -398,7 +426,7 @@
398
426
  //History.debug('History.onHashChange', arguments);
399
427
 
400
428
  // Prepare
401
- var currentUrl = ((event && event.newURL) || document.location.href),
429
+ var currentUrl = ((event && event.newURL) || History.getLocationHref()),
402
430
  currentHash = History.getHashByUrl(currentUrl),
403
431
  currentState = null,
404
432
  currentStateHash = null,
@@ -429,7 +457,7 @@
429
457
  }
430
458
 
431
459
  // Create State
432
- currentState = History.extractState(History.getFullUrl(currentHash||document.location.href,false),true);
460
+ currentState = History.extractState(History.getFullUrl(currentHash||History.getLocationHref()),true);
433
461
 
434
462
  // Check if we are the same state
435
463
  if ( History.isLastSavedState(currentState) ) {
@@ -460,7 +488,7 @@
460
488
 
461
489
  // Push the new HTML5 State
462
490
  //History.debug('History.onHashChange: success hashchange');
463
- History.pushState(currentState.data,currentState.title,currentState.url,false);
491
+ History.pushState(currentState.data,currentState.title,encodeURI(currentState.url),false);
464
492
 
465
493
  // End onHashChange closure
466
494
  return true;
@@ -479,9 +507,14 @@
479
507
  History.pushState = function(data,title,url,queue){
480
508
  //History.debug('History.pushState: called', arguments);
481
509
 
510
+ // We assume that the URL passed in is URI-encoded, but this makes
511
+ // sure that it's fully URI encoded; any '%'s that are encoded are
512
+ // converted back into '%'s
513
+ url = encodeURI(url).replace(/%25/g, "%");
514
+
482
515
  // Check the State
483
516
  if ( History.getHashByUrl(url) ) {
484
- throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
517
+ throw new Error('History.js does not support states with fragment-identifiers (hashes/anchors).');
485
518
  }
486
519
 
487
520
  // Handle Queueing
@@ -505,7 +538,8 @@
505
538
  newStateHash = History.getHashByState(newState),
506
539
  oldState = History.getState(false),
507
540
  oldStateHash = History.getHashByState(oldState),
508
- html4Hash = History.getHash();
541
+ html4Hash = History.getHash(),
542
+ wasExpected = History.expectedStateId == newState.id;
509
543
 
510
544
  // Store the newState
511
545
  History.storeState(newState);
@@ -524,19 +558,18 @@
524
558
  return false;
525
559
  }
526
560
 
527
- // Update HTML4 Hash
528
- if ( newStateHash !== html4Hash && newStateHash !== History.getShortUrl(document.location.href) ) {
529
- //History.debug('History.pushState: update hash', newStateHash, html4Hash);
530
- History.setHash(newStateHash,false);
531
- return false;
532
- }
533
-
534
561
  // Update HTML5 State
535
562
  History.saveState(newState);
536
563
 
537
564
  // Fire HTML5 Event
538
- //History.debug('History.pushState: trigger popstate');
539
- History.Adapter.trigger(window,'statechange');
565
+ if(!wasExpected)
566
+ History.Adapter.trigger(window,'statechange');
567
+
568
+ // Update HTML4 Hash
569
+ if ( !History.isHashEqual(newStateHash, html4Hash) && !History.isHashEqual(newStateHash, History.getShortUrl(History.getLocationHref())) ) {
570
+ History.setHash(newStateHash,false);
571
+ }
572
+
540
573
  History.busy(false);
541
574
 
542
575
  // End pushState closure
@@ -555,9 +588,14 @@
555
588
  History.replaceState = function(data,title,url,queue){
556
589
  //History.debug('History.replaceState: called', arguments);
557
590
 
591
+ // We assume that the URL passed in is URI-encoded, but this makes
592
+ // sure that it's fully URI encoded; any '%'s that are encoded are
593
+ // converted back into '%'s
594
+ url = encodeURI(url).replace(/%25/g, "%");
595
+
558
596
  // Check the State
559
597
  if ( History.getHashByUrl(url) ) {
560
- throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
598
+ throw new Error('History.js does not support states with fragment-identifiers (hashes/anchors).');
561
599
  }
562
600
 
563
601
  // Handle Queueing
@@ -578,14 +616,40 @@
578
616
 
579
617
  // Fetch the State Objects
580
618
  var newState = History.createStateObject(data,title,url),
619
+ newStateHash = History.getHashByState(newState),
581
620
  oldState = History.getState(false),
621
+ oldStateHash = History.getHashByState(oldState),
582
622
  previousState = History.getStateByIndex(-2);
583
623
 
584
624
  // Discard Old State
585
625
  History.discardState(oldState,newState,previousState);
586
626
 
587
- // Alias to PushState
588
- History.pushState(newState.data,newState.title,newState.url,false);
627
+ // If the url hasn't changed, just store and save the state
628
+ // and fire a statechange event to be consistent with the
629
+ // html 5 api
630
+ if ( newStateHash === oldStateHash ) {
631
+ // Store the newState
632
+ History.storeState(newState);
633
+ History.expectedStateId = newState.id;
634
+
635
+ // Recycle the State
636
+ History.recycleState(newState);
637
+
638
+ // Force update of the title
639
+ History.setTitle(newState);
640
+
641
+ // Update HTML5 State
642
+ History.saveState(newState);
643
+
644
+ // Fire HTML5 Event
645
+ //History.debug('History.pushState: trigger popstate');
646
+ History.Adapter.trigger(window,'statechange');
647
+ History.busy(false);
648
+ }
649
+ else {
650
+ // Alias to PushState
651
+ History.pushState(newState.data,newState.title,newState.url,false);
652
+ }
589
653
 
590
654
  // End replaceState closure
591
655
  return true;
@@ -613,9 +677,9 @@
613
677
 
614
678
  }; // History.initHtml4
615
679
 
616
- // Try and Initialise History
680
+ // Try to Initialise History
617
681
  if ( typeof History.init !== 'undefined' ) {
618
682
  History.init();
619
683
  }
620
684
 
621
- })(window);
685
+ })(window);
@@ -1,6 +1,6 @@
1
1
  /*
2
- http://www.JSON.org/json2.js
3
- 2011-10-19
2
+ json2.js
3
+ 2013-05-26
4
4
 
5
5
  Public Domain.
6
6
 
@@ -159,8 +159,7 @@
159
159
  // Create a JSON object only if one does not already exist. We create the
160
160
  // methods in a closure to avoid creating global variables.
161
161
 
162
- var JSON;
163
- if (!JSON) {
162
+ if (typeof JSON !== 'object') {
164
163
  JSON = {};
165
164
  }
166
165
 
@@ -174,7 +173,7 @@ if (!JSON) {
174
173
 
175
174
  if (typeof Date.prototype.toJSON !== 'function') {
176
175
 
177
- Date.prototype.toJSON = function (key) {
176
+ Date.prototype.toJSON = function () {
178
177
 
179
178
  return isFinite(this.valueOf())
180
179
  ? this.getUTCFullYear() + '-' +
@@ -188,7 +187,7 @@ if (!JSON) {
188
187
 
189
188
  String.prototype.toJSON =
190
189
  Number.prototype.toJSON =
191
- Boolean.prototype.toJSON = function (key) {
190
+ Boolean.prototype.toJSON = function () {
192
191
  return this.valueOf();
193
192
  };
194
193
  }
metadata CHANGED
@@ -1,49 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jquery-historyjs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
5
- prerelease:
4
+ version: 0.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - William Weidendorf
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-03-09 00:00:00.000000000 Z
11
+ date: 2013-10-25 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: railties
16
- requirement: &70137982107680 !ruby/object:Gem::Requirement
17
- none: false
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '3.0'
22
20
  type: :runtime
23
21
  prerelease: false
24
- version_requirements: *70137982107680
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
25
27
  - !ruby/object:Gem::Dependency
26
28
  name: thor
27
- requirement: &70137982117720 !ruby/object:Gem::Requirement
28
- none: false
29
+ requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
- - - ! '>='
31
+ - - '>='
31
32
  - !ruby/object:Gem::Version
32
33
  version: '0.14'
33
34
  type: :runtime
34
35
  prerelease: false
35
- version_requirements: *70137982117720
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0.14'
36
41
  - !ruby/object:Gem::Dependency
37
42
  name: bundler
38
- requirement: &70137982114440 !ruby/object:Gem::Requirement
39
- none: false
43
+ requirement: !ruby/object:Gem::Requirement
40
44
  requirements:
41
- - - ! '>='
45
+ - - '>='
42
46
  - !ruby/object:Gem::Version
43
47
  version: 1.0.0
44
48
  type: :development
45
49
  prerelease: false
46
- version_requirements: *70137982114440
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.0
47
55
  description: This gem provides History.js and the related HTML4 dependencies for using
48
56
  History.js with jQuery in your Rails 3+ application.
49
57
  email:
@@ -73,29 +81,25 @@ files:
73
81
  - vendor/assets/javascripts/json2.js
74
82
  homepage: http://github.com/wweidendorf/jquery-historyjs
75
83
  licenses: []
84
+ metadata: {}
76
85
  post_install_message:
77
86
  rdoc_options: []
78
87
  require_paths:
79
88
  - lib
80
89
  required_ruby_version: !ruby/object:Gem::Requirement
81
- none: false
82
90
  requirements:
83
- - - ! '>='
91
+ - - '>='
84
92
  - !ruby/object:Gem::Version
85
93
  version: '0'
86
- segments:
87
- - 0
88
- hash: -3263187480763743088
89
94
  required_rubygems_version: !ruby/object:Gem::Requirement
90
- none: false
91
95
  requirements:
92
- - - ! '>='
96
+ - - '>='
93
97
  - !ruby/object:Gem::Version
94
98
  version: 1.3.6
95
99
  requirements: []
96
100
  rubyforge_project: jquery-historyjs
97
- rubygems_version: 1.8.11
101
+ rubygems_version: 2.0.2
98
102
  signing_key:
99
- specification_version: 3
103
+ specification_version: 4
100
104
  summary: Use History.js with Rails 3 and jQuery
101
105
  test_files: []