import observable = require("data/observable"); import view = require("ui/core/view"); import proxy = require("ui/core/proxy"); import definition = require("ui/list-view"); import dependencyObservable = require("ui/core/dependency-observable"); import color = require("color"); import * as builderModule from "ui/builder"; import * as labelModule from "ui/label"; import * as observableArrayModule from "data/observable-array"; import * as weakEventsModule from "ui/core/weak-event-listener"; import {isString, isFunction} from "utils/types"; import { Bindable } from "ui/core/bindable"; var builder: typeof builderModule; function ensureBuilder() { if (!builder) { builder = require("ui/builder"); } } var label: typeof labelModule; function ensureLabel() { if (!label) { label = require("ui/label"); } } var observableArray: typeof observableArrayModule; function ensureObservableArray() { if (!observableArray) { observableArray = require("data/observable-array"); } } var weakEvents: typeof weakEventsModule; function ensureWeakEvents() { if (!weakEvents) { weakEvents = require("ui/core/weak-event-listener"); } } var ITEMS = "items"; var ITEMTEMPLATE = "itemTemplate"; var ITEMTEMPLATES = "itemTemplates"; var ISSCROLLING = "isScrolling"; var LISTVIEW = "ListView"; var SEPARATORCOLOR = "separatorColor"; var ROWHEIGHT = "rowHeight"; export module knownTemplates { export var itemTemplate = "itemTemplate"; } export module knownMultiTemplates { export var itemTemplates = "itemTemplates"; } function onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) { var listView = data.object; listView._onItemsPropertyChanged(data); } function onItemTemplatePropertyChanged(data: dependencyObservable.PropertyChangeData) { var listView = data.object; listView.refresh(); } function onItemTemplatesPropertyChanged(data: dependencyObservable.PropertyChangeData) { var listView = data.object; listView._onItemTemplatesPropertyChanged(data); } function onRowHeightPropertyChanged(data: dependencyObservable.PropertyChangeData) { var listView = data.object; listView._onRowHeightPropertyChanged(data); } export class ListView extends view.View implements definition.ListView { public static itemLoadingEvent = "itemLoading"; public static itemTapEvent = "itemTap"; public static loadMoreItemsEvent = "loadMoreItems"; public static knownFunctions = ["itemTemplateSelector"]; //See component-builder.ts isKnownFunction private _itemTemplateSelector: (item: any, index: number, items: any) => string; private _itemTemplateSelectorBindable = new Bindable(); public _defaultTemplate: view.KeyedTemplate = { key: "default", createView: () => { if (this.itemTemplate) { ensureBuilder(); return builder.parse(this.itemTemplate, this); } return undefined; } } public _itemTemplatesInternal = new Array(this._defaultTemplate); public static separatorColorProperty = new dependencyObservable.Property( SEPARATORCOLOR, LISTVIEW, new proxy.PropertyMetadata(undefined)); public static itemsProperty = new dependencyObservable.Property( ITEMS, LISTVIEW, new proxy.PropertyMetadata( undefined, dependencyObservable.PropertyMetadataSettings.AffectsLayout, onItemsPropertyChanged ) ); public static itemTemplateProperty = new dependencyObservable.Property( ITEMTEMPLATE, LISTVIEW, new proxy.PropertyMetadata( undefined, dependencyObservable.PropertyMetadataSettings.AffectsLayout, onItemTemplatePropertyChanged ) ); public static itemTemplatesProperty = new dependencyObservable.Property( ITEMTEMPLATES, LISTVIEW, new proxy.PropertyMetadata( undefined, dependencyObservable.PropertyMetadataSettings.AffectsLayout, onItemTemplatesPropertyChanged ) ); public static isScrollingProperty = new dependencyObservable.Property( ISSCROLLING, LISTVIEW, new proxy.PropertyMetadata( false, dependencyObservable.PropertyMetadataSettings.None ) ); public static rowHeightProperty = new dependencyObservable.Property( ROWHEIGHT, LISTVIEW, new proxy.PropertyMetadata( -1, dependencyObservable.PropertyMetadataSettings.AffectsLayout, onRowHeightPropertyChanged ) ); get items(): any { return this._getValue(ListView.itemsProperty); } set items(value: any) { this._setValue(ListView.itemsProperty, value); } get itemTemplate(): string | view.Template { return this._getValue(ListView.itemTemplateProperty); } set itemTemplate(value: string | view.Template) { this._setValue(ListView.itemTemplateProperty, value); } get itemTemplates(): string | Array { return this._getValue(ListView.itemTemplatesProperty); } set itemTemplates(value: string | Array) { let newValue = value; if (isString(newValue)){ ensureBuilder(); newValue = builder.parseMultipleTemplates(newValue, this); } this._setValue(ListView.itemTemplatesProperty, newValue); } 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 (isString(value)){ this._itemTemplateSelectorBindable.bind({ sourceProperty: null, targetProperty: "templateKey", expression: value }); this._itemTemplateSelector = (item: any, index: number, items: any) => { item["$index"] = index; this._itemTemplateSelectorBindable.bindingContext = item; return this._itemTemplateSelectorBindable.get("templateKey"); }; } else if (isFunction(value)) { this._itemTemplateSelector = <((item: any, index: number, items: any) => string)>value; } } get isScrolling(): boolean { return false; } set isScrolling(value: boolean) { // Do nothing. } get separatorColor(): color.Color { return this._getValue(ListView.separatorColorProperty); } set separatorColor(value: color.Color) { this._setValue(ListView.separatorColorProperty, value instanceof color.Color ? value : new color.Color(value)); } get rowHeight(): number { return this._getValue(ListView.rowHeightProperty); } set rowHeight(value: number) { this._setValue(ListView.rowHeightProperty, value); } public refresh() { // } public scrollToIndex(index: number) { // } public _getItemTemplate(index: number): view.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]; } } // This is the default template return this._itemTemplatesInternal[0]; } public _prepareItem(item: view.View, index: number) { if (item) { item.bindingContext = this._getDataItem(index); } } private _getDataItem(index: number): any { let thisItems = this.items; return thisItems.getItem ? thisItems.getItem(index) : thisItems[index]; } public _getDefaultItemContent(index: number): view.View { ensureLabel(); var lbl = new label.Label(); lbl.bind({ targetProperty: "text", sourceProperty: "$value" }); return lbl; } public _onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) { ensureObservableArray(); ensureWeakEvents(); if (data.oldValue instanceof observable.Observable) { weakEvents.removeWeakEventListener(data.oldValue, observableArray.ObservableArray.changeEvent, this._onItemsChanged, this); } if (data.newValue instanceof observable.Observable) { weakEvents.addWeakEventListener(data.newValue, observableArray.ObservableArray.changeEvent, this._onItemsChanged, this); } this.refresh(); } private _onItemsChanged(args: observable.EventData) { this.refresh(); } public _onRowHeightPropertyChanged(data: dependencyObservable.PropertyChangeData) { this.refresh(); } public _onItemTemplatesPropertyChanged(data: dependencyObservable.PropertyChangeData) { // } }