mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
BUG Don't double unescape URLs in history.js (fixes #8170)
Merged in pull request https://github.com/balupton/history.js/pull/108. This has been a serious problem with the library for more than a year, see https://github.com/balupton/history.js/issues/228.
This commit is contained in:
parent
dadd9e1b98
commit
64d3a3dafc
@ -78,6 +78,19 @@
|
||||
return isLast;
|
||||
};
|
||||
|
||||
/**
|
||||
* History.isHashEqual(newHash, oldHash)
|
||||
* Checks to see if two hashes are functionally equal
|
||||
* @param {string} newHash
|
||||
* @param {string} oldHash
|
||||
* @return {boolean} true
|
||||
*/
|
||||
History.isHashEqual = function(newHash, oldHash){
|
||||
newHash = encodeURIComponent(newHash).replace(/%25/g, "%");
|
||||
oldHash = encodeURIComponent(oldHash).replace(/%25/g, "%");
|
||||
return newHash === oldHash;
|
||||
};
|
||||
|
||||
/**
|
||||
* History.saveHash(newHash)
|
||||
* Push a Hash
|
||||
@ -300,8 +313,9 @@
|
||||
checkerRunning = true;
|
||||
|
||||
// Fetch
|
||||
var documentHash = History.getHash()||'',
|
||||
iframeHash = History.unescapeHash(iframe.contentWindow.document.location.hash)||'';
|
||||
var
|
||||
documentHash = History.getHash(),
|
||||
iframeHash = History.getHash(iframe.contentWindow.document.location);
|
||||
|
||||
// The Document Hash has changed (application caused)
|
||||
if ( documentHash !== lastDocumentHash ) {
|
||||
@ -398,7 +412,7 @@
|
||||
//History.debug('History.onHashChange', arguments);
|
||||
|
||||
// Prepare
|
||||
var currentUrl = ((event && event.newURL) || document.location.href),
|
||||
var currentUrl = ((event && event.newURL) || History.getLocationHref()),
|
||||
currentHash = History.getHashByUrl(currentUrl),
|
||||
currentState = null,
|
||||
currentStateHash = null,
|
||||
@ -429,9 +443,10 @@
|
||||
}
|
||||
|
||||
// Create State
|
||||
|
||||
// MODIFIED ischommer: URL normalization needs to respect our <base> tag,
|
||||
// otherwise will go into infinite loops
|
||||
currentState = History.extractState(History.getFullUrl(currentHash||document.location.href,true),true);
|
||||
currentState = History.extractState(History.getFullUrl(currentHash||History.getLocationHref(),true),true);
|
||||
// END MODIFIED
|
||||
|
||||
// Check if we are the same state
|
||||
@ -463,7 +478,7 @@
|
||||
|
||||
// Push the new HTML5 State
|
||||
//History.debug('History.onHashChange: success hashchange');
|
||||
History.pushState(currentState.data,currentState.title,currentState.url,false);
|
||||
History.pushState(currentState.data,currentState.title,encodeURI(currentState.url),false);
|
||||
|
||||
// End onHashChange closure
|
||||
return true;
|
||||
@ -482,6 +497,11 @@
|
||||
History.pushState = function(data,title,url,queue){
|
||||
//History.debug('History.pushState: called', arguments);
|
||||
|
||||
// We assume that the URL passed in is URI-encoded, but this makes
|
||||
// sure that it's fully URI encoded; any '%'s that are encoded are
|
||||
// converted back into '%'s
|
||||
url = encodeURI(url).replace(/%25/g, "%");
|
||||
|
||||
// Check the State
|
||||
if ( History.getHashByUrl(url) ) {
|
||||
throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
|
||||
@ -528,7 +548,7 @@
|
||||
}
|
||||
|
||||
// Update HTML4 Hash
|
||||
if ( newStateHash !== html4Hash && newStateHash !== History.getShortUrl(document.location.href) ) {
|
||||
if ( !History.isHashEqual(newStateHash, html4Hash) && !History.isHashEqual(newStateHash, History.getShortUrl(History.getLocationHref())) ) {
|
||||
//History.debug('History.pushState: update hash', newStateHash, html4Hash);
|
||||
History.setHash(newStateHash,false);
|
||||
return false;
|
||||
@ -558,9 +578,14 @@
|
||||
History.replaceState = function(data,title,url,queue){
|
||||
//History.debug('History.replaceState: called', arguments);
|
||||
|
||||
// We assume that the URL passed in is URI-encoded, but this makes
|
||||
// sure that it's fully URI encoded; any '%'s that are encoded are
|
||||
// converted back into '%'s
|
||||
url = encodeURI(url).replace(/%25/g, "%");
|
||||
|
||||
// Check the State
|
||||
if ( History.getHashByUrl(url) ) {
|
||||
throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
|
||||
throw new Error('History.js does not support states with fragment-identifiers (hashes/anchors).');
|
||||
}
|
||||
|
||||
// Handle Queueing
|
||||
|
@ -416,7 +416,7 @@
|
||||
// Fetch
|
||||
var
|
||||
State = History.getState(false,false),
|
||||
stateUrl = (State||{}).url||document.location.href,
|
||||
stateUrl = (State||{}).url||History.getLocationHref(),
|
||||
pageUrl;
|
||||
|
||||
// Create
|
||||
@ -435,7 +435,7 @@
|
||||
*/
|
||||
History.getBasePageUrl = function(){
|
||||
// Create
|
||||
var basePageUrl = document.location.href.replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){
|
||||
var basePageUrl = (History.getLocationHref()).replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){
|
||||
return (/[^\/]$/).test(part) ? '' : part;
|
||||
}).replace(/\/+$/,'')+'/';
|
||||
|
||||
@ -522,6 +522,36 @@
|
||||
return shortUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* History.getLocationHref(document)
|
||||
* Returns a normalized version of document.location.href
|
||||
* accounting for browser inconsistencies, etc.
|
||||
*
|
||||
* This URL will be URI-encoded and will include the hash
|
||||
*
|
||||
* @param {object} document
|
||||
* @return {string} url
|
||||
*/
|
||||
History.getLocationHref = function(doc) {
|
||||
doc = doc || document;
|
||||
|
||||
// most of the time, this will be true
|
||||
if (doc.URL === doc.location.href)
|
||||
return doc.location.href;
|
||||
|
||||
// some versions of webkit URI-decode document.location.href
|
||||
// but they leave document.URL in an encoded state
|
||||
if (doc.location.href === decodeURIComponent(doc.URL))
|
||||
return doc.URL;
|
||||
|
||||
// FF 3.6 only updates document.URL when a page is reloaded
|
||||
// document.location.href is updated correctly
|
||||
if (doc.location.hash && decodeURIComponent(doc.location.href.replace(/^[^#]+/, "")) === doc.location.hash)
|
||||
return doc.location.href;
|
||||
|
||||
return doc.URL || doc.location.href;
|
||||
};
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// State Storage
|
||||
@ -673,7 +703,7 @@
|
||||
newState = {};
|
||||
newState.normalized = true;
|
||||
newState.title = oldState.title||'';
|
||||
newState.url = History.getFullUrl(History.unescapeString(oldState.url||document.location.href));
|
||||
newState.url = History.getFullUrl(oldState.url?decodeURIComponent(oldState.url):(History.getLocationHref()));
|
||||
newState.hash = History.getShortUrl(newState.url);
|
||||
newState.data = History.cloneObject(oldState.data);
|
||||
|
||||
@ -728,7 +758,7 @@
|
||||
var State = {
|
||||
'data': data,
|
||||
'title': title,
|
||||
'url': url
|
||||
'url': encodeURIComponent(url||"")
|
||||
};
|
||||
|
||||
// Expand the State
|
||||
@ -1035,36 +1065,15 @@
|
||||
|
||||
/**
|
||||
* History.getHash()
|
||||
* @param {Location=} location
|
||||
* Gets the current document hash
|
||||
* Note: unlike location.hash, this is guaranteed to return the escaped hash in all browsers
|
||||
* @return {string}
|
||||
*/
|
||||
History.getHash = function(){
|
||||
var hash = History.unescapeHash(document.location.hash);
|
||||
return hash;
|
||||
};
|
||||
|
||||
/**
|
||||
* History.unescapeString()
|
||||
* Unescape a string
|
||||
* @param {String} str
|
||||
* @return {string}
|
||||
*/
|
||||
History.unescapeString = function(str){
|
||||
// Prepare
|
||||
var result = str,
|
||||
tmp;
|
||||
|
||||
// Unescape hash
|
||||
while ( true ) {
|
||||
tmp = window.unescape(result);
|
||||
if ( tmp === result ) {
|
||||
break;
|
||||
}
|
||||
result = tmp;
|
||||
}
|
||||
|
||||
// Return result
|
||||
return result;
|
||||
History.getHash = function(location){
|
||||
if ( !location ) location = document.location;
|
||||
var href = location.href.replace( /^[^#]*/, "" );
|
||||
return href.substr(1);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1078,7 +1087,7 @@
|
||||
var result = History.normalizeHash(hash);
|
||||
|
||||
// Unescape hash
|
||||
result = History.unescapeString(result);
|
||||
result = decodeURIComponent(result);
|
||||
|
||||
// Return result
|
||||
return result;
|
||||
@ -1105,7 +1114,7 @@
|
||||
*/
|
||||
History.setHash = function(hash,queue){
|
||||
// Prepare
|
||||
var adjustedHash, State, pageUrl;
|
||||
var State, pageUrl;
|
||||
|
||||
// Handle Queueing
|
||||
if ( queue !== false && History.busy() ) {
|
||||
@ -1123,9 +1132,6 @@
|
||||
// Log
|
||||
//History.debug('History.setHash: called',hash);
|
||||
|
||||
// Prepare
|
||||
adjustedHash = History.escapeHash(hash);
|
||||
|
||||
// Make Busy + Continue
|
||||
History.busy(true);
|
||||
|
||||
@ -1138,7 +1144,7 @@
|
||||
// PushState
|
||||
History.pushState(State.data,State.title,State.url,false);
|
||||
}
|
||||
else if ( document.location.hash !== adjustedHash ) {
|
||||
else if ( History.getHash() !== hash ) {
|
||||
// Hash is a proper hash, so apply it
|
||||
|
||||
// Handle browser bugs
|
||||
@ -1149,11 +1155,11 @@
|
||||
pageUrl = History.getPageUrl();
|
||||
|
||||
// Safari hash apply
|
||||
History.pushState(null,null,pageUrl+'#'+adjustedHash,false);
|
||||
History.pushState(null,null,pageUrl+'#'+hash,false);
|
||||
}
|
||||
else {
|
||||
// Normal hash apply
|
||||
document.location.hash = adjustedHash;
|
||||
document.location.hash = hash;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1171,7 +1177,7 @@
|
||||
var result = History.normalizeHash(hash);
|
||||
|
||||
// Escape hash
|
||||
result = window.escape(result);
|
||||
result = window.encodeURIComponent(result);
|
||||
|
||||
// IE6 Escape Bug
|
||||
if ( !History.bugs.hashEscape ) {
|
||||
@ -1446,7 +1452,7 @@
|
||||
|
||||
// Get the Last State which has the new URL
|
||||
var
|
||||
urlState = History.extractState(document.location.href),
|
||||
urlState = History.extractState(History.getLocationHref()),
|
||||
newState;
|
||||
|
||||
// Check for a difference
|
||||
@ -1617,7 +1623,7 @@
|
||||
currentHash = History.getHash();
|
||||
if ( currentHash ) {
|
||||
// Expand Hash
|
||||
currentState = History.extractState(currentHash||document.location.href,true);
|
||||
currentState = History.extractState(currentHash||History.getLocationHref(),true);
|
||||
if ( currentState ) {
|
||||
// We were able to parse it, it must be a State!
|
||||
// Let's forward to replaceState
|
||||
@ -1650,13 +1656,13 @@
|
||||
}
|
||||
else {
|
||||
// Initial State
|
||||
newState = History.extractState(document.location.href);
|
||||
newState = History.extractState(History.getLocationHref());
|
||||
}
|
||||
|
||||
// The State did not exist in our store
|
||||
if ( !newState ) {
|
||||
// Regenerate the State
|
||||
newState = History.createStateObject(null,null,document.location.href);
|
||||
newState = History.createStateObject(null,null,History.getLocationHref());
|
||||
}
|
||||
|
||||
// Clean
|
||||
@ -1836,7 +1842,7 @@
|
||||
/**
|
||||
* Create the initial State
|
||||
*/
|
||||
History.saveState(History.storeState(History.extractState(document.location.href,true)));
|
||||
History.saveState(History.storeState(History.extractState(History.getLocationHref(),true)));
|
||||
|
||||
/**
|
||||
* Bind for Saving Store
|
||||
|
Loading…
Reference in New Issue
Block a user