@lumjs/compat 1.0.0 → 1.1.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.
- package/CHANGELOG.md +12 -1
- package/lib/v4/deprecated.js +122 -0
- package/lib/{descriptors.js → v4/descriptors.js} +0 -0
- package/lib/v4/loadtracker.js +509 -0
- package/lib/{v4-meta.js → v4/meta.js} +0 -0
- package/lib/v4/object-helpers.js +191 -0
- package/lib/v4/promise.js +381 -0
- package/lib/{prop.js → v4/prop.js} +0 -0
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,10 +6,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.1.0] - 2022-08-11
|
|
10
|
+
### Changed
|
|
11
|
+
- Moved all *v4* stuff into a new `v4` sub-module.
|
|
12
|
+
- Kept `compat/v4-meta` as an alias to `compat/v4/meta`.
|
|
13
|
+
### Added
|
|
14
|
+
- `v4/deprecated`
|
|
15
|
+
- `v4/loadtracker`
|
|
16
|
+
- `v4/object-helpers`
|
|
17
|
+
- `v4/promise`
|
|
18
|
+
|
|
9
19
|
## [1.0.0] - 2022-07-29
|
|
10
20
|
### Added
|
|
11
21
|
- Initial release.
|
|
12
22
|
|
|
13
|
-
[Unreleased]: https://github.com/supernovus/lum.compat.js/compare/v1.
|
|
23
|
+
[Unreleased]: https://github.com/supernovus/lum.compat.js/compare/v1.1.0...HEAD
|
|
24
|
+
[1.1.0]: https://github.com/supernovus/lum.compat.js/compare/v1.0.0...v1.1.0
|
|
14
25
|
[1.0.0]: https://github.com/supernovus/lum.compat.js/releases/tag/v1.0.0
|
|
15
26
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mark a function/method/property as deprecated.
|
|
3
|
+
*
|
|
4
|
+
* Adds a warning to the Console that the method is deprecated.
|
|
5
|
+
*
|
|
6
|
+
* It can also optionally give example replacement code, and run a function
|
|
7
|
+
* that will call the replacement code automatically.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} name The name of the deprecated method/property/etc.
|
|
10
|
+
*
|
|
11
|
+
* This should actually be the full method signature, or at least the
|
|
12
|
+
* signature matching what a call to the deprecated method made.
|
|
13
|
+
*
|
|
14
|
+
* So rather than 'someOldMethod', use 'MyClass.someOldMethod(foo, bar)'
|
|
15
|
+
* as a more detailed name. This is only used in the Console warning.
|
|
16
|
+
*
|
|
17
|
+
* This is the only mandatory parameter.
|
|
18
|
+
*
|
|
19
|
+
* @param {mixed} [replace={}] Replacement options.
|
|
20
|
+
*
|
|
21
|
+
* If this is a {string}, it is the same as passing an {object} with
|
|
22
|
+
* the following options specified:
|
|
23
|
+
*
|
|
24
|
+
* ```{msg: replace}```
|
|
25
|
+
*
|
|
26
|
+
* If it is a {function}, it is the same as passing an {object} with
|
|
27
|
+
* the following options specified:
|
|
28
|
+
*
|
|
29
|
+
* ```{exec: replace, msg: true, strip: true}```
|
|
30
|
+
*
|
|
31
|
+
* If it is an {object}, then it will be a set of options:
|
|
32
|
+
*
|
|
33
|
+
* "exec" {function}
|
|
34
|
+
*
|
|
35
|
+
* If specified, this function will be called and the value returned.
|
|
36
|
+
* No paramters are passed to the function, so it should be a simple
|
|
37
|
+
* anonymous closure which simply calls the actual replacement code.
|
|
38
|
+
*
|
|
39
|
+
* "msg" {string|boolean}
|
|
40
|
+
*
|
|
41
|
+
* If this is a {string} it will be added to the warning output.
|
|
42
|
+
*
|
|
43
|
+
* If this is `true` and `exec` is set, we will extract the function
|
|
44
|
+
* text using `exec.toString()` and add it to the warning output.
|
|
45
|
+
*
|
|
46
|
+
* In any other cases, no replacement message will be appended.
|
|
47
|
+
*
|
|
48
|
+
* "strip" {boolean}
|
|
49
|
+
*
|
|
50
|
+
* If this is `true`, then we will strip `'function() { return '`
|
|
51
|
+
* from the start of the function text (whitespace ignored), as well
|
|
52
|
+
* as stripping '}' from the very end of the function text.
|
|
53
|
+
*
|
|
54
|
+
* This is only applicable if `exec` is set, and `msg` is `true`.
|
|
55
|
+
*
|
|
56
|
+
* If the `replace` value is none of the above, it will be ignored.
|
|
57
|
+
*
|
|
58
|
+
* @return {mixed} The output is dependent on the parameters passed.
|
|
59
|
+
*
|
|
60
|
+
* If `replace` is a function or an object with
|
|
61
|
+
*
|
|
62
|
+
* In any other case the return value will be undefined.
|
|
63
|
+
*
|
|
64
|
+
* @alias module:@lumjs/compat/v4/deprecated
|
|
65
|
+
*/
|
|
66
|
+
module.exports = function (name, replace={})
|
|
67
|
+
{
|
|
68
|
+
const DEP_MSG = ':Deprecated =>';
|
|
69
|
+
const REP_MSG = ':replaceWith =>';
|
|
70
|
+
|
|
71
|
+
if (typeof replace === S)
|
|
72
|
+
{ // A string replacement example only.
|
|
73
|
+
replace = {msg: replace};
|
|
74
|
+
}
|
|
75
|
+
else if (typeof replace === F)
|
|
76
|
+
{ // A function replacement.
|
|
77
|
+
replace = {exec: replace, msg: true, strip: true};
|
|
78
|
+
}
|
|
79
|
+
else if (!is_obj(replace))
|
|
80
|
+
{ // Not an object, that's not valid.
|
|
81
|
+
replace = {};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const msgs = [DEP_MSG, name];
|
|
85
|
+
const exec = (typeof replace.exec === F)
|
|
86
|
+
? replace.exec
|
|
87
|
+
: null;
|
|
88
|
+
|
|
89
|
+
if (exec && replace.msg === true)
|
|
90
|
+
{ // Extract the function text.
|
|
91
|
+
const strip = (typeof replace.strip === B)
|
|
92
|
+
? replace.strip
|
|
93
|
+
: false;
|
|
94
|
+
|
|
95
|
+
let methtext = replace.exec.toString();
|
|
96
|
+
|
|
97
|
+
if (strip)
|
|
98
|
+
{ // Remove wrapping anonymous closure function.
|
|
99
|
+
methtext = methtext.replace(/^function\(\)\s*\{\s*(return\s*)?/, '');
|
|
100
|
+
methtext = methtext.replace(/\s*\}$/, '');
|
|
101
|
+
// Also support arrow function version.
|
|
102
|
+
methtext = methtext.replace(/^\(\)\s*\=\>\s*/, '');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Set the replacement msg to the method text.
|
|
106
|
+
replace.msg = methtext;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (typeof replace.msg === 'string')
|
|
110
|
+
{ // A replacement message.
|
|
111
|
+
msgs.push(REP_MSG, replace.msg);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Show the messages.
|
|
115
|
+
console.warn(...msgs);
|
|
116
|
+
|
|
117
|
+
// Finally, call the replacement function if it was defined.
|
|
118
|
+
if (exec)
|
|
119
|
+
{
|
|
120
|
+
return exec();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
|
|
2
|
+
const core = require('@lumjs/core');
|
|
3
|
+
const {F,S,B,needObj,needType,def} = core.types
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Track if libraries, plugins, or whatever are loaded.
|
|
7
|
+
*
|
|
8
|
+
* Automatically manages events that are trigged on load.
|
|
9
|
+
* Also will automatically run events assigned *after* the
|
|
10
|
+
* desired item has been loaded.
|
|
11
|
+
*
|
|
12
|
+
* Can handle custom tests in addition to the default
|
|
13
|
+
* test which simply see's if the `loadTracker.mark()`
|
|
14
|
+
* method has been called for the specified name.
|
|
15
|
+
*
|
|
16
|
+
* @class Lum.LoadTracker
|
|
17
|
+
*/
|
|
18
|
+
class LoadTracker
|
|
19
|
+
{
|
|
20
|
+
/**
|
|
21
|
+
* Build a LoadTracker
|
|
22
|
+
*
|
|
23
|
+
* @param {object} [opts] - Named options for custom behaviours.
|
|
24
|
+
*
|
|
25
|
+
* @param {function} [opts.or] A custom test for `is()` method.
|
|
26
|
+
* If this returns true, `is()` will return true immediately.
|
|
27
|
+
* Mutually exclusive with the `opts.and` option.
|
|
28
|
+
*
|
|
29
|
+
* The function will have `this` set to the `LoadTracker` instance.
|
|
30
|
+
* It will be passed the same arguments sent to the `is()` method.
|
|
31
|
+
* The function must return a boolean value indicating if the item
|
|
32
|
+
* is considered *loaded* for the purposes of this loader instance.
|
|
33
|
+
*
|
|
34
|
+
* @param {function} [opts.and] A custom test for `is()` method.
|
|
35
|
+
* If this returns false, `is()` will return false immediately.
|
|
36
|
+
* Mutually exclusive with the `opts.or` option.
|
|
37
|
+
*
|
|
38
|
+
* The same function notes as `opts.or` apply to this as well.
|
|
39
|
+
*
|
|
40
|
+
* @param {boolean} [opts.before=false] When to run the custom test.
|
|
41
|
+
* If `true` the custom test is run before the standard test.
|
|
42
|
+
* If `false` the custom test is run after the standard test.
|
|
43
|
+
*
|
|
44
|
+
* If `opts.or` was used, and whichever test is ran first returns
|
|
45
|
+
* `true`, the other test won't be run at all.
|
|
46
|
+
*
|
|
47
|
+
* Likewise, if `opts.and` was used, and whichever test is ran first
|
|
48
|
+
* returns `false`, the other test won't be run at all.
|
|
49
|
+
*
|
|
50
|
+
* @param {function} [opts.check] A custom test for the `check*` methods.
|
|
51
|
+
* If specified, this will be ran *before* checking the rest of the
|
|
52
|
+
* arguments. The first parameter passed to the function is a boolean,
|
|
53
|
+
* indicating if only a single return value is expected; `checkOne()`
|
|
54
|
+
* passes `true` while `checkAll()` passes false. All subsequent
|
|
55
|
+
* parameters will be the arguments passed to the calling method.
|
|
56
|
+
* The function will have `this` set to the `LoadTracker` instance.
|
|
57
|
+
*
|
|
58
|
+
* When called from `checkOne()` if it returns a string, that will
|
|
59
|
+
* be returned as the missing item name. Return nil if no errors.
|
|
60
|
+
*
|
|
61
|
+
* When called from `checkAll()` if it returns an Array, all items
|
|
62
|
+
* from that array will be added to the list of missing items, and
|
|
63
|
+
* then the regular `checkAll()` logic will continue. If however it
|
|
64
|
+
* returns a string, then that will be returned as the sole item in
|
|
65
|
+
* the missing list without running any further `checkAll()` logic.
|
|
66
|
+
* Return nil or an *empty* array if no errors.
|
|
67
|
+
*
|
|
68
|
+
*/
|
|
69
|
+
constructor(opts={})
|
|
70
|
+
{
|
|
71
|
+
needObj(opts);
|
|
72
|
+
|
|
73
|
+
def(this, '$loaded', {}); // List of loaded libraries.
|
|
74
|
+
def(this, '$onload', {}); // Events to trigger when libraries are loaded.
|
|
75
|
+
|
|
76
|
+
let isTest = false, testOr = false;
|
|
77
|
+
if (typeof opts.or === F)
|
|
78
|
+
{ // A test that can override
|
|
79
|
+
isTest = opts.or;
|
|
80
|
+
testOr = true;
|
|
81
|
+
}
|
|
82
|
+
else if (typeof opts.and === F)
|
|
83
|
+
{
|
|
84
|
+
isTest = opts.and;
|
|
85
|
+
testOr = false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
def(this, '$isTest', isTest);
|
|
89
|
+
def(this, '$isOr', testOr);
|
|
90
|
+
def(this, '$is1st', opts.before ?? false);
|
|
91
|
+
def(this, '$check', opts.check ?? false);
|
|
92
|
+
def(this, '$typeOne', opts.type ?? 'item');
|
|
93
|
+
def(this, '$typeAll', opts.types ?? this.$typeOne + 's');
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Assign a callback function to be called.
|
|
99
|
+
*
|
|
100
|
+
* All callbacks for a given `name` will be ran when
|
|
101
|
+
* that `name` has been passed to `mark()` or `call()`.
|
|
102
|
+
*
|
|
103
|
+
* @param {string} name - The name of the item to be loaded.
|
|
104
|
+
* @param {function} event - The callback function.
|
|
105
|
+
*
|
|
106
|
+
* @returns {boolean} - Is the method call deferred?
|
|
107
|
+
* If `true` the `name` has not been marked as loaded, so the
|
|
108
|
+
* method has been added to a queue that will be called
|
|
109
|
+
*/
|
|
110
|
+
on(name, event)
|
|
111
|
+
{
|
|
112
|
+
needType(S, name, "Name must be a string");
|
|
113
|
+
needType(F, event, "Event must be a function");
|
|
114
|
+
|
|
115
|
+
if (!Array.isArray(this.$onload[name]))
|
|
116
|
+
{ // Add an array of events.
|
|
117
|
+
def(this.$onload, name, []);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
this.$onload[name].push(event);
|
|
121
|
+
|
|
122
|
+
if (this.is(name))
|
|
123
|
+
{ // Execute the function right now.
|
|
124
|
+
event.call(Lum, name, false);
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Mark an item as loaded.
|
|
133
|
+
*
|
|
134
|
+
* @param {string} name - Item being marked as loaded.
|
|
135
|
+
* @param {boolean} [call=true] Also call `call()` method?
|
|
136
|
+
* @param {boolean} [skipTest=true] Passed to `call()` method.
|
|
137
|
+
*/
|
|
138
|
+
mark(name, call=true, skipTest=true)
|
|
139
|
+
{
|
|
140
|
+
def(this.$loaded, name, true);
|
|
141
|
+
if (call)
|
|
142
|
+
{
|
|
143
|
+
this.call(name, skipTest);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Call all of the callback function for an item.
|
|
149
|
+
*
|
|
150
|
+
* @param {string} name - The name of the item.
|
|
151
|
+
* @param {boolean} [skipTest=false] Skip the `is()` test?
|
|
152
|
+
* If `false` we call `this.is(name)` and will only continue
|
|
153
|
+
* if it returns a true value. If `true` we call without testing.
|
|
154
|
+
*
|
|
155
|
+
* @returns {boolean} - If the events were called or not.
|
|
156
|
+
*/
|
|
157
|
+
call(name, skipTest=false)
|
|
158
|
+
{
|
|
159
|
+
if (!skipTest && !this.is(name))
|
|
160
|
+
{ // Okay, we cannot call if the item isn't loaded.
|
|
161
|
+
console.error("Cannot call events if item is not loaded", name, this);
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (Array.isArray(this.$onload[name]))
|
|
166
|
+
{
|
|
167
|
+
for (const event of this.$onload[name])
|
|
168
|
+
{
|
|
169
|
+
event.call(Lum, name, true);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Check if the item is loaded.
|
|
178
|
+
*
|
|
179
|
+
* @param {string} name - The item to check.
|
|
180
|
+
* @returns {boolean}
|
|
181
|
+
*/
|
|
182
|
+
is(name)
|
|
183
|
+
{
|
|
184
|
+
if (typeof name !== S)
|
|
185
|
+
{
|
|
186
|
+
console.error("Name must be a string", name);
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let okay = false;
|
|
191
|
+
|
|
192
|
+
const hasTest = (typeof this.$isTest === F);
|
|
193
|
+
const test1st = this.$is1st;
|
|
194
|
+
const testOr = this.$isOr;
|
|
195
|
+
|
|
196
|
+
// A test that indicates we can return `okay` value.
|
|
197
|
+
const done = () => (!hasTest || (testOr && okay) || (!testOr && !okay));
|
|
198
|
+
|
|
199
|
+
if (hasTest && test1st)
|
|
200
|
+
{ // A custom test that is called before the normal test.
|
|
201
|
+
okay = this.$isTest(...arguments);
|
|
202
|
+
console.debug("is:before", okay, this);
|
|
203
|
+
if (done()) return okay;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Call the normal test, is the name marked?
|
|
207
|
+
okay = (this.$loaded[name] ?? false);
|
|
208
|
+
if (done()) return okay;
|
|
209
|
+
|
|
210
|
+
if (hasTest && !test1st)
|
|
211
|
+
{ // A custom test that is called after the normal test.
|
|
212
|
+
okay = this.$isTest(...arguments);
|
|
213
|
+
console.debug("is:after", okay, this);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return okay;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get a list of loaded items.
|
|
221
|
+
*
|
|
222
|
+
* This only includes items that have been marked using the
|
|
223
|
+
* `mark()` method.
|
|
224
|
+
*
|
|
225
|
+
* @param {(boolean|function)} [sort=false] Should we sort the results?
|
|
226
|
+
* If this is `true` we use the default sorting algorithm.
|
|
227
|
+
* If this is a function, it's passed to the `array.sort()` method.
|
|
228
|
+
* Any other value and the list will be in the order returned
|
|
229
|
+
* by the `Object.keys()` method.
|
|
230
|
+
*
|
|
231
|
+
* @returns {Array} The list of loaded items.
|
|
232
|
+
*/
|
|
233
|
+
list(sort=false)
|
|
234
|
+
{
|
|
235
|
+
let list = Object.keys(this.$loaded);
|
|
236
|
+
if (sort === true)
|
|
237
|
+
{ // If sort is boolean true, use default sorting algorithm.
|
|
238
|
+
list.sort();
|
|
239
|
+
}
|
|
240
|
+
else if (typeof sort === F)
|
|
241
|
+
{ // A custom sort function.
|
|
242
|
+
list.sort(sort);
|
|
243
|
+
}
|
|
244
|
+
return list;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The same output as `list(false)` but as a readonly accessor property.
|
|
249
|
+
*/
|
|
250
|
+
get keys()
|
|
251
|
+
{
|
|
252
|
+
return Object.keys(this.$loaded);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Return the first item that isn't loaded.
|
|
257
|
+
*
|
|
258
|
+
* @param {string} ...names - Any items you want to look for.
|
|
259
|
+
*
|
|
260
|
+
* @returns {string|undefined} If no items are missing, will be undefined.
|
|
261
|
+
*/
|
|
262
|
+
checkOne()
|
|
263
|
+
{
|
|
264
|
+
if (typeof this.$check === F)
|
|
265
|
+
{
|
|
266
|
+
const check = this.$check(true, ...arguments);
|
|
267
|
+
console.debug("checkOne:$check", check, this);
|
|
268
|
+
if (typeof check === S && check.trim() !== '')
|
|
269
|
+
{ // A non-empty string was passed.
|
|
270
|
+
return check;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
for (const lib of arguments)
|
|
275
|
+
{
|
|
276
|
+
if (!this.is(lib))
|
|
277
|
+
{
|
|
278
|
+
return lib;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Return a full list of any missing items.
|
|
285
|
+
*
|
|
286
|
+
* @param {string} ...names - Any items you want to look for.
|
|
287
|
+
*
|
|
288
|
+
* @returns {Array} A list of missing items.
|
|
289
|
+
*/
|
|
290
|
+
checkAll()
|
|
291
|
+
{
|
|
292
|
+
const missing = [];
|
|
293
|
+
|
|
294
|
+
if (typeof this.$check === F)
|
|
295
|
+
{
|
|
296
|
+
const check = this.$check(false, ...arguments);
|
|
297
|
+
console.debug("checkAll:$check", check, this);
|
|
298
|
+
if (Array.isArray(check))
|
|
299
|
+
{ // May have missing items, or be empty.
|
|
300
|
+
missing.push(...check);
|
|
301
|
+
}
|
|
302
|
+
else if (typeof check === S)
|
|
303
|
+
{ // A string indicates we can continue no further.
|
|
304
|
+
missing.push(check);
|
|
305
|
+
return missing;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
for (const lib of arguments)
|
|
310
|
+
{
|
|
311
|
+
if (!this.is(lib))
|
|
312
|
+
{
|
|
313
|
+
missing.push(lib);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return missing;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Setup a namespace object with wrapper methods.
|
|
322
|
+
*
|
|
323
|
+
* @param {object} ns - The namespace object, may also be a function.
|
|
324
|
+
* @param {object} [names] A map of alternate names for the methods.
|
|
325
|
+
*
|
|
326
|
+
* The default method names are:
|
|
327
|
+
*
|
|
328
|
+
* `mark` → Call `lt.mark`, returns `ourself()`.
|
|
329
|
+
* `has` → Proxy `lt.is`.
|
|
330
|
+
* `check` → Proxy `lt.checkOne`.
|
|
331
|
+
* `checkAll` → Proxy `lt.checkAll`.
|
|
332
|
+
* `list` → Proxy `lt.list`.
|
|
333
|
+
* `need` → Call `check`, if any missing, throw Error.
|
|
334
|
+
* `want` → Call `check`, return true if all are loaded, false if not.
|
|
335
|
+
* `onLoad` → Proxy `on`.
|
|
336
|
+
*
|
|
337
|
+
* If any of the method names are already present, they will be skipped.
|
|
338
|
+
*
|
|
339
|
+
*/
|
|
340
|
+
setupNamespace(ns, names={})
|
|
341
|
+
{
|
|
342
|
+
needObj(ns, true, "Invalid namespace object");
|
|
343
|
+
needObj(names, false, "Names must be an object");
|
|
344
|
+
|
|
345
|
+
const thisLoad = this; // Contextual instance reference.
|
|
346
|
+
let propName; // Will be set by hasnt() closure.
|
|
347
|
+
|
|
348
|
+
const getname = (name) => names[name] ?? name;
|
|
349
|
+
|
|
350
|
+
const hasnt = (name) =>
|
|
351
|
+
{
|
|
352
|
+
propName = getname(name);
|
|
353
|
+
return (ns[propName] === undefined);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const addfunc = (func) => def(ns, propName, func);
|
|
357
|
+
const addgetter = (func) => def(ns, propName, {get: func});
|
|
358
|
+
|
|
359
|
+
// Options for need() and want().
|
|
360
|
+
const loadOpts = def(ns, '$loadOpts',
|
|
361
|
+
{
|
|
362
|
+
checkAll: false,
|
|
363
|
+
warnings: false,
|
|
364
|
+
}).$loadOpts;
|
|
365
|
+
|
|
366
|
+
if (hasnt('mark'))
|
|
367
|
+
{
|
|
368
|
+
addfunc(function()
|
|
369
|
+
{
|
|
370
|
+
thisLoad.mark(...arguments);
|
|
371
|
+
return ourself();
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (hasnt('has'))
|
|
376
|
+
{
|
|
377
|
+
addfunc(function()
|
|
378
|
+
{
|
|
379
|
+
return thisLoad.is(...arguments);
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (hasnt('check'))
|
|
384
|
+
{
|
|
385
|
+
addfunc(function()
|
|
386
|
+
{
|
|
387
|
+
return thisLoad.checkOne(...arguments);
|
|
388
|
+
})
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (hasnt('checkAll'))
|
|
392
|
+
{
|
|
393
|
+
addfunc(function()
|
|
394
|
+
{
|
|
395
|
+
return thisLoad.checkAll(...arguments);
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (hasnt('list'))
|
|
400
|
+
{
|
|
401
|
+
addfunc(function()
|
|
402
|
+
{
|
|
403
|
+
return thisLoad.list(...arguments);
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (hasnt('missing'))
|
|
408
|
+
{
|
|
409
|
+
addfunc(function(
|
|
410
|
+
{
|
|
411
|
+
fatal = false,
|
|
412
|
+
all = loadOpts.checkAll,
|
|
413
|
+
warn = loadOpts.warnings,
|
|
414
|
+
ok = this,
|
|
415
|
+
},
|
|
416
|
+
...items)
|
|
417
|
+
{
|
|
418
|
+
const thisCheck = all ? getname('checkAll') : getname('check');
|
|
419
|
+
const result = ns[thisCheck](...items);
|
|
420
|
+
|
|
421
|
+
if (typeof result === S
|
|
422
|
+
|| (all && Array.isArray(result) && result.length > 0))
|
|
423
|
+
{ // There are missing libraries.
|
|
424
|
+
const typeName = all ? thisLoad.$typeAll : thisLoad.$typeOne;
|
|
425
|
+
const missing = fatal ? JSON.stringify(result) : result;
|
|
426
|
+
|
|
427
|
+
if (fatal)
|
|
428
|
+
{
|
|
429
|
+
throw new Error(`Missing required ${typeName}: ${missing}`);
|
|
430
|
+
}
|
|
431
|
+
else
|
|
432
|
+
{
|
|
433
|
+
if (warn)
|
|
434
|
+
{
|
|
435
|
+
console.warn("Missing", typeName, missing);
|
|
436
|
+
}
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// If we reached here, nothing was reported as missing.
|
|
442
|
+
return ok;
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (hasnt('need'))
|
|
447
|
+
{
|
|
448
|
+
addfunc(function()
|
|
449
|
+
{
|
|
450
|
+
const missing = getname('missing');
|
|
451
|
+
return ns[missing]({fatal: true, ok: ourself()}, ...arguments);
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (hasnt('want'))
|
|
456
|
+
{
|
|
457
|
+
addfunc(function()
|
|
458
|
+
{
|
|
459
|
+
const missing = getname('missing');
|
|
460
|
+
return ns[missing]({fatal: false, ok: true}, ...arguments);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (hasnt('all'))
|
|
465
|
+
{
|
|
466
|
+
addgetter(function()
|
|
467
|
+
{
|
|
468
|
+
loadOpts.checkAll = true;
|
|
469
|
+
return ns;
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (hasnt('one'))
|
|
474
|
+
{
|
|
475
|
+
addgetter(function()
|
|
476
|
+
{
|
|
477
|
+
loadOpts.checkAll = false;
|
|
478
|
+
return ns;
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (hasnt('showWarnings'))
|
|
483
|
+
{
|
|
484
|
+
addfunc(function(val)
|
|
485
|
+
{
|
|
486
|
+
if (typeof val === B)
|
|
487
|
+
{
|
|
488
|
+
loadOpts.warnings = val;
|
|
489
|
+
return this;
|
|
490
|
+
}
|
|
491
|
+
else
|
|
492
|
+
{
|
|
493
|
+
return loadOpts.warnings;
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (hasnt('onLoad'))
|
|
499
|
+
{
|
|
500
|
+
addfunc(function()
|
|
501
|
+
{
|
|
502
|
+
return thisLoad.on(...arguments);
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
}
|
|
507
|
+
} // LoadTracker class
|
|
508
|
+
|
|
509
|
+
module.exports = LoadTracker;
|
|
File without changes
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
const core = require('@lumjs/core');
|
|
2
|
+
const {O,F,S,B,isObj} = core.types;
|
|
3
|
+
const {clone,copyProps} = core.obj;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A way to handle Mixins/Traits.
|
|
7
|
+
*
|
|
8
|
+
* This is basically a magic wrapper around {@link Lum.obj.into} which we
|
|
9
|
+
* use instead of Object.assign() as we don't want to overwrite properties
|
|
10
|
+
* by default.
|
|
11
|
+
*
|
|
12
|
+
* As it's designed to extend the class prototype and only the prototype,
|
|
13
|
+
* it will see if anything passed to it is a function/class and if so, it
|
|
14
|
+
* will automatically use the prototype of the function/class. If you want
|
|
15
|
+
* to copy static class properties, use {@link Lum.obj.into} instead of this.
|
|
16
|
+
*
|
|
17
|
+
* @param {object|function} target - The target we are copying into.
|
|
18
|
+
* @param {...*} sources - The source traits we want to mix in.
|
|
19
|
+
*
|
|
20
|
+
* @return {object|function} The `target` will be returned.
|
|
21
|
+
*
|
|
22
|
+
* @alias module:@lumjs/compat/v4/object-helpers.mixin
|
|
23
|
+
*/
|
|
24
|
+
exports.mixin = function (target, ...inSources)
|
|
25
|
+
{
|
|
26
|
+
var outSources = [];
|
|
27
|
+
|
|
28
|
+
function unwrap (what)
|
|
29
|
+
{
|
|
30
|
+
if (typeof what === F && typeof what.prototype === O)
|
|
31
|
+
{
|
|
32
|
+
return what.prototype;
|
|
33
|
+
}
|
|
34
|
+
else if (isObj(what))
|
|
35
|
+
{
|
|
36
|
+
return what;
|
|
37
|
+
}
|
|
38
|
+
else
|
|
39
|
+
{
|
|
40
|
+
throw new Error("Invalid function/object passed to addTraits()");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
target = unwrap(target); // Ensure the target is an object.
|
|
45
|
+
|
|
46
|
+
for (var s in inSources)
|
|
47
|
+
{
|
|
48
|
+
var source = inSources[s];
|
|
49
|
+
if (typeof source === B || typeof source === S)
|
|
50
|
+
{ // A special option statement, push it directly.
|
|
51
|
+
outSources.push(source);
|
|
52
|
+
}
|
|
53
|
+
else
|
|
54
|
+
{ // Anything else needs to be unwrapped.
|
|
55
|
+
outSources.push(unwrap(source));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return exports.into(target, outSources);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Copy properties between objects. Can be used for mixins/traits.
|
|
64
|
+
*
|
|
65
|
+
* For each of the sources specified, this will call:
|
|
66
|
+
*
|
|
67
|
+
* ```Lum.obj.copy(source, target, opts)```
|
|
68
|
+
*
|
|
69
|
+
* The current `opts` can be changed dynamically using special statements.
|
|
70
|
+
* See below for details on the statements to make that work.
|
|
71
|
+
* The default `opts` is `{default: true, overwrite: false}`
|
|
72
|
+
*
|
|
73
|
+
* @param {object|function} target - The target we are copying into.
|
|
74
|
+
* @param {...*} sources - The sources to copy from, and options.
|
|
75
|
+
*
|
|
76
|
+
* If a source is a boolean, it will reset the `opts.overwrite` property.
|
|
77
|
+
*
|
|
78
|
+
* If a source is the string 'default' we set the `opts` to:
|
|
79
|
+
* `{default: true, overwrite: opts.overwrite}`
|
|
80
|
+
*
|
|
81
|
+
* If a source is the string 'all' we set the `opts` to:
|
|
82
|
+
* `{all: true, overwrite: opts.overwrite}`
|
|
83
|
+
*
|
|
84
|
+
* If a source is an object with a property of `__copy_opts` which is `true`
|
|
85
|
+
* then the `opts` will be set to the source itself.
|
|
86
|
+
*
|
|
87
|
+
* If a source is an object with a property of `__copy_opts` which is an
|
|
88
|
+
* `object` then the `opts` will be set to the object, and the rest of
|
|
89
|
+
* the properties from the source will be copied as usual.
|
|
90
|
+
*
|
|
91
|
+
* If the source is any other object or function, it will be considered a
|
|
92
|
+
* valid source to copy into the `target`.
|
|
93
|
+
*
|
|
94
|
+
* Anything else will be invalid and will throw an Error.
|
|
95
|
+
*
|
|
96
|
+
* @return {object|function} The `target` will be returned.
|
|
97
|
+
*
|
|
98
|
+
* @method Lum.obj.into
|
|
99
|
+
*/
|
|
100
|
+
exports.into = function (target, ...sources)
|
|
101
|
+
{
|
|
102
|
+
let opts = {default: true, overwrite: false}; // default opts.
|
|
103
|
+
|
|
104
|
+
// console.debug("Lum.obj.copyInto()", target, sources);
|
|
105
|
+
|
|
106
|
+
for (let s in sources)
|
|
107
|
+
{
|
|
108
|
+
let source = sources[s];
|
|
109
|
+
const stype = typeof source;
|
|
110
|
+
// console.debug("source", source, stype);
|
|
111
|
+
if (stype === B)
|
|
112
|
+
{
|
|
113
|
+
opts.overwrite = source;
|
|
114
|
+
}
|
|
115
|
+
else if (stype === S)
|
|
116
|
+
{
|
|
117
|
+
if (source === 'default')
|
|
118
|
+
{
|
|
119
|
+
opts = {default: true, overwrite: opts.overwrite};
|
|
120
|
+
}
|
|
121
|
+
else if (source === 'all')
|
|
122
|
+
{
|
|
123
|
+
opts = {all: true, overwrite: opts.overwrite};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (stype === O || stype === F)
|
|
127
|
+
{
|
|
128
|
+
// console.debug("copying properties", source);
|
|
129
|
+
if (source.__copy_opts === true)
|
|
130
|
+
{ // Source is copy options.
|
|
131
|
+
opts = source;
|
|
132
|
+
continue; // Nothing more to do here.
|
|
133
|
+
}
|
|
134
|
+
else if (isObj(source.__copy_opts))
|
|
135
|
+
{ // Copy options included in source.
|
|
136
|
+
opts = source.__copy_opts;
|
|
137
|
+
source = clone(source); // Make a copy of the source.
|
|
138
|
+
delete(source.__copy_opts); // Remove the __copy_opts.
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Copy the properties.
|
|
142
|
+
copyProps(source, target, opts);
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
{
|
|
146
|
+
throw new Error("Invalid function/object passed to copyInto()");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return target;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Clone a simple object, using the {@link Lum._.clone} function.
|
|
155
|
+
*
|
|
156
|
+
* By default it uses `Lum._.CLONE.JSON` mode for cloning, but this can
|
|
157
|
+
* be adjusted as desired by passing a `cloneOpts.mode` option.
|
|
158
|
+
*
|
|
159
|
+
* Can also clone extended properties that aren't serialized in JSON.
|
|
160
|
+
*
|
|
161
|
+
* @param {object} object The object or function to clone.
|
|
162
|
+
*
|
|
163
|
+
* @param {object} [copyProperties] Use {@link Lum.copyProperties} as well.
|
|
164
|
+
*
|
|
165
|
+
* If copyProperties is defined, and is a non-false value, then we'll
|
|
166
|
+
* call {@link Lum.obj.copy} after cloning to copy 'special' properties.
|
|
167
|
+
*
|
|
168
|
+
* @param {object} [cloneOpts] Options to send to {@link Lum._clone}
|
|
169
|
+
*
|
|
170
|
+
* This can be any options supported by the {@link Lum._.clone} function.
|
|
171
|
+
*
|
|
172
|
+
* @return {object} A clone of the object.
|
|
173
|
+
*
|
|
174
|
+
*/
|
|
175
|
+
exports.clone = function(object, copyProperties, cloneOpts)
|
|
176
|
+
{
|
|
177
|
+
if (!isObj(cloneOpts))
|
|
178
|
+
{
|
|
179
|
+
cloneOpts = {mode: clone.MODE.JSON};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (copyProperties)
|
|
183
|
+
{
|
|
184
|
+
cloneOpts.copy = copyProperties;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
//console.debug("Lum.obj.clone", object, copyProperties, cloneOpts);
|
|
188
|
+
|
|
189
|
+
return clone(object, cloneOpts);
|
|
190
|
+
}
|
|
191
|
+
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
const {B,O,F} = require('@lumjs/core').types;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @class LumPromise
|
|
5
|
+
*
|
|
6
|
+
* Build the Promise object.
|
|
7
|
+
*
|
|
8
|
+
* @param (object|boolean) options Options for the Promise object.
|
|
9
|
+
*
|
|
10
|
+
* If options is a boolean, it's assumed to be the 'jquery' option.
|
|
11
|
+
*
|
|
12
|
+
* Recognized properties if options is an object:
|
|
13
|
+
*
|
|
14
|
+
* jquery: (boolean) If true, run this._extendJQuery(options);
|
|
15
|
+
* If false, run this._extendInternal(options);
|
|
16
|
+
*
|
|
17
|
+
* @deprecated Use HTML 5 Promises, or the jQuery.Deferred API directly.
|
|
18
|
+
*/
|
|
19
|
+
function LumPromise(options)
|
|
20
|
+
{
|
|
21
|
+
if (typeof options === B)
|
|
22
|
+
{ // Assume the 'jquery' option was passed implicitly.
|
|
23
|
+
options = {jquery: options};
|
|
24
|
+
}
|
|
25
|
+
else if (typeof options !== O || options === null)
|
|
26
|
+
{ // Ensure options is an object, and auto-select jQuery if it's loaded.
|
|
27
|
+
options = {jquery: (typeof jQuery === O)};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (options.jquery)
|
|
31
|
+
{
|
|
32
|
+
this._extendJQuery(options)
|
|
33
|
+
}
|
|
34
|
+
else
|
|
35
|
+
{
|
|
36
|
+
this._extendInternal(options);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const lpp = LumPromise.prototype;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Add the methods from jQuery.Deferred to ourself.
|
|
44
|
+
*
|
|
45
|
+
* If jQuery is not loaded, this will throw an error.
|
|
46
|
+
*/
|
|
47
|
+
lpp._extendJQuery = function (options)
|
|
48
|
+
{
|
|
49
|
+
if (jQuery === undefined)
|
|
50
|
+
{
|
|
51
|
+
throw new Error("Cannot use 'jquery' without jQuery loaded.");
|
|
52
|
+
}
|
|
53
|
+
var def = jQuery.Deferred();
|
|
54
|
+
for (var f in def)
|
|
55
|
+
{
|
|
56
|
+
this[f] = def[f];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Create our own internal represenation of the Deferred API.
|
|
62
|
+
*
|
|
63
|
+
* Setters: done(), fail(), always(), progress()
|
|
64
|
+
* Promise chaining: then(), catch()
|
|
65
|
+
* Triggers: resolve(), reject(), notify()
|
|
66
|
+
* Targetted triggers: resolveWith(), rejectWith(), notifyWith()
|
|
67
|
+
* Info: state()
|
|
68
|
+
*
|
|
69
|
+
*/
|
|
70
|
+
lpp._extendInternal = function (options)
|
|
71
|
+
{
|
|
72
|
+
// A copy of this for use in closures.
|
|
73
|
+
var self = this;
|
|
74
|
+
|
|
75
|
+
// Private storage for the state of the Promise.
|
|
76
|
+
var state = 'pending';
|
|
77
|
+
|
|
78
|
+
// Private storage for the arguments used to resolve/reject.
|
|
79
|
+
var final_args;
|
|
80
|
+
|
|
81
|
+
// Private storage for the 'this' object to use in callbacks.
|
|
82
|
+
var final_this = this;
|
|
83
|
+
|
|
84
|
+
var callbacks =
|
|
85
|
+
{
|
|
86
|
+
always: [],
|
|
87
|
+
done: [],
|
|
88
|
+
fail: [],
|
|
89
|
+
progress: [],
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Private function to run registered callbacks.
|
|
93
|
+
function apply_callbacks (name, args, current_this)
|
|
94
|
+
{
|
|
95
|
+
if (args === undefined)
|
|
96
|
+
{
|
|
97
|
+
args = final_args;
|
|
98
|
+
}
|
|
99
|
+
if (current_this === undefined)
|
|
100
|
+
{
|
|
101
|
+
current_this = final_this;
|
|
102
|
+
}
|
|
103
|
+
var cbs = callbacks[name];
|
|
104
|
+
if (cbs && cbs.length)
|
|
105
|
+
{
|
|
106
|
+
for (var i = 0; i < cbs.length; i++)
|
|
107
|
+
{
|
|
108
|
+
var cb = cbs[i];
|
|
109
|
+
cb.apply(current_this, args);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Private function to create a listener.
|
|
115
|
+
function create_listener (name, validStates)
|
|
116
|
+
{
|
|
117
|
+
var listener = function ()
|
|
118
|
+
{
|
|
119
|
+
var args = Array.prototype.slice.call(arguments);
|
|
120
|
+
for (var i = 0; i < args.length; i++)
|
|
121
|
+
{
|
|
122
|
+
if (typeof args[i] === O && Array.isArray(args[i]))
|
|
123
|
+
{ // An array of callbacks, recurse them.
|
|
124
|
+
listener.apply(self, args[i]);
|
|
125
|
+
}
|
|
126
|
+
else if (typeof args[i] === F)
|
|
127
|
+
{
|
|
128
|
+
if (state === 'pending')
|
|
129
|
+
{ // Add the callback to the appropriate listener queue.
|
|
130
|
+
callbacks[name].push(args[i]);
|
|
131
|
+
}
|
|
132
|
+
else if (validStates.indexOf(state) != -1)
|
|
133
|
+
{ // Execute the callback now.
|
|
134
|
+
args[i].apply(final_this, final_args);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else
|
|
138
|
+
{
|
|
139
|
+
console.warn("Unhandled parameter passed to "+name, args[i]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return self;
|
|
143
|
+
}
|
|
144
|
+
return listener;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Add our event assignment methods.
|
|
148
|
+
var meths =
|
|
149
|
+
{
|
|
150
|
+
done: ['resolved'],
|
|
151
|
+
fail: ['rejected'],
|
|
152
|
+
always: ['resolved', 'rejected'],
|
|
153
|
+
progress: [],
|
|
154
|
+
};
|
|
155
|
+
for (var mname in meths)
|
|
156
|
+
{
|
|
157
|
+
var mstate = meths[mname];
|
|
158
|
+
self[mname] = create_listener(mname, mstate);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Add our trigger methods.
|
|
162
|
+
self.resolve = function ()
|
|
163
|
+
{
|
|
164
|
+
if (state === 'pending')
|
|
165
|
+
{
|
|
166
|
+
var args = Array.prototype.slice.call(arguments);
|
|
167
|
+
if (args.length === 1 && typeof args[0] === O &&
|
|
168
|
+
typeof args[0].then === F)
|
|
169
|
+
{ // Passed a promise. We'll 'then' it, and resolve again from it.
|
|
170
|
+
args[0].then(function ()
|
|
171
|
+
{
|
|
172
|
+
self.resolve.apply(self, arguments);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
else
|
|
176
|
+
{ // Not a promise, let's do this.
|
|
177
|
+
state = 'resolved';
|
|
178
|
+
final_args = args;
|
|
179
|
+
apply_callbacks('always');
|
|
180
|
+
apply_callbacks('done');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
self.resolveWith = function (withObj)
|
|
186
|
+
{
|
|
187
|
+
if (state === 'pending')
|
|
188
|
+
{
|
|
189
|
+
final_this = withObj;
|
|
190
|
+
var resolveArgs = Array.prototype.slice.call(arguments, 1);
|
|
191
|
+
self.resolve.apply(self, resolveArgs);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
self.reject = function ()
|
|
196
|
+
{
|
|
197
|
+
if (state === 'pending')
|
|
198
|
+
{
|
|
199
|
+
var args = Array.prototype.slice.call(arguments);
|
|
200
|
+
if (args.length === 1 && typeof args[0] === O &&
|
|
201
|
+
typeof args[0].then === F)
|
|
202
|
+
{ // Passed a promise. We'll 'then' it, and resolve again from it.
|
|
203
|
+
args[0].then(null, function ()
|
|
204
|
+
{
|
|
205
|
+
self.reject.apply(self, arguments);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
else
|
|
209
|
+
{ // Not a promise, let's do this.
|
|
210
|
+
state = 'rejected';
|
|
211
|
+
final_args = args;
|
|
212
|
+
apply_callbacks('always');
|
|
213
|
+
apply_callbacks('fail');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
self.rejectWith = function (withObj)
|
|
219
|
+
{
|
|
220
|
+
if (state === 'pending')
|
|
221
|
+
{
|
|
222
|
+
final_this = withObj;
|
|
223
|
+
var rejectArgs = Array.prototype.slice.call(arguments, 1);
|
|
224
|
+
self.reject.apply(self, rejectArgs);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
self.notify = function ()
|
|
229
|
+
{
|
|
230
|
+
if (state === 'pending')
|
|
231
|
+
{
|
|
232
|
+
var args = Array.prototype.slice.call(arguments);
|
|
233
|
+
if (args.length === 1 && typeof args[0] === O &&
|
|
234
|
+
typeof args[0].then === F)
|
|
235
|
+
{ // Passed a promise. We'll 'then' it, and resolve again from it.
|
|
236
|
+
args[0].then(null, null, function ()
|
|
237
|
+
{
|
|
238
|
+
self.notify.apply(self, arguments);
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
else
|
|
242
|
+
{ // Not a promise, let's do this.
|
|
243
|
+
apply_callbacks('progress', args);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
self.notifyWith = function (withObj)
|
|
249
|
+
{
|
|
250
|
+
if (state === 'pending')
|
|
251
|
+
{
|
|
252
|
+
var args = Array.prototype.slice.call(arguments, 1);
|
|
253
|
+
if (args.length === 1 && typeof args[0] === O &&
|
|
254
|
+
typeof args[0].then === F)
|
|
255
|
+
{ // Passed a promise. We'll 'then' it, and resolve again from it.
|
|
256
|
+
args[0].then(null, null, function ()
|
|
257
|
+
{
|
|
258
|
+
var subargs = Array.prototype.slice.call(arguments);
|
|
259
|
+
subargs.unshift(withObj);
|
|
260
|
+
self.notifyWith.apply(self, subargs);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
else
|
|
264
|
+
{ // Not a promise, let's do this.
|
|
265
|
+
apply_callbacks('progress', args, withObj);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
self.catch = function (failFilter)
|
|
271
|
+
{
|
|
272
|
+
return self.then(null, failFilter);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
self.then = function (doneFilter, failFilter, progressFilter)
|
|
276
|
+
{
|
|
277
|
+
var newPromise = new LumPromise(false);
|
|
278
|
+
|
|
279
|
+
function make_callback (filterSpec)
|
|
280
|
+
{
|
|
281
|
+
var callback = function ()
|
|
282
|
+
{
|
|
283
|
+
var useWith = (this !== self);
|
|
284
|
+
var args = Array.prototype.slice.call(arguments);
|
|
285
|
+
var result = filterSpec.filter.apply(this, args);
|
|
286
|
+
if (useWith)
|
|
287
|
+
{
|
|
288
|
+
newPromise[filterSpec.methodWith](this, result);
|
|
289
|
+
}
|
|
290
|
+
else
|
|
291
|
+
{
|
|
292
|
+
newPromise[filterSpec.methodName](result);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return callback;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
var filterSpecs =
|
|
299
|
+
{
|
|
300
|
+
done:
|
|
301
|
+
{
|
|
302
|
+
filter: doneFilter,
|
|
303
|
+
methodName: 'resolve',
|
|
304
|
+
methodWith: 'resolveWith',
|
|
305
|
+
},
|
|
306
|
+
fail:
|
|
307
|
+
{
|
|
308
|
+
filter: failFilter,
|
|
309
|
+
methodName: 'reject',
|
|
310
|
+
methodWith: 'rejectWith',
|
|
311
|
+
},
|
|
312
|
+
progress:
|
|
313
|
+
{
|
|
314
|
+
filter: progressFilter,
|
|
315
|
+
methodName: 'notify',
|
|
316
|
+
methodWith: 'notifyWith',
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
for (var onName in filterSpecs)
|
|
321
|
+
{
|
|
322
|
+
var filterSpec = filterSpecs[onName];
|
|
323
|
+
if (typeof filterSpec.filter === F)
|
|
324
|
+
{
|
|
325
|
+
var callback = make_callback(filterSpec);
|
|
326
|
+
self[onName](callback);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return newPromise;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
self.state = function ()
|
|
334
|
+
{
|
|
335
|
+
return state;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Execute a delayed 'done' action.
|
|
341
|
+
*
|
|
342
|
+
* @param mixed obj The object to send to the done().
|
|
343
|
+
* @param str ts The textStatus to send to done().
|
|
344
|
+
* @param mixed xhr Object to use as XHR (default is this.)
|
|
345
|
+
* @param int timeout The timeout (in ms) defaults to 5.
|
|
346
|
+
*/
|
|
347
|
+
lpp.deferDone = function (obj, ts, xhr, timeout)
|
|
348
|
+
{
|
|
349
|
+
var self = this;
|
|
350
|
+
if (timeout === undefined)
|
|
351
|
+
timeout = 5; // 5ms should be enough time to register .done events.
|
|
352
|
+
if (xhr === undefined)
|
|
353
|
+
xhr = self;
|
|
354
|
+
self.doneTimer = setTimeout(function()
|
|
355
|
+
{
|
|
356
|
+
self.resolve(obj, ts, xhr);
|
|
357
|
+
}, timeout);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Execute a delayed 'fail' action.
|
|
362
|
+
*
|
|
363
|
+
* @param mixed error The message, code, or object to send to fail().
|
|
364
|
+
* @param str ts The textStatus to send to fail().
|
|
365
|
+
* @param mixed xhr Object to use as XHR (default is this.)
|
|
366
|
+
* @param int timeout The timeout (in ms) defaults to 5.
|
|
367
|
+
*/
|
|
368
|
+
lpp.deferFail = function (error, ts, xhr, timeout)
|
|
369
|
+
{
|
|
370
|
+
var self = this;
|
|
371
|
+
if (timeout === undefined)
|
|
372
|
+
timeout = 5;
|
|
373
|
+
if (xhr === undefined)
|
|
374
|
+
xhr = self;
|
|
375
|
+
self.failTimer = setTimeout(function ()
|
|
376
|
+
{
|
|
377
|
+
self.reject(xhr, ts, error);
|
|
378
|
+
}, timeout);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
module.exports = LumPromise;
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumjs/compat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./lib/index.js",
|
|
7
|
-
"./v4-meta": "./lib/v4
|
|
7
|
+
"./v4-meta": "./lib/v4/meta.js",
|
|
8
|
+
"./v4/*": "./lib/v4/*.js",
|
|
8
9
|
"./package.json": "./package.json"
|
|
9
10
|
},
|
|
10
11
|
"license": "MIT",
|