Files
Alexander Vakrilov cc97a16800 feat: Scoped Packages (#7911)
* chore: move tns-core-modules to nativescript-core

* chore: preparing compat generate script

* chore: add missing definitions

* chore: no need for http-request to be private

* chore: packages chore

* test: generate tests for tns-core-modules

* chore: add anroid module for consistency

* chore: add .npmignore

* chore: added privateModulesWhitelist

* chore(webpack): added bundle-entry-points

* chore: scripts

* chore: tests changed to use @ns/core

* test: add scoped-packages test project

* test: fix types

* test: update test project

* chore: build scripts

* chore: update build script

* chore: npm scripts cleanup

* chore: make the compat pgk work with old wp config

* test: generate diff friendly tests

* chore: create barrel exports

* chore: move files after rebase

* chore: typedoc config

* chore: compat mode

* chore: review of barrels

* chore: remove tns-core-modules import after rebase

* chore: dev workflow setup

* chore: update developer-workflow

* docs: experiment with API extractor

* chore: api-extractor and barrel exports

* chore: api-extractor configs

* chore: generate d.ts rollup with api-extractor

* refactor: move methods inside Frame

* chore: fic tests to use Frame static methods

* refactor: create Builder class

* refactor: use Builder class in tests

* refactor: include Style in ui barrel

* chore: separate compat build script

* chore: fix tslint errors

* chore: update NATIVESCRIPT_CORE_ARGS

* chore: fix compat pack

* chore: fix ui-test-app build with linked modules

* chore: Application, ApplicationSettings, Connectivity and Http

* chore: export Trace, Profiling and Utils

* refactor: Static create methods for ImageSource

* chore: fix deprecated usages of ImageSource

* chore: move Span and FormattedString to ui

* chore: add events-args and ImageSource to index files

* chore: check for CLI >= 6.2 when building for IOS

* chore: update travis build

* chore: copy Pod file to compat package

* chore: update error msg ui-tests-app

* refactor: Apply suggestions from code review

Co-Authored-By: Martin Yankov <m.i.yankov@gmail.com>

* chore: typings and refs

* chore: add missing d.ts files for public API

* chore: adress code review FB

* chore: update api-report

* chore: dev-workflow for other apps

* chore: api update

* chore: update api-report
2019-10-17 00:45:33 +03:00

176 lines
5.7 KiB
TypeScript

import { Repeater as RepeaterDefinition, ItemsSource } from ".";
import { Label } from "../label";
import { LayoutBase, CustomLayoutView, View, Template, Property, layout, CSSType } from "../layouts/layout-base";
import { StackLayout } from "../layouts/stack-layout";
import { ObservableArray, ChangedData } from "../../data/observable-array";
import { addWeakEventListener, removeWeakEventListener } from "../core/weak-event-listener";
import { Builder } from "../builder";
import { profile } from "../../profiling";
export * from "../layouts/layout-base";
export module knownTemplates {
export const itemTemplate = "itemTemplate";
}
@CSSType("Repeater")
export class Repeater extends CustomLayoutView implements RepeaterDefinition {
private _isDirty = false;
public ios;
public android;
constructor() {
super();
// TODO: Do we need this as property?
this.itemsLayout = new StackLayout();
}
public items: any[] | ItemsSource;
public itemTemplate: string | Template;
public itemsLayout: LayoutBase;
@profile
public onLoaded() {
if (this._isDirty) {
this.refresh();
}
super.onLoaded();
}
public _requestRefresh() {
this._isDirty = true;
if (this.isLoaded) {
this.refresh();
}
}
public refresh() {
if (this.itemsLayout) {
this.itemsLayout.removeChildren();
}
if (!this.items) {
return;
}
const length = this.items.length;
for (let i = 0; i < length; i++) {
const viewToAdd = this.itemTemplate ? Builder.parse(this.itemTemplate, this) : this._getDefaultItemContent(i);
const dataItem = this._getDataItem(i);
viewToAdd.bindingContext = dataItem;
this.itemsLayout.addChild(viewToAdd);
}
this._isDirty = false;
}
public _onItemsChanged(data: ChangedData<any>) {
// TODO: use the event args and optimize this code by remove/add single items instead of full rebuild.
this._requestRefresh();
}
public _getDefaultItemContent(index: number): View {
const lbl = new Label();
lbl.bind({
targetProperty: "text",
sourceProperty: "$value"
});
return lbl;
}
private _getDataItem(index: number): any {
let items = <ItemsSource>this.items;
return items.getItem ? items.getItem(index) : this.items[index];
}
get _childrenCount(): number {
return this.itemsLayout ? 1 : 0;
}
public eachChildView(callback: (child: View) => boolean) {
if (this.itemsLayout) {
callback(this.itemsLayout);
}
}
public onLayout(left: number, top: number, right: number, bottom: number): void {
const insets = this.getSafeAreaInsets();
const paddingLeft = this.effectiveBorderLeftWidth + this.effectivePaddingLeft + insets.left;
const paddingTop = this.effectiveBorderTopWidth + this.effectivePaddingTop + insets.top;
const paddingRight = this.effectiveBorderRightWidth + this.effectivePaddingRight + insets.right;
const paddingBottom = this.effectiveBorderBottomWidth + this.effectivePaddingBottom + insets.bottom;
const childLeft = paddingLeft;
const childTop = paddingTop;
const childRight = right - left - paddingRight;
const childBottom = bottom - top - paddingBottom;
View.layoutChild(this, this.itemsLayout, childLeft, childTop, childRight, childBottom);
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
const result = View.measureChild(this, this.itemsLayout, widthMeasureSpec, heightMeasureSpec);
const width = layout.getMeasureSpecSize(widthMeasureSpec);
const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);
const height = layout.getMeasureSpecSize(heightMeasureSpec);
const heightMode = layout.getMeasureSpecMode(heightMeasureSpec);
const widthAndState = View.resolveSizeAndState(result.measuredWidth, width, widthMode, 0);
const heightAndState = View.resolveSizeAndState(result.measuredHeight, height, heightMode, 0);
this.setMeasuredDimension(widthAndState, heightAndState);
}
}
Repeater.prototype.recycleNativeView = "auto";
/**
* Represents the item template property of each ListView instance.
*/
export const itemTemplateProperty = new Property<Repeater, string | Template>({
name: "itemTemplate", affectsLayout: true, valueChanged: (target) => {
target._requestRefresh();
}
});
itemTemplateProperty.register(Repeater);
/**
* Represents the property backing the items property of each ListView instance.
*/
export const itemsProperty = new Property<Repeater, any[] | ItemsSource>({
name: "items", affectsLayout: true, valueChanged: (target, oldValue, newValue) => {
if (oldValue instanceof ObservableArray) {
removeWeakEventListener(oldValue, ObservableArray.changeEvent, target._onItemsChanged, target);
}
if (newValue instanceof ObservableArray) {
addWeakEventListener(newValue, ObservableArray.changeEvent, target._onItemsChanged, target);
}
target._requestRefresh();
}
});
itemsProperty.register(Repeater);
export const itemsLayoutProperty = new Property<Repeater, LayoutBase>({
name: "itemsLayout", affectsLayout: true, valueChanged: (target, oldValue, newValue) => {
if (oldValue) {
target._removeView(oldValue);
oldValue.removeChildren();
}
if (newValue) {
target._addView(newValue);
}
target._requestRefresh();
}
});
itemsLayoutProperty.register(Repeater);