UNPKG

@danielkalen/simplybind

Version:

Magically simple, framework-less one-way/two-way data binding for frontend/backend in ~5kb.

108 lines (85 loc) 2.47 kB
import * as LogManager from 'aurelia-logging'; import {subscriberCollection} from './subscriber-collection'; const logger = LogManager.getLogger('property-observation'); export const propertyAccessor = { getValue: (obj, propertyName) => obj[propertyName], setValue: (value, obj, propertyName) => { obj[propertyName] = value; } }; export class PrimitiveObserver { doNotCache = true; constructor(primitive, propertyName) { this.primitive = primitive; this.propertyName = propertyName; } getValue() { return this.primitive[this.propertyName]; } setValue() { let type = typeof this.primitive; throw new Error(`The ${this.propertyName} property of a ${type} (${this.primitive}) cannot be assigned.`); } subscribe() { } unsubscribe() { } } @subscriberCollection() export class SetterObserver { constructor(taskQueue, obj, propertyName) { this.taskQueue = taskQueue; this.obj = obj; this.propertyName = propertyName; this.queued = false; this.observing = false; } getValue() { return this.obj[this.propertyName]; } setValue(newValue) { this.obj[this.propertyName] = newValue; } getterValue() { return this.currentValue; } setterValue(newValue) { let oldValue = this.currentValue; if (oldValue !== newValue) { if (!this.queued) { this.oldValue = oldValue; this.queued = true; this.taskQueue.queueMicroTask(this); } this.currentValue = newValue; } } call() { let oldValue = this.oldValue; let newValue = this.currentValue; this.queued = false; this.callSubscribers(newValue, oldValue); } subscribe(context, callable) { if (!this.observing) { this.convertProperty(); } this.addSubscriber(context, callable); } unsubscribe(context, callable) { this.removeSubscriber(context, callable); } convertProperty() { this.observing = true; this.currentValue = this.obj[this.propertyName]; this.setValue = this.setterValue; this.getValue = this.getterValue; if (!Reflect.defineProperty(this.obj, this.propertyName, { configurable: true, enumerable: this.propertyName in this.obj ? this.obj.propertyIsEnumerable(this.propertyName) : true, get: this.getValue.bind(this), set: this.setValue.bind(this) })) { logger.warn(`Cannot observe property '${this.propertyName}' of object`, this.obj); } } }