From 93aba0f226d9841491b3ff2ecd56965e1368b66e Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Wed, 5 Feb 2014 11:17:22 -0500 Subject: [PATCH] fix($location): support alternative means of setting application base path In HTML, the tag is used to configure how relative hyperlinks are resolved. In Angular, it has another use, configuring how URLs are rewritten. Because of this, setting the base URL to some external path outside of the application would cause $location.$$parse() to throw (which is the desired behaviour). This change enables developers to imperatively configure the application basePath, taking advantage of the natural HTML use of the tag without breaking Angular applications. Example: ``` angular.module("test", []) .config(function($locationProvider) { $locationProvider.baseHref("http://foo.com/the/base/application/path/"); }); ``` Closes #4442 --- src/ng/browser.js | 3 ++- src/ng/location.js | 22 ++++++++++++++++++++-- test/ng/locationSpec.js | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/ng/browser.js b/src/ng/browser.js index 73606fe7c2d8..51f2bebb0555 100644 --- a/src/ng/browser.js +++ b/src/ng/browser.js @@ -1,4 +1,5 @@ 'use strict'; +var BASE_HREF_REGEXP = /^(https?\:)?\/\/[^\/]*/; /** * ! This is a private undocumented service ! @@ -253,7 +254,7 @@ function Browser(window, document, $log, $sniffer) { */ self.baseHref = function() { var href = baseElement.attr('href'); - return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : ''; + return href ? href.replace(BASE_HREF_REGEXP, '') : ''; }; ////////////////////////////////////////////////////////////// diff --git a/src/ng/location.js b/src/ng/location.js index 9ab99cb719fa..5d37831feac6 100644 --- a/src/ng/location.js +++ b/src/ng/location.js @@ -531,7 +531,8 @@ function locationGetterSetter(property, preprocess) { */ function $LocationProvider(){ var hashPrefix = '', - html5Mode = false; + html5Mode = false, + _baseHref; /** * @ngdoc property @@ -567,6 +568,22 @@ function $LocationProvider(){ } }; + /** + * @ngdoc property + * @name ng.$locationProvider#baseHref + * @methodOf ng.$locationProvider + * @description + * In situations where it is desireable to specify an external URL within the `` tag, for + * simplifying access to external resources, this configuration method will override the + * tag and enable location rewrites to work as expected; + * + * @param {string} href Base application url + */ + this.baseHref = function(href) { + /* global BASE_HREF_REGEXP */ + _baseHref = href && href.replace(BASE_HREF_REGEXP, ''); + }; + /** * @ngdoc event * @name ng.$location#$locationChangeStart @@ -600,7 +617,8 @@ function $LocationProvider(){ function( $rootScope, $browser, $sniffer, $rootElement) { var $location, LocationMode, - baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to '' + // if base[href] is undefined, it defaults to '' + baseHref = isString(_baseHref) ? _baseHref : $browser.baseHref(), initialUrl = $browser.url(), appBase; diff --git a/test/ng/locationSpec.js b/test/ng/locationSpec.js index ff823d306efd..2b97cfc69e48 100644 --- a/test/ng/locationSpec.js +++ b/test/ng/locationSpec.js @@ -1256,6 +1256,23 @@ describe('$location', function() { }).not.toThrow(); }); }); + + + it('should use $locationProvider.baseHref() as base url if available', function() { + module(function($locationProvider) { + $locationProvider.baseHref("http://host.com/ngApp/"); + $locationProvider.html5Mode(true); + return function($browser, $rootElement, $document){ + $browser.url("http://host.com/ngApp/"); + $browser.$$baseHref = "http://server/assets"; + }; + }); + + inject(function($rootScope, $location, $browser) { + expect(function() { $location.$$parse($location.$$rewrite("http://host.com/ngApp/routeA")); }).not.toThrow(); + expect($location.path()).toBe('/routeA'); + }); + }); });