@nativescript-community/ui-pager
Version:
A NativeScript Pager / Carousel component that allows the user to swipe left and right through pages of data.
391 lines (386 loc) • 16.7 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, TemplateRef, ViewContainerRef, Component, ViewChild, Output, ContentChild, Input, InjectionToken, Directive, Inject, Host, forwardRef, ChangeDetectionStrategy, NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { Pager, PagerItem, PagerLog, PagerError } from '@nativescript-community/ui-pager';
import { registerElement, isListLikeIterable, extractSingleViewRecursive, isInvisibleNode } from '@nativescript/angular';
import { isIOS, Trace, LayoutBase } from '@nativescript/core';
import { ObservableArray } from '@nativescript/core/data/observable-array';
import { profile } from '@nativescript/core/profiling';
const _c0 = ["loader"];
registerElement('Pager', () => Pager);
registerElement('PagerItem', () => PagerItem);
const NG_VIEW = '_ngViewRef';
class ItemContext {
$implicit;
item;
index;
even;
odd;
constructor($implicit, item, index, even, odd) {
this.$implicit = $implicit;
this.item = item;
this.index = index;
this.even = even;
this.odd = odd;
}
}
class TemplatedItemsComponent {
_iterableDiffers;
templatedItemsView;
_items;
_differ;
_templateMap;
_selectedIndex;
loader;
setupItemView = new EventEmitter();
itemTemplateQuery;
itemTemplate;
get items() {
return this._items;
}
set items(value) {
this._items = value;
let needDiffer = true;
if (value instanceof ObservableArray) {
needDiffer = false;
}
if (needDiffer && !this._differ && isListLikeIterable(value)) {
this._differ = this._iterableDiffers.find(this._items).create((_index, item) => item);
}
this.templatedItemsView.items = this._items;
}
get selectedIndex() {
return this._selectedIndex;
}
set selectedIndex(value) {
this._selectedIndex = value;
this.templatedItemsView.selectedIndex = this._selectedIndex;
}
ngAfterViewInit() {
if (!!this._selectedIndex) {
setTimeout(() => {
if (isIOS) {
this.templatedItemsView.scrollToIndexAnimated(this._selectedIndex, false);
}
this.templatedItemsView.selectedIndex = this._selectedIndex;
});
}
}
constructor(_elementRef, _iterableDiffers) {
this._iterableDiffers = _iterableDiffers;
this.templatedItemsView = _elementRef.nativeElement;
this.templatedItemsView.on('itemLoading', this.onItemLoading, this);
this.templatedItemsView.on('itemDisposing', this.onItemDisposing, this);
}
ngAfterContentInit() {
if (Trace.isEnabled()) {
PagerLog('TemplatedItemsView.ngAfterContentInit()');
}
this.setItemTemplates();
}
ngOnDestroy() {
this.templatedItemsView.off('itemLoading', this.onItemLoading, this);
this.templatedItemsView.off('itemDisposing', this.onItemDisposing, this);
}
setItemTemplates() {
if (!this.items)
return;
// The itemTemplateQuery may be changed after list items are added that contain <template> inside,
// so cache and use only the original template to avoid errors.
this.itemTemplate = this.itemTemplateQuery;
if (this._templateMap) {
if (Trace.isEnabled()) {
PagerLog('Setting templates');
}
const templates = [];
this._templateMap.forEach((value) => {
templates.push(value);
});
this.templatedItemsView.itemTemplates = templates;
}
}
registerTemplate(key, template) {
if (Trace.isEnabled()) {
PagerLog(`registerTemplate for key: ${key}`);
}
if (!this._templateMap) {
this._templateMap = new Map();
}
const keyedTemplate = {
key,
createView: this.getItemTemplateViewFactory(template)
};
this._templateMap.set(key, keyedTemplate);
}
onItemLoading(args) {
if (!args.view && !this.itemTemplate) {
return;
}
if (!this.items)
return;
const index = args.index;
const items = args.object.items;
const currentItem = typeof items.getItem === 'function' ? items.getItem(index) : items[index];
let viewRef;
if (args.view) {
if (Trace.isEnabled()) {
PagerLog(`onItemLoading: ${index} - Reusing existing view`);
}
viewRef = args.view[NG_VIEW];
// Getting angular view from original element (in cases when ProxyViewContainer
// is used NativeScript internally wraps it in a StackLayout)
if (!viewRef && args.view instanceof LayoutBase && args.view.getChildrenCount() > 0) {
viewRef = args.view.getChildAt(0)[NG_VIEW];
}
if (!viewRef && Trace.isEnabled()) {
PagerError(`ViewReference not found for item ${index}. View recycling is not working`);
}
}
if (!viewRef) {
if (Trace.isEnabled()) {
PagerLog(`onItemLoading: ${index} - Creating view from template`);
}
viewRef = this.loader.createEmbeddedView(this.itemTemplate, new ItemContext(), 0);
args.view = getItemViewRoot(viewRef);
args.view[NG_VIEW] = viewRef;
}
this.setupViewRef(viewRef, currentItem, index);
this.detectChangesOnChild(viewRef, index);
}
onItemDisposing(args) {
if (!args.view) {
return;
}
let viewRef;
if (args.view) {
if (Trace.isEnabled()) {
PagerLog(`onItemDisposing: ${args.index} - Removing angular view`);
}
viewRef = args.view[NG_VIEW];
// Getting angular view from original element (in cases when ProxyViewContainer
// is used NativeScript internally wraps it in a StackLayout)
if (!viewRef && args.view instanceof LayoutBase && args.view.getChildrenCount() > 0) {
viewRef = args.view.getChildAt(0)[NG_VIEW];
}
if (!viewRef && Trace.isEnabled()) {
PagerError(`ViewReference not found for item ${args.index}. View disposing is not working`);
}
}
if (viewRef) {
if (Trace.isEnabled()) {
PagerLog(`onItemDisposing: ${args.index} - Disposing view reference`);
}
viewRef.destroy();
}
}
setupViewRef(viewRef, data, index) {
const context = viewRef.context;
context.$implicit = data;
context.item = data;
context.index = index;
context.even = index % 2 === 0;
context.odd = !context.even;
this.setupItemView.next({
view: viewRef,
data,
index,
context
});
}
getItemTemplateViewFactory(template) {
return () => {
const viewRef = this.loader.createEmbeddedView(template, new ItemContext(), 0);
const resultView = getItemViewRoot(viewRef);
resultView[NG_VIEW] = viewRef;
return resultView;
};
}
detectChangesOnChild(viewRef, index) {
if (Trace.isEnabled()) {
PagerLog(`Manually detect changes in child: ${index}`);
}
viewRef.markForCheck();
viewRef.detectChanges();
}
ngDoCheck() {
if (this._differ) {
if (Trace.isEnabled()) {
PagerLog('ngDoCheck() - execute differ');
}
const changes = this._differ.diff(this._items);
if (changes) {
if (Trace.isEnabled()) {
PagerLog('ngDoCheck() - refresh');
}
this.templatedItemsView.refresh();
}
}
}
static ɵfac = function TemplatedItemsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TemplatedItemsComponent)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.IterableDiffers)); };
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TemplatedItemsComponent, selectors: [["ng-component"]], contentQueries: function TemplatedItemsComponent_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
i0.ɵɵcontentQuery(dirIndex, TemplateRef, 5);
} if (rf & 2) {
let _t;
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.itemTemplateQuery = _t.first);
} }, viewQuery: function TemplatedItemsComponent_Query(rf, ctx) { if (rf & 1) {
i0.ɵɵviewQuery(_c0, 5, ViewContainerRef);
} if (rf & 2) {
let _t;
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.loader = _t.first);
} }, inputs: { items: "items", selectedIndex: "selectedIndex" }, outputs: { setupItemView: "setupItemView" }, decls: 0, vars: 0, template: function TemplatedItemsComponent_Template(rf, ctx) { }, encapsulation: 2 });
}
__decorate([
profile
], TemplatedItemsComponent.prototype, "onItemLoading", null);
__decorate([
profile
], TemplatedItemsComponent.prototype, "onItemDisposing", null);
__decorate([
profile
], TemplatedItemsComponent.prototype, "detectChangesOnChild", null);
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TemplatedItemsComponent, [{
type: Component,
args: [{
template: ''
}]
}], () => [{ type: i0.ElementRef }, { type: i0.IterableDiffers }], { loader: [{
type: ViewChild,
args: ['loader', { read: ViewContainerRef, static: false }]
}], setupItemView: [{
type: Output
}], itemTemplateQuery: [{
type: ContentChild,
args: [TemplateRef, { static: false }]
}], items: [{
type: Input
}], selectedIndex: [{
type: Input
}], onItemLoading: [], onItemDisposing: [], detectChangesOnChild: [] }); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TemplatedItemsComponent, { className: "TemplatedItemsComponent", filePath: "pager-items-comp.ts", lineNumber: 60 }); })();
function getItemViewRoot(viewRef, rootLocator = extractSingleViewRecursive) {
return rootLocator(viewRef.rootNodes, 0);
}
const TEMPLATED_ITEMS_COMPONENT = new InjectionToken('TemplatedItemsComponent');
class PagerItemDirective {
templateRef;
owner;
viewContainer;
item;
constructor(templateRef, owner, viewContainer) {
this.templateRef = templateRef;
this.owner = owner;
this.viewContainer = viewContainer;
}
ensureItem() {
if (!this.item) {
this.item = new PagerItem();
}
}
applyConfig() {
this.ensureItem();
}
ngOnInit() {
this.applyConfig();
const viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
// Filter out text nodes and comments
const realViews = viewRef.rootNodes.filter((node) => !isInvisibleNode(node));
if (realViews.length > 0) {
const view = realViews[0];
this.item.addChild(view);
this.owner.nativeElement._addChildFromBuilder('PagerItem', this.item);
}
}
static ɵfac = function PagerItemDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PagerItemDirective)(i0.ɵɵdirectiveInject(i0.TemplateRef), i0.ɵɵdirectiveInject(TEMPLATED_ITEMS_COMPONENT, 1), i0.ɵɵdirectiveInject(i0.ViewContainerRef)); };
static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: PagerItemDirective, selectors: [["", "pagerItem", ""]] });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PagerItemDirective, [{
type: Directive,
args: [{
selector: '[pagerItem]'
}]
}], () => [{ type: i0.TemplateRef }, { type: TemplatedItemsComponent, decorators: [{
type: Inject,
args: [TEMPLATED_ITEMS_COMPONENT]
}, {
type: Host
}] }, { type: i0.ViewContainerRef }], null); })();
class TemplateKeyDirective {
templateRef;
comp;
constructor(templateRef, comp) {
this.templateRef = templateRef;
this.comp = comp;
}
set pagerTemplateKey(value) {
if (this.comp && this.templateRef) {
this.comp.registerTemplate(value, this.templateRef);
}
}
static ɵfac = function TemplateKeyDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TemplateKeyDirective)(i0.ɵɵdirectiveInject(i0.TemplateRef), i0.ɵɵdirectiveInject(TEMPLATED_ITEMS_COMPONENT, 1)); };
static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: TemplateKeyDirective, selectors: [["", "pagerTemplateKey", ""]], inputs: { pagerTemplateKey: "pagerTemplateKey" } });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TemplateKeyDirective, [{
type: Directive,
args: [{ selector: '[pagerTemplateKey]' }]
}], () => [{ type: i0.TemplateRef }, { type: TemplatedItemsComponent, decorators: [{
type: Inject,
args: [TEMPLATED_ITEMS_COMPONENT]
}, {
type: Host
}] }], { pagerTemplateKey: [{
type: Input
}] }); })();
class PagerComponent extends TemplatedItemsComponent {
get nativeElement() {
return this.templatedItemsView;
}
constructor(_elementRef, _iterableDiffers) {
super(_elementRef, _iterableDiffers);
}
static ɵfac = function PagerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PagerComponent)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.IterableDiffers)); };
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PagerComponent, selectors: [["Pager"]], features: [i0.ɵɵProvidersFeature([
{
provide: TEMPLATED_ITEMS_COMPONENT,
useExisting: forwardRef(() => PagerComponent)
}
]), i0.ɵɵInheritDefinitionFeature], decls: 3, vars: 0, consts: [["loader", ""]], template: function PagerComponent_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵelementStart(0, "DetachedContainer");
i0.ɵɵelement(1, "Placeholder", null, 0);
i0.ɵɵelementEnd();
} }, encapsulation: 2, changeDetection: 0 });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PagerComponent, [{
type: Component,
args: [{
selector: 'Pager',
template: ` <DetachedContainer>
<Placeholder #loader></Placeholder>
</DetachedContainer>`,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: TEMPLATED_ITEMS_COMPONENT,
useExisting: forwardRef(() => PagerComponent)
}
]
}]
}], () => [{ type: i0.ElementRef }, { type: i0.IterableDiffers }], null); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PagerComponent, { className: "PagerComponent", filePath: "index.ts", lineNumber: 21 }); })();
class PagerModule {
static ɵfac = function PagerModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PagerModule)(); };
static ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: PagerModule });
static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({});
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PagerModule, [{
type: NgModule,
args: [{
declarations: [PagerComponent, TemplateKeyDirective, PagerItemDirective],
exports: [PagerComponent, TemplateKeyDirective, PagerItemDirective],
schemas: [NO_ERRORS_SCHEMA]
}]
}], null, null); })();
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(PagerModule, { declarations: [PagerComponent, TemplateKeyDirective, PagerItemDirective], exports: [PagerComponent, TemplateKeyDirective, PagerItemDirective] }); })();
/**
* Generated bundle index. Do not edit.
*/
export { PagerComponent, PagerItemDirective, PagerModule, TemplateKeyDirective, TemplatedItemsComponent };
//# sourceMappingURL=nativescript-community-ui-pager-angular.mjs.map