mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-05-09 15:24:43 +00:00
parent
0f44964e5e
commit
6593a3e082
3 changed files with 125 additions and 33 deletions
|
|
@ -23,6 +23,10 @@ function encodePath(path) {
|
||||||
return segments.join('/');
|
return segments.join('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stripHash(url) {
|
||||||
|
return url.split('#')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function matchUrl(url, obj) {
|
function matchUrl(url, obj) {
|
||||||
var match = URL_MATCH.exec(url);
|
var match = URL_MATCH.exec(url);
|
||||||
|
|
@ -102,19 +106,19 @@ function convertToHashbangUrl(url, basePath, hashPrefix) {
|
||||||
* @param {string} url HTML5 url
|
* @param {string} url HTML5 url
|
||||||
* @param {string} pathPrefix
|
* @param {string} pathPrefix
|
||||||
*/
|
*/
|
||||||
function LocationUrl(url, pathPrefix) {
|
function LocationUrl(url, pathPrefix, appBaseUrl) {
|
||||||
pathPrefix = pathPrefix || '';
|
pathPrefix = pathPrefix || '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse given html5 (regular) url string into properties
|
* Parse given html5 (regular) url string into properties
|
||||||
* @param {string} url HTML5 url
|
* @param {string} newAbsoluteUrl HTML5 url
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.$$parse = function(url) {
|
this.$$parse = function(newAbsoluteUrl) {
|
||||||
var match = matchUrl(url, this);
|
var match = matchUrl(newAbsoluteUrl, this);
|
||||||
|
|
||||||
if (match.path.indexOf(pathPrefix) !== 0) {
|
if (match.path.indexOf(pathPrefix) !== 0) {
|
||||||
throw Error('Invalid url "' + url + '", missing path prefix "' + pathPrefix + '" !');
|
throw Error('Invalid url "' + newAbsoluteUrl + '", missing path prefix "' + pathPrefix + '" !');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$$path = decodeURIComponent(match.path.substr(pathPrefix.length));
|
this.$$path = decodeURIComponent(match.path.substr(pathPrefix.length));
|
||||||
|
|
@ -137,6 +141,14 @@ function LocationUrl(url, pathPrefix) {
|
||||||
pathPrefix + this.$$url;
|
pathPrefix + this.$$url;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.$$rewriteAppUrl = function(absoluteLinkUrl) {
|
||||||
|
if(absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
|
||||||
|
return absoluteLinkUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.$$parse(url);
|
this.$$parse(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,7 +161,7 @@ function LocationUrl(url, pathPrefix) {
|
||||||
* @param {string} url Legacy url
|
* @param {string} url Legacy url
|
||||||
* @param {string} hashPrefix Prefix for hash part (containing path and search)
|
* @param {string} hashPrefix Prefix for hash part (containing path and search)
|
||||||
*/
|
*/
|
||||||
function LocationHashbangUrl(url, hashPrefix) {
|
function LocationHashbangUrl(url, hashPrefix, appBaseUrl) {
|
||||||
var basePath;
|
var basePath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -192,6 +204,13 @@ function LocationHashbangUrl(url, hashPrefix) {
|
||||||
basePath + (this.$$url ? '#' + hashPrefix + this.$$url : '');
|
basePath + (this.$$url ? '#' + hashPrefix + this.$$url : '');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.$$rewriteAppUrl = function(absoluteLinkUrl) {
|
||||||
|
if(absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
|
||||||
|
return absoluteLinkUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.$$parse(url);
|
this.$$parse(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,6 +399,19 @@ LocationUrl.prototype = {
|
||||||
|
|
||||||
LocationHashbangUrl.prototype = inherit(LocationUrl.prototype);
|
LocationHashbangUrl.prototype = inherit(LocationUrl.prototype);
|
||||||
|
|
||||||
|
function LocationHashbangInHtml5Url(url, hashPrefix, appBaseUrl, baseExtra) {
|
||||||
|
LocationHashbangUrl.apply(this, arguments);
|
||||||
|
|
||||||
|
|
||||||
|
this.$$rewriteAppUrl = function(absoluteLinkUrl) {
|
||||||
|
if (absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
|
||||||
|
return appBaseUrl + baseExtra + '#' + hashPrefix + absoluteLinkUrl.substr(appBaseUrl.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationHashbangInHtml5Url.prototype = inherit(LocationHashbangUrl.prototype);
|
||||||
|
|
||||||
function locationGetter(property) {
|
function locationGetter(property) {
|
||||||
return function() {
|
return function() {
|
||||||
return this[property];
|
return this[property];
|
||||||
|
|
@ -479,26 +511,33 @@ function $LocationProvider(){
|
||||||
basePath,
|
basePath,
|
||||||
pathPrefix,
|
pathPrefix,
|
||||||
initUrl = $browser.url(),
|
initUrl = $browser.url(),
|
||||||
absUrlPrefix;
|
initUrlParts = matchUrl(initUrl),
|
||||||
|
appBaseUrl;
|
||||||
|
|
||||||
if (html5Mode) {
|
if (html5Mode) {
|
||||||
basePath = $browser.baseHref() || '/';
|
basePath = $browser.baseHref() || '/';
|
||||||
pathPrefix = pathPrefixFromBase(basePath);
|
pathPrefix = pathPrefixFromBase(basePath);
|
||||||
|
appBaseUrl =
|
||||||
|
composeProtocolHostPort(initUrlParts.protocol, initUrlParts.host, initUrlParts.port) +
|
||||||
|
pathPrefix + '/';
|
||||||
|
|
||||||
if ($sniffer.history) {
|
if ($sniffer.history) {
|
||||||
$location = new LocationUrl(
|
$location = new LocationUrl(
|
||||||
convertToHtml5Url(initUrl, basePath, hashPrefix),
|
convertToHtml5Url(initUrl, basePath, hashPrefix),
|
||||||
pathPrefix);
|
pathPrefix, appBaseUrl);
|
||||||
} else {
|
} else {
|
||||||
$location = new LocationHashbangUrl(
|
$location = new LocationHashbangInHtml5Url(
|
||||||
convertToHashbangUrl(initUrl, basePath, hashPrefix),
|
convertToHashbangUrl(initUrl, basePath, hashPrefix),
|
||||||
hashPrefix);
|
hashPrefix, appBaseUrl, basePath.substr(pathPrefix.length + 1));
|
||||||
}
|
}
|
||||||
// link rewriting
|
|
||||||
absUrlPrefix = composeProtocolHostPort(
|
|
||||||
$location.protocol(), $location.host(), $location.port()) + pathPrefix;
|
|
||||||
} else {
|
} else {
|
||||||
$location = new LocationHashbangUrl(initUrl, hashPrefix);
|
appBaseUrl =
|
||||||
absUrlPrefix = $location.absUrl().split('#')[0];
|
composeProtocolHostPort(initUrlParts.protocol, initUrlParts.host, initUrlParts.port) +
|
||||||
|
(initUrlParts.path || '') +
|
||||||
|
(initUrlParts.search ? ('?' + initUrlParts.search) : '') +
|
||||||
|
'#' + hashPrefix + '/';
|
||||||
|
|
||||||
|
$location = new LocationHashbangUrl(initUrl, hashPrefix, appBaseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rootElement.bind('click', function(event) {
|
$rootElement.bind('click', function(event) {
|
||||||
|
|
@ -510,27 +549,22 @@ function $LocationProvider(){
|
||||||
var elm = jqLite(event.target);
|
var elm = jqLite(event.target);
|
||||||
|
|
||||||
// traverse the DOM up to find first A tag
|
// traverse the DOM up to find first A tag
|
||||||
while (elm.length && lowercase(elm[0].nodeName) !== 'a') {
|
while (lowercase(elm[0].nodeName) !== 'a') {
|
||||||
|
if (elm[0] === $rootElement[0]) return;
|
||||||
elm = elm.parent();
|
elm = elm.parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
var absHref = elm.prop('href'),
|
var absHref = elm.prop('href'),
|
||||||
href;
|
rewrittenUrl = $location.$$rewriteAppUrl(absHref);
|
||||||
|
|
||||||
if (!absHref ||
|
if (absHref && !elm.attr('target') && rewrittenUrl) {
|
||||||
elm.attr('target') ||
|
// update location manually
|
||||||
absHref.indexOf(absUrlPrefix) !== 0) { // link to different domain or base path
|
$location.$$parse(rewrittenUrl);
|
||||||
return;
|
$rootScope.$apply();
|
||||||
|
event.preventDefault();
|
||||||
|
// hack to work around FF6 bug 684208 when scenario runner clicks on links
|
||||||
|
window.angular['ff-684208-preventDefault'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update location with href without the prefix
|
|
||||||
href = absHref.substr(absUrlPrefix.length);
|
|
||||||
if (href.indexOf('#' + hashPrefix) == 0) href = href.substr(hashPrefix.length + 1);
|
|
||||||
$location.url(href);
|
|
||||||
$rootScope.$apply();
|
|
||||||
event.preventDefault();
|
|
||||||
// hack to work around FF6 bug 684208 when scenario runner clicks on links
|
|
||||||
window.angular['ff-684208-preventDefault'] = true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
2
src/ngMock/angular-mocks.js
vendored
2
src/ngMock/angular-mocks.js
vendored
|
|
@ -39,7 +39,7 @@ angular.mock.$Browser = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.isMock = true;
|
this.isMock = true;
|
||||||
self.$$url = "http://server";
|
self.$$url = "http://server/";
|
||||||
self.$$lastUrl = self.$$url; // used by url polling fn
|
self.$$lastUrl = self.$$url; // used by url polling fn
|
||||||
self.pollFns = [];
|
self.pollFns = [];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1029,6 +1029,64 @@ describe('$location', function() {
|
||||||
expect($browser.url()).toEqual(base + '#!/view2');
|
expect($browser.url()).toEqual(base + '#!/view2');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should not intercept link clicks outside the app base url space', function() {
|
||||||
|
var base, clickHandler;
|
||||||
|
module(function($provide) {
|
||||||
|
$provide.value('$rootElement', {
|
||||||
|
bind: function(event, handler) {
|
||||||
|
expect(event).toEqual('click');
|
||||||
|
clickHandler = handler;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return function($browser) {
|
||||||
|
$browser.url(base = 'http://server/');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
inject(function($rootScope, $compile, $browser, $rootElement, $document, $location) {
|
||||||
|
// make IE happy
|
||||||
|
jqLite(window.document.body).html('<a href="http://server/test.html">link</a>');
|
||||||
|
|
||||||
|
var event = {
|
||||||
|
target: jqLite(window.document.body).find('a')[0],
|
||||||
|
preventDefault: jasmine.createSpy('preventDefault')
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
clickHandler(event);
|
||||||
|
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should not intercept hash link clicks outside the app base url space', function() {
|
||||||
|
var base, clickHandler;
|
||||||
|
module(function($provide) {
|
||||||
|
$provide.value('$rootElement', {
|
||||||
|
bind: function(event, handler) {
|
||||||
|
expect(event).toEqual('click');
|
||||||
|
clickHandler = handler;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return function($browser) {
|
||||||
|
$browser.url(base = 'http://server/');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
inject(function($rootScope, $compile, $browser, $rootElement, $document, $location) {
|
||||||
|
// make IE happy
|
||||||
|
jqLite(window.document.body).html('<a href="http://server/index.html#test">link</a>');
|
||||||
|
|
||||||
|
var event = {
|
||||||
|
target: jqLite(window.document.body).find('a')[0],
|
||||||
|
preventDefault: jasmine.createSpy('preventDefault')
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
clickHandler(event);
|
||||||
|
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1111,7 +1169,7 @@ describe('$location', function() {
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
it('should listen on click events on href and prevent browser default in hasbang mode', function() {
|
it('should listen on click events on href and prevent browser default in hashbang mode', function() {
|
||||||
module(function() {
|
module(function() {
|
||||||
return function($rootElement, $compile, $rootScope) {
|
return function($rootElement, $compile, $rootScope) {
|
||||||
$rootElement.html('<a href="http://server/#/somePath">link</a>');
|
$rootElement.html('<a href="http://server/#/somePath">link</a>');
|
||||||
|
|
@ -1162,7 +1220,7 @@ describe('$location', function() {
|
||||||
log += '$locationChangeStart';
|
log += '$locationChangeStart';
|
||||||
});
|
});
|
||||||
$rootScope.$on('$locationChangeSuccess', function() {
|
$rootScope.$on('$locationChangeSuccess', function() {
|
||||||
throw new Error('after cancalation in html5 mode');
|
throw new Error('after cancelation in html5 mode');
|
||||||
});
|
});
|
||||||
|
|
||||||
browserTrigger(link, 'click');
|
browserTrigger(link, 'click');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue