diff --git a/docs/content/error/$location/nobase.ngdoc b/docs/content/error/$location/nobase.ngdoc
new file mode 100644
index 000000000000..b1a489019d30
--- /dev/null
+++ b/docs/content/error/$location/nobase.ngdoc
@@ -0,0 +1,51 @@
+@ngdoc error
+@name $location:nobase
+@fullName $location in HTML5 mode requires a tag to be present!
+@description
+
+If you configure {@link ng.$location `$location`} to use
+{@ng.provider.$locationProvider `html5Mode`} (`history.pushState`), you need to specify the base URL for the application with a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag.
+
+The base URL is then used to resolve all relative URLs throughout the application regardless of the
+entry point into the app.
+
+If you are deploying your app into the root context (e.g. `https://myapp.com/`), set the base URL to `/`:
+
+```html
+
+
+ ...
+
+```
+
+If you are deploying your app into a sub-context (e.g. `https://myapp.com/subapp/`), set the base URL to the
+URL of the subcontext:
+
+```html
+
+
+ ...
+
+```
+
+Before Angular 1.3 we didn't have this hard requirement and it was easy to write apps that worked
+when deployed in the root context but were broken when moved to a sub-context because in the
+sub-context all absolute urls would resolve to the root context of the app. To prevent this,
+use relative URLs throughout your app:
+
+```html
+
+User Profile
+
+
+
+User Profile
+
+```
+
+Additionally, if you want to support [browsers that don't have the `history.pushState`
+API](http://caniuse.com/#feat=history), the fallback mechanism provided by `$location`
+won't work well without specifying the base url of the application.
+
+In order to make it easier to migrate from hashbang mode to html5 mode, we require that the base
+URL is always specified when `$location`'s `html5mode` is enabled.
\ No newline at end of file
diff --git a/docs/content/guide/$location.ngdoc b/docs/content/guide/$location.ngdoc
index f7a1557a90f8..241bed03f2fe 100644
--- a/docs/content/guide/$location.ngdoc
+++ b/docs/content/guide/$location.ngdoc
@@ -325,20 +325,22 @@ to URLs that should be handled with `.`. Now, links to locations, which are not
are not prefixed with `.` and will not be intercepted by the `otherwise` rule in your `$routeProvider`.
-### Server side
+### Relative links
-Using this mode requires URL rewriting on server side, basically you have to rewrite all your links
-to entry point of your application (e.g. index.html)
+Be sure to check all relative links, images, scripts etc. Angular requires you to specify the url base in
+the head of your main html file (``). With that, relative urls will
+always be resolved to this base url, event if the initial url of the document was different.
-### Relative links
+There is one exception: Links that only contain a hash fragment (e.g. ``)
+will only change `$location.hash()` and not modify the url otherwise. This is useful for scrolling
+to anchors on the same page without needing to know on which page the user currently is.
-Be sure to check all relative links, images, scripts etc. You must either specify the url base in
-the head of your main html file (``) or you must use absolute urls
-(starting with `/`) everywhere because relative urls will be resolved to absolute urls using the
-initial absolute url of the document, which is often different from the root of the application.
+### Server side
-Running Angular apps with the History API enabled from document root is strongly encouraged as it
-takes care of all relative link issues.
+Using this mode requires URL rewriting on server side, basically you have to rewrite all your links
+to entry point of your application (e.g. index.html). Requiring a `` tag is also important for
+this case, as it allows Angular to differentiate between the part of the url that is the application
+base and the path that should be handeled by the application.
### Sending links among different browsers
diff --git a/src/ng/location.js b/src/ng/location.js
index 98dec092dd26..2afd68818f60 100644
--- a/src/ng/location.js
+++ b/src/ng/location.js
@@ -127,21 +127,32 @@ function LocationHtml5Url(appBase, basePrefix) {
this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
};
- this.$$rewrite = function(url) {
+ this.$$parseLinkUrl = function(url, relHref) {
+ if (relHref && relHref[0] === '#') {
+ // special case for links to hash fragments:
+ // keep the old url and only replace the hash fragment
+ this.hash(relHref.slice(1));
+ return true;
+ }
var appUrl, prevAppUrl;
+ var rewrittenUrl;
if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
prevAppUrl = appUrl;
if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
- return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
+ rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
} else {
- return appBase + prevAppUrl;
+ rewrittenUrl = appBase + prevAppUrl;
}
} else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
- return appBaseNoFile + appUrl;
+ rewrittenUrl = appBaseNoFile + appUrl;
} else if (appBaseNoFile == url + '/') {
- return appBaseNoFile;
+ rewrittenUrl = appBaseNoFile;
+ }
+ if (rewrittenUrl) {
+ this.$$parse(rewrittenUrl);
}
+ return !!rewrittenUrl;
};
}
@@ -231,10 +242,12 @@ function LocationHashbangUrl(appBase, hashPrefix) {
this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
};
- this.$$rewrite = function(url) {
+ this.$$parseLinkUrl = function(url, relHref) {
if(stripHash(appBase) == stripHash(url)) {
- return url;
+ this.$$parse(url);
+ return true;
}
+ return false;
};
}
@@ -254,16 +267,28 @@ function LocationHashbangInHtml5Url(appBase, hashPrefix) {
var appBaseNoFile = stripFile(appBase);
- this.$$rewrite = function(url) {
+ this.$$parseLinkUrl = function(url, relHref) {
+ if (relHref && relHref[0] === '#') {
+ // special case for links to hash fragments:
+ // keep the old url and only replace the hash fragment
+ this.hash(relHref.slice(1));
+ return true;
+ }
+
+ var rewrittenUrl;
var appUrl;
if ( appBase == stripHash(url) ) {
- return url;
+ rewrittenUrl = url;
} else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
- return appBase + hashPrefix + appUrl;
+ rewrittenUrl = appBase + hashPrefix + appUrl;
} else if ( appBaseNoFile === url + '/') {
- return appBaseNoFile;
+ rewrittenUrl = appBaseNoFile;
}
+ if (rewrittenUrl) {
+ this.$$parse(rewrittenUrl);
+ }
+ return !!rewrittenUrl;
};
this.$$compose = function() {
@@ -626,6 +651,10 @@ function $LocationProvider(){
appBase;
if (html5Mode) {
+ if (!baseHref) {
+ throw $locationMinErr('nobase',
+ "$location in HTML5 mode requires a tag to be present!");
+ }
appBase = serverBase(initialUrl) + (baseHref || '/');
LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
} else {
@@ -633,7 +662,7 @@ function $LocationProvider(){
LocationMode = LocationHashbangUrl;
}
$location = new LocationMode(appBase, '#' + hashPrefix);
- $location.$$parse($location.$$rewrite(initialUrl));
+ $location.$$parseLinkUrl(initialUrl, initialUrl);
var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
@@ -652,6 +681,9 @@ function $LocationProvider(){
}
var absHref = elm.prop('href');
+ // get the actual href attribute - see
+ // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
+ var relHref = elm.attr('href') || elm.attr('xlink:href');
if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
// SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
@@ -662,50 +694,15 @@ function $LocationProvider(){
// Ignore when url is started with javascript: or mailto:
if (IGNORE_URI_REGEXP.test(absHref)) return;
- // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9)
- // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or
- // somewhere#anchor or http://example.com/somewhere
- if (LocationMode === LocationHashbangInHtml5Url) {
- // get the actual href attribute - see
- // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
- var href = elm.attr('href') || elm.attr('xlink:href');
-
- if (href && href.indexOf('://') < 0) { // Ignore absolute URLs
- var prefix = '#' + hashPrefix;
- if (href[0] == '/') {
- // absolute path - replace old path
- absHref = appBase + prefix + href;
- } else if (href[0] == '#') {
- // local anchor
- absHref = appBase + prefix + ($location.path() || '/') + href;
- } else {
- // relative path - join with current path
- var stack = $location.path().split("/"),
- parts = href.split("/");
- if (stack.length === 2 && !stack[1]) stack.length = 1;
- for (var i=0; i');
+ $documentProvider.$get = function() {
+ return {
+ 0: window.document,
+ find: jasmine.createSpy('find').andReturn(baseElement)
+ };
+ };
$browserProvider.$get = function($document, $window) {
var sniffer = {history: true, hashchange: false};
var logs = {log:[], warn:[], info:[], error:[]};
@@ -93,6 +100,7 @@ describe('$location', function() {
/* global Browser: false */
var b = new Browser($window, $document, fakeLog, sniffer);
b.pollFns = [];
+ b.$$baseHref = '/';
return b;
};
});
@@ -297,9 +305,9 @@ describe('$location', function() {
});
it('should not rewrite when hashbang url is not given', function() {
- initService(true, '!', true);
+ initService({html5Mode:true,hashPrefix: '!',supportHistory: true});
inject(
- initBrowser('http://domain.com/base/a/b', '/base'),
+ initBrowser({url:'http://domain.com/base/a/b',basePath: '/base'}),
function($rootScope, $location, $browser) {
expect($browser.url()).toBe('http://domain.com/base/a/b');
}
@@ -532,24 +540,24 @@ describe('$location', function() {
});
- function initService(html5Mode, hashPrefix, supportHistory) {
+ function initService(options) {
return module(function($provide, $locationProvider){
- $locationProvider.html5Mode(html5Mode);
- $locationProvider.hashPrefix(hashPrefix);
- $provide.value('$sniffer', {history: supportHistory});
+ $locationProvider.html5Mode(options.html5Mode);
+ $locationProvider.hashPrefix(options.hashPrefix);
+ $provide.value('$sniffer', {history: options.supportHistory});
});
}
- function initBrowser(url, basePath) {
+ function initBrowser(options) {
return function($browser){
- $browser.url(url);
- $browser.$$baseHref = basePath;
+ $browser.url(options.url);
+ $browser.$$baseHref = options.basePath;
};
}
describe('wiring', function() {
- beforeEach(initService(false, '!', true));
- beforeEach(inject(initBrowser('http://new.com/a/b#!', 'http://new.com/a/b')));
+ beforeEach(initService({html5Mode:false,hashPrefix: '!',supportHistory: true}));
+ beforeEach(inject(initBrowser({url:'http://new.com/a/b#!',basePath: 'http://new.com/a/b'})));
it('should update $location when browser url changes', inject(function($browser, $location) {
@@ -673,9 +681,9 @@ describe('$location', function() {
describe('disabled history', function() {
it('should use hashbang url with hash prefix', function() {
- initService(false, '!');
+ initService({html5Mode:false,hashPrefix: '!'});
inject(
- initBrowser('http://domain.com/base/index.html#!/a/b', '/base/index.html'),
+ initBrowser({url:'http://domain.com/base/index.html#!/a/b',basePath: '/base/index.html'}),
function($rootScope, $location, $browser) {
expect($browser.url()).toBe('http://domain.com/base/index.html#!/a/b');
$location.path('/new');
@@ -688,9 +696,9 @@ describe('$location', function() {
it('should use hashbang url without hash prefix', function() {
- initService(false, '');
+ initService({html5Mode:false,hashPrefix: ''});
inject(
- initBrowser('http://domain.com/base/index.html#/a/b', '/base/index.html'),
+ initBrowser({url:'http://domain.com/base/index.html#/a/b',basePath: '/base/index.html'}),
function($rootScope, $location, $browser) {
expect($browser.url()).toBe('http://domain.com/base/index.html#/a/b');
$location.path('/new');
@@ -711,9 +719,9 @@ describe('$location', function() {
}));
it('should use hashbang url with hash prefix', function() {
- initService(true, '!!', false);
+ initService({html5Mode:true,hashPrefix: '!!',supportHistory: false});
inject(
- initBrowser('http://domain.com/base/index.html#!!/a/b', '/base/index.html'),
+ initBrowser({url:'http://domain.com/base/index.html#!!/a/b',basePath: '/base/index.html'}),
function($rootScope, $location, $browser) {
expect($browser.url()).toBe('http://domain.com/base/index.html#!!/a/b');
$location.path('/new');
@@ -726,9 +734,9 @@ describe('$location', function() {
it('should redirect to hashbang url when new url given', function() {
- initService(true, '!');
+ initService({html5Mode:true,hashPrefix: '!'});
inject(
- initBrowser('http://domain.com/base/new-path/index.html', '/base/index.html'),
+ initBrowser({url:'http://domain.com/base/new-path/index.html',basePath: '/base/index.html'}),
function($browser, $location) {
expect($browser.url()).toBe('http://domain.com/base/index.html#!/new-path/index.html');
}
@@ -736,9 +744,9 @@ describe('$location', function() {
});
it('should correctly convert html5 url with path matching basepath to hashbang url', function () {
- initService(true, '!', false);
+ initService({html5Mode:true,hashPrefix: '!',supportHistory: false});
inject(
- initBrowser('http://domain.com/base/index.html', '/base/index.html'),
+ initBrowser({url:'http://domain.com/base/index.html',basePath: '/base/index.html'}),
function($browser, $location) {
expect($browser.url()).toBe('http://domain.com/base/index.html#!/index.html');
}
@@ -755,9 +763,9 @@ describe('$location', function() {
}));
it('should use new url', function() {
- initService(true, '', true);
+ initService({html5Mode:true,hashPrefix: '',supportHistory: true});
inject(
- initBrowser('http://domain.com/base/old/index.html#a', '/base/index.html'),
+ initBrowser({url:'http://domain.com/base/old/index.html#a',basePath: '/base/index.html'}),
function($rootScope, $location, $browser) {
expect($browser.url()).toBe('http://domain.com/base/old/index.html#a');
$location.path('/new');
@@ -770,9 +778,9 @@ describe('$location', function() {
it('should rewrite when hashbang url given', function() {
- initService(true, '!', true);
+ initService({html5Mode:true,hashPrefix: '!',supportHistory: true});
inject(
- initBrowser('http://domain.com/base/index.html#!/a/b', '/base/index.html'),
+ initBrowser({url:'http://domain.com/base/index.html#!/a/b',basePath: '/base/index.html'}),
function($rootScope, $location, $browser) {
expect($browser.url()).toBe('http://domain.com/base/a/b');
$location.path('/new');
@@ -786,9 +794,9 @@ describe('$location', function() {
it('should rewrite when hashbang url given (without hash prefix)', function() {
- initService(true, '', true);
+ initService({html5Mode:true,hashPrefix: '',supportHistory: true});
inject(
- initBrowser('http://domain.com/base/index.html#/a/b', '/base/index.html'),
+ initBrowser({url:'http://domain.com/base/index.html#/a/b',basePath: '/base/index.html'}),
function($rootScope, $location, $browser) {
expect($browser.url()).toBe('http://domain.com/base/a/b');
expect($location.path()).toBe('/a/b');
@@ -796,18 +804,6 @@ describe('$location', function() {
);
});
-
- it('should set appBase to serverBase if base[href] is missing', function() {
- initService(true, '!', true);
- inject(
- initBrowser('http://domain.com/my/view1#anchor1', ''),
- function($rootScope, $location, $browser) {
- expect($browser.url()).toBe('http://domain.com/my/view1#anchor1');
- expect($location.path()).toBe('/my/view1');
- expect($location.hash()).toBe('anchor1');
- }
- );
- });
});
describe('PATH_MATCH', function() {
@@ -843,21 +839,23 @@ describe('$location', function() {
var root, link, originalBrowser, lastEventPreventDefault;
- function configureService(linkHref, html5Mode, supportHist, relLink, attrs, content) {
- if (typeof relLink !== "boolean") {
- content = attrs;
- attrs = relLink;
- relLink = false;
- }
+ function configureService(options) {
+ var linkHref = options.linkHref,
+ html5Mode = options.html5Mode,
+ supportHist = options.supportHist,
+ relLink = options.relLink,
+ attrs = options.attrs,
+ content = options.content;
+
module(function($provide, $locationProvider) {
attrs = attrs ? ' ' + attrs + ' ' : '';
- // fake the base behavior
if (typeof linkHref === 'string') {
if (!relLink) {
if (linkHref[0] == '/') {
linkHref = 'http://host.com' + linkHref;
} else if(!linkHref.match(/:\/\//)) {
+ // fake the behavior of tag
linkHref = 'http://host.com/base/' + linkHref;
}
}
@@ -882,8 +880,8 @@ describe('$location', function() {
}
function initBrowser() {
- return function($browser){
- $browser.url('http://host.com/base');
+ return function($browser, $document){
+ $browser.url('http://host.com/base/index.html');
$browser.$$baseHref = '/base/index.html';
};
}
@@ -917,7 +915,7 @@ describe('$location', function() {
it('should rewrite rel link to new url when history enabled on new browser', function() {
- configureService('link?a#b', true, true);
+ configureService({linkHref: 'link?a#b', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
@@ -930,7 +928,7 @@ describe('$location', function() {
it('should do nothing if already on the same URL', function() {
- configureService('/base/', true, true);
+ configureService({linkHref: '/base/', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
@@ -957,7 +955,7 @@ describe('$location', function() {
it('should rewrite abs link to new url when history enabled on new browser', function() {
- configureService('/base/link?a#b', true, true);
+ configureService({linkHref: '/base/link?a#b', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
@@ -970,7 +968,7 @@ describe('$location', function() {
it('should rewrite rel link to hashbang url when history enabled on old browser', function() {
- configureService('link?a#b', true, false);
+ configureService({linkHref: 'link?a#b', html5Mode: true, supportHist: false});
inject(
initBrowser(),
initLocation(),
@@ -984,7 +982,7 @@ describe('$location', function() {
// Regression (gh-7721)
it('should not throw when clicking anchor with no href attribute when history enabled on old browser', function() {
- configureService(null, true, false);
+ configureService({linkHref: null, html5Mode: true, supportHist: false});
inject(
initBrowser(),
initLocation(),
@@ -997,12 +995,14 @@ describe('$location', function() {
it('should produce relative paths correctly when $location.path() is "/" when history enabled on old browser', function() {
- configureService('partial1', true, false, true);
+ configureService({linkHref: 'partial1', html5Mode: true, supportHist: false});
inject(
initBrowser(),
initLocation(),
- function($browser, $location) {
- $location.path('/');
+ function($browser, $location, $rootScope) {
+ $rootScope.$apply(function() {
+ $location.path('/');
+ });
browserTrigger(link, 'click');
expectRewriteTo($browser, 'http://host.com/base/index.html#!/partial1');
}
@@ -1011,7 +1011,7 @@ describe('$location', function() {
it('should rewrite abs link to hashbang url when history enabled on old browser', function() {
- configureService('/base/link?a#b', true, false);
+ configureService({linkHref: '/base/link?a#b', html5Mode: true, supportHist: false});
inject(
initBrowser(),
initLocation(),
@@ -1024,7 +1024,7 @@ describe('$location', function() {
it('should not rewrite full url links do different domain', function() {
- configureService('http://www.dot.abc/a?b=c', true);
+ configureService({linkHref: 'http://www.dot.abc/a?b=c', html5Mode: true});
inject(
initBrowser(),
initLocation(),
@@ -1037,7 +1037,7 @@ describe('$location', function() {
it('should not rewrite links with target="_blank"', function() {
- configureService('/a?b=c', true, true, 'target="_blank"');
+ configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="_blank"'});
inject(
initBrowser(),
initLocation(),
@@ -1050,7 +1050,7 @@ describe('$location', function() {
it('should not rewrite links with target specified', function() {
- configureService('/a?b=c', true, true, 'target="some-frame"');
+ configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="some-frame"'});
inject(
initBrowser(),
initLocation(),
@@ -1063,7 +1063,7 @@ describe('$location', function() {
it('should not rewrite links with `javascript:` URI', function() {
- configureService(' jAvAsCrIpT:throw new Error("Boom!")', true, true, true);
+ configureService({linkHref: ' jAvAsCrIpT:throw new Error("Boom!")', html5Mode: true, supportHist: true, relLink: true});
inject(
initBrowser(),
initLocation(),
@@ -1076,7 +1076,7 @@ describe('$location', function() {
it('should not rewrite links with `mailto:` URI', function() {
- configureService(' mAiLtO:foo@bar.com', true, true, true);
+ configureService({linkHref: ' mAiLtO:foo@bar.com', html5Mode: true, supportHist: true, relLink: true});
inject(
initBrowser(),
initLocation(),
@@ -1089,7 +1089,7 @@ describe('$location', function() {
it('should rewrite full url links to same domain and base path', function() {
- configureService('http://host.com/base/new', true);
+ configureService({linkHref: 'http://host.com/base/new', html5Mode: true});
inject(
initBrowser(),
initLocation(),
@@ -1102,7 +1102,7 @@ describe('$location', function() {
it('should rewrite when clicked span inside link', function() {
- configureService('some/link', true, true, '', 'link');
+ configureService({linkHref: 'some/link', html5Mode: true, supportHist: true, attrs: '', content: 'link'});
inject(
initBrowser(),
initLocation(),
@@ -1118,7 +1118,7 @@ describe('$location', function() {
it('should not rewrite when link to different base path when history enabled on new browser',
function() {
- configureService('/other_base/link', true, true);
+ configureService({linkHref: '/other_base/link', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
@@ -1132,7 +1132,7 @@ describe('$location', function() {
it('should not rewrite when link to different base path when history enabled on old browser',
function() {
- configureService('/other_base/link', true, false);
+ configureService({linkHref: '/other_base/link', html5Mode: true, supportHist: false});
inject(
initBrowser(),
initLocation(),
@@ -1145,7 +1145,7 @@ describe('$location', function() {
it('should not rewrite when link to different base path when history disabled', function() {
- configureService('/other_base/link', false);
+ configureService({linkHref: '/other_base/link', html5Mode: false});
inject(
initBrowser(),
initLocation(),
@@ -1159,7 +1159,7 @@ describe('$location', function() {
it('should not rewrite when full link to different base path when history enabled on new browser',
function() {
- configureService('http://host.com/other_base/link', true, true);
+ configureService({linkHref: 'http://host.com/other_base/link', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
@@ -1173,7 +1173,7 @@ describe('$location', function() {
it('should not rewrite when full link to different base path when history enabled on old browser',
function() {
- configureService('http://host.com/other_base/link', true, false);
+ configureService({linkHref: 'http://host.com/other_base/link', html5Mode: true, supportHist: false});
inject(
initBrowser(),
initLocation(),
@@ -1186,7 +1186,7 @@ describe('$location', function() {
it('should not rewrite when full link to different base path when history disabled', function() {
- configureService('http://host.com/other_base/link', false);
+ configureService({linkHref: 'http://host.com/other_base/link', html5Mode: false});
inject(
initBrowser(),
initLocation(),
@@ -1197,57 +1197,45 @@ describe('$location', function() {
);
});
-
- it('should rewrite relative links relative to current path when history disabled', function() {
- configureService('link', true, false, true);
- inject(
- initBrowser(),
- initLocation(),
- function($browser, $location) {
- $location.path('/some');
- browserTrigger(link, 'click');
- expectRewriteTo($browser, 'http://host.com/base/index.html#!/some/link');
- }
- );
- });
-
-
- it('should replace current path when link begins with "/" and history disabled', function() {
- configureService('/link', true, false, true);
+ it('should replace current hash fragment when link begins with "#" history disabled', function() {
+ configureService({linkHref: '#link', html5Mode: true, supportHist: false, relLink: true});
inject(
initBrowser(),
initLocation(),
- function($browser, $location) {
- $location.path('/some');
+ function($browser, $location, $rootScope) {
+ $rootScope.$apply(function() {
+ $location.path('/some');
+ $location.hash('foo');
+ });
browserTrigger(link, 'click');
- expectRewriteTo($browser, 'http://host.com/base/index.html#!/link');
+ expect($location.hash()).toBe('link');
+ expectRewriteTo($browser, 'http://host.com/base/index.html#!/some#link');
}
);
});
-
- it('should replace current hash fragment when link begins with "#" history disabled', function() {
- configureService('#link', true, false, true);
+ it('should replace current hash fragment when link begins with "#" history enabled', function() {
+ configureService({linkHref: '#link', html5Mode: true, supportHist: true, relLink: true});
inject(
initBrowser(),
initLocation(),
- function($browser, $location) {
- // Initialize browser URL
- $location.path('/some');
- $location.hash('foo');
+ function($browser, $location, $rootScope) {
+ $rootScope.$apply(function() {
+ $location.path('/some');
+ $location.hash('foo');
+ });
browserTrigger(link, 'click');
expect($location.hash()).toBe('link');
- expectRewriteTo($browser, 'http://host.com/base/index.html#!/some#link');
+ expectRewriteTo($browser, 'http://host.com/base/some#link');
}
);
});
-
// don't run next tests on IE<9, as browserTrigger does not simulate pressed keys
if (!msie || msie >= 9) {
it('should not rewrite when clicked with ctrl pressed', function() {
- configureService('/a?b=c', true, true);
+ configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
@@ -1260,7 +1248,7 @@ describe('$location', function() {
it('should not rewrite when clicked with meta pressed', function() {
- configureService('/a?b=c', true, true);
+ configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
@@ -1354,7 +1342,8 @@ describe('$location', function() {
var event = {
target: jqLite(window.document.body).find('a')[0],
- preventDefault: jasmine.createSpy('preventDefault')
+ preventDefault: jasmine.createSpy('preventDefault'),
+ isDefaultPrevented: jasmine.createSpy().andReturn(false)
};
@@ -1384,7 +1373,8 @@ describe('$location', function() {
var event = {
target: jqLite(window.document.body).find('a')[0],
- preventDefault: jasmine.createSpy('preventDefault')
+ preventDefault: jasmine.createSpy('preventDefault'),
+ isDefaultPrevented: jasmine.createSpy().andReturn(false)
};
@@ -1549,8 +1539,12 @@ describe('$location', function() {
it('should listen on click events on href and prevent browser default in html5 mode', function() {
- module(function($locationProvider) {
+ module(function($locationProvider, $provide) {
$locationProvider.html5Mode(true);
+ $provide.decorator('$browser', function($delegate) {
+ $delegate.$$baseHref = '/';
+ return $delegate;
+ });
return function($rootElement, $compile, $rootScope) {
$rootElement.html('link');
$compile($rootElement)($rootScope);
@@ -1607,6 +1601,13 @@ describe('$location', function() {
);
});
+ function parseLinkAndReturn(location, url, relHref) {
+ if (location.$$parseLinkUrl(url, relHref)) {
+ return location.absUrl();
+ }
+ return undefined;
+ }
+
describe('LocationHtml5Url', function() {
var location, locationIndex;
@@ -1616,13 +1617,18 @@ describe('$location', function() {
});
it('should rewrite URL', function() {
- expect(location.$$rewrite('http://other')).toEqual(undefined);
- expect(location.$$rewrite('http://server/pre')).toEqual('http://server/pre/');
- expect(location.$$rewrite('http://server/pre/')).toEqual('http://server/pre/');
- expect(location.$$rewrite('http://server/pre/otherPath')).toEqual('http://server/pre/otherPath');
- expect(locationIndex.$$rewrite('http://server/pre')).toEqual('http://server/pre/');
- expect(locationIndex.$$rewrite('http://server/pre/')).toEqual('http://server/pre/');
- expect(locationIndex.$$rewrite('http://server/pre/otherPath')).toEqual('http://server/pre/otherPath');
+ expect(parseLinkAndReturn(location, 'http://other')).toEqual(undefined);
+ expect(parseLinkAndReturn(location, 'http://server/pre')).toEqual('http://server/pre/');
+ expect(parseLinkAndReturn(location, 'http://server/pre/')).toEqual('http://server/pre/');
+ expect(parseLinkAndReturn(location, 'http://server/pre/otherPath')).toEqual('http://server/pre/otherPath');
+ // Note: relies on the previous state!
+ expect(parseLinkAndReturn(location, 'someIgnoredAbsoluteHref', '#test')).toEqual('http://server/pre/otherPath#test');
+
+ expect(parseLinkAndReturn(locationIndex, 'http://server/pre')).toEqual('http://server/pre/');
+ expect(parseLinkAndReturn(locationIndex, 'http://server/pre/')).toEqual('http://server/pre/');
+ expect(parseLinkAndReturn(locationIndex, 'http://server/pre/otherPath')).toEqual('http://server/pre/otherPath');
+ // Note: relies on the previous state!
+ expect(parseLinkAndReturn(location, 'someIgnoredAbsoluteHref', '#test')).toEqual('http://server/pre/otherPath#test');
});
});
@@ -1630,14 +1636,21 @@ describe('$location', function() {
describe('LocationHashbangUrl', function() {
var location;
+ function parseLinkAndReturn(location, url, relHref) {
+ if (location.$$parseLinkUrl(url, relHref)) {
+ return location.absUrl();
+ }
+ return undefined;
+ }
+
it('should rewrite URL', function() {
/* jshint scripturl: true */
location = new LocationHashbangUrl('http://server/pre/', '#');
- expect(location.$$rewrite('http://other')).toEqual(undefined);
- expect(location.$$rewrite('http://server/pre/')).toEqual('http://server/pre/');
- expect(location.$$rewrite('http://server/pre/#otherPath')).toEqual('http://server/pre/#otherPath');
- expect(location.$$rewrite('javascript:void(0)')).toEqual(undefined);
+ expect(parseLinkAndReturn(location, 'http://other')).toEqual(undefined);
+ expect(parseLinkAndReturn(location, 'http://server/pre/')).toEqual('http://server/pre/');
+ expect(parseLinkAndReturn(location, 'http://server/pre/#otherPath')).toEqual('http://server/pre/#/otherPath');
+ expect(parseLinkAndReturn(location, 'javascript:void(0)')).toEqual(undefined);
});
it("should not set hash if one was not originally specified", function() {
@@ -1687,13 +1700,18 @@ describe('$location', function() {
});
it('should rewrite URL', function() {
- expect(location.$$rewrite('http://other')).toEqual(undefined);
- expect(location.$$rewrite('http://server/pre')).toEqual('http://server/pre/');
- expect(location.$$rewrite('http://server/pre/')).toEqual('http://server/pre/');
- expect(location.$$rewrite('http://server/pre/otherPath')).toEqual('http://server/pre/#!otherPath');
- expect(locationIndex.$$rewrite('http://server/pre')).toEqual('http://server/pre/');
- expect(locationIndex.$$rewrite('http://server/pre/')).toEqual(undefined);
- expect(locationIndex.$$rewrite('http://server/pre/otherPath')).toEqual('http://server/pre/index.html#!otherPath');
+ expect(parseLinkAndReturn(location, 'http://other')).toEqual(undefined);
+ expect(parseLinkAndReturn(location, 'http://server/pre')).toEqual('http://server/pre/#!');
+ expect(parseLinkAndReturn(location, 'http://server/pre/')).toEqual('http://server/pre/#!');
+ expect(parseLinkAndReturn(location, 'http://server/pre/otherPath')).toEqual('http://server/pre/#!/otherPath');
+ // Note: relies on the previous state!
+ expect(parseLinkAndReturn(location, 'someIgnoredAbsoluteHref', '#test')).toEqual('http://server/pre/#!/otherPath#test');
+
+ expect(parseLinkAndReturn(locationIndex, 'http://server/pre')).toEqual('http://server/pre/index.html#!');
+ expect(parseLinkAndReturn(locationIndex, 'http://server/pre/')).toEqual(undefined);
+ expect(parseLinkAndReturn(locationIndex, 'http://server/pre/otherPath')).toEqual('http://server/pre/index.html#!/otherPath');
+ // Note: relies on the previous state!
+ expect(parseLinkAndReturn(locationIndex, 'someIgnoredAbsoluteHref', '#test')).toEqual('http://server/pre/index.html#!/otherPath#test');
});
});
});