UNPKG

bugcore

Version:

bugcore is a JavaScript library that provides a foundational architecture for object oriented JS

308 lines (253 loc) 10.4 kB
/* * Copyright (c) 2016 airbug Inc. http://airbug.com * * bugcore may be freely distributed under the MIT license. */ //------------------------------------------------------------------------------- // Annotations //------------------------------------------------------------------------------- //@Export('ObservableObject') //@Require('Class') //@Require('ClearChange') //@Require('DualMap') //@Require('IObjectable') //@Require('IObservable') //@Require('Obj') //@Require('ObjectUtil') //@Require('Observable') //@Require('RemovePropertyChange') //@Require('SetPropertyChange') //------------------------------------------------------------------------------- // Context //------------------------------------------------------------------------------- require('bugpack').context("*", function(bugpack) { //------------------------------------------------------------------------------- // BugPack //------------------------------------------------------------------------------- var Class = bugpack.require('Class'); var ClearChange = bugpack.require('ClearChange'); var DualMap = bugpack.require('DualMap'); var IObjectable = bugpack.require('IObjectable'); var IObservable = bugpack.require('IObservable'); var Obj = bugpack.require('Obj'); var ObjectUtil = bugpack.require('ObjectUtil'); var Observable = bugpack.require('Observable'); var RemovePropertyChange = bugpack.require('RemovePropertyChange'); var SetPropertyChange = bugpack.require('SetPropertyChange'); //------------------------------------------------------------------------------- // Declare Class //------------------------------------------------------------------------------- /** * @class * @extends {Observable} * @implements {IObjectable} */ var ObservableObject = Class.extend(Observable, /** @lends {ObservableObject.prototype} */{ _name: "ObservableObject", //------------------------------------------------------------------------------- // Constructor //------------------------------------------------------------------------------- /** * @constructs * @param {Object} observedObject */ _constructor: function(observedObject) { this._super(); //------------------------------------------------------------------------------- // Private Properties //------------------------------------------------------------------------------- /** * @private * @type {Object} */ this.observedObject = {}; /** * @private * @type {DualMap.<string, IObservable>} */ this.observablePropertyMap = new DualMap(); if (observedObject) { this.observedObject = Obj.clone(observedObject, true); } }, //------------------------------------------------------------------------------- // Getters and Setters //------------------------------------------------------------------------------- /** * @return {Object} */ getObservedObject: function() { return this.observedObject; }, //------------------------------------------------------------------------------- // IObjectable Implementation //------------------------------------------------------------------------------- /** * @return {Object} */ toObject: function() { var object = {}; this.forIn(function(propertyName, propertyValue) { object[propertyName] = propertyValue; }); return object; }, //------------------------------------------------------------------------------- // Observable Methods //------------------------------------------------------------------------------- /** * @override * @param {Observation} observation */ propagateObservation: function(observation) { var _this = this; var propertyNames = this.findPropertyNamesByObservable(observation.getReportingObservable()); propertyNames.forEach(function(propertyName) { var observationClone = observation.clone(); var observationPath = observationClone.getObservationPath(); if (observationPath !== "") { observationPath = "." + observationPath; } observationPath = propertyName + observationPath; observationClone.setObservationPath(observationPath); _this._super(observationClone); }); }, //------------------------------------------------------------------------------- // Public Methods //------------------------------------------------------------------------------- /** * */ clearProperties: function() { var _this = this; this.observedObject = {}; this.observablePropertyMap.forEach(function(observable, propertyName) { _this.removeObservableProperty(propertyName); }); this.notifyObservers(new ClearChange()); }, /** * @param {function(string, *)} func */ forIn: function(func) { ObjectUtil.forIn(this.observedObject, func); }, /** * @param {string} propertyName * @return {*} */ getProperty: function(propertyName) { return ObjectUtil.getProperty(this.observedObject, propertyName); }, /** * @param {string} propertyName * @return {*} */ hasProperty: function(propertyName) { return ObjectUtil.hasProperty(this.observedObject, propertyName); }, /** * @param {string} propertyName */ removeProperty: function(propertyName) { if (ObjectUtil.hasProperty(this.observedObject, propertyName)) { var previousValue = this.getProperty(propertyName); if (this.hasObservableProperty(propertyName)) { this.removeObservableProperty(propertyName); } delete this.observedObject[propertyName]; this.notifyObservers(new RemovePropertyChange(propertyName, previousValue), propertyName); } }, /** * @param {string} propertyName * @param {*} propertyValue */ setProperty: function(propertyName, propertyValue) { var previousValue = this.getProperty(propertyName); if (!Obj.equals(previousValue, propertyValue)) { if (this.hasObservableProperty(propertyName)) { this.removeObservableProperty(propertyName); } this.observedObject[propertyName] = propertyValue; if (Class.doesImplement(propertyValue, IObservable)) { this.putObservableProperty(propertyName, propertyValue); } this.notifyObservers(new SetPropertyChange(propertyName, propertyValue, previousValue), propertyName); } }, /** * @param {Object} propertiesObject */ setProperties: function(propertiesObject) { var _this = this; ObjectUtil.forIn(propertiesObject, function(propertyName, propertyValue) { _this.setProperty(propertyName, propertyValue); }); }, //------------------------------------------------------------------------------- // Private Methods //------------------------------------------------------------------------------- /** * @private * @param {IObservable} observable * @return {boolean} */ containsObservable: function(observable) { return this.observablePropertyMap.containsValue(observable); }, /** * @private * @param {IObservable} observable * @return {Collection.<string>} */ findPropertyNamesByObservable: function(observable) { return this.observablePropertyMap.getKeys(observable) }, /** * @private * @param {string} propertyName * @return {IObservable} */ getObservableProperty: function(propertyName) { return this.observablePropertyMap.getValue(propertyName); }, /** * @private * @param {string} propertyName * @return {boolean} */ hasObservableProperty: function(propertyName) { return this.observablePropertyMap.containsKey(propertyName); }, /** * @private * @param propertyName * @param observable */ putObservableProperty: function(propertyName, observable) { this.observablePropertyMap.put(propertyName, observable); observable.addObservationPropagator(this); }, /** * @private * @param {string} propertyName */ removeObservableProperty: function(propertyName) { var observable = this.getObservableProperty(propertyName); this.observablePropertyMap.removeByKey(propertyName); if (!this.containsObservable(observable)) { observable.removeObservationPropagator(this); } } }); //------------------------------------------------------------------------------- // Implement Interfaces //------------------------------------------------------------------------------- Class.implement(ObservableObject, IObjectable); //------------------------------------------------------------------------------- // Exports //------------------------------------------------------------------------------- bugpack.export('ObservableObject', ObservableObject); });