From f72deb072986cecb597b03a05eb3a88f06cf145e Mon Sep 17 00:00:00 2001 From: Aluan Haddad Date: Mon, 12 Feb 2018 18:05:40 -0500 Subject: [PATCH] Added the BindablePropertyConfig interface * describes the configuration object that can be passed to customize the bindable decorator and the BindableProperty class * used the interface type appropriate * fixed a few minor typos (spelling) * built and ran tests (+1 squashed commits) --- dist/aurelia-templating.d.ts | 34 +++++++++++++--- dist/aurelia-templating.js | 48 ++++++++++++++++------- dist/es2015/aurelia-templating.js | 16 ++++---- dist/native-modules/aurelia-templating.js | 2 +- dist/system/aurelia-templating.js | 4 +- src/bindable-property.js | 14 +++---- src/decorators.js | 10 ++--- src/interfaces.js | 19 +++++++++ 8 files changed, 104 insertions(+), 43 deletions(-) diff --git a/dist/aurelia-templating.d.ts b/dist/aurelia-templating.d.ts index f75c808d..0c22088b 100644 --- a/dist/aurelia-templating.d.ts +++ b/dist/aurelia-templating.d.ts @@ -24,10 +24,10 @@ import { import { Binding, createOverrideContext, + bindingMode, ValueConverterResource, BindingBehaviorResource, subscriberCollection, - bindingMode, ObserverLocator, EventManager } from 'aurelia-binding'; @@ -238,6 +238,30 @@ export declare interface DynamicComponentGetViewStrategy { getViewStrategy(): string | ViewStrategy; } +/** +* An optional interface describing the configuration object that can be specified to customize bindable properties. +*/ +/** +* An optional interface describing the configuration object that can be specified to customize bindable properties. +*/ +export declare interface BindablePropertyConfig { + + /** + * The default binding mode of the property. + */ + defaultBindingMode?: bindingMode; + + /** + * The name of a view model method to invoke when the property is updated. + */ + changeHandler?: string; + + /** + * The name of the property. + */ + name?: string; +} + /** * Instructs the composition engine how to dynamically compose a component. */ @@ -1673,9 +1697,9 @@ export declare class BindableProperty { /** * Creates an instance of BindableProperty. - * @param nameOrConfig The name of the property or a cofiguration object. + * @param nameOrConfig The name of the property or a configuration object. */ - constructor(nameOrConfig: string | Object); + constructor(nameOrConfig: string | BindablePropertyConfig); /** * Registers this bindable property with particular Class and Behavior instance. @@ -1876,7 +1900,7 @@ export declare function customElement(name: string): any; * @param defaultBindingMode The default binding mode to use when the attribute is bound with .bind. * @param aliases The array of aliases to associate to the custom attribute. */ -export declare function customAttribute(name: string, defaultBindingMode?: number, aliases?: string[]): any; +export declare function customAttribute(name: string, defaultBindingMode?: bindingMode, aliases?: string[]): any; /** * Decorator: Applied to custom attributes. Indicates that whatever element the @@ -1889,7 +1913,7 @@ export declare function templateController(target?: any): any; * Decorator: Specifies that a property is bindable through HTML. * @param nameOrConfigOrTarget The name of the property, or a configuration object. */ -export declare function bindable(nameOrConfigOrTarget?: string | Object, key?: any, descriptor?: any): any; +export declare function bindable(nameOrConfigOrTarget?: string | BindablePropertyConfig, key?: any, descriptor?: any): any; /** * Decorator: Specifies that the decorated custom attribute has options that diff --git a/dist/aurelia-templating.js b/dist/aurelia-templating.js index 1f9ea8a6..57c23630 100644 --- a/dist/aurelia-templating.js +++ b/dist/aurelia-templating.js @@ -4,7 +4,7 @@ import {DOM,PLATFORM,FEATURE} from 'aurelia-pal'; import {relativeToFile} from 'aurelia-path'; import {TemplateRegistryEntry,Loader} from 'aurelia-loader'; import {inject,Container,resolver} from 'aurelia-dependency-injection'; -import {Binding,createOverrideContext,ValueConverterResource,BindingBehaviorResource,subscriberCollection,bindingMode,ObserverLocator,EventManager} from 'aurelia-binding'; +import {Binding,createOverrideContext,bindingMode,ValueConverterResource,BindingBehaviorResource,subscriberCollection,ObserverLocator,EventManager} from 'aurelia-binding'; import {TaskQueue} from 'aurelia-task-queue'; /** @@ -2177,6 +2177,24 @@ interface DynamicComponentGetViewStrategy { getViewStrategy(): string|ViewStrategy; } +/** +* An optional interface describing the configuration object that can be specified to customize bindable properties. +*/ +interface BindablePropertyConfig { + /** + * The default binding mode of the property. + */ + defaultBindingMode?: bindingMode; + /** + * The name of a view model method to invoke when the property is updated. + */ + changeHandler?: string; + /** + * The name of the property. + */ + name?: string; +} + function getAnimatableElement(view) { if (view.animatableElement !== undefined) { return view.animatableElement; @@ -4520,9 +4538,9 @@ function getObserver(instance, name) { export class BindableProperty { /** * Creates an instance of BindableProperty. - * @param nameOrConfig The name of the property or a cofiguration object. + * @param nameOrConfig The name of the property or a configuration object. */ - constructor(nameOrConfig: string | Object) { + constructor(nameOrConfig: string | BindablePropertyConfig) { if (typeof nameOrConfig === 'string') { this.name = nameOrConfig; } else { @@ -4706,11 +4724,11 @@ export class BindableProperty { } observer = observerLookup[name] = new BehaviorPropertyObserver( - this.owner.taskQueue, - viewModel, - name, - selfSubscriber - ); + this.owner.taskQueue, + viewModel, + name, + selfSubscriber + ); Object.defineProperty(viewModel, name, { configurable: true, @@ -5759,7 +5777,7 @@ function validateBehaviorName(name, type) { * @param instance The resource instance. */ export function resource(instance: Object): any { - return function(target) { + return function (target) { metadata.define(metadata.resource, instance, target); }; } @@ -5796,8 +5814,8 @@ export function customElement(name: string): any { * @param defaultBindingMode The default binding mode to use when the attribute is bound with .bind. * @param aliases The array of aliases to associate to the custom attribute. */ -export function customAttribute(name: string, defaultBindingMode?: number, aliases?: string[]): any { - return function(target) { +export function customAttribute(name: string, defaultBindingMode?: bindingMode, aliases?: string[]): any { + return function (target) { let r = metadata.getOrCreateOwn(metadata.resource, HtmlBehaviorResource, target); r.attributeName = validateBehaviorName(name, 'custom attribute'); r.attributeDefaultBindingMode = defaultBindingMode; @@ -5823,7 +5841,7 @@ export function templateController(target?): any { * Decorator: Specifies that a property is bindable through HTML. * @param nameOrConfigOrTarget The name of the property, or a configuration object. */ -export function bindable(nameOrConfigOrTarget?: string | Object, key?, descriptor?): any { +export function bindable(nameOrConfigOrTarget?: string | BindablePropertyConfig, key?, descriptor?): any { let deco = function(target, key2, descriptor2) { let actualTarget = key2 ? target.constructor : target; //is it on a property or a class? let r = metadata.getOrCreateOwn(metadata.resource, HtmlBehaviorResource, actualTarget); @@ -5929,7 +5947,7 @@ export function processContent(processor: boolean | Function): any { * element container. */ export function containerless(target?): any { - let deco = function(t) { + let deco = function (t) { let r = metadata.getOrCreateOwn(metadata.resource, HtmlBehaviorResource, t); r.containerless = true; }; @@ -5962,14 +5980,14 @@ export function useView(path: string): any { * @param dependencies A list of dependencies that the template has. * @param dependencyBaseUrl A base url from which the dependencies will be loaded. */ -export function inlineView(markup:string, dependencies?:Array, dependencyBaseUrl?:string): any { +export function inlineView(markup: string, dependencies?: Array, dependencyBaseUrl?: string): any { return useViewStrategy(new InlineViewStrategy(markup, dependencies, dependencyBaseUrl)); } /** * Decorator: Indicates that the component has no view. */ -export function noView(targetOrDependencies?:Function|Array, dependencyBaseUrl?:string): any { +export function noView(targetOrDependencies?: Function | Array, dependencyBaseUrl?: string): any { let target; let dependencies; if (typeof targetOrDependencies === 'function') { diff --git a/dist/es2015/aurelia-templating.js b/dist/es2015/aurelia-templating.js index 301204cf..66b36ef6 100644 --- a/dist/es2015/aurelia-templating.js +++ b/dist/es2015/aurelia-templating.js @@ -6,7 +6,7 @@ import { DOM, PLATFORM, FEATURE } from 'aurelia-pal'; import { relativeToFile } from 'aurelia-path'; import { TemplateRegistryEntry, Loader } from 'aurelia-loader'; import { inject, Container, resolver } from 'aurelia-dependency-injection'; -import { Binding, createOverrideContext, ValueConverterResource, BindingBehaviorResource, subscriberCollection, bindingMode, ObserverLocator, EventManager } from 'aurelia-binding'; +import { Binding, createOverrideContext, bindingMode, ValueConverterResource, BindingBehaviorResource, subscriberCollection, ObserverLocator, EventManager } from 'aurelia-binding'; import { TaskQueue } from 'aurelia-task-queue'; export const animationEvent = { @@ -630,7 +630,7 @@ export let ViewLocator = (_temp2 = _class7 = class ViewLocator { }, _class7.viewStrategyMetadataKey = 'aurelia:view-strategy', _temp2); function mi(name) { - throw new Error(`BindingLanguage must implement ${ name }().`); + throw new Error(`BindingLanguage must implement ${name}().`); } export let BindingLanguage = class BindingLanguage { @@ -1060,7 +1060,7 @@ function register(lookup, name, resource, type) { let existing = lookup[name]; if (existing) { if (existing !== resource) { - throw new Error(`Attempted to register ${ type } when one with the same name already exists. Name: ${ name }.`); + throw new Error(`Attempted to register ${type} when one with the same name already exists. Name: ${name}.`); } return; @@ -2998,7 +2998,7 @@ export let ViewEngine = (_dec8 = inject(Loader, Container, ViewCompiler, ModuleA importIds = dependencies.map(x => x.src); names = dependencies.map(x => x.name); - logger.debug(`importing resources for ${ registryEntry.address }`, importIds); + logger.debug(`importing resources for ${registryEntry.address}`, importIds); if (target) { let viewModelRequires = metadata.get(ViewEngine.viewModelRequireMetadataKey, target); @@ -3013,7 +3013,7 @@ export let ViewEngine = (_dec8 = inject(Loader, Container, ViewCompiler, ModuleA names.push(req.as); } } - logger.debug(`importing ViewModel resources for ${ compileInstruction.associatedModuleId }`, importIds.slice(templateImportCount)); + logger.debug(`importing ViewModel resources for ${compileInstruction.associatedModuleId}`, importIds.slice(templateImportCount)); } } @@ -3026,7 +3026,7 @@ export let ViewEngine = (_dec8 = inject(Loader, Container, ViewCompiler, ModuleA let resourceModule = this.moduleAnalyzer.analyze(normalizedId, viewModelModule, moduleMember); if (!resourceModule.mainResource) { - throw new Error(`No view model found in module "${ moduleImport }".`); + throw new Error(`No view model found in module "${moduleImport}".`); } resourceModule.initialize(this.container); @@ -3442,7 +3442,7 @@ export let BindableProperty = class BindableProperty { } else if ('propertyChanged' in viewModel) { selfSubscriber = (newValue, oldValue) => viewModel.propertyChanged(name, newValue, oldValue); } else if (changeHandlerName !== null) { - throw new Error(`Change handler ${ changeHandlerName } was specified but not declared on the class.`); + throw new Error(`Change handler ${changeHandlerName} was specified but not declared on the class.`); } if (defaultValue !== undefined) { @@ -4353,7 +4353,7 @@ export let ElementConfigResource = class ElementConfigResource { function validateBehaviorName(name, type) { if (/[A-Z]/.test(name)) { let newName = _hyphenate(name); - LogManager.getLogger('templating').warn(`'${ name }' is not a valid ${ type } name and has been converted to '${ newName }'. Upper-case letters are not allowed because the DOM is not case-sensitive.`); + LogManager.getLogger('templating').warn(`'${name}' is not a valid ${type} name and has been converted to '${newName}'. Upper-case letters are not allowed because the DOM is not case-sensitive.`); return newName; } return name; diff --git a/dist/native-modules/aurelia-templating.js b/dist/native-modules/aurelia-templating.js index 45b51210..8bf60243 100644 --- a/dist/native-modules/aurelia-templating.js +++ b/dist/native-modules/aurelia-templating.js @@ -12,7 +12,7 @@ import { DOM, PLATFORM, FEATURE } from 'aurelia-pal'; import { relativeToFile } from 'aurelia-path'; import { TemplateRegistryEntry, Loader } from 'aurelia-loader'; import { inject, Container, resolver } from 'aurelia-dependency-injection'; -import { Binding, createOverrideContext, ValueConverterResource, BindingBehaviorResource, subscriberCollection, bindingMode, ObserverLocator, EventManager } from 'aurelia-binding'; +import { Binding, createOverrideContext, bindingMode, ValueConverterResource, BindingBehaviorResource, subscriberCollection, ObserverLocator, EventManager } from 'aurelia-binding'; import { TaskQueue } from 'aurelia-task-queue'; export var animationEvent = { diff --git a/dist/system/aurelia-templating.js b/dist/system/aurelia-templating.js index f33e6957..b0cf0be4 100644 --- a/dist/system/aurelia-templating.js +++ b/dist/system/aurelia-templating.js @@ -3,7 +3,7 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia-path', 'aurelia-loader', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-task-queue'], function (_export, _context) { "use strict"; - var LogManager, metadata, Origin, protocol, DOM, PLATFORM, FEATURE, relativeToFile, TemplateRegistryEntry, Loader, inject, Container, resolver, Binding, createOverrideContext, ValueConverterResource, BindingBehaviorResource, subscriberCollection, bindingMode, ObserverLocator, EventManager, TaskQueue, _createClass, _typeof, _class, _temp, _dec, _class2, _dec2, _class3, _dec3, _class4, _dec4, _class5, _dec5, _class6, _class7, _temp2, _dec6, _class8, _class9, _temp3, _class11, _dec7, _class13, _dec8, _class14, _class15, _temp4, _dec9, _class16, _dec10, _class17, _dec11, _class18, animationEvent, Animator, CompositionTransactionNotifier, CompositionTransactionOwnershipToken, CompositionTransaction, capitalMatcher, ViewEngineHooksResource, ElementEvents, EventHandlerImpl, ResourceLoadContext, ViewCompileInstruction, BehaviorInstruction, TargetInstruction, viewStrategy, RelativeViewStrategy, ConventionalViewStrategy, NoViewStrategy, TemplateRegistryViewStrategy, InlineViewStrategy, ViewLocator, BindingLanguage, noNodes, SlotCustomAttribute, PassThroughSlot, ShadowSlot, ShadowDOM, ViewResources, View, ViewSlot, ProviderResolver, providerResolverInstance, BoundViewFactory, ViewFactory, nextInjectorId, lastAUTargetID, ViewCompiler, ResourceModule, ResourceDescription, ModuleAnalyzer, logger, ProxyViewFactory, auSlotBehavior, ViewEngine, Controller, BehaviorPropertyObserver, BindableProperty, lastProviderId, HtmlBehaviorResource, ChildObserver, noMutations, ChildObserverBinder, SwapStrategies, CompositionEngine, ElementConfigResource, defaultShadowDOMOptions, TemplatingEngine; + var LogManager, metadata, Origin, protocol, DOM, PLATFORM, FEATURE, relativeToFile, TemplateRegistryEntry, Loader, inject, Container, resolver, Binding, createOverrideContext, bindingMode, ValueConverterResource, BindingBehaviorResource, subscriberCollection, ObserverLocator, EventManager, TaskQueue, _createClass, _typeof, _class, _temp, _dec, _class2, _dec2, _class3, _dec3, _class4, _dec4, _class5, _dec5, _class6, _class7, _temp2, _dec6, _class8, _class9, _temp3, _class11, _dec7, _class13, _dec8, _class14, _class15, _temp4, _dec9, _class16, _dec10, _class17, _dec11, _class18, animationEvent, Animator, CompositionTransactionNotifier, CompositionTransactionOwnershipToken, CompositionTransaction, capitalMatcher, ViewEngineHooksResource, ElementEvents, EventHandlerImpl, ResourceLoadContext, ViewCompileInstruction, BehaviorInstruction, TargetInstruction, viewStrategy, RelativeViewStrategy, ConventionalViewStrategy, NoViewStrategy, TemplateRegistryViewStrategy, InlineViewStrategy, ViewLocator, BindingLanguage, noNodes, SlotCustomAttribute, PassThroughSlot, ShadowSlot, ShadowDOM, ViewResources, View, ViewSlot, ProviderResolver, providerResolverInstance, BoundViewFactory, ViewFactory, nextInjectorId, lastAUTargetID, ViewCompiler, ResourceModule, ResourceDescription, ModuleAnalyzer, logger, ProxyViewFactory, auSlotBehavior, ViewEngine, Controller, BehaviorPropertyObserver, BindableProperty, lastProviderId, HtmlBehaviorResource, ChildObserver, noMutations, ChildObserverBinder, SwapStrategies, CompositionEngine, ElementConfigResource, defaultShadowDOMOptions, TemplatingEngine; @@ -735,10 +735,10 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- }, function (_aureliaBinding) { Binding = _aureliaBinding.Binding; createOverrideContext = _aureliaBinding.createOverrideContext; + bindingMode = _aureliaBinding.bindingMode; ValueConverterResource = _aureliaBinding.ValueConverterResource; BindingBehaviorResource = _aureliaBinding.BindingBehaviorResource; subscriberCollection = _aureliaBinding.subscriberCollection; - bindingMode = _aureliaBinding.bindingMode; ObserverLocator = _aureliaBinding.ObserverLocator; EventManager = _aureliaBinding.EventManager; }, function (_aureliaTaskQueue) { diff --git a/src/bindable-property.js b/src/bindable-property.js index 4cb134d2..a7749ceb 100644 --- a/src/bindable-property.js +++ b/src/bindable-property.js @@ -33,9 +33,9 @@ function getObserver(instance, name) { export class BindableProperty { /** * Creates an instance of BindableProperty. - * @param nameOrConfig The name of the property or a cofiguration object. + * @param nameOrConfig The name of the property or a configuration object. */ - constructor(nameOrConfig: string | Object) { + constructor(nameOrConfig: string | BindablePropertyConfig) { if (typeof nameOrConfig === 'string') { this.name = nameOrConfig; } else { @@ -219,11 +219,11 @@ export class BindableProperty { } observer = observerLookup[name] = new BehaviorPropertyObserver( - this.owner.taskQueue, - viewModel, - name, - selfSubscriber - ); + this.owner.taskQueue, + viewModel, + name, + selfSubscriber + ); Object.defineProperty(viewModel, name, { configurable: true, diff --git a/src/decorators.js b/src/decorators.js index 083b6955..8b5e8345 100644 --- a/src/decorators.js +++ b/src/decorators.js @@ -58,7 +58,7 @@ export function customElement(name: string): any { * @param defaultBindingMode The default binding mode to use when the attribute is bound with .bind. * @param aliases The array of aliases to associate to the custom attribute. */ -export function customAttribute(name: string, defaultBindingMode?: number, aliases?: string[]): any { +export function customAttribute(name: string, defaultBindingMode?: bindingMode, aliases?: string[]): any { return function(target) { let r = metadata.getOrCreateOwn(metadata.resource, HtmlBehaviorResource, target); r.attributeName = validateBehaviorName(name, 'custom attribute'); @@ -85,7 +85,7 @@ export function templateController(target?): any { * Decorator: Specifies that a property is bindable through HTML. * @param nameOrConfigOrTarget The name of the property, or a configuration object. */ -export function bindable(nameOrConfigOrTarget?: string | Object, key?, descriptor?): any { +export function bindable(nameOrConfigOrTarget?: string | BindablePropertyConfig, key?, descriptor?): any { let deco = function(target, key2, descriptor2) { let actualTarget = key2 ? target.constructor : target; //is it on a property or a class? let r = metadata.getOrCreateOwn(metadata.resource, HtmlBehaviorResource, actualTarget); @@ -191,7 +191,7 @@ export function processContent(processor: boolean | Function): any { * element container. */ export function containerless(target?): any { - let deco = function(t) { + let deco = function (t) { let r = metadata.getOrCreateOwn(metadata.resource, HtmlBehaviorResource, t); r.containerless = true; }; @@ -224,14 +224,14 @@ export function useView(path: string): any { * @param dependencies A list of dependencies that the template has. * @param dependencyBaseUrl A base url from which the dependencies will be loaded. */ -export function inlineView(markup:string, dependencies?:Array, dependencyBaseUrl?:string): any { +export function inlineView(markup: string, dependencies?: Array, dependencyBaseUrl?: string): any { return useViewStrategy(new InlineViewStrategy(markup, dependencies, dependencyBaseUrl)); } /** * Decorator: Indicates that the component has no view. */ -export function noView(targetOrDependencies?:Function|Array, dependencyBaseUrl?:string): any { +export function noView(targetOrDependencies?: Function | Array, dependencyBaseUrl?: string): any { let target; let dependencies; if (typeof targetOrDependencies === 'function') { diff --git a/src/interfaces.js b/src/interfaces.js index 8d6dbd88..ab4d7dc9 100644 --- a/src/interfaces.js +++ b/src/interfaces.js @@ -1,3 +1,4 @@ +import {bindingMode} from 'aurelia-binding'; import {View} from './view'; import {ViewStrategy} from './view-strategy'; @@ -67,3 +68,21 @@ interface DynamicComponentGetViewStrategy { */ getViewStrategy(): string|ViewStrategy; } + +/** +* An optional interface describing the configuration object that can be specified to customize bindable properties. +*/ +interface BindablePropertyConfig { + /** + * The default binding mode of the property. + */ + defaultBindingMode?: bindingMode; + /** + * The name of a view model method to invoke when the property is updated. + */ + changeHandler?: string; + /** + * The name of the property. + */ + name?: string; +}