From 30989b598d2ca0452cb3352e623ac2140e3324c8 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Wed, 14 Dec 2011 15:37:42 +0100 Subject: [PATCH] ENHANCEMENT Added path manipulation lib from jQuery.mobile, using it to ensure all URLs are made absolute (to fix IE issues) --- admin/code/LeftAndMain.php | 1 + admin/javascript/LeftAndMain.Content.js | 3 +- admin/javascript/LeftAndMain.js | 2 +- admin/javascript/lib.js | 239 ++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 admin/javascript/lib.js diff --git a/admin/code/LeftAndMain.php b/admin/code/LeftAndMain.php index 809fa9be9..fbd395d27 100644 --- a/admin/code/LeftAndMain.php +++ b/admin/code/LeftAndMain.php @@ -233,6 +233,7 @@ class LeftAndMain extends Controller { THIRDPARTY_DIR . '/jquery/jquery.js', THIRDPARTY_DIR . '/jquery-livequery/jquery.livequery.js', SAPPHIRE_DIR . '/javascript/jquery-ondemand/jquery.ondemand.js', + SAPPHIRE_DIR . '/admin/javascript/lib.js', THIRDPARTY_DIR . '/jquery-ui/jquery-ui.js', THIRDPARTY_DIR . '/json-js/json2.js', THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js', diff --git a/admin/javascript/LeftAndMain.Content.js b/admin/javascript/LeftAndMain.Content.js index 6fd80c626..2c98be0a8 100644 --- a/admin/javascript/LeftAndMain.Content.js +++ b/admin/javascript/LeftAndMain.Content.js @@ -271,7 +271,8 @@ var url = $(node).find('a:first').attr('href'); if(url && url != '#') { - if($(node).find('a:first').is(':internal')) url = $('base').attr('href') + url; + + if($(node).find('a:first').is(':internal')) url = url = $.path.makeUrlAbsolute(url, $('base').attr('href')); // Reload only edit form if it exists (side-by-side view of tree and edit view), otherwise reload whole panel if(container.find('.cms-edit-form').length) { url += '?cms-view-form=1'; diff --git a/admin/javascript/LeftAndMain.js b/admin/javascript/LeftAndMain.js index 8b3d662ae..5b62963cd 100644 --- a/admin/javascript/LeftAndMain.js +++ b/admin/javascript/LeftAndMain.js @@ -144,7 +144,7 @@ jQuery.noConflict(); // which matches one class on the menu window.History.pushState(data, title, url); } else { - window.location = url; + window.location = $.path.makeUrlAbsolute(url, $('base').attr('href')); } }, diff --git a/admin/javascript/lib.js b/admin/javascript/lib.js new file mode 100644 index 000000000..6df032e0c --- /dev/null +++ b/admin/javascript/lib.js @@ -0,0 +1,239 @@ +(function($) { + + // Copyright (c) 2011 John Resig, http://jquery.com/ + + // Permission is hereby granted, free of charge, to any person obtaining + // a copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to + // permit persons to whom the Software is furnished to do so, subject to + // the following conditions: + + // The above copyright notice and this permission notice shall be + // included in all copies or substantial portions of the Software. + + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + //define vars for interal use + var $window = $( window ), + $html = $( 'html' ), + $head = $( 'head' ), + + //url path helpers for use in relative url management + path = { + + // This scary looking regular expression parses an absolute URL or its relative + // variants (protocol, site, document, query, and hash), into the various + // components (protocol, host, path, query, fragment, etc that make up the + // URL as well as some other commonly used sub-parts. When used with RegExp.exec() + // or String.match, it parses the URL into a results array that looks like this: + // + // [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content + // [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread + // [2]: http://jblas:password@mycompany.com:8080/mail/inbox + // [3]: http://jblas:password@mycompany.com:8080 + // [4]: http: + // [5]: // + // [6]: jblas:password@mycompany.com:8080 + // [7]: jblas:password + // [8]: jblas + // [9]: password + // [10]: mycompany.com:8080 + // [11]: mycompany.com + // [12]: 8080 + // [13]: /mail/inbox + // [14]: /mail/ + // [15]: inbox + // [16]: ?msg=1234&type=unread + // [17]: #msg-content + // + urlParseRE: /^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/, + + //Parse a URL into a structure that allows easy access to + //all of the URL components by name. + parseUrl: function( url ) { + // If we're passed an object, we'll assume that it is + // a parsed url object and just return it back to the caller. + if ( $.type( url ) === "object" ) { + return url; + } + + var matches = path.urlParseRE.exec( url || "" ) || []; + + // Create an object that allows the caller to access the sub-matches + // by name. Note that IE returns an empty string instead of undefined, + // like all other browsers do, so we normalize everything so its consistent + // no matter what browser we're running on. + return { + href: matches[ 0 ] || "", + hrefNoHash: matches[ 1 ] || "", + hrefNoSearch: matches[ 2 ] || "", + domain: matches[ 3 ] || "", + protocol: matches[ 4 ] || "", + doubleSlash: matches[ 5 ] || "", + authority: matches[ 6 ] || "", + username: matches[ 8 ] || "", + password: matches[ 9 ] || "", + host: matches[ 10 ] || "", + hostname: matches[ 11 ] || "", + port: matches[ 12 ] || "", + pathname: matches[ 13 ] || "", + directory: matches[ 14 ] || "", + filename: matches[ 15 ] || "", + search: matches[ 16 ] || "", + hash: matches[ 17 ] || "" + }; + }, + + //Turn relPath into an asbolute path. absPath is + //an optional absolute path which describes what + //relPath is relative to. + makePathAbsolute: function( relPath, absPath ) { + if ( relPath && relPath.charAt( 0 ) === "/" ) { + return relPath; + } + + relPath = relPath || ""; + absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : ""; + + var absStack = absPath ? absPath.split( "/" ) : [], + relStack = relPath.split( "/" ); + for ( var i = 0; i < relStack.length; i++ ) { + var d = relStack[ i ]; + switch ( d ) { + case ".": + break; + case "..": + if ( absStack.length ) { + absStack.pop(); + } + break; + default: + absStack.push( d ); + break; + } + } + return "/" + absStack.join( "/" ); + }, + + //Returns true if both urls have the same domain. + isSameDomain: function( absUrl1, absUrl2 ) { + return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain; + }, + + //Returns true for any relative variant. + isRelativeUrl: function( url ) { + // All relative Url variants have one thing in common, no protocol. + return path.parseUrl( url ).protocol === ""; + }, + + //Returns true for an absolute url. + isAbsoluteUrl: function( url ) { + return path.parseUrl( url ).protocol !== ""; + }, + + //Turn the specified realtive URL into an absolute one. This function + //can handle all relative variants (protocol, site, document, query, fragment). + makeUrlAbsolute: function( relUrl, absUrl ) { + if ( !path.isRelativeUrl( relUrl ) ) { + return relUrl; + } + + var relObj = path.parseUrl( relUrl ), + absObj = path.parseUrl( absUrl ), + protocol = relObj.protocol || absObj.protocol, + doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash ), + authority = relObj.authority || absObj.authority, + hasPath = relObj.pathname !== "", + pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ), + search = relObj.search || ( !hasPath && absObj.search ) || "", + hash = relObj.hash; + + return protocol + doubleSlash + authority + pathname + search + hash; + }, + + //Add search (aka query) params to the specified url. + addSearchParams: function( url, params ) { + var u = path.parseUrl( url ), + p = ( typeof params === "object" ) ? $.param( params ) : params, + s = u.search || "?"; + return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" ); + }, + + convertUrlToDataUrl: function( absUrl ) { + var u = path.parseUrl( absUrl ); + if ( path.isEmbeddedPage( u ) ) { + // For embedded pages, remove the dialog hash key as in getFilePath(), + // otherwise the Data Url won't match the id of the embedded Page. + return u.hash.split( dialogHashKey )[0].replace( /^#/, "" ); + } else if ( path.isSameDomain( u, documentBase ) ) { + return u.hrefNoHash.replace( documentBase.domain, "" ); + } + return absUrl; + }, + + //get path from current hash, or from a file path + get: function( newPath ) { + if( newPath === undefined ) { + newPath = location.hash; + } + return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' ); + }, + + //return the substring of a filepath before the sub-page key, for making a server request + getFilePath: function( path ) { + var splitkey = '&' + $.mobile.subPageUrlKey; + return path && path.split( splitkey )[0].split( dialogHashKey )[0]; + }, + + //set location hash to path + set: function( path ) { + location.hash = path; + }, + + //test if a given url (string) is a path + //NOTE might be exceptionally naive + isPath: function( url ) { + return ( /\// ).test( url ); + }, + + //return a url path with the window's location protocol/hostname/pathname removed + clean: function( url ) { + return url.replace( documentBase.domain, "" ); + }, + + //just return the url without an initial # + stripHash: function( url ) { + return url.replace( /^#/, "" ); + }, + + //remove the preceding hash, any query params, and dialog notations + cleanHash: function( hash ) { + return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) ); + }, + + //check whether a url is referencing the same domain, or an external domain or different protocol + //could be mailto, etc + isExternal: function( url ) { + var u = path.parseUrl( url ); + return u.protocol && u.domain !== documentUrl.domain ? true : false; + }, + + hasProtocol: function( url ) { + return ( /^(:?\w+:)/ ).test( url ); + } + }; + + $.path = path; + + // Internal Helper + $.expr[':'].internal = function(obj){return obj.href.match(/^mailto\:/) || (obj.hostname == location.hostname);}; + $.expr[':'].external = function(obj){return !$(obj).is(':internal')}; +}(jQuery)); \ No newline at end of file