UNPKG

@pshurygin/ngx-quicklink

Version:
359 lines (344 loc) 15.1 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@angular/router'), require('rxjs')) : typeof define === 'function' && define.amd ? define('@pshurygin/ngx-quicklink', ['exports', '@angular/core', '@angular/router', 'rxjs'], factory) : (global = global || self, factory((global.pshurygin = global.pshurygin || {}, global.pshurygin['ngx-quicklink'] = {}), global.ng.core, global.ng.router, global.rxjs)); }(this, function (exports, core, router, rxjs) { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ function __decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function __param(paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } } function __metadata(metadataKey, metadataValue) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); } // Using a global registry so we can keep it populated across lazy-loaded // modules with different parent injectors which create instance of the registry. var globalRegistry = []; var PrefetchRegistry = /** @class */ (function () { function PrefetchRegistry(router) { this.router = router; this.trees = globalRegistry; } PrefetchRegistry.prototype.add = function (tree) { this.trees.push(tree); }; PrefetchRegistry.prototype.remove = function (tree) { this.trees.splice(this.trees.indexOf(tree), 1); }; PrefetchRegistry.prototype.shouldPrefetch = function (url) { var tree = this.router.parseUrl(url); return this.trees.some(containsTree.bind(null, tree)); }; PrefetchRegistry = __decorate([ core.Injectable(), __metadata("design:paramtypes", [router.Router]) ], PrefetchRegistry); return PrefetchRegistry; }()); function containsQueryParams(container, containee) { // TODO: This does not handle array params correctly. return (Object.keys(containee).length <= Object.keys(container).length && Object.keys(containee).every(function (key) { return containee[key] === container[key]; })); } function containsTree(containee, container) { return (containsQueryParams(container.queryParams, containee.queryParams) && containsSegmentGroup(container.root, containee.root, containee.root.segments)); } function containsSegmentGroup(container, containee, containeePaths) { if (container.segments.length > containeePaths.length) { var current = container.segments.slice(0, containeePaths.length); if (!equalPath(current, containeePaths)) return false; if (containee.hasChildren()) return false; return true; } else if (container.segments.length === containeePaths.length) { if (!equalPath(container.segments, containeePaths)) return false; if (!containee.hasChildren()) return true; for (var c in containee.children) { if (!container.children[c]) break; if (containsSegmentGroup(container.children[c], containee.children[c], containee.children[c].segments)) return true; } return false; } else { var current = containeePaths.slice(0, container.segments.length); var next = containeePaths.slice(container.segments.length); if (!equalPath(container.segments, current)) return false; if (!container.children[router.PRIMARY_OUTLET]) return false; return containsSegmentGroup(container.children[router.PRIMARY_OUTLET], containee, next); } } function equalPath(as, bs) { if (as.length !== bs.length) return false; return as.every(function (a, i) { return a.path === bs[i].path || a.path.startsWith(':') || bs[i].path.startsWith(':'); }); } var ɵ0 = function (cb) { var start = Date.now(); return setTimeout(function () { cb({ didTimeout: false, timeRemaining: function () { return Math.max(0, 50 - (Date.now() - start)); } }); }, 1); }, ɵ1 = function () { }; var requestIdleCallback = typeof window !== 'undefined' ? window.requestIdleCallback || ɵ0 : ɵ1; var observerSupported = function () { return typeof window !== 'undefined' ? !!window.IntersectionObserver : false; }; var LinkHandler = new core.InjectionToken('LinkHandler'); var ObservableLinkHandler = /** @class */ (function () { function ObservableLinkHandler(loader, queue, ngZone) { var _this = this; this.loader = loader; this.queue = queue; this.ngZone = ngZone; this.elementLink = new Map(); this.observer = observerSupported() ? new IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (entry.isIntersecting) { var link = entry.target; var routerLink_1 = _this.elementLink.get(link); if (!routerLink_1 || !routerLink_1.urlTree) return; _this.queue.add(routerLink_1.urlTree); _this.observer.unobserve(link); requestIdleCallback(function () { _this.loader.preload().subscribe(function () { return void 0; }); _this.queue.remove(routerLink_1.urlTree); }); } }); }) : null; } ObservableLinkHandler.prototype.register = function (el) { var _this = this; this.elementLink.set(el.element, el); this.ngZone.runOutsideAngular(function () { _this.observer.observe(el.element); }); }; // First call to unregister will not hit this. ObservableLinkHandler.prototype.unregister = function (el) { if (this.elementLink.has(el.element)) { this.observer.unobserve(el.element); this.elementLink.delete(el.element); } }; ObservableLinkHandler.prototype.supported = function () { return observerSupported(); }; ObservableLinkHandler = __decorate([ core.Injectable(), __metadata("design:paramtypes", [router.RouterPreloader, PrefetchRegistry, core.NgZone]) ], ObservableLinkHandler); return ObservableLinkHandler; }()); var PreloadLinkHandler = /** @class */ (function () { function PreloadLinkHandler(loader, queue) { this.loader = loader; this.queue = queue; } PreloadLinkHandler.prototype.register = function (el) { var _this = this; this.queue.add(el.urlTree); requestIdleCallback(function () { return _this.loader.preload().subscribe(function () { return void 0; }); }); }; PreloadLinkHandler.prototype.unregister = function (_) { }; PreloadLinkHandler.prototype.supported = function () { return true; }; PreloadLinkHandler = __decorate([ core.Injectable(), __metadata("design:paramtypes", [router.RouterPreloader, PrefetchRegistry]) ], PreloadLinkHandler); return PreloadLinkHandler; }()); var LinkDirective = /** @class */ (function () { function LinkDirective(linkHandlers, el, link, linkWithHref) { this.linkHandlers = linkHandlers; this.el = el; this.linkHandler = this.linkHandlers.filter(function (h) { return h.supported(); }).shift(); this.rl = link || linkWithHref; } LinkDirective.prototype.ngOnChanges = function (c) { if (c.routerLink) { this.linkHandler.unregister(this); this.linkHandler.register(this); } }; LinkDirective.prototype.ngOnDestroy = function () { this.linkHandler.unregister(this); }; Object.defineProperty(LinkDirective.prototype, "element", { get: function () { return this.el.nativeElement; }, enumerable: true, configurable: true }); Object.defineProperty(LinkDirective.prototype, "urlTree", { get: function () { return this.rl.urlTree; }, enumerable: true, configurable: true }); __decorate([ core.Input(), __metadata("design:type", Object) ], LinkDirective.prototype, "routerLink", void 0); LinkDirective = __decorate([ core.Directive({ selector: '[routerLink]' }), __param(0, core.Inject(LinkHandler)), __param(2, core.Optional()), __param(3, core.Optional()), __metadata("design:paramtypes", [Array, core.ElementRef, router.RouterLink, router.RouterLinkWithHref]) ], LinkDirective); return LinkDirective; }()); var QuicklinkStrategy = /** @class */ (function () { function QuicklinkStrategy(queue, router) { this.queue = queue; this.router = router; this.loading = new Set(); } QuicklinkStrategy.prototype.preload = function (route, load) { if (this.loading.has(route)) { // Don't preload the same route twice return rxjs.EMPTY; } var conn = typeof window !== 'undefined' ? navigator.connection : undefined; if (conn) { // Don't preload if the user is on 2G. or if Save-Data is enabled.. if ((conn.effectiveType || '').includes('2g') || conn.saveData) return rxjs.EMPTY; } // Prevent from preloading if (route.data && route.data.preload === false) { return rxjs.EMPTY; } var fullPath = findPath(this.router.config, route); if (this.queue.shouldPrefetch(fullPath)) { this.loading.add(route); return load(); } return rxjs.EMPTY; }; QuicklinkStrategy = __decorate([ core.Injectable(), __metadata("design:paramtypes", [PrefetchRegistry, router.Router]) ], QuicklinkStrategy); return QuicklinkStrategy; }()); var findPath = function (config, route) { config = config.slice(); var parent = new Map(); var visited = new Set(); var _loop_1 = function () { var el = config.shift(); visited.add(el); if (el === route) return "break"; var children = el.children || []; var current_1 = el._loadedConfig; if (current_1 && current_1.routes) { children = children.concat(current_1.routes); } children.forEach(function (r) { if (visited.has(r)) return; parent.set(r, el); config.push(r); }); }; while (config.length) { var state_1 = _loop_1(); if (state_1 === "break") break; } var path = ''; var current = route; while (current) { if (isPrimaryRoute(current)) { path = "/" + current.path + path; } else { path = "/(" + current.outlet + ":" + current.path + path + ")"; } current = parent.get(current); } return path; }; function isPrimaryRoute(route) { return route.outlet === router.PRIMARY_OUTLET || !route.outlet; } var QuicklinkModule = /** @class */ (function () { function QuicklinkModule() { } QuicklinkModule = __decorate([ core.NgModule({ declarations: [LinkDirective], providers: [ { provide: LinkHandler, useClass: ObservableLinkHandler, multi: true }, { provide: LinkHandler, useClass: PreloadLinkHandler, multi: true }, PrefetchRegistry, QuicklinkStrategy ], exports: [LinkDirective] }) ], QuicklinkModule); return QuicklinkModule; }()); exports.QuicklinkModule = QuicklinkModule; exports.QuicklinkStrategy = QuicklinkStrategy; exports.ɵa = LinkHandler; exports.ɵb = ObservableLinkHandler; exports.ɵc = PreloadLinkHandler; exports.ɵe = PrefetchRegistry; exports.ɵɵLinkDirective = LinkDirective; Object.defineProperty(exports, '__esModule', { value: true }); })); //# sourceMappingURL=pshurygin-ngx-quicklink.umd.js.map