1- import { BrowserLocation } from './browser_location ' ;
1+ import { LocationStrategy } from './location_strategy ' ;
22import { StringWrapper , isPresent , CONST_EXPR } from 'angular2/src/facade/lang' ;
33import { EventEmitter , ObservableWrapper } from 'angular2/src/facade/async' ;
44import { OpaqueToken , Injectable , Optional , Inject } from 'angular2/di' ;
55
66export const appBaseHrefToken : OpaqueToken = CONST_EXPR ( new OpaqueToken ( 'locationHrefToken' ) ) ;
77
8+ /**
9+ * This is the service that an application developer will directly interact with.
10+ *
11+ * Responsible for normalizing the URL against the application's base href.
12+ * A normalized URL is absolute from the URL host, includes the application's base href, and has no
13+ * trailing slash:
14+ * - `/my/app/user/123` is normalized
15+ * - `my/app/user/123` **is not** normalized
16+ * - `/my/app/user/123/` **is not** normalized
17+ */
818@Injectable ( )
919export class Location {
1020 private _subject : EventEmitter ;
1121 private _baseHref : string ;
1222
13- constructor ( public _browserLocation : BrowserLocation ,
23+ constructor ( public _platformStrategy : LocationStrategy ,
1424 @Optional ( ) @Inject ( appBaseHrefToken ) href ?: string ) {
1525 this . _subject = new EventEmitter ( ) ;
16- this . _baseHref = stripIndexHtml ( isPresent ( href ) ? href : this . _browserLocation . getBaseHref ( ) ) ;
17- this . _browserLocation . onPopState ( ( _ ) => this . _onPopState ( _ ) ) ;
26+ this . _baseHref = stripTrailingSlash (
27+ stripIndexHtml ( isPresent ( href ) ? href : this . _platformStrategy . getBaseHref ( ) ) ) ;
28+ this . _platformStrategy . onPopState ( ( _ ) => this . _onPopState ( _ ) ) ;
1829 }
1930
2031 _onPopState ( _ ) : void { ObservableWrapper . callNext ( this . _subject , { 'url' : this . path ( ) } ) ; }
2132
22- path ( ) : string { return this . normalize ( this . _browserLocation . path ( ) ) ; }
33+ path ( ) : string { return this . normalize ( this . _platformStrategy . path ( ) ) ; }
2334
24- normalize ( url : string ) : string { return this . _stripBaseHref ( stripIndexHtml ( url ) ) ; }
35+ normalize ( url : string ) : string {
36+ return stripTrailingSlash ( this . _stripBaseHref ( stripIndexHtml ( url ) ) ) ;
37+ }
2538
2639 normalizeAbsolutely ( url : string ) : string {
27- if ( url . length > 0 && url [ 0 ] != '/' ) {
40+ if ( ! url . startsWith ( '/' ) ) {
2841 url = '/' + url ;
2942 }
30- return this . _addBaseHref ( url ) ;
43+ return stripTrailingSlash ( this . _addBaseHref ( url ) ) ;
3144 }
3245
3346 _stripBaseHref ( url : string ) : string {
34- if ( this . _baseHref . length > 0 && StringWrapper . startsWith ( url , this . _baseHref ) ) {
35- return StringWrapper . substring ( url , this . _baseHref . length ) ;
47+ if ( this . _baseHref . length > 0 && url . startsWith ( this . _baseHref ) ) {
48+ return url . substring ( this . _baseHref . length ) ;
3649 }
3750 return url ;
3851 }
3952
4053 _addBaseHref ( url : string ) : string {
41- if ( ! StringWrapper . startsWith ( url , this . _baseHref ) ) {
54+ if ( ! url . startsWith ( this . _baseHref ) ) {
4255 return this . _baseHref + url ;
4356 }
4457 return url ;
4558 }
4659
4760 go ( url : string ) : void {
4861 var finalUrl = this . normalizeAbsolutely ( url ) ;
49- this . _browserLocation . pushState ( null , '' , finalUrl ) ;
62+ this . _platformStrategy . pushState ( null , '' , finalUrl ) ;
5063 }
5164
52- forward ( ) : void { this . _browserLocation . forward ( ) ; }
65+ forward ( ) : void { this . _platformStrategy . forward ( ) ; }
5366
54- back ( ) : void { this . _browserLocation . back ( ) ; }
67+ back ( ) : void { this . _platformStrategy . back ( ) ; }
5568
5669 subscribe ( onNext , onThrow = null , onReturn = null ) : void {
5770 ObservableWrapper . subscribe ( this . _subject , onNext , onThrow , onReturn ) ;
@@ -61,12 +74,16 @@ export class Location {
6174
6275
6376function stripIndexHtml ( url : string ) : string {
64- // '/ index.html'.length == 11
65- if ( url . length > 10 && StringWrapper . substring ( url , url . length - 11 ) == '/index.html' ) {
66- return StringWrapper . substring ( url , 0 , url . length - 11 ) ;
77+ if ( / \/ i n d e x .h t m l $ / g . test ( url ) ) {
78+ // '/index.html'.length == 11
79+ return url . substring ( 0 , url . length - 11 ) ;
6780 }
68- if ( url . length > 1 && url [ url . length - 1 ] == '/' ) {
69- url = StringWrapper . substring ( url , 0 , url . length - 1 ) ;
81+ return url ;
82+ }
83+
84+ function stripTrailingSlash ( url : string ) : string {
85+ if ( / \/ $ / g. test ( url ) ) {
86+ url = url . substring ( 0 , url . length - 1 ) ;
7087 }
7188 return url ;
7289}
0 commit comments