mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00

* 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
176 lines
5.7 KiB
TypeScript
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);
|