UNPKG

@angular/common

Version:

Angular - commonly needed directives and services

303 lines (297 loc) 8.7 kB
/** * @license Angular v21.0.6 * (c) 2010-2025 Google LLC. https://angular.dev/ * License: MIT */ import * as i0 from '@angular/core'; import { inject, Injectable, InjectionToken, DOCUMENT, Optional, Inject, ɵɵinject as __inject } from '@angular/core'; import { Subject } from 'rxjs'; import { PlatformLocation } from './_platform_location-chunk.mjs'; function joinWithSlash(start, end) { if (!start) return end; if (!end) return start; if (start.endsWith('/')) { return end.startsWith('/') ? start + end.slice(1) : start + end; } return end.startsWith('/') ? start + end : `${start}/${end}`; } function stripTrailingSlash(url) { const pathEndIdx = url.search(/#|\?|$/); return url[pathEndIdx - 1] === '/' ? url.slice(0, pathEndIdx - 1) + url.slice(pathEndIdx) : url; } function normalizeQueryParams(params) { return params && params[0] !== '?' ? `?${params}` : params; } class LocationStrategy { historyGo(relativePosition) { throw new Error(ngDevMode ? 'Not implemented' : ''); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocationStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocationStrategy, providedIn: 'root', useFactory: () => inject(PathLocationStrategy) }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocationStrategy, decorators: [{ type: Injectable, args: [{ providedIn: 'root', useFactory: () => inject(PathLocationStrategy) }] }] }); const APP_BASE_HREF = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'appBaseHref' : ''); class PathLocationStrategy extends LocationStrategy { _platformLocation; _baseHref; _removeListenerFns = []; constructor(_platformLocation, href) { super(); this._platformLocation = _platformLocation; this._baseHref = href ?? this._platformLocation.getBaseHrefFromDOM() ?? inject(DOCUMENT).location?.origin ?? ''; } ngOnDestroy() { while (this._removeListenerFns.length) { this._removeListenerFns.pop()(); } } onPopState(fn) { this._removeListenerFns.push(this._platformLocation.onPopState(fn), this._platformLocation.onHashChange(fn)); } getBaseHref() { return this._baseHref; } prepareExternalUrl(internal) { return joinWithSlash(this._baseHref, internal); } path(includeHash = false) { const pathname = this._platformLocation.pathname + normalizeQueryParams(this._platformLocation.search); const hash = this._platformLocation.hash; return hash && includeHash ? `${pathname}${hash}` : pathname; } pushState(state, title, url, queryParams) { const externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams)); this._platformLocation.pushState(state, title, externalUrl); } replaceState(state, title, url, queryParams) { const externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams)); this._platformLocation.replaceState(state, title, externalUrl); } forward() { this._platformLocation.forward(); } back() { this._platformLocation.back(); } getState() { return this._platformLocation.getState(); } historyGo(relativePosition = 0) { this._platformLocation.historyGo?.(relativePosition); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: PathLocationStrategy, deps: [{ token: PlatformLocation }, { token: APP_BASE_HREF, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: PathLocationStrategy, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: PathLocationStrategy, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: PlatformLocation }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [APP_BASE_HREF] }] }] }); class Location { _subject = new Subject(); _basePath; _locationStrategy; _urlChangeListeners = []; _urlChangeSubscription = null; constructor(locationStrategy) { this._locationStrategy = locationStrategy; const baseHref = this._locationStrategy.getBaseHref(); this._basePath = _stripOrigin(stripTrailingSlash(_stripIndexHtml(baseHref))); this._locationStrategy.onPopState(ev => { this._subject.next({ 'url': this.path(true), 'pop': true, 'state': ev.state, 'type': ev.type }); }); } ngOnDestroy() { this._urlChangeSubscription?.unsubscribe(); this._urlChangeListeners = []; } path(includeHash = false) { return this.normalize(this._locationStrategy.path(includeHash)); } getState() { return this._locationStrategy.getState(); } isCurrentPathEqualTo(path, query = '') { return this.path() == this.normalize(path + normalizeQueryParams(query)); } normalize(url) { return Location.stripTrailingSlash(_stripBasePath(this._basePath, _stripIndexHtml(url))); } prepareExternalUrl(url) { if (url && url[0] !== '/') { url = '/' + url; } return this._locationStrategy.prepareExternalUrl(url); } go(path, query = '', state = null) { this._locationStrategy.pushState(state, '', path, query); this._notifyUrlChangeListeners(this.prepareExternalUrl(path + normalizeQueryParams(query)), state); } replaceState(path, query = '', state = null) { this._locationStrategy.replaceState(state, '', path, query); this._notifyUrlChangeListeners(this.prepareExternalUrl(path + normalizeQueryParams(query)), state); } forward() { this._locationStrategy.forward(); } back() { this._locationStrategy.back(); } historyGo(relativePosition = 0) { this._locationStrategy.historyGo?.(relativePosition); } onUrlChange(fn) { this._urlChangeListeners.push(fn); this._urlChangeSubscription ??= this.subscribe(v => { this._notifyUrlChangeListeners(v.url, v.state); }); return () => { const fnIndex = this._urlChangeListeners.indexOf(fn); this._urlChangeListeners.splice(fnIndex, 1); if (this._urlChangeListeners.length === 0) { this._urlChangeSubscription?.unsubscribe(); this._urlChangeSubscription = null; } }; } _notifyUrlChangeListeners(url = '', state) { this._urlChangeListeners.forEach(fn => fn(url, state)); } subscribe(onNext, onThrow, onReturn) { return this._subject.subscribe({ next: onNext, error: onThrow ?? undefined, complete: onReturn ?? undefined }); } static normalizeQueryParams = normalizeQueryParams; static joinWithSlash = joinWithSlash; static stripTrailingSlash = stripTrailingSlash; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: Location, deps: [{ token: LocationStrategy }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: Location, providedIn: 'root', useFactory: createLocation }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: Location, decorators: [{ type: Injectable, args: [{ providedIn: 'root', useFactory: createLocation }] }], ctorParameters: () => [{ type: LocationStrategy }] }); function createLocation() { return new Location(__inject(LocationStrategy)); } function _stripBasePath(basePath, url) { if (!basePath || !url.startsWith(basePath)) { return url; } const strippedUrl = url.substring(basePath.length); if (strippedUrl === '' || ['/', ';', '?', '#'].includes(strippedUrl[0])) { return strippedUrl; } return url; } function _stripIndexHtml(url) { return url.replace(/\/index.html$/, ''); } function _stripOrigin(baseHref) { const isAbsoluteUrl = new RegExp('^(https?:)?//').test(baseHref); if (isAbsoluteUrl) { const [, pathname] = baseHref.split(/\/\/[^\/]+/); return pathname; } return baseHref; } export { APP_BASE_HREF, Location, LocationStrategy, PathLocationStrategy, joinWithSlash, normalizeQueryParams }; //# sourceMappingURL=_location-chunk.mjs.map