chore: format

This commit is contained in:
Nathan Walker
2020-07-05 14:57:06 -07:00
parent 8f2900ad0b
commit da3c0b973d
379 changed files with 71587 additions and 54582 deletions

View File

@@ -1,7 +1,8 @@
import { ItemEventData, ItemsSource } from ".";
import {
ListViewBase,
separatorColorProperty, itemTemplatesProperty
ListViewBase,
separatorColorProperty,
itemTemplatesProperty,
} from "./list-view-common";
import { View, KeyedTemplate } from "../core/view";
import { unsetValue } from "../core/properties";
@@ -20,332 +21,392 @@ const LOADMOREITEMS = ListViewBase.loadMoreItemsEvent;
const ITEMTAP = ListViewBase.itemTapEvent;
interface ItemClickListener {
new(owner: ListView): android.widget.AdapterView.OnItemClickListener;
new (owner: ListView): android.widget.AdapterView.OnItemClickListener;
}
let ItemClickListener: ItemClickListener;
function initializeItemClickListener(): void {
if (ItemClickListener) {
return;
}
if (ItemClickListener) {
return;
}
@Interfaces([android.widget.AdapterView.OnItemClickListener])
class ItemClickListenerImpl extends java.lang.Object implements android.widget.AdapterView.OnItemClickListener {
constructor(public owner: ListView) {
super();
@Interfaces([android.widget.AdapterView.OnItemClickListener])
class ItemClickListenerImpl extends java.lang.Object
implements android.widget.AdapterView.OnItemClickListener {
constructor(public owner: ListView) {
super();
return global.__native(this);
}
return global.__native(this);
}
onItemClick<T extends android.widget.Adapter>(parent: android.widget.AdapterView<T>, convertView: android.view.View, index: number, id: number) {
const owner = this.owner;
const view = owner._realizedTemplates.get(owner._getItemTemplate(index).key).get(convertView);
owner.notify({ eventName: ITEMTAP, object: owner, index: index, view: view });
}
}
onItemClick<T extends android.widget.Adapter>(
parent: android.widget.AdapterView<T>,
convertView: android.view.View,
index: number,
id: number
) {
const owner = this.owner;
const view = owner._realizedTemplates
.get(owner._getItemTemplate(index).key)
.get(convertView);
owner.notify({
eventName: ITEMTAP,
object: owner,
index: index,
view: view,
});
}
}
ItemClickListener = ItemClickListenerImpl;
ItemClickListener = ItemClickListenerImpl;
}
export class ListView extends ListViewBase {
nativeViewProtected: android.widget.ListView;
private _androidViewId: number = -1;
nativeViewProtected: android.widget.ListView;
private _androidViewId: number = -1;
public _realizedItems = new Map<android.view.View, View>();
public _realizedTemplates = new Map<string, Map<android.view.View, View>>();
public _realizedItems = new Map<android.view.View, View>();
public _realizedTemplates = new Map<string, Map<android.view.View, View>>();
@profile()
public createNativeView() {
const listView = new android.widget.ListView(this._context);
listView.setDescendantFocusability(android.view.ViewGroup.FOCUS_AFTER_DESCENDANTS);
@profile()
public createNativeView() {
const listView = new android.widget.ListView(this._context);
listView.setDescendantFocusability(
android.view.ViewGroup.FOCUS_AFTER_DESCENDANTS
);
// Fixes issue with black random black items when scrolling
listView.setCacheColorHint(android.graphics.Color.TRANSPARENT);
// Fixes issue with black random black items when scrolling
listView.setCacheColorHint(android.graphics.Color.TRANSPARENT);
return listView;
}
return listView;
}
public initNativeView(): void {
super.initNativeView();
this.updateEffectiveRowHeight();
public initNativeView(): void {
super.initNativeView();
this.updateEffectiveRowHeight();
const nativeView = this.nativeViewProtected;
initializeItemClickListener();
ensureListViewAdapterClass();
const adapter = new ListViewAdapterClass(this);
nativeView.setAdapter(adapter);
(<any>nativeView).adapter = adapter;
const nativeView = this.nativeViewProtected;
initializeItemClickListener();
ensureListViewAdapterClass();
const adapter = new ListViewAdapterClass(this);
nativeView.setAdapter(adapter);
(<any>nativeView).adapter = adapter;
const itemClickListener = new ItemClickListener(this);
nativeView.setOnItemClickListener(itemClickListener);
(<any>nativeView).itemClickListener = itemClickListener;
const itemClickListener = new ItemClickListener(this);
nativeView.setOnItemClickListener(itemClickListener);
(<any>nativeView).itemClickListener = itemClickListener;
if (this._androidViewId < 0) {
this._androidViewId = android.view.View.generateViewId();
}
nativeView.setId(this._androidViewId);
}
if (this._androidViewId < 0) {
this._androidViewId = android.view.View.generateViewId();
}
nativeView.setId(this._androidViewId);
}
public disposeNativeView() {
const nativeView = this.nativeViewProtected;
nativeView.setAdapter(null);
(<any>nativeView).itemClickListener.owner = null;
(<any>nativeView).adapter.owner = null;
this.clearRealizedCells();
super.disposeNativeView();
}
public disposeNativeView() {
const nativeView = this.nativeViewProtected;
nativeView.setAdapter(null);
(<any>nativeView).itemClickListener.owner = null;
(<any>nativeView).adapter.owner = null;
this.clearRealizedCells();
super.disposeNativeView();
}
public onLoaded() {
super.onLoaded();
// Without this call itemClick won't be fired... :(
this.requestLayout();
}
public onLoaded() {
super.onLoaded();
// Without this call itemClick won't be fired... :(
this.requestLayout();
}
public refresh() {
const nativeView = this.nativeViewProtected;
if (!nativeView || !nativeView.getAdapter()) {
return;
}
public refresh() {
const nativeView = this.nativeViewProtected;
if (!nativeView || !nativeView.getAdapter()) {
return;
}
// clear bindingContext when it is not observable because otherwise bindings to items won't reevaluate
this._realizedItems.forEach((view, nativeView) => {
if (!(view.bindingContext instanceof Observable)) {
view.bindingContext = null;
}
});
// clear bindingContext when it is not observable because otherwise bindings to items won't reevaluate
this._realizedItems.forEach((view, nativeView) => {
if (!(view.bindingContext instanceof Observable)) {
view.bindingContext = null;
}
});
(<android.widget.BaseAdapter>nativeView.getAdapter()).notifyDataSetChanged();
}
(<android.widget.BaseAdapter>(
nativeView.getAdapter()
)).notifyDataSetChanged();
}
public scrollToIndex(index: number) {
const nativeView = this.nativeViewProtected;
if (nativeView) {
nativeView.setSelection(index);
}
}
public scrollToIndex(index: number) {
const nativeView = this.nativeViewProtected;
if (nativeView) {
nativeView.setSelection(index);
}
}
public scrollToIndexAnimated(index: number) {
const nativeView = this.nativeViewProtected;
if (nativeView) {
nativeView.smoothScrollToPosition(index);
}
}
public scrollToIndexAnimated(index: number) {
const nativeView = this.nativeViewProtected;
if (nativeView) {
nativeView.smoothScrollToPosition(index);
}
}
get _childrenCount(): number {
return this._realizedItems.size;
}
get _childrenCount(): number {
return this._realizedItems.size;
}
public eachChildView(callback: (child: View) => boolean): void {
this._realizedItems.forEach((view, nativeView) => {
if (view.parent instanceof ListView) {
callback(view);
}
else {
// in some cases (like item is unloaded from another place (like angular) view.parent becomes undefined)
if (view.parent) {
callback(<View>view.parent);
}
}
});
}
public eachChildView(callback: (child: View) => boolean): void {
this._realizedItems.forEach((view, nativeView) => {
if (view.parent instanceof ListView) {
callback(view);
} else {
// in some cases (like item is unloaded from another place (like angular) view.parent becomes undefined)
if (view.parent) {
callback(<View>view.parent);
}
}
});
}
public _dumpRealizedTemplates() {
console.log(`Realized Templates:`);
this._realizedTemplates.forEach((value, index) => {
console.log(`\t${index}:`);
value.forEach((value, index) => {
console.log(`\t\t${index.hashCode()}: ${value}`);
});
});
console.log(`Realized Items Size: ${this._realizedItems.size}`);
}
public _dumpRealizedTemplates() {
console.log(`Realized Templates:`);
this._realizedTemplates.forEach((value, index) => {
console.log(`\t${index}:`);
value.forEach((value, index) => {
console.log(`\t\t${index.hashCode()}: ${value}`);
});
});
console.log(`Realized Items Size: ${this._realizedItems.size}`);
}
private clearRealizedCells(): void {
// clear the cache
this._realizedItems.forEach((view, nativeView) => {
if (view.parent) {
// This is to clear the StackLayout that is used to wrap non LayoutBase & ProxyViewContainer instances.
if (!(view.parent instanceof ListView)) {
this._removeView(view.parent);
}
view.parent._removeView(view);
}
});
private clearRealizedCells(): void {
// clear the cache
this._realizedItems.forEach((view, nativeView) => {
if (view.parent) {
// This is to clear the StackLayout that is used to wrap non LayoutBase & ProxyViewContainer instances.
if (!(view.parent instanceof ListView)) {
this._removeView(view.parent);
}
view.parent._removeView(view);
}
});
this._realizedItems.clear();
this._realizedTemplates.clear();
}
this._realizedItems.clear();
this._realizedTemplates.clear();
}
public isItemAtIndexVisible(index: number): boolean {
let nativeView = this.nativeViewProtected;
const start = nativeView.getFirstVisiblePosition();
const end = nativeView.getLastVisiblePosition();
public isItemAtIndexVisible(index: number): boolean {
let nativeView = this.nativeViewProtected;
const start = nativeView.getFirstVisiblePosition();
const end = nativeView.getLastVisiblePosition();
return (index >= start && index <= end);
}
return index >= start && index <= end;
}
[separatorColorProperty.getDefault](): { dividerHeight: number, divider: android.graphics.drawable.Drawable } {
let nativeView = this.nativeViewProtected;
[separatorColorProperty.getDefault](): {
dividerHeight: number;
divider: android.graphics.drawable.Drawable;
} {
let nativeView = this.nativeViewProtected;
return {
dividerHeight: nativeView.getDividerHeight(),
divider: nativeView.getDivider()
};
}
[separatorColorProperty.setNative](value: Color | { dividerHeight: number, divider: android.graphics.drawable.Drawable }) {
let nativeView = this.nativeViewProtected;
if (value instanceof Color) {
nativeView.setDivider(new android.graphics.drawable.ColorDrawable(value.android));
nativeView.setDividerHeight(1);
} else {
nativeView.setDivider(value.divider);
nativeView.setDividerHeight(value.dividerHeight);
}
}
return {
dividerHeight: nativeView.getDividerHeight(),
divider: nativeView.getDivider(),
};
}
[separatorColorProperty.setNative](
value:
| Color
| {
dividerHeight: number;
divider: android.graphics.drawable.Drawable;
}
) {
let nativeView = this.nativeViewProtected;
if (value instanceof Color) {
nativeView.setDivider(
new android.graphics.drawable.ColorDrawable(value.android)
);
nativeView.setDividerHeight(1);
} else {
nativeView.setDivider(value.divider);
nativeView.setDividerHeight(value.dividerHeight);
}
}
[itemTemplatesProperty.getDefault](): KeyedTemplate[] {
return null;
}
[itemTemplatesProperty.setNative](value: KeyedTemplate[]) {
this._itemTemplatesInternal = new Array<KeyedTemplate>(this._defaultTemplate);
if (value) {
this._itemTemplatesInternal = this._itemTemplatesInternal.concat(value);
}
[itemTemplatesProperty.getDefault](): KeyedTemplate[] {
return null;
}
[itemTemplatesProperty.setNative](value: KeyedTemplate[]) {
this._itemTemplatesInternal = new Array<KeyedTemplate>(
this._defaultTemplate
);
if (value) {
this._itemTemplatesInternal = this._itemTemplatesInternal.concat(
value
);
}
this.nativeViewProtected.setAdapter(new ListViewAdapterClass(this));
this.refresh();
}
this.nativeViewProtected.setAdapter(new ListViewAdapterClass(this));
this.refresh();
}
}
let ListViewAdapterClass;
function ensureListViewAdapterClass() {
if (ListViewAdapterClass) {
return;
}
if (ListViewAdapterClass) {
return;
}
class ListViewAdapter extends android.widget.BaseAdapter {
constructor(public owner: ListView) {
super();
class ListViewAdapter extends android.widget.BaseAdapter {
constructor(public owner: ListView) {
super();
return global.__native(this);
}
return global.__native(this);
}
public getCount() {
return this.owner && this.owner.items && this.owner.items.length ? this.owner.items.length : 0;
}
public getCount() {
return this.owner && this.owner.items && this.owner.items.length
? this.owner.items.length
: 0;
}
public getItem(i: number) {
if (this.owner && this.owner.items && i < this.owner.items.length) {
let getItem = (<ItemsSource>this.owner.items).getItem;
public getItem(i: number) {
if (this.owner && this.owner.items && i < this.owner.items.length) {
let getItem = (<ItemsSource>this.owner.items).getItem;
return getItem ? getItem.call(this.owner.items, i) : this.owner.items[i];
}
return getItem
? getItem.call(this.owner.items, i)
: this.owner.items[i];
}
return null;
}
return null;
}
public getItemId(i: number) {
let item = this.getItem(i);
let id = i;
if (this.owner && item && this.owner.items) {
id = this.owner.itemIdGenerator(item, i, this.owner.items);
}
public getItemId(i: number) {
let item = this.getItem(i);
let id = i;
if (this.owner && item && this.owner.items) {
id = this.owner.itemIdGenerator(item, i, this.owner.items);
}
return long(id);
}
return long(id);
}
public hasStableIds(): boolean {
return true;
}
public hasStableIds(): boolean {
return true;
}
public getViewTypeCount() {
return this.owner._itemTemplatesInternal.length;
}
public getViewTypeCount() {
return this.owner._itemTemplatesInternal.length;
}
public getItemViewType(index: number) {
let template = this.owner._getItemTemplate(index);
let itemViewType = this.owner._itemTemplatesInternal.indexOf(template);
public getItemViewType(index: number) {
let template = this.owner._getItemTemplate(index);
let itemViewType = this.owner._itemTemplatesInternal.indexOf(
template
);
return itemViewType;
}
return itemViewType;
}
@profile()
public getView(index: number, convertView: android.view.View, parent: android.view.ViewGroup): android.view.View {
//this.owner._dumpRealizedTemplates();
@profile()
public getView(
index: number,
convertView: android.view.View,
parent: android.view.ViewGroup
): android.view.View {
//this.owner._dumpRealizedTemplates();
if (!this.owner) {
return null;
}
if (!this.owner) {
return null;
}
let totalItemCount = this.owner.items ? this.owner.items.length : 0;
if (index === (totalItemCount - 1)) {
this.owner.notify({ eventName: LOADMOREITEMS, object: this.owner });
}
let totalItemCount = this.owner.items ? this.owner.items.length : 0;
if (index === totalItemCount - 1) {
this.owner.notify({
eventName: LOADMOREITEMS,
object: this.owner,
});
}
// Recycle an existing view or create a new one if needed.
let template = this.owner._getItemTemplate(index);
let view: View;
if (convertView) {
view = this.owner._realizedTemplates.get(template.key).get(convertView);
if (!view) {
throw new Error(`There is no entry with key '${convertView}' in the realized views cache for template with key'${template.key}'.`);
}
}
else {
view = template.createView();
}
// Recycle an existing view or create a new one if needed.
let template = this.owner._getItemTemplate(index);
let view: View;
if (convertView) {
view = this.owner._realizedTemplates
.get(template.key)
.get(convertView);
if (!view) {
throw new Error(
`There is no entry with key '${convertView}' in the realized views cache for template with key'${template.key}'.`
);
}
} else {
view = template.createView();
}
let args: ItemEventData = {
eventName: ITEMLOADING, object: this.owner, index: index, view: view,
android: parent,
ios: undefined
};
let args: ItemEventData = {
eventName: ITEMLOADING,
object: this.owner,
index: index,
view: view,
android: parent,
ios: undefined,
};
this.owner.notify(args);
this.owner.notify(args);
if (!args.view) {
args.view = this.owner._getDefaultItemContent(index);
}
if (!args.view) {
args.view = this.owner._getDefaultItemContent(index);
}
if (args.view) {
if (this.owner._effectiveRowHeight > -1) {
args.view.height = this.owner.rowHeight;
}
else {
args.view.height = <Length>unsetValue;
}
if (args.view) {
if (this.owner._effectiveRowHeight > -1) {
args.view.height = this.owner.rowHeight;
} else {
args.view.height = <Length>unsetValue;
}
this.owner._prepareItem(args.view, index);
if (!args.view.parent) {
// Proxy containers should not get treated as layouts.
// Wrap them in a real layout as well.
if (args.view instanceof LayoutBase &&
!(args.view instanceof ProxyViewContainer)) {
this.owner._addView(args.view);
convertView = args.view.nativeViewProtected;
} else {
let sp = new StackLayout();
sp.addChild(args.view);
this.owner._addView(sp);
this.owner._prepareItem(args.view, index);
if (!args.view.parent) {
// Proxy containers should not get treated as layouts.
// Wrap them in a real layout as well.
if (
args.view instanceof LayoutBase &&
!(args.view instanceof ProxyViewContainer)
) {
this.owner._addView(args.view);
convertView = args.view.nativeViewProtected;
} else {
let sp = new StackLayout();
sp.addChild(args.view);
this.owner._addView(sp);
convertView = sp.nativeViewProtected;
}
}
convertView = sp.nativeViewProtected;
}
}
// Cache the view for recycling
let realizedItemsForTemplateKey = this.owner._realizedTemplates.get(template.key);
if (!realizedItemsForTemplateKey) {
realizedItemsForTemplateKey = new Map<android.view.View, View>();
this.owner._realizedTemplates.set(template.key, realizedItemsForTemplateKey);
}
realizedItemsForTemplateKey.set(convertView, args.view);
this.owner._realizedItems.set(convertView, args.view);
}
// Cache the view for recycling
let realizedItemsForTemplateKey = this.owner._realizedTemplates.get(
template.key
);
if (!realizedItemsForTemplateKey) {
realizedItemsForTemplateKey = new Map<
android.view.View,
View
>();
this.owner._realizedTemplates.set(
template.key,
realizedItemsForTemplateKey
);
}
realizedItemsForTemplateKey.set(convertView, args.view);
this.owner._realizedItems.set(convertView, args.view);
}
return convertView;
}
}
return convertView;
}
}
ListViewAdapterClass = ListViewAdapter;
ListViewAdapterClass = ListViewAdapter;
}

View File

@@ -1,180 +1,202 @@
import { View, Template, KeyedTemplate } from "../core/view";
import { Color } from '../../color';
import { EventData } from '../../data/observable';
import { Length } from '../styling/style-properties';
import { Style } from '../styling/style';
import { Color } from "../../color";
import { EventData } from "../../data/observable";
import { Length } from "../styling/style-properties";
import { Style } from "../styling/style";
import { Property, CssProperty } from "../core/properties";
/**
* Known template names.
*/
export module knownTemplates {
/**
* The ListView item template.
*/
export const itemTemplate: string;
/**
* The ListView item template.
*/
export const itemTemplate: string;
}
/**
* Represents a view that shows items in a vertically scrolling list.
*/
export class ListView extends View {
/**
* String value used when hooking to itemLoading event.
*/
public static itemLoadingEvent: string;
/**
* String value used when hooking to itemTap event.
*/
public static itemTapEvent: string;
/**
* String value used when hooking to loadMoreItems event.
*/
public static loadMoreItemsEvent: string;
/**
* String value used when hooking to itemLoading event.
*/
public static itemLoadingEvent: string;
/**
* String value used when hooking to itemTap event.
*/
public static itemTapEvent: string;
/**
* String value used when hooking to loadMoreItems event.
*/
public static loadMoreItemsEvent: string;
/**
* Gets the native [android widget](http://developer.android.com/reference/android/widget/ListView.html) that represents the user interface for this component. Valid only when running on Android OS.
*/
android: any /* android.widget.ListView */;
/**
* Gets the native [android widget](http://developer.android.com/reference/android/widget/ListView.html) that represents the user interface for this component. Valid only when running on Android OS.
*/
android: any /* android.widget.ListView */;
/**
* Gets the native [iOS view](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/) that represents the user interface for this component. Valid only when running on iOS.
*/
ios: any /* UITableView */;
/**
* Gets the native [iOS view](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/) that represents the user interface for this component. Valid only when running on iOS.
*/
ios: any /* UITableView */;
/**
* Gets or set the items collection of the ListView.
* The items property can be set to an array or an object defining length and getItem(index) method.
*/
items: any[] | ItemsSource;
/**
* Gets or set the items collection of the ListView.
* The items property can be set to an array or an object defining length and getItem(index) method.
*/
items: any[] | ItemsSource;
/**
* Gets or set the item template of the ListView.
*/
itemTemplate: string | Template;
/**
* Gets or set the item template of the ListView.
*/
itemTemplate: string | Template;
/**
* Gets or set the list of item templates for the item template selector
*/
itemTemplates: string | Array<KeyedTemplate>;
/**
* Gets or set the list of item templates for the item template selector
*/
itemTemplates: string | Array<KeyedTemplate>;
/**
* A function that returns the appropriate ket template based on the data item.
*/
itemTemplateSelector: string | ((item: any, index: number, items: any) => string);
/**
* A function that returns the appropriate ket template based on the data item.
*/
itemTemplateSelector:
| string
| ((item: any, index: number, items: any) => string);
/**
* Item id generator
*/
itemIdGenerator: (item: any, index: number, items: any) => number;
/**
* Item id generator
*/
itemIdGenerator: (item: any, index: number, items: any) => number;
/**
* Gets or set the items separator line color of the ListView.
*/
separatorColor: Color;
/**
* Gets or set the items separator line color of the ListView.
*/
separatorColor: Color;
/**
* Gets or set row height of the ListView.
*/
rowHeight: Length;
/**
* Gets or set row height of the ListView.
*/
rowHeight: Length;
/**
* Gets or set the estimated height of rows in the ListView.
* The default value is 44px.
*/
iosEstimatedRowHeight: Length;
/**
* Gets or set the estimated height of rows in the ListView.
* The default value is 44px.
*/
iosEstimatedRowHeight: Length;
/**
* Forces the ListView to reload all its items.
*/
refresh();
/**
* Forces the ListView to reload all its items.
*/
refresh();
/**
* Scrolls the specified item with index into view.
* [iOS](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UITableView_Class/#//apple_ref/occ/instm/UITableView/scrollToRowAtIndexPath:atScrollPosition:animated:)
* [Android](http://developer.android.com/reference/android/widget/ListView.html#setSelection(int))
* @param index - Item index.
*/
scrollToIndex(index: number);
/**
* Scrolls the specified item with index into view.
* [iOS](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UITableView_Class/#//apple_ref/occ/instm/UITableView/scrollToRowAtIndexPath:atScrollPosition:animated:)
* [Android](http://developer.android.com/reference/android/widget/ListView.html#setSelection(int))
* @param index - Item index.
*/
scrollToIndex(index: number);
/**
* Scrolls the specified item with index into view with animation.
* [iOS](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UITableView_Class/#//apple_ref/occ/instm/UITableView/scrollToRowAtIndexPath:atScrollPosition:animated:)
* [Android](https://developer.android.com/reference/android/widget/ListView.html#smoothScrollToPosition(int))
* @param index - Item index.
*/
scrollToIndexAnimated(index: number);
/**
* Scrolls the specified item with index into view with animation.
* [iOS](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UITableView_Class/#//apple_ref/occ/instm/UITableView/scrollToRowAtIndexPath:atScrollPosition:animated:)
* [Android](https://developer.android.com/reference/android/widget/ListView.html#smoothScrollToPosition(int))
* @param index - Item index.
*/
scrollToIndexAnimated(index: number);
/**
* Checks if Specified item with index is visible.
* @param index - Item index.
*/
isItemAtIndexVisible(index: number): boolean;
/**
* Checks if Specified item with index is visible.
* @param index - Item index.
*/
isItemAtIndexVisible(index: number): boolean;
/**
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
* @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change").
* @param callback - Callback function which will be executed when event is raised.
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
*/
on(eventNames: string, callback: (data: EventData) => void, thisArg?: any);
/**
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
* @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change").
* @param callback - Callback function which will be executed when event is raised.
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
*/
on(eventNames: string, callback: (data: EventData) => void, thisArg?: any);
/**
* Raised when a View for the data at the specified index should be created.
* The result should be returned trough the view property of the event data.
* Note, that the view property of the event data can be pre-initialized with
* an old instance of a view, so that it can be reused.
*/
on(event: "itemLoading", callback: (args: ItemEventData) => void, thisArg?: any);
/**
* Raised when a View for the data at the specified index should be created.
* The result should be returned trough the view property of the event data.
* Note, that the view property of the event data can be pre-initialized with
* an old instance of a view, so that it can be reused.
*/
on(
event: "itemLoading",
callback: (args: ItemEventData) => void,
thisArg?: any
);
/**
* Raised when an item inside the ListView is tapped.
*/
on(event: "itemTap", callback: (args: ItemEventData) => void, thisArg?: any);
/**
* Raised when an item inside the ListView is tapped.
*/
on(
event: "itemTap",
callback: (args: ItemEventData) => void,
thisArg?: any
);
/**
* Raised when the ListView is scrolled so that its last item is visible.
*/
on(event: "loadMoreItems", callback: (args: EventData) => void, thisArg?: any);
/**
* Raised when the ListView is scrolled so that its last item is visible.
*/
on(
event: "loadMoreItems",
callback: (args: EventData) => void,
thisArg?: any
);
}
/**
* Event data containing information for the index and the view associated to a list view item.
*/
export interface ItemEventData extends EventData {
/**
* The index of the item, for which the event is raised.
*/
index: number;
/**
* The index of the item, for which the event is raised.
*/
index: number;
/**
* The view that is associated to the item, for which the event is raised.
*/
view: View;
/**
* The view that is associated to the item, for which the event is raised.
*/
view: View;
/**
* Gets the native [iOS view](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewCell_Class/) that represents the user interface where the view is hosted. Valid only when running on iOS.
*/
ios: any /* UITableViewCell */;
/**
* Gets the native [iOS view](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewCell_Class/) that represents the user interface where the view is hosted. Valid only when running on iOS.
*/
ios: any /* UITableViewCell */;
/**
* Gets the native [android widget](http://developer.android.com/reference/android/view/ViewGroup.html) that represents the user interface where the view is hosted. Valid only when running on Android OS.
*/
android: any /* android.view.ViewGroup */;
/**
* Gets the native [android widget](http://developer.android.com/reference/android/view/ViewGroup.html) that represents the user interface where the view is hosted. Valid only when running on Android OS.
*/
android: any /* android.view.ViewGroup */;
}
export interface ItemsSource {
length: number;
getItem(index: number): any;
length: number;
getItem(index: number): any;
}
export interface TemplatedItemsView {
items: any[] | ItemsSource;
itemTemplate: string | Template;
itemTemplates?: string | Array<KeyedTemplate>;
refresh(): void;
on(event: "itemLoading", callback: (args: ItemEventData) => void, thisArg?: any);
off(event: "itemLoading", callback: (args: EventData) => void, thisArg?: any);
items: any[] | ItemsSource;
itemTemplate: string | Template;
itemTemplates?: string | Array<KeyedTemplate>;
refresh(): void;
on(
event: "itemLoading",
callback: (args: ItemEventData) => void,
thisArg?: any
);
off(
event: "itemLoading",
callback: (args: EventData) => void,
thisArg?: any
);
}
/**
@@ -190,7 +212,10 @@ export const itemTemplateProperty: Property<ListView, string | Template>;
/**
* Represents the items template property of each ListView instance.
*/
export const itemTemplatesProperty: Property<ListView, string | Array<KeyedTemplate>>;
export const itemTemplatesProperty: Property<
ListView,
string | Array<KeyedTemplate>
>;
/**
* Represents the separator color backing property.

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,16 @@
import { ListView as ListViewDefinition, ItemsSource, ItemEventData, TemplatedItemsView } from ".";
import { View, ContainerView, Template, KeyedTemplate, CSSType } from "../core/view";
import {
ListView as ListViewDefinition,
ItemsSource,
ItemEventData,
TemplatedItemsView,
} from ".";
import {
View,
ContainerView,
Template,
KeyedTemplate,
CSSType,
} from "../core/view";
import { Property, CoercibleProperty, CssProperty } from "../core/properties";
import { Length } from "../styling/style-properties";
import { Style } from "../styling/style";
@@ -8,205 +19,269 @@ import { Builder } from "../builder";
import { Label } from "../label";
import { Observable, EventData } from "../../data/observable";
import { ObservableArray, ChangedData } from "../../data/observable-array";
import { addWeakEventListener, removeWeakEventListener } from "../core/weak-event-listener";
import {
addWeakEventListener,
removeWeakEventListener,
} from "../core/weak-event-listener";
// TODO: Think of a way to register these instead of relying on hardcoded values.
export module knownTemplates {
export const itemTemplate = "itemTemplate";
export const itemTemplate = "itemTemplate";
}
export module knownMultiTemplates {
export const itemTemplates = "itemTemplates";
export const itemTemplates = "itemTemplates";
}
const autoEffectiveRowHeight = -1;
@CSSType("ListView")
export abstract class ListViewBase extends ContainerView implements ListViewDefinition, TemplatedItemsView {
public static itemLoadingEvent = "itemLoading";
public static itemTapEvent = "itemTap";
public static loadMoreItemsEvent = "loadMoreItems";
// TODO: get rid of such hacks.
public static knownFunctions = ["itemTemplateSelector", "itemIdGenerator"]; //See component-builder.ts isKnownFunction
export abstract class ListViewBase extends ContainerView
implements ListViewDefinition, TemplatedItemsView {
public static itemLoadingEvent = "itemLoading";
public static itemTapEvent = "itemTap";
public static loadMoreItemsEvent = "loadMoreItems";
// TODO: get rid of such hacks.
public static knownFunctions = ["itemTemplateSelector", "itemIdGenerator"]; //See component-builder.ts isKnownFunction
private _itemIdGenerator: (item: any, index: number, items: any) => number = (_item: any, index: number) => index;
private _itemTemplateSelector: (item: any, index: number, items: any) => string;
private _itemTemplateSelectorBindable = new Label();
public _defaultTemplate: KeyedTemplate = {
key: "default",
createView: () => {
if (this.itemTemplate) {
return Builder.parse(this.itemTemplate, this);
}
private _itemIdGenerator: (
item: any,
index: number,
items: any
) => number = (_item: any, index: number) => index;
private _itemTemplateSelector: (
item: any,
index: number,
items: any
) => string;
private _itemTemplateSelectorBindable = new Label();
public _defaultTemplate: KeyedTemplate = {
key: "default",
createView: () => {
if (this.itemTemplate) {
return Builder.parse(this.itemTemplate, this);
}
return undefined;
}
};
return undefined;
},
};
public _itemTemplatesInternal = new Array<KeyedTemplate>(this._defaultTemplate);
public _effectiveRowHeight: number = autoEffectiveRowHeight;
public rowHeight: Length;
public iosEstimatedRowHeight: Length;
public items: any[] | ItemsSource;
public itemTemplate: string | Template;
public itemTemplates: string | Array<KeyedTemplate>;
public _itemTemplatesInternal = new Array<KeyedTemplate>(
this._defaultTemplate
);
public _effectiveRowHeight: number = autoEffectiveRowHeight;
public rowHeight: Length;
public iosEstimatedRowHeight: Length;
public items: any[] | ItemsSource;
public itemTemplate: string | Template;
public itemTemplates: string | Array<KeyedTemplate>;
get separatorColor(): Color {
return this.style.separatorColor;
}
set separatorColor(value: Color) {
this.style.separatorColor = value;
}
get separatorColor(): Color {
return this.style.separatorColor;
}
set separatorColor(value: Color) {
this.style.separatorColor = value;
}
get itemTemplateSelector(): string | ((item: any, index: number, items: any) => string) {
return this._itemTemplateSelector;
}
set itemTemplateSelector(value: string | ((item: any, index: number, items: any) => string)) {
if (typeof value === "string") {
this._itemTemplateSelectorBindable.bind({
sourceProperty: null,
targetProperty: "templateKey",
expression: value
});
this._itemTemplateSelector = (item: any, index: number, items: any) => {
item["$index"] = index;
get itemTemplateSelector():
| string
| ((item: any, index: number, items: any) => string) {
return this._itemTemplateSelector;
}
set itemTemplateSelector(
value: string | ((item: any, index: number, items: any) => string)
) {
if (typeof value === "string") {
this._itemTemplateSelectorBindable.bind({
sourceProperty: null,
targetProperty: "templateKey",
expression: value,
});
this._itemTemplateSelector = (
item: any,
index: number,
items: any
) => {
item["$index"] = index;
if (this._itemTemplateSelectorBindable.bindingContext === item) {
this._itemTemplateSelectorBindable.bindingContext = null;
}
if (
this._itemTemplateSelectorBindable.bindingContext === item
) {
this._itemTemplateSelectorBindable.bindingContext = null;
}
this._itemTemplateSelectorBindable.bindingContext = item;
this._itemTemplateSelectorBindable.bindingContext = item;
return this._itemTemplateSelectorBindable.get("templateKey");
};
}
else if (typeof value === "function") {
this._itemTemplateSelector = value;
}
}
return this._itemTemplateSelectorBindable.get("templateKey");
};
} else if (typeof value === "function") {
this._itemTemplateSelector = value;
}
}
get itemIdGenerator(): (item: any, index: number, items: any) => number {
return this._itemIdGenerator;
}
set itemIdGenerator(generatorFn: (item: any, index: number, items: any) => number) {
this._itemIdGenerator = generatorFn;
}
get itemIdGenerator(): (item: any, index: number, items: any) => number {
return this._itemIdGenerator;
}
set itemIdGenerator(
generatorFn: (item: any, index: number, items: any) => number
) {
this._itemIdGenerator = generatorFn;
}
public refresh() {
//
}
public refresh() {
//
}
public scrollToIndex(index: number) {
//
}
public scrollToIndex(index: number) {
//
}
public scrollToIndexAnimated(index: number) {
//
}
public scrollToIndexAnimated(index: number) {
//
}
public _getItemTemplate(index: number): KeyedTemplate {
let templateKey = "default";
if (this.itemTemplateSelector) {
let dataItem = this._getDataItem(index);
templateKey = this._itemTemplateSelector(dataItem, index, this.items);
}
public _getItemTemplate(index: number): KeyedTemplate {
let templateKey = "default";
if (this.itemTemplateSelector) {
let dataItem = this._getDataItem(index);
templateKey = this._itemTemplateSelector(
dataItem,
index,
this.items
);
}
for (let i = 0, length = this._itemTemplatesInternal.length; i < length; i++) {
if (this._itemTemplatesInternal[i].key === templateKey) {
return this._itemTemplatesInternal[i];
}
}
for (
let i = 0, length = this._itemTemplatesInternal.length;
i < length;
i++
) {
if (this._itemTemplatesInternal[i].key === templateKey) {
return this._itemTemplatesInternal[i];
}
}
// This is the default template
return this._itemTemplatesInternal[0];
}
// This is the default template
return this._itemTemplatesInternal[0];
}
public _prepareItem(item: View, index: number) {
if (item) {
item.bindingContext = this._getDataItem(index);
}
}
public _prepareItem(item: View, index: number) {
if (item) {
item.bindingContext = this._getDataItem(index);
}
}
private _getDataItem(index: number): any {
let thisItems = <ItemsSource>this.items;
private _getDataItem(index: number): any {
let thisItems = <ItemsSource>this.items;
return thisItems.getItem ? thisItems.getItem(index) : thisItems[index];
}
return thisItems.getItem ? thisItems.getItem(index) : thisItems[index];
}
public _getDefaultItemContent(index: number): View {
let lbl = new Label();
lbl.bind({
targetProperty: "text",
sourceProperty: "$value"
});
public _getDefaultItemContent(index: number): View {
let lbl = new Label();
lbl.bind({
targetProperty: "text",
sourceProperty: "$value",
});
return lbl;
}
return lbl;
}
public _onItemsChanged(args: ChangedData<any>) {
this.refresh();
}
public _onItemsChanged(args: ChangedData<any>) {
this.refresh();
}
public _onRowHeightPropertyChanged(oldValue: Length, newValue: Length) {
this.refresh();
}
public _onRowHeightPropertyChanged(oldValue: Length, newValue: Length) {
this.refresh();
}
public isItemAtIndexVisible(index: number) {
return false;
}
public isItemAtIndexVisible(index: number) {
return false;
}
protected updateEffectiveRowHeight(): void {
rowHeightProperty.coerce(this);
}
protected updateEffectiveRowHeight(): void {
rowHeightProperty.coerce(this);
}
}
ListViewBase.prototype.recycleNativeView = "auto";
export interface ListViewBase {
on(eventNames: string, callback: (data: EventData) => void, thisArg?: any);
on(event: "itemLoading", callback: (args: ItemEventData) => void, thisArg?: any);
on(event: "itemTap", callback: (args: ItemEventData) => void, thisArg?: any);
on(event: "loadMoreItems", callback: (args: EventData) => void, thisArg?: any);
on(eventNames: string, callback: (data: EventData) => void, thisArg?: any);
on(
event: "itemLoading",
callback: (args: ItemEventData) => void,
thisArg?: any
);
on(
event: "itemTap",
callback: (args: ItemEventData) => void,
thisArg?: any
);
on(
event: "loadMoreItems",
callback: (args: EventData) => void,
thisArg?: any
);
}
/**
* Represents the property backing the items property of each ListView instance.
*/
export const itemsProperty = new Property<ListViewBase, any[] | ItemsSource>({
name: "items", valueChanged: (target, oldValue, newValue) => {
if (oldValue instanceof Observable) {
removeWeakEventListener(oldValue, ObservableArray.changeEvent, target._onItemsChanged, target);
}
name: "items",
valueChanged: (target, oldValue, newValue) => {
if (oldValue instanceof Observable) {
removeWeakEventListener(
oldValue,
ObservableArray.changeEvent,
target._onItemsChanged,
target
);
}
if (newValue instanceof Observable) {
addWeakEventListener(newValue, ObservableArray.changeEvent, target._onItemsChanged, target);
}
if (newValue instanceof Observable) {
addWeakEventListener(
newValue,
ObservableArray.changeEvent,
target._onItemsChanged,
target
);
}
target.refresh();
}
target.refresh();
},
});
itemsProperty.register(ListViewBase);
/**
* Represents the item template property of each ListView instance.
*/
export const itemTemplateProperty = new Property<ListViewBase, string | Template>({
name: "itemTemplate", valueChanged: (target) => {
target.refresh();
}
export const itemTemplateProperty = new Property<
ListViewBase,
string | Template
>({
name: "itemTemplate",
valueChanged: (target) => {
target.refresh();
},
});
itemTemplateProperty.register(ListViewBase);
/**
* Represents the items template property of each ListView instance.
*/
export const itemTemplatesProperty = new Property<ListViewBase, string | Array<KeyedTemplate>>({
name: "itemTemplates", valueConverter: (value) => {
if (typeof value === "string") {
return Builder.parseMultipleTemplates(value, null);
}
export const itemTemplatesProperty = new Property<
ListViewBase,
string | Array<KeyedTemplate>
>({
name: "itemTemplates",
valueConverter: (value) => {
if (typeof value === "string") {
return Builder.parseMultipleTemplates(value, null);
}
return value;
}
return value;
},
});
itemTemplatesProperty.register(ListViewBase);
@@ -215,22 +290,36 @@ const defaultRowHeight: Length = "auto";
* Represents the observable property backing the rowHeight property of each ListView instance.
*/
export const rowHeightProperty = new CoercibleProperty<ListViewBase, Length>({
name: "rowHeight", defaultValue: defaultRowHeight, equalityComparer: Length.equals,
coerceValue: (target, value) => {
// We coerce to default value if we don't have display density.
return target.nativeViewProtected ? value : defaultRowHeight;
},
valueChanged: (target, oldValue, newValue) => {
target._effectiveRowHeight = Length.toDevicePixels(newValue, autoEffectiveRowHeight);
target._onRowHeightPropertyChanged(oldValue, newValue);
}, valueConverter: Length.parse
name: "rowHeight",
defaultValue: defaultRowHeight,
equalityComparer: Length.equals,
coerceValue: (target, value) => {
// We coerce to default value if we don't have display density.
return target.nativeViewProtected ? value : defaultRowHeight;
},
valueChanged: (target, oldValue, newValue) => {
target._effectiveRowHeight = Length.toDevicePixels(
newValue,
autoEffectiveRowHeight
);
target._onRowHeightPropertyChanged(oldValue, newValue);
},
valueConverter: Length.parse,
});
rowHeightProperty.register(ListViewBase);
export const iosEstimatedRowHeightProperty = new Property<ListViewBase, Length>({
name: "iosEstimatedRowHeight", valueConverter: (v) => Length.parse(v)
});
export const iosEstimatedRowHeightProperty = new Property<ListViewBase, Length>(
{
name: "iosEstimatedRowHeight",
valueConverter: (v) => Length.parse(v),
}
);
iosEstimatedRowHeightProperty.register(ListViewBase);
export const separatorColorProperty = new CssProperty<Style, Color>({ name: "separatorColor", cssName: "separator-color", equalityComparer: Color.equals, valueConverter: (v) => new Color(v) });
export const separatorColorProperty = new CssProperty<Style, Color>({
name: "separatorColor",
cssName: "separator-color",
equalityComparer: Color.equals,
valueConverter: (v) => new Color(v),
});
separatorColorProperty.register(Style);