UNPKG

ovuse

Version:

WPF-inspired Web UI framework

203 lines (202 loc) 9.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const _1 = require("."); const utils_1 = require("./utils"); class PropertyPath { constructor(owner, path, source) { this.name = null; this.next = null; this.prev = null; this.sourceProperty = null; this.indexers = null; this.owner = owner; this.path = path; this.source = source; this.build(); this.attachShource(); } attachShource() { if (this.sourceProperty == undefined) { if (this.source.subscribePropertyChanges != undefined) this.source.subscribePropertyChanges(this); } else if (this.source["unsubscribeDependencyPropertyChanges"] != undefined) this.source.subscribeDependencyPropertyChanges(this); } detachSource() { if (this.source.unsubscribePropertyChanges != undefined) this.source.unsubscribePropertyChanges(this); //if source is not a DependencyObject I can't subscribe/unsubscribe to its property changes if (this.source["unsubscribeDependencyPropertyChanges"] != undefined) this.source.unsubscribeDependencyPropertyChanges(this); } lookForIndexers() { var re = /([\w_]+)(\[([\w_]+)\])/gmi; var m; var nameStr = this.name; if ((m = re.exec(nameStr)) !== undefined) { if (m == undefined) { this.indexers = null; return; } if (m.index === re.lastIndex) { re.lastIndex++; } //there is at least an indexer in the form property[...]... //property name is returned in m[1] this.name = m[1]; //so get the first indexer and save it in this.indexers this.indexers = []; this.indexers.push(m[3]); //for now support up to 2 indexer like 'property[..][..]' //search for a second indexer if exists re = /([\w_]+)(\[([\w_]+)\])(\[([\w_]+)\])/gmi; if ((m = re.exec(nameStr)) !== undefined) { if (m == undefined) { this.indexers = null; return; } if (m.index === re.lastIndex) { re.lastIndex++; } this.indexers.push(m[5]); } } else this.indexers = null; } build() { var oldNext = this.next; if (this.next != undefined) { this.next.detachSource(); this.next.prev = null; } if (this.path == "" || this.path == ".") { this.name = "."; this.next = null; } else { var dotIndex = this.path.indexOf("."); if (dotIndex > -1) { //first token of path is the name of property to look in source object this.name = this.path.substring(0, dotIndex); this.lookForIndexers(); this.sourceProperty = _1.DependencyObject.lookupProperty(this.source, this.name); //NOTE: this.source can be n UIElement(quite often) and it has custom getValue method that looks for parent values //for the same property given it has FrameworkPropertyMetadataOptions.Inherits as option defined for property //see UEelement.ts/getValue var sourcePropertyValue = (this.sourceProperty != undefined) ? this.source.getValue(this.sourceProperty) : //if it's a dep property get value using DependencyObject hierarchy utils_1.getPropertyValue(this.source, this.name); //otherwise try using normal property lookup method //this.source[this.name]; //if an indexer list is defined (binding to something like 'property[...]...') //go deeper to property value accessed with the indexer if (this.indexers != undefined && sourcePropertyValue != undefined) { sourcePropertyValue = sourcePropertyValue[this.indexers[0]]; if (this.indexers.length > 1 && sourcePropertyValue != undefined) sourcePropertyValue = sourcePropertyValue[this.indexers[1]]; } if (sourcePropertyValue != undefined) { //is source value is not undefined means I can go further in search... var nextPath = this.path.substring(dotIndex + 1); if (this.next == undefined || this.next.path != nextPath || this.next.source != sourcePropertyValue) this.next = new PropertyPath(this.owner, this.path.substring(dotIndex + 1), sourcePropertyValue); else if (this.next != undefined) this.next.build(); } else { this.next = null; } } else { this.name = this.path; this.lookForIndexers(); this.sourceProperty = _1.DependencyObject.lookupProperty(this.source, this.name); this.next = null; } } if (this.next != undefined) { this.next.attachShource(); //attachSource() test if already attached this.next.prev = this; } if (this.next != oldNext) this.onPathChanged(); } onPathChanged() { if (this.prev != undefined) this.prev.onPathChanged(); else { this.owner.updateTarget(); } } getValue() { if (this.next != undefined) return this.next.getValue(); else if (this.name == ".") return { success: true, value: this.source, source: this.source, property: undefined }; else if (this.name != undefined && this.path.indexOf(".") == -1) { if (_1.DependencyObject.logBindingTraceToConsole) if (this.sourceProperty == undefined && (!(this.name in this.source))) { var typeName = _1.getObjectTypeId(this.source); console.log("[Bindings] Unable to find property '{0}' on type '{1}'".format(this.name, typeName == undefined ? "<noneType>" : typeName)); } var sourcePropertyValue = (this.sourceProperty != undefined) ? this.source.getValue(this.sourceProperty) : //if it's a dep property get value using DependencyObject hierarchy utils_1.getPropertyValue(this.source, this.name); //otherwise try using normal property lookup method //this.source[this.name]; //if an indexer list is defined (binding to something like 'property[...]...') //go deeper to property value accessed with the indexer if (this.indexers != undefined && sourcePropertyValue != undefined) { sourcePropertyValue = sourcePropertyValue[this.indexers[0]]; if (this.indexers.length > 1 && sourcePropertyValue != undefined) sourcePropertyValue = sourcePropertyValue[this.indexers[1]]; } return { success: true, value: sourcePropertyValue, source: this.source, property: this.sourceProperty }; } else return { success: false }; } setValue(value) { if (this.next != undefined) this.next.setValue(value); else if (this.name != undefined && this.path.indexOf(".") == -1) { if (this.indexers != undefined) throw new Error("Unable to update source when indexers are specified in binding path"); if (this.sourceProperty != undefined) this.source.setValue(this.sourceProperty, value); else utils_1.setPropertyValue(this.source, this.name, value); //try update source using default property lookup access //this.source[this.name] = value;//try update source using default property lookup access } } onDependencyPropertyChanged(DependencyObject, DependencyProperty) { if (DependencyObject == this.source && DependencyProperty.name == this.name) { this.build(); this.owner.updateTarget(); } } onChangeProperty(source, propertyName, value) { if (source == this.source && propertyName == this.name) { this.build(); this.owner.updateTarget(); } } } exports.PropertyPath = PropertyPath;