mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-06-19 17:53:27 +08:00
feat($location): add ability to opt-out of <base/> tag requirement in html5Mode
This feature allows disabling Angular's requirement of using a <base/> tag
when using location in html5Mode, for applications that do not require
using $location in html5Mode in IE9. To accomplish this, the $locationProvider.html5Mode
method has been changed to accept a definition object which can optionally set a
requireBase property to false, removing the requirement of a <base> tag being present
when html5Mode is enabled.
BREAKING CHANGE: The $location.html5Mode API has changed to allow enabling html5Mode by
passing an object (as well as still supporting passing a boolean). Symmetrically, the
method now returns an object instead of a boolean value.
To migrate, follow the code example below:
Before:
var mode = $locationProvider.html5Mode();
After:
var mode = $locationProvider.html5Mode().enabled;
Fixes #8934
This commit is contained in:
@@ -4,7 +4,19 @@
|
||||
@description
|
||||
|
||||
If you configure {@link ng.$location `$location`} to use
|
||||
{@link api/ng.provider.$locationProvider `html5Mode`} (`history.pushState`), you need to specify the base URL for the application with a [`<base href="">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag.
|
||||
{@link api/ng.provider.$locationProvider `html5Mode`} (`history.pushState`), you need to specify the base URL for the application with a [`<base href="">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag or configure
|
||||
`$locationProvider` to not require a base tag by passing a definition object with
|
||||
`requireBase:false` to `$locationProvider.html5Mode()`:
|
||||
|
||||
```javascript
|
||||
$locationProvider.html5Mode({
|
||||
enabled: true,
|
||||
requireBase: false
|
||||
});
|
||||
```
|
||||
|
||||
Note that removing the requirement for a <base> tag will have adverse side effects when resolving
|
||||
relative paths with `$location` in IE9.
|
||||
|
||||
The base URL is then used to resolve all relative URLs throughout the application regardless of the
|
||||
entry point into the app.
|
||||
|
||||
@@ -91,10 +91,11 @@ To configure the `$location` service, retrieve the
|
||||
{@link ng.$locationProvider $locationProvider} and set the parameters as follows:
|
||||
|
||||
|
||||
- **html5Mode(mode)**: {boolean}<br />
|
||||
`true` - see HTML5 mode<br />
|
||||
`false` - see Hashbang mode<br />
|
||||
default: `false`
|
||||
- **html5Mode(mode)**: {boolean|Object}<br />
|
||||
`true` or `enabled:true` - see HTML5 mode<br />
|
||||
`false` or `enabled:false` - see Hashbang mode<br />
|
||||
`requireBase:true` - see Relative links<br />
|
||||
default: `enabled:false`
|
||||
|
||||
- **hashPrefix(prefix)**: {string}<br />
|
||||
prefix used for Hashbang URLs (used in Hashbang mode or in legacy browser in Html5 mode)<br />
|
||||
@@ -328,9 +329,11 @@ reload to the original link.
|
||||
|
||||
### Relative links
|
||||
|
||||
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 (`<base href="/my-base">`). With that, relative urls will
|
||||
always be resolved to this base url, event if the initial url of the document was different.
|
||||
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 (`<base href="/my-base">`) unless `html5Mode.requireBase` is
|
||||
set to `false` in the html5Mode definition object passed to `$locationProvider.html5Mode()`. With
|
||||
that, relative urls will always be resolved to this base url, event if the initial url of the
|
||||
document was different.
|
||||
|
||||
There is one exception: Links that only contain a hash fragment (e.g. `<a href="#target">`)
|
||||
will only change `$location.hash()` and not modify the url otherwise. This is useful for scrolling
|
||||
|
||||
@@ -584,7 +584,10 @@ function locationGetterSetter(property, preprocess) {
|
||||
*/
|
||||
function $LocationProvider(){
|
||||
var hashPrefix = '',
|
||||
html5Mode = false;
|
||||
html5Mode = {
|
||||
enabled: false,
|
||||
requireBase: true
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -606,12 +609,30 @@ function $LocationProvider(){
|
||||
* @ngdoc method
|
||||
* @name $locationProvider#html5Mode
|
||||
* @description
|
||||
* @param {boolean=} mode Use HTML5 strategy if available.
|
||||
* @returns {*} current value if used as getter or itself (chaining) if used as setter
|
||||
* @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
|
||||
* If object, sets `enabled` and `requireBase` to respective values.
|
||||
* - **enabled** – `{boolean}` – Sets `html5Mode.enabled`. If true, will rely on
|
||||
* `history.pushState` to change urls where supported. Will fall back to hash-prefixed paths
|
||||
* in browsers that do not support `pushState`.
|
||||
* - **requireBase** - `{boolean}` - Sets `html5Mode.requireBase` (default: `true`). When
|
||||
* html5Mode is enabled, specifies whether or not a <base> tag is required to be present. If
|
||||
* `enabled` and `requireBase` are true, and a base tag is not present, an error will be
|
||||
* thrown when `$location` is injected. See the
|
||||
* {@link guide/$location $location guide for more information}
|
||||
*
|
||||
* @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
|
||||
*/
|
||||
this.html5Mode = function(mode) {
|
||||
if (isDefined(mode)) {
|
||||
html5Mode = mode;
|
||||
if (isBoolean(mode)) {
|
||||
html5Mode.enabled = mode;
|
||||
return this;
|
||||
} else if (isObject(mode)) {
|
||||
html5Mode.enabled = isBoolean(mode.enabled) ?
|
||||
mode.enabled :
|
||||
html5Mode.enabled;
|
||||
html5Mode.requireBase = isBoolean(mode.requireBase) ?
|
||||
mode.requireBase :
|
||||
html5Mode.requireBase;
|
||||
return this;
|
||||
} else {
|
||||
return html5Mode;
|
||||
@@ -653,8 +674,8 @@ function $LocationProvider(){
|
||||
initialUrl = $browser.url(),
|
||||
appBase;
|
||||
|
||||
if (html5Mode) {
|
||||
if (!baseHref) {
|
||||
if (html5Mode.enabled) {
|
||||
if (!baseHref && html5Mode.requireBase) {
|
||||
throw $locationMinErr('nobase',
|
||||
"$location in HTML5 mode requires a <base> tag to be present!");
|
||||
}
|
||||
|
||||
@@ -1639,6 +1639,77 @@ describe('$location', function() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
describe('html5Mode', function() {
|
||||
it('should set enabled and requireBase when called with object', function() {
|
||||
module(function($locationProvider) {
|
||||
expect($locationProvider.html5Mode()).toEqual({
|
||||
enabled: false,
|
||||
requireBase: true
|
||||
});
|
||||
});
|
||||
|
||||
inject(function(){});
|
||||
});
|
||||
|
||||
|
||||
it('should only overwrite existing properties if values are boolean', function() {
|
||||
module(function($locationProvider) {
|
||||
$locationProvider.html5Mode({
|
||||
enabled: 'duh',
|
||||
requireBase: 'probably'
|
||||
});
|
||||
|
||||
expect($locationProvider.html5Mode()).toEqual({
|
||||
enabled: false,
|
||||
requireBase: true
|
||||
});
|
||||
});
|
||||
|
||||
inject(function(){});
|
||||
});
|
||||
|
||||
|
||||
it('should not set unknown input properties to html5Mode object', function() {
|
||||
module(function($locationProvider) {
|
||||
$locationProvider.html5Mode({
|
||||
someProp: 'foo'
|
||||
});
|
||||
|
||||
expect($locationProvider.html5Mode()).toEqual({
|
||||
enabled: false,
|
||||
requireBase: true
|
||||
});
|
||||
});
|
||||
|
||||
inject(function(){});
|
||||
});
|
||||
|
||||
|
||||
it('should default to enabled:false and requireBase:true', function() {
|
||||
module(function($locationProvider) {
|
||||
expect($locationProvider.html5Mode()).toEqual({
|
||||
enabled: false,
|
||||
requireBase: true
|
||||
});
|
||||
});
|
||||
|
||||
inject(function(){});
|
||||
});
|
||||
|
||||
|
||||
it('should return html5Mode object when called without value', function() {
|
||||
module(function($locationProvider) {
|
||||
expect($locationProvider.html5Mode()).toEqual({
|
||||
enabled: false,
|
||||
requireBase: true
|
||||
});
|
||||
});
|
||||
|
||||
inject(function(){});
|
||||
});
|
||||
});
|
||||
|
||||
describe('LocationHtml5Url', function() {
|
||||
var location, locationIndex;
|
||||
|
||||
@@ -1661,6 +1732,39 @@ describe('$location', function() {
|
||||
// Note: relies on the previous state!
|
||||
expect(parseLinkAndReturn(location, 'someIgnoredAbsoluteHref', '#test')).toEqual('http://server/pre/otherPath#test');
|
||||
});
|
||||
|
||||
|
||||
it('should complain if no base tag present', function() {
|
||||
module(function($locationProvider) {
|
||||
$locationProvider.html5Mode(true);
|
||||
});
|
||||
|
||||
inject(function($browser, $injector) {
|
||||
$browser.$$baseHref = undefined;
|
||||
expect(function() {
|
||||
$injector.get('$location');
|
||||
}).toThrowMinErr('$location', 'nobase',
|
||||
"$location in HTML5 mode requires a <base> tag to be present!");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should not complain if baseOptOut set to true in html5Mode', function() {
|
||||
module(function($locationProvider) {
|
||||
$locationProvider.html5Mode({
|
||||
enabled: true,
|
||||
requireBase: false
|
||||
});
|
||||
});
|
||||
|
||||
inject(function($browser, $injector) {
|
||||
$browser.$$baseHref = undefined;
|
||||
expect(function() {
|
||||
$injector.get('$location');
|
||||
}).not.toThrowMinErr('$location', 'nobase',
|
||||
"$location in HTML5 mode requires a <base> tag to be present!");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user