UNPKG

6.41 kBJavaScriptView Raw
1"use strict";
2/*-----------------------------------------------------------------------------
3| Copyright (c) 2014-2017, PhosphorJS Contributors
4|
5| Distributed under the terms of the BSD 3-Clause License.
6|
7| The full license is in the file LICENSE, distributed with this software.
8|----------------------------------------------------------------------------*/
9Object.defineProperty(exports, "__esModule", { value: true });
10/**
11 * A class which attaches a value to an external object.
12 *
13 * #### Notes
14 * Attached properties are used to extend the state of an object with
15 * semantic data from an unrelated class. They also encapsulate value
16 * creation, coercion, and notification.
17 *
18 * Because attached property values are stored in a hash table, which
19 * in turn is stored in a WeakMap keyed on the owner object, there is
20 * non-trivial storage overhead involved in their use. The pattern is
21 * therefore best used for the storage of rare data.
22 */
23var AttachedProperty = /** @class */ (function () {
24 /**
25 * Construct a new attached property.
26 *
27 * @param options - The options for initializing the property.
28 */
29 function AttachedProperty(options) {
30 this._pid = Private.nextPID();
31 this.name = options.name;
32 this._create = options.create;
33 this._coerce = options.coerce || null;
34 this._compare = options.compare || null;
35 this._changed = options.changed || null;
36 }
37 /**
38 * Get the current value of the property for a given owner.
39 *
40 * @param owner - The property owner of interest.
41 *
42 * @returns The current value of the property.
43 *
44 * #### Notes
45 * If the value has not yet been set, the default value will be
46 * computed and assigned as the current value of the property.
47 */
48 AttachedProperty.prototype.get = function (owner) {
49 var value;
50 var map = Private.ensureMap(owner);
51 if (this._pid in map) {
52 value = map[this._pid];
53 }
54 else {
55 value = map[this._pid] = this._createValue(owner);
56 }
57 return value;
58 };
59 /**
60 * Set the current value of the property for a given owner.
61 *
62 * @param owner - The property owner of interest.
63 *
64 * @param value - The value for the property.
65 *
66 * #### Notes
67 * If the value has not yet been set, the default value will be
68 * computed and used as the previous value for the comparison.
69 */
70 AttachedProperty.prototype.set = function (owner, value) {
71 var oldValue;
72 var map = Private.ensureMap(owner);
73 if (this._pid in map) {
74 oldValue = map[this._pid];
75 }
76 else {
77 oldValue = map[this._pid] = this._createValue(owner);
78 }
79 var newValue = this._coerceValue(owner, value);
80 this._maybeNotify(owner, oldValue, map[this._pid] = newValue);
81 };
82 /**
83 * Explicitly coerce the current property value for a given owner.
84 *
85 * @param owner - The property owner of interest.
86 *
87 * #### Notes
88 * If the value has not yet been set, the default value will be
89 * computed and used as the previous value for the comparison.
90 */
91 AttachedProperty.prototype.coerce = function (owner) {
92 var oldValue;
93 var map = Private.ensureMap(owner);
94 if (this._pid in map) {
95 oldValue = map[this._pid];
96 }
97 else {
98 oldValue = map[this._pid] = this._createValue(owner);
99 }
100 var newValue = this._coerceValue(owner, oldValue);
101 this._maybeNotify(owner, oldValue, map[this._pid] = newValue);
102 };
103 /**
104 * Get or create the default value for the given owner.
105 */
106 AttachedProperty.prototype._createValue = function (owner) {
107 var create = this._create;
108 return create(owner);
109 };
110 /**
111 * Coerce the value for the given owner.
112 */
113 AttachedProperty.prototype._coerceValue = function (owner, value) {
114 var coerce = this._coerce;
115 return coerce ? coerce(owner, value) : value;
116 };
117 /**
118 * Compare the old value and new value for equality.
119 */
120 AttachedProperty.prototype._compareValue = function (oldValue, newValue) {
121 var compare = this._compare;
122 return compare ? compare(oldValue, newValue) : oldValue === newValue;
123 };
124 /**
125 * Run the change notification if the given values are different.
126 */
127 AttachedProperty.prototype._maybeNotify = function (owner, oldValue, newValue) {
128 var changed = this._changed;
129 if (changed && !this._compareValue(oldValue, newValue)) {
130 changed(owner, oldValue, newValue);
131 }
132 };
133 return AttachedProperty;
134}());
135exports.AttachedProperty = AttachedProperty;
136/**
137 * The namespace for the `AttachedProperty` class statics.
138 */
139(function (AttachedProperty) {
140 /**
141 * Clear the stored property data for the given owner.
142 *
143 * @param owner - The property owner of interest.
144 *
145 * #### Notes
146 * This will clear all property values for the owner, but it will
147 * **not** run the change notification for any of the properties.
148 */
149 function clearData(owner) {
150 Private.ownerData.delete(owner);
151 }
152 AttachedProperty.clearData = clearData;
153})(AttachedProperty = exports.AttachedProperty || (exports.AttachedProperty = {}));
154exports.AttachedProperty = AttachedProperty;
155/**
156 * The namespace for the module implementation details.
157 */
158var Private;
159(function (Private) {
160 /**
161 * A weak mapping of property owner to property map.
162 */
163 Private.ownerData = new WeakMap();
164 /**
165 * A function which computes successive unique property ids.
166 */
167 Private.nextPID = (function () {
168 var id = 0;
169 return function () {
170 var rand = Math.random();
171 var stem = ("" + rand).slice(2);
172 return "pid-" + stem + "-" + id++;
173 };
174 })();
175 /**
176 * Lookup the data map for the property owner.
177 *
178 * This will create the map if one does not already exist.
179 */
180 function ensureMap(owner) {
181 var map = Private.ownerData.get(owner);
182 if (map) {
183 return map;
184 }
185 map = Object.create(null);
186 Private.ownerData.set(owner, map);
187 return map;
188 }
189 Private.ensureMap = ensureMap;
190})(Private || (Private = {}));