@lumjs/core 1.10.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/observable.js +92 -47
  2. package/package.json +1 -1
package/lib/observable.js CHANGED
@@ -1,5 +1,7 @@
1
1
 
2
2
  const {B,F,S,def,isObj,isComplex,TYPES,console} = require('./types');
3
+ const {duplicateAll: clone} = require('./obj/copyall');
4
+ const lock = Object.freeze;
3
5
 
4
6
  /**
5
7
  * Make an object support the *Observable* API.
@@ -11,29 +13,57 @@ const {B,F,S,def,isObj,isComplex,TYPES,console} = require('./types');
11
13
  * @param {string} [opts.wildcard='*'] The event name used as a wildcard.
12
14
  * @param {boolean} [opts.wrapthis=false] If `true`, `this` will be a wrapper.
13
15
  *
14
- * If 'wrapthis' is true, the function will be called with a wrapper object as
15
- * the 'this' variable instead of the target object. The wrapper will be:
16
+ * If `wrapthis` is `true`, the function will be called with a wrapper object
17
+ * as the `this` variable instead of the target object. The wrapper will be:
16
18
  *
17
19
  * ```js
18
20
  * {
21
+ * isObservable:
22
+ * {
23
+ * event: true, // This is an event data object.
24
+ * target: false, // This is not the target object.
25
+ * },
19
26
  * self: el, // The target object.
20
27
  * name: event, // The event name that was triggered.
21
28
  * wildcard: bool, // Will be true if this was a wildcard event handler.
22
29
  * func: function, // The function being called.
30
+ * args: array, // The arguments passed to trigger.
23
31
  * }
24
32
  * ```
25
33
  *
26
- * @param {boolean} [opts.addname=!opts.wrapthis] If `true` callbacks with
27
- * multiple events will have the name of the triggered event added as
28
- * the first parameter.
34
+ * The object will be frozen so its values cannot be modified.
35
+ *
36
+ * @param {boolean} [opts.wrapargs=false] If `true`, the functions will be
37
+ * passed a single object as the sole argument. The object will be the same
38
+ * as the one from `opts.wrapthis`.
39
+ *
40
+ * @param {boolean} [opts.addname] If `true` callbacks with
41
+ * multiple events will have the name of the triggered event added as
42
+ * the first parameter.
43
+ *
44
+ * If either `wrapthis` or `wrapargs` are `true`, then this will default
45
+ * to `false`, otherwise it will default to `true`.
46
+ *
47
+ * @param {boolean} [opts.addis] If `true` add a read-only, frozen
48
+ * object property named `isObservable` with the value:
49
+ *
50
+ * ```js
51
+ * {
52
+ * event: false, // This is not an event data object.
53
+ * target: true, // This is the target object.
54
+ * }
55
+ * ```
56
+ *
57
+ * If either `wrapthis` or `wrapargs` are `true`, then this will default
58
+ * to `true`, otherwise it will default to `false`.
29
59
  *
30
- * @param {boolean} [opts.addis=opts.wrapthis] If `true` add immutable
31
- * property named `isObservable` which will have a value of `true`.
32
60
  * @param {string} [opts.addme] If set, add a method with this name
33
- * to the object, which is a version of `observable()` with the
34
- * default options being the same as the current `opts`.
35
- * If `opts.wrapthis` is `true`, then this defaults to `'makeObservable'`.
36
- * In any other case it defaults to `null`.
61
+ * to the `el` object, which is a version of `observable()` with the
62
+ * default options being the same as the current `opts`.
63
+ *
64
+ * @param {string} [opts.addre] If set, add a method with this name
65
+ * to the `el` object, which is a function that can re-build the
66
+ * observable API methods with new `opts` replacing the old ones.
37
67
  *
38
68
  * @returns {object} el
39
69
  *
@@ -69,30 +99,46 @@ function observable (el={}, opts={})
69
99
  ? opts.wildcard
70
100
  : '*';
71
101
 
72
- const wrapthis = (typeof opts.wrapthis === 'boolean')
102
+ const wrapthis = (typeof opts.wrapthis === B)
73
103
  ? opts.wrapthis
74
104
  : false;
75
105
 
76
- const addname = (typeof opts.addname === 'boolean')
106
+ const wrapargs = (typeof opts.wrapargs === B)
107
+ ? opts.wrapargs
108
+ : false;
109
+
110
+ const wrapped = (wrapthis || wrapargs);
111
+
112
+ const addname = (typeof opts.addname === B)
77
113
  ? opts.addname
78
- : !wrapthis;
114
+ : !wrapped;
79
115
 
80
- const addis = (typeof opts.addis === 'boolean')
116
+ const addis = (typeof opts.addis === B)
81
117
  ? opts.addis
82
- : wrapthis;
118
+ : wrapped;
83
119
 
84
120
  const validIdent = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
85
121
 
86
- const addme = (typeof opts.addme === 'string'
122
+ const addme = (typeof opts.addme === S
87
123
  && validIdent.test(opts.addme))
88
124
  ? opts.addme
89
- : (wrapthis ? 'makeObservable' : null);
125
+ : null;
126
+
127
+ const addre = (typeof opts.addre === S
128
+ && validIdent.test(opts.addre))
129
+ ? opts.addre
130
+ : null;
90
131
 
91
132
  const slice = Array.prototype.slice;
92
133
 
93
134
  function onEachEvent (e, fn)
94
135
  {
95
- e.replace(/\S+/g, fn);
136
+ const es = e.split(/\s+/);
137
+ const me = es.length > 1;
138
+ for (e of es)
139
+ {
140
+ fn(e, me);
141
+ }
96
142
  }
97
143
 
98
144
  const add = def(el);
@@ -102,29 +148,28 @@ function observable (el={}, opts={})
102
148
  if (fn.busy) return;
103
149
  fn.busy = 1;
104
150
 
105
- let fthis;
151
+ let fobj;
106
152
 
107
- if (wrapthis)
108
- {
153
+ if (wrapthis || wrapargs)
154
+ { // Something is going to use our wrapper object.
109
155
  const isWild = (name === wildcard);
110
156
  const fname = isWild ? (addname ? args[0] : args.shift()) : name;
111
- fthis =
112
- {
157
+ fobj =
158
+ lock({
159
+ isObservable: lock({event: true, target: false}),
113
160
  self: el,
114
161
  name: fname,
115
162
  func: fn,
116
163
  wildcard: isWild,
117
- };
118
- }
119
- else
120
- {
121
- fthis = el;
164
+ args,
165
+ });
122
166
  }
123
167
 
124
- let fargs = (fn.typed && addname) ? [name].concat(args) : args;
125
-
168
+ const fthis = wrapthis ? fobj : el;
169
+ const fargs = wrapargs ? [fobj]
170
+ : ((fn.typed && addname) ? [name].concat(args) : args);
171
+
126
172
  fn.apply(fthis, fargs);
127
-
128
173
  fn.busy = 0;
129
174
  }
130
175
 
@@ -147,10 +192,10 @@ function observable (el={}, opts={})
147
192
  return el;
148
193
  }
149
194
 
150
- onEachEvent(events, function(name, pos)
195
+ onEachEvent(events, function(name, typed)
151
196
  {
152
197
  (callbacks[name] = callbacks[name] || []).push(fn);
153
- fn.typed = pos > 0;
198
+ fn.typed = typed;
154
199
  });
155
200
 
156
201
  return el;
@@ -244,28 +289,28 @@ function observable (el={}, opts={})
244
289
 
245
290
  if (addis)
246
291
  {
247
- add('isObservable', true);
292
+ add('isObservable', lock({event: false, target: true}));
248
293
  }
249
294
 
250
295
  if (addme)
251
296
  { // Add a wrapper for observable() that sets new default options.
252
- const ourProps = Object.keys(opts);
253
297
  add(addme, function (obj=null, mopts={})
254
298
  {
255
- if (ourProps.length > 0)
256
- {
257
- for (const prop of ourProps)
258
- {
259
- if (mopts[prop] === undefined)
260
- {
261
- mopts[prop] = opts[prop];
262
- }
263
- }
264
- }
265
- return observable(obj, mopts);
299
+ return observable(obj, clone(opts, mopts));
300
+ });
301
+ }
302
+
303
+ if (addre)
304
+ { // Add a method to change the observable options.
305
+ add(addre, function(opts={})
306
+ {
307
+ return observable(el, opts);
266
308
  });
267
309
  }
268
310
 
311
+ // Metadata
312
+ add('$$observable$$', lock({opts, observable}));
313
+
269
314
  return el
270
315
 
271
316
  } // observable()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumjs/core",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "main": "lib/index.js",
5
5
  "exports":
6
6
  {