Skip to content

Commit 5eae33d

Browse files
author
Wei Wang
committed
feat(location): add configurable attr to force html5mode link rewriting
See this discussion: angular#14959 When using html5mode, sometimes it is necessary to not use the <base> tag in order to support SVG icons. An example of this is in the discussion linked above. When we do this, sometimes we also want to disable "rewriteLinks" so that we can still leave the Angular application via navigation. This feature allows the user to explicitly mark an <a> tag as a link that should not refresh from server, even if rewriteLinks is disabled.
1 parent 5fc9933 commit 5eae33d

File tree

3 files changed

+70
-11
lines changed

3 files changed

+70
-11
lines changed

docs/content/guide/$location.ngdoc

+14-3
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ To configure the `$location` service, retrieve the
9595
`true` or `enabled:true` - see HTML5 mode<br />
9696
`false` or `enabled:false` - see Hashbang mode<br />
9797
`requireBase:true` - see Relative links<br />
98+
`rewriteLinks:true` - see Html link rewriting<br />
99+
`rewriteLinks:'string'` - see Html link rewriting<br />
98100
default: `enabled:false`
99101

100102
- **hashPrefix(prefix)**: {string}<br />
@@ -326,6 +328,18 @@ reload to the original link.
326328
- Links starting with '/' that lead to a different base path<br>
327329
Example: `<a href="/not-my-base/link">link</a>`
328330

331+
If `html5Mode.rewriteLinks` is set to `false` in the html5Mode definition object passed to
332+
`$locationProvider.html5Mode()`, the browser will perform a full page reload for every link.
333+
`html5Mode.rewriteLinks` can also be set to a string, which will enable link re-writing only on
334+
links that have the given attribute.
335+
336+
For example, if `html5Mode.rewriteLinks` is set to "internal-link":
337+
- `<a href="/some/path" internal-link>link</a>` will be rewritten
338+
- `<a href="/some/path">link</a>` will perform a full page reload
339+
340+
Note that attribute name (de)normalization does not apply here, so "internalLink" is different from
341+
"internal-link".
342+
329343

330344
### Relative links
331345

@@ -853,6 +867,3 @@ angular.module('locationExample', [])
853867
# Related API
854868

855869
* {@link ng.$location `$location` API}
856-
857-
858-

src/ng/location.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -750,8 +750,12 @@ function $LocationProvider() {
750750
* whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
751751
* true, and a base tag is not present, an error will be thrown when `$location` is injected.
752752
* See the {@link guide/$location $location guide for more information}
753-
* - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
754-
* enables/disables url rewriting for relative links.
753+
* - **rewriteLinks** - `{boolean|String}` - (default: `true`) When html5Mode is enabled,
754+
* enables/disables url rewriting for relative links. If set to a string, url rewriting will
755+
* only happen on links with an attribute that matches the given string. For example, if set
756+
* to "internal-link", then the URL will only be rewritten for `<a internal-link>` links. Note
757+
* that attribute name (de)normalization is not happening here. So "internal-link" is
758+
* different from "internalLink".
755759
*
756760
* @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
757761
*/
@@ -769,7 +773,7 @@ function $LocationProvider() {
769773
html5Mode.requireBase = mode.requireBase;
770774
}
771775

772-
if (isBoolean(mode.rewriteLinks)) {
776+
if (isBoolean(mode.rewriteLinks) || isString(mode.rewriteLinks)) {
773777
html5Mode.rewriteLinks = mode.rewriteLinks;
774778
}
775779

@@ -866,10 +870,11 @@ function $LocationProvider() {
866870
}
867871

868872
$rootElement.on('click', function(event) {
873+
var rewriteLinks = html5Mode.rewriteLinks;
869874
// TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
870875
// currently we open nice url link and redirect then
871876

872-
if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which === 2 || event.button === 2) return;
877+
if (!rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which === 2 || event.button === 2) return;
873878

874879
var elm = jqLite(event.target);
875880

@@ -879,6 +884,8 @@ function $LocationProvider() {
879884
if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
880885
}
881886

887+
if (isString(rewriteLinks) && isUndefined(elm.attr(rewriteLinks))) return;
888+
882889
var absHref = elm.prop('href');
883890
// get the actual href attribute - see
884891
// http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx

test/ng/locationSpec.js

+45-4
Original file line numberDiff line numberDiff line change
@@ -1588,7 +1588,7 @@ describe('$location', function() {
15881588

15891589

15901590
it('should not rewrite links when rewriting links is disabled', function() {
1591-
configureTestLink({linkHref: 'link?a#b', html5Mode: {enabled: true, rewriteLinks:false}, supportHist: true});
1591+
configureTestLink({linkHref: 'link?a#b'});
15921592
initService({html5Mode:{enabled: true, rewriteLinks:false},supportHistory:true});
15931593
inject(
15941594
initBrowser({ url: 'http://host.com/base/index.html', basePath: '/base/index.html' }),
@@ -1601,6 +1601,34 @@ describe('$location', function() {
16011601
});
16021602

16031603

1604+
it('should rewrite links when the specified rewriteLinks attr is detected', function() {
1605+
configureTestLink({linkHref: 'link?a#b', attrs: 'force-rewrite'});
1606+
initService({html5Mode:{enabled: true, rewriteLinks:'force-rewrite'},supportHistory:true});
1607+
inject(
1608+
initBrowser({ url: 'http://host.com/base/index.html', basePath: '/base/index.html' }),
1609+
setupRewriteChecks(),
1610+
function($browser) {
1611+
browserTrigger(link, 'click');
1612+
expectRewriteTo($browser, 'http://host.com/base/link?a#b');
1613+
}
1614+
);
1615+
});
1616+
1617+
1618+
it('should not rewrite links when the specified rewriteLinks attr is not detected', function() {
1619+
configureTestLink({linkHref: 'link?a#b'});
1620+
initService({html5Mode:{enabled: true, rewriteLinks:'yes-rewrite'},supportHistory:true});
1621+
inject(
1622+
initBrowser({ url: 'http://host.com/base/index.html', basePath: '/base/index.html' }),
1623+
setupRewriteChecks(),
1624+
function($browser) {
1625+
browserTrigger(link, 'click');
1626+
expectNoRewrite($browser);
1627+
}
1628+
);
1629+
});
1630+
1631+
16041632
it('should rewrite full url links to same domain and base path', function() {
16051633
configureTestLink({linkHref: 'http://host.com/base/new'});
16061634
initService({html5Mode:true,supportHistory:false,hashPrefix:'!'});
@@ -1692,7 +1720,7 @@ describe('$location', function() {
16921720

16931721
it('should not rewrite when full link to different base path when history enabled on old browser',
16941722
function() {
1695-
configureTestLink({linkHref: 'http://host.com/other_base/link', html5Mode: true, supportHist: false});
1723+
configureTestLink({linkHref: 'http://host.com/other_base/link'});
16961724
inject(
16971725
initBrowser({ url: 'http://host.com/base/index.html', basePath: '/base/index.html' }),
16981726
setupRewriteChecks(),
@@ -2357,12 +2385,12 @@ describe('$location', function() {
23572385
});
23582386

23592387

2360-
it('should only overwrite existing properties if values are boolean', function() {
2388+
it('should only overwrite existing properties if values are the correct type', function() {
23612389
module(function($locationProvider) {
23622390
$locationProvider.html5Mode({
23632391
enabled: 'duh',
23642392
requireBase: 'probably',
2365-
rewriteLinks: 'nope'
2393+
rewriteLinks: 500
23662394
});
23672395

23682396
expect($locationProvider.html5Mode()).toEqual({
@@ -2376,6 +2404,19 @@ describe('$location', function() {
23762404
});
23772405

23782406

2407+
it('should allow rewriteLinks config to be set to a string', function() {
2408+
module(function($locationProvider) {
2409+
$locationProvider.html5Mode({
2410+
rewriteLinks: 'yes-rewrite'
2411+
});
2412+
2413+
expect($locationProvider.html5Mode().rewriteLinks).toEqual('yes-rewrite');
2414+
});
2415+
2416+
inject(function() {});
2417+
});
2418+
2419+
23792420
it('should not set unknown input properties to html5Mode object', function() {
23802421
module(function($locationProvider) {
23812422
$locationProvider.html5Mode({

0 commit comments

Comments
 (0)