@nebularstreams/libmui 0.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/dist/libui.cjs.js +2 -0
- package/dist/libui.cjs.js.map +1 -0
- package/dist/libui.esm.js +2 -0
- package/dist/libui.esm.js.map +1 -0
- package/dist/libui.umd.js +2 -0
- package/dist/libui.umd.js.map +1 -0
- package/package.json +24 -0
- package/rollup.config.js +27 -0
- package/src/index.js +29 -0
- package/src/util/fuckingconfirm.js +28 -0
- package/src/util/mithril-range.js +444 -0
- package/src/util/util.clone.js +10 -0
- package/src/util/util.tokenizer.js +227 -0
- package/src/util/widgets.core.js +314 -0
- package/src/util/widgets.js +72 -0
- package/src/util/widgets.utils.js +10 -0
- package/src/widgets/Basic.js +335 -0
- package/src/widgets/CardieWidget.js +168 -0
- package/src/widgets/ComboPrompt.js +112 -0
- package/src/widgets/InputWidget.js +238 -0
- package/src/widgets/NoticeWidget.js +32 -0
- package/src/widgets/OverflowUtils.js +449 -0
- package/src/widgets/RangeWidget.js +200 -0
- package/src/widgets/Separator.js +21 -0
- package/src/widgets/SwitchWidget.js +42 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import m from "mithril";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
///////////////////////////////////////////////
|
|
5
|
+
// Mithril Range
|
|
6
|
+
// (c) 2017-2018 by Mike Linkovich
|
|
7
|
+
// https://github.com/spacejack/mithril-range
|
|
8
|
+
// License: MIT
|
|
9
|
+
///////////////////////////////////////////////
|
|
10
|
+
const
|
|
11
|
+
|
|
12
|
+
NONE = 0,
|
|
13
|
+
MOUSE = 1,
|
|
14
|
+
TOUCH = 2,
|
|
15
|
+
|
|
16
|
+
// So we aren't triggered by echoed mouse events (some mobile browsers)
|
|
17
|
+
DEVICE_DELAY = 350,
|
|
18
|
+
|
|
19
|
+
isIOS = !!navigator.userAgent.match(/iPhone|iPad|iPod/i);
|
|
20
|
+
|
|
21
|
+
// This is some unbelievable stone-age nonsense.
|
|
22
|
+
// Workaround for webkit bug where event.preventDefault
|
|
23
|
+
// within touchmove handler fails to prevent scrolling.
|
|
24
|
+
|
|
25
|
+
let
|
|
26
|
+
iOSHackApplied = false;
|
|
27
|
+
|
|
28
|
+
/** Clamp number to range */
|
|
29
|
+
function clamp(n, min, max) {
|
|
30
|
+
return Math.min(Math.max(n, min), max);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function applyIOSHack() {
|
|
34
|
+
// Only apply this hack if iOS, haven't yet applied it,
|
|
35
|
+
// and only if a component is actually created
|
|
36
|
+
if (!isIOS || iOSHackApplied) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
window.addEventListener("touchmove", function () {
|
|
40
|
+
});
|
|
41
|
+
iOSHackApplied = true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function quantize(val, min, max, step) {
|
|
45
|
+
if (max - min <= 0) {
|
|
46
|
+
return min;
|
|
47
|
+
}
|
|
48
|
+
if (step <= 0) {
|
|
49
|
+
return clamp(val, min, max);
|
|
50
|
+
}
|
|
51
|
+
const
|
|
52
|
+
steps = Math.ceil((max - min) / step),
|
|
53
|
+
v = min + Math.round(steps * (val - min) / (max - min)) * step;
|
|
54
|
+
return clamp(v, min, max);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
exports.quantize = quantize;
|
|
58
|
+
|
|
59
|
+
/** Range Component */
|
|
60
|
+
function MithrilRange() {
|
|
61
|
+
let
|
|
62
|
+
elHit,
|
|
63
|
+
elBar,
|
|
64
|
+
elBar0,
|
|
65
|
+
elBar1,
|
|
66
|
+
elHandle,
|
|
67
|
+
rcBar,
|
|
68
|
+
device = NONE,
|
|
69
|
+
pressed = false,
|
|
70
|
+
|
|
71
|
+
useAbsolute = false,
|
|
72
|
+
factorCoarse = 4,
|
|
73
|
+
factorFine = 1,
|
|
74
|
+
absolute,
|
|
75
|
+
lastRead,
|
|
76
|
+
|
|
77
|
+
// Attrs we need to cache
|
|
78
|
+
min = 0,
|
|
79
|
+
max = 10,
|
|
80
|
+
value = 0,
|
|
81
|
+
startValue = 0,
|
|
82
|
+
step = 1,
|
|
83
|
+
orientation = "horizontal",
|
|
84
|
+
onchange,
|
|
85
|
+
ondrag;
|
|
86
|
+
|
|
87
|
+
// App handlers
|
|
88
|
+
function onPressAbsolute(x, y) {
|
|
89
|
+
startValue = value;
|
|
90
|
+
pressed = absolute = true;
|
|
91
|
+
rcBar = elBar.getBoundingClientRect();
|
|
92
|
+
const val = moveHandleAbsolute(x, y);
|
|
93
|
+
if (val !== value) {
|
|
94
|
+
value = val;
|
|
95
|
+
if (ondrag && ondrag(value) !== false) {
|
|
96
|
+
m.redraw();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function onPressDelta(x, y, e, isTouch) {
|
|
102
|
+
startValue = value;
|
|
103
|
+
pressed = true;
|
|
104
|
+
absolute = false;
|
|
105
|
+
rcBar = elBar.getBoundingClientRect();
|
|
106
|
+
lastRead = (orientation === "vertical") ? y : x;
|
|
107
|
+
if (!isTouch) e.target.requestPointerLock();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function moveHandleAbsolute(x, y) {
|
|
111
|
+
|
|
112
|
+
let
|
|
113
|
+
barLength,
|
|
114
|
+
delta;
|
|
115
|
+
|
|
116
|
+
if (orientation === "vertical") {
|
|
117
|
+
|
|
118
|
+
barLength = rcBar.bottom - rcBar.top;
|
|
119
|
+
delta = rcBar.bottom - y;
|
|
120
|
+
|
|
121
|
+
} else {
|
|
122
|
+
barLength = rcBar.right - rcBar.left;
|
|
123
|
+
delta = x - rcBar.left;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
delta = clamp(delta, 0, barLength);
|
|
127
|
+
const val = quantize((delta / barLength) * (max - min) + min, min, max, step);
|
|
128
|
+
setStyles(val);
|
|
129
|
+
return val;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function moveHandleDelta(x, y, event) {
|
|
133
|
+
|
|
134
|
+
const
|
|
135
|
+
factor = event.shiftKey
|
|
136
|
+
? factorCoarse
|
|
137
|
+
: (event.metaKey || event.ctrlKey)
|
|
138
|
+
? 4 * factorCoarse
|
|
139
|
+
: factorFine;
|
|
140
|
+
|
|
141
|
+
let
|
|
142
|
+
delta;
|
|
143
|
+
|
|
144
|
+
if (orientation === "vertical") {
|
|
145
|
+
delta = event.movementY || 0;
|
|
146
|
+
} else {
|
|
147
|
+
delta = event.movementX || 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let newVal;
|
|
151
|
+
let s = step > 0 ? step : (max - min) / 100;
|
|
152
|
+
|
|
153
|
+
if (delta < 0) {
|
|
154
|
+
newVal = Math.max(value + s * factor * delta, min);
|
|
155
|
+
} else if (delta > 0) { // right/up
|
|
156
|
+
newVal = Math.min(value + s * factor * delta, max);
|
|
157
|
+
} else {
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
newVal = quantize(newVal, min, max, step);
|
|
162
|
+
|
|
163
|
+
setStyles(newVal);
|
|
164
|
+
return newVal;
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function onPress(x, y, event) {
|
|
169
|
+
return useAbsolute
|
|
170
|
+
? onPressAbsolute(x, y, event)
|
|
171
|
+
: onPressDelta(x, y, event);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function moveHandle(x, y, event) {
|
|
175
|
+
return absolute
|
|
176
|
+
? moveHandleAbsolute(x, y, event)
|
|
177
|
+
: moveHandleDelta(x, y, event);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Event handlers
|
|
181
|
+
function onMouseDown(e) {
|
|
182
|
+
if (device === TOUCH) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
device = MOUSE;
|
|
186
|
+
if (e.button !== 0) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
window.addEventListener("mousemove", onMouseMove);
|
|
190
|
+
window.addEventListener("mouseup", onMouseUp);
|
|
191
|
+
onPress(e.clientX, e.clientY, e);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function onMouseMove(e) {
|
|
195
|
+
e.preventDefault();
|
|
196
|
+
onMove(e.clientX, e.clientY, e);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function onMouseUp(e) {
|
|
200
|
+
window.removeEventListener("mousemove", onMouseMove);
|
|
201
|
+
window.removeEventListener("mouseup", onMouseUp);
|
|
202
|
+
onRelease(e.clientX, e.clientY, e);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function onTouchStart(e) {
|
|
206
|
+
if (device === MOUSE) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
elHit.addEventListener("touchmove", onTouchMove);
|
|
210
|
+
elHit.addEventListener("touchend", onTouchEnd);
|
|
211
|
+
const t = e.changedTouches[0];
|
|
212
|
+
onPress(t.clientX, t.clientY, e, true);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function onTouchMove(e) {
|
|
216
|
+
e.preventDefault();
|
|
217
|
+
const t = e.changedTouches[0];
|
|
218
|
+
onMove(t.clientX, t.clientY, e);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function onTouchEnd(e) {
|
|
222
|
+
elHit.removeEventListener("touchmove", onTouchMove);
|
|
223
|
+
elHit.removeEventListener("touchend", onTouchEnd);
|
|
224
|
+
const t = e.changedTouches[0];
|
|
225
|
+
onRelease(t.clientX, t.clientY, t);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function onKeyDown(e) {
|
|
229
|
+
|
|
230
|
+
const k = e.keyCode;
|
|
231
|
+
let newVal;
|
|
232
|
+
|
|
233
|
+
if (k === 33) { // pgup
|
|
234
|
+
e.preventDefault();
|
|
235
|
+
let s = Math.max((max - min) / 10, step);
|
|
236
|
+
if (s <= 0) {
|
|
237
|
+
s = 1;
|
|
238
|
+
}
|
|
239
|
+
newVal = quantize(value + s, min, max, step);
|
|
240
|
+
} else if (k === 34) { // pgdown
|
|
241
|
+
e.preventDefault();
|
|
242
|
+
let s = Math.max((max - min) / 10, step);
|
|
243
|
+
if (s <= 0) {
|
|
244
|
+
s = 1;
|
|
245
|
+
}
|
|
246
|
+
newVal = quantize(value - s, min, max, step);
|
|
247
|
+
} else if (k === 35) { // end
|
|
248
|
+
e.preventDefault();
|
|
249
|
+
newVal = max;
|
|
250
|
+
} else if (k === 36) { // home
|
|
251
|
+
e.preventDefault();
|
|
252
|
+
newVal = min;
|
|
253
|
+
} else if (k === 37 || k === 40) { // left/down
|
|
254
|
+
e.preventDefault();
|
|
255
|
+
let s = (step > 0 ? step : (max - min) / 10) * (e.shiftKey ? 0.25 : (e.ctrlKey || e.metaKey) ? 4 : 1);
|
|
256
|
+
newVal = Math.max(value - s, min);
|
|
257
|
+
} else if (k === 38 || k === 39) { // right/up
|
|
258
|
+
e.preventDefault();
|
|
259
|
+
let s = (step > 0 ? step : (max - min) / 10) * (e.shiftKey ? 0.25 : (e.ctrlKey || e.metaKey) ? 4 : 1);
|
|
260
|
+
newVal = Math.min(value + s, max);
|
|
261
|
+
} else if (k === 48) { // 0
|
|
262
|
+
newVal = (max + min) / 2;
|
|
263
|
+
}
|
|
264
|
+
if (typeof newVal !== "number" || newVal === value) {
|
|
265
|
+
return; // no change to make
|
|
266
|
+
}
|
|
267
|
+
value = newVal;
|
|
268
|
+
setStyles(value);
|
|
269
|
+
if (onchange && onchange(value) !== false) {
|
|
270
|
+
m.redraw();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function onMove(x, y, event) {
|
|
275
|
+
if (!pressed) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const val = moveHandle(x, y, event);
|
|
280
|
+
if (val !== value) {
|
|
281
|
+
value = val;
|
|
282
|
+
if (ondrag && ondrag(value) !== false) {
|
|
283
|
+
m.redraw();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function onRelease(x, y, e) {
|
|
289
|
+
|
|
290
|
+
if (!pressed) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
pressed = false;
|
|
295
|
+
value = moveHandle(x, y, e);
|
|
296
|
+
|
|
297
|
+
if (onchange && onchange(value) !== false) {
|
|
298
|
+
m.redraw();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/*
|
|
302
|
+
if (value !== startValue) {
|
|
303
|
+
if (onchange && onchange(value) !== false) {
|
|
304
|
+
m.redraw();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
*/
|
|
308
|
+
|
|
309
|
+
if (!absolute) document.exitPointerLock();
|
|
310
|
+
|
|
311
|
+
setTimeout(function () {
|
|
312
|
+
if (!pressed) {
|
|
313
|
+
device = NONE;
|
|
314
|
+
}
|
|
315
|
+
}, DEVICE_DELAY);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** Compute handle position style */
|
|
319
|
+
function positionStyle(val) {
|
|
320
|
+
let s = (val - min) / (max - min);
|
|
321
|
+
if (orientation === "vertical") {
|
|
322
|
+
s = 1.0 - s;
|
|
323
|
+
}
|
|
324
|
+
return String(100 * s) + "%";
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** Set styles for movable parts */
|
|
328
|
+
function setStyles(value) {
|
|
329
|
+
const
|
|
330
|
+
ps = positionStyle(value),
|
|
331
|
+
rps = positionStyle(max - value + min);
|
|
332
|
+
|
|
333
|
+
if (orientation === "vertical") {
|
|
334
|
+
elHandle.style.top = ps;
|
|
335
|
+
elBar0.style.height = ps;
|
|
336
|
+
elBar1.style.height = rps;
|
|
337
|
+
} else {
|
|
338
|
+
elHandle.style.left = ps;
|
|
339
|
+
elBar0.style.width = rps;
|
|
340
|
+
elBar1.style.width = ps;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** Some attrs need to be cached (and updated) so that they are current in event handlers */
|
|
345
|
+
function updateAttrs(attrs) {
|
|
346
|
+
min = attrs.min;
|
|
347
|
+
max = attrs.max;
|
|
348
|
+
step = (typeof attrs.step === "number" && !Number.isNaN(attrs.step))
|
|
349
|
+
? clamp(attrs.step, 0, max - min) : 1;
|
|
350
|
+
orientation = attrs.orientation === "vertical" ? "vertical" : "horizontal";
|
|
351
|
+
onchange = attrs.onchange;
|
|
352
|
+
ondrag = attrs.ondrag;
|
|
353
|
+
if (typeof attrs.value === "number") {
|
|
354
|
+
value = clamp(attrs.value, min, max);
|
|
355
|
+
}
|
|
356
|
+
useAbsolute = !attrs.relative;
|
|
357
|
+
factorCoarse = (attrs.factor && attrs.factor[0]) || 4;
|
|
358
|
+
factorFine = (attrs.factor && attrs.factor[1]) || 1;
|
|
359
|
+
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/** Return mithril component hooks object */
|
|
363
|
+
return {
|
|
364
|
+
oncreate: ({attrs, dom}) => {
|
|
365
|
+
applyIOSHack();
|
|
366
|
+
updateAttrs(attrs);
|
|
367
|
+
elHit = dom;
|
|
368
|
+
elBar = elHit.querySelector(".mithril-range-bar");
|
|
369
|
+
elBar0 = elBar.querySelector(".mithril-range-bar-0");
|
|
370
|
+
elBar1 = elBar.querySelector(".mithril-range-bar-1");
|
|
371
|
+
elHandle = elBar.querySelector(".mithril-range-handle");
|
|
372
|
+
elHit.addEventListener("mousedown", onMouseDown);
|
|
373
|
+
elHit.addEventListener("touchstart", onTouchStart);
|
|
374
|
+
elHit.addEventListener("keydown", onKeyDown);
|
|
375
|
+
},
|
|
376
|
+
onremove: function () {
|
|
377
|
+
window.removeEventListener("mousemove", onMouseMove);
|
|
378
|
+
window.removeEventListener("mouseup", onMouseUp);
|
|
379
|
+
elHit.removeEventListener("mousedown", onMouseDown);
|
|
380
|
+
elHit.removeEventListener("touchstart", onTouchStart);
|
|
381
|
+
elHit.removeEventListener("touchmove", onTouchMove);
|
|
382
|
+
elHit.removeEventListener("touchend", onTouchEnd);
|
|
383
|
+
elHit.removeEventListener("keydown", onKeyDown);
|
|
384
|
+
},
|
|
385
|
+
view: function ({attrs, children}) {
|
|
386
|
+
|
|
387
|
+
updateAttrs(attrs);
|
|
388
|
+
value = quantize(value, min, max, step);
|
|
389
|
+
const a = {
|
|
390
|
+
class: "mithril-range nokey" + (attrs.relative ? " isrelative " : " ") + (value === 0 ? "atzero" : value < 0 ? "belowzero" : "overzero") + (attrs.class != null ? " " + attrs.class : ""),
|
|
391
|
+
tabIndex: "0",
|
|
392
|
+
role: "slider",
|
|
393
|
+
"aria-valuemin": String(min),
|
|
394
|
+
"aria-valuemax": String(max),
|
|
395
|
+
"aria-valuenow": String(value),
|
|
396
|
+
"aria-orientation": orientation
|
|
397
|
+
};
|
|
398
|
+
if (attrs.id) {
|
|
399
|
+
a.id = attrs.id;
|
|
400
|
+
}
|
|
401
|
+
// noinspection JSUnresolvedVariable
|
|
402
|
+
if (attrs.ariaLabelledby) {
|
|
403
|
+
a["aria-labelledby"] = attrs.ariaLabelledby;
|
|
404
|
+
}
|
|
405
|
+
if (attrs.disabled) {
|
|
406
|
+
a.style = {pointerEvents: "none"};
|
|
407
|
+
a["aria-disabled"] = "true";
|
|
408
|
+
}
|
|
409
|
+
const
|
|
410
|
+
ps = positionStyle(value),
|
|
411
|
+
rps = positionStyle(max - value + min);
|
|
412
|
+
let
|
|
413
|
+
handleStyle,
|
|
414
|
+
bar0Style,
|
|
415
|
+
bar1Style;
|
|
416
|
+
|
|
417
|
+
if (orientation === "vertical") {
|
|
418
|
+
handleStyle = {top: ps};
|
|
419
|
+
bar0Style = {height: ps};
|
|
420
|
+
bar1Style = {height: rps};
|
|
421
|
+
} else {
|
|
422
|
+
handleStyle = {left: ps};
|
|
423
|
+
bar0Style = {width: rps};
|
|
424
|
+
bar1Style = {width: ps};
|
|
425
|
+
}
|
|
426
|
+
return m("div", a, m("div", {class: "mithril-range-bar nokey"}, m("div", {
|
|
427
|
+
class: "mithril-range-bar-0 nokey",
|
|
428
|
+
style: bar0Style
|
|
429
|
+
}), m("div", {
|
|
430
|
+
class: "mithril-range-bar-1 nokey",
|
|
431
|
+
style: bar1Style
|
|
432
|
+
}), m("div", {
|
|
433
|
+
class: "mithril-range-handle nokey",
|
|
434
|
+
style: handleStyle
|
|
435
|
+
}, children)), !!attrs.name && m("input", {
|
|
436
|
+
type: "hidden",
|
|
437
|
+
name: attrs.name,
|
|
438
|
+
value: String(value)
|
|
439
|
+
}));
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
export default MithrilRange;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* String Tokenizer functions
|
|
5
|
+
*
|
|
6
|
+
* Substitutes parameters inside strings
|
|
7
|
+
* Parameters are separated by $ at the beggining and end: $PARAM$, $PARAM1$
|
|
8
|
+
* Parameters can navigate source object like $object/very/deep$
|
|
9
|
+
* Parameters can include VERY SIMPLE default values like $object/very/deep=myvalue$
|
|
10
|
+
*
|
|
11
|
+
* Note that default values cannot contain conflicting regexp symbols. This is a side functionality
|
|
12
|
+
* and never meant to support any default value use case, but alpha chars and numbers
|
|
13
|
+
*
|
|
14
|
+
* (c) Rodolfo LP 2001 - Public Domain
|
|
15
|
+
*
|
|
16
|
+
* @typedef {{ id:string,url:string}} UrlDefinition
|
|
17
|
+
* @typedef {{ message:string, getTitle:boolean=false, defaultTitle:string="url" }} ResolveUrlOptions
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/* eslint-disable no-use-before-define,no-unused-vars,prefer-destructuring,no-param-reassign,no-prototype-builtins */
|
|
21
|
+
|
|
22
|
+
// eslint-disable-next-line no-useless-escape
|
|
23
|
+
// noinspection RegExpRedundantEscape
|
|
24
|
+
const
|
|
25
|
+
TAG = "[TOKENIZER]",
|
|
26
|
+
TOK_EXPR = /\$([A-Za-z0-9_\/\:\=]+)\$/g,
|
|
27
|
+
|
|
28
|
+
tokenize = (str, obj, isEncode) => tokenizeCore(str, obj, {
|
|
29
|
+
encode: isEncode,
|
|
30
|
+
defvalue: ""
|
|
31
|
+
}),
|
|
32
|
+
tokenizeKeep = (str, obj, isEncode) => tokenizeCore(str, obj, {encode: isEncode}),
|
|
33
|
+
tokenizeWithDefault = (str, obj, defaultValue) => tokenizeCore(str, obj, defaultValue == null ? null : {defvalue: defaultValue}),
|
|
34
|
+
tokenizeStrict = (str, obj, isEncode, isUnescape) => tokenizeCore(str, obj, {
|
|
35
|
+
encode: isEncode,
|
|
36
|
+
unescape: isUnescape,
|
|
37
|
+
dothrow: true
|
|
38
|
+
}),
|
|
39
|
+
|
|
40
|
+
Parsers = {
|
|
41
|
+
daterel: epoch => new Date(epoch).toISOString()
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
function tokenizeCore(str, obj, options) {
|
|
45
|
+
|
|
46
|
+
if (!str) return "";
|
|
47
|
+
if (typeof (str) !== "string") return str;
|
|
48
|
+
|
|
49
|
+
// eslint-disable-next-line no-param-reassign
|
|
50
|
+
options = options || {};
|
|
51
|
+
obj = obj || {};
|
|
52
|
+
|
|
53
|
+
let ckey;
|
|
54
|
+
|
|
55
|
+
return str.replace(TOK_EXPR, (match, complexkey) => {
|
|
56
|
+
|
|
57
|
+
let defval = null,
|
|
58
|
+
isFreak = false;
|
|
59
|
+
|
|
60
|
+
if (complexkey.indexOf("=") > 0) {
|
|
61
|
+
ckey = complexkey.split("=");
|
|
62
|
+
complexkey = ckey[0];
|
|
63
|
+
isFreak = (ckey.length === 3);
|
|
64
|
+
// eslint-disable-next-line no-nested-ternary
|
|
65
|
+
defval = isFreak
|
|
66
|
+
? options.dothrow ? ckey[2] : null
|
|
67
|
+
: ckey[1];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const typed = complexkey.split(":"),
|
|
71
|
+
key = typed[0],
|
|
72
|
+
keytype = typed[1] || null,
|
|
73
|
+
|
|
74
|
+
keys = key.split("/"),
|
|
75
|
+
root = keys.shift();
|
|
76
|
+
|
|
77
|
+
let
|
|
78
|
+
data = obj[root];
|
|
79
|
+
|
|
80
|
+
if (typeof (data) === "number") data = "" + data;
|
|
81
|
+
|
|
82
|
+
let fdata = (keys.length ? getPointedData(data, keys.join("/")) : data) || defval;
|
|
83
|
+
|
|
84
|
+
if (fdata == null && options.dothrow) {
|
|
85
|
+
throw new Error("Parameter " + root + (keys.length ? "/" + keys.join("/") : "") + " is required");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (fdata == null) {
|
|
89
|
+
fdata = options.hasOwnProperty("defvalue")
|
|
90
|
+
? options.defvalue
|
|
91
|
+
: "$" + key + (isFreak ? "==" + ckey[2] : "") + "$";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (keytype && Parsers[keytype]) {
|
|
95
|
+
fdata = Parsers[keytype](fdata);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (options.unescape) {
|
|
99
|
+
fdata = unescape(fdata);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return (options.encode ? escape(fdata) : fdata);
|
|
103
|
+
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Resolves a pointer into a JSON data structure
|
|
109
|
+
* @param {Object} data JSON Data
|
|
110
|
+
* @param {String} pointer Pointer expression
|
|
111
|
+
* @return {Object | null} resolved data
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
const getPointedData = function (data, pointer) {
|
|
115
|
+
if (!pointer) return data;
|
|
116
|
+
try {
|
|
117
|
+
const ps = pointer.split("/");
|
|
118
|
+
let d = data;
|
|
119
|
+
// eslint-disable-next-line guard-for-in
|
|
120
|
+
for (const l in ps) {
|
|
121
|
+
d = d[ps[l]];
|
|
122
|
+
if (!d) {
|
|
123
|
+
d = null;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return d;
|
|
128
|
+
} catch (e) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Tokenizes one object with another
|
|
135
|
+
* @param {object} source
|
|
136
|
+
* @param {object} tokenizeValues
|
|
137
|
+
* @param strict Whether to require all templates to be resolved
|
|
138
|
+
* @retuen {object} source
|
|
139
|
+
*/
|
|
140
|
+
|
|
141
|
+
function tokenizeObject(source, tokenizeValues, strict, asNewObject) {
|
|
142
|
+
|
|
143
|
+
const tokenizer = strict ? tokenizeStrict : tokenizeKeep;
|
|
144
|
+
const retObject = asNewObject ? {} : source;
|
|
145
|
+
|
|
146
|
+
if (typeof source === "string") {
|
|
147
|
+
return tokenizer(source, tokenizeValues);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (typeof source === "object") {
|
|
151
|
+
|
|
152
|
+
if (source.length) {
|
|
153
|
+
// root is an array
|
|
154
|
+
// an array
|
|
155
|
+
const arr = [];
|
|
156
|
+
for (const item of source) {
|
|
157
|
+
arr.push(tokenizeObject(item, tokenizeValues, strict, true));
|
|
158
|
+
}
|
|
159
|
+
return arr;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
for (const prop of Object.keys(source)) {
|
|
163
|
+
const value = source[prop];
|
|
164
|
+
if (typeof value === "object") {
|
|
165
|
+
retObject[prop] = tokenizeObject(value, tokenizeValues, strict, true);
|
|
166
|
+
} else if (typeof value === "string") {
|
|
167
|
+
retObject[prop] = tokenizer(source[prop], tokenizeValues);
|
|
168
|
+
} else {
|
|
169
|
+
retObject[prop] = value;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return retObject;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Resolves a playout URL
|
|
178
|
+
* @param {string|UrlDefinition} tokenizedUrl The URL to parse
|
|
179
|
+
* @param {Object=} parameters Parameters to tokenize the URL with
|
|
180
|
+
* @param {ResolveUrlOptions=} options Miscellaneous options for this call
|
|
181
|
+
* @return string
|
|
182
|
+
*/
|
|
183
|
+
|
|
184
|
+
function tokenizeUrl(tokenizedUrl, parameters, options) {
|
|
185
|
+
|
|
186
|
+
options = options || {};
|
|
187
|
+
|
|
188
|
+
const
|
|
189
|
+
{message, getTitle, defaultTitle} = options,
|
|
190
|
+
finalDefaultTitle = defaultTitle || "Url",
|
|
191
|
+
title = typeof tokenizedUrl === "string"
|
|
192
|
+
? defaultTitle
|
|
193
|
+
: (typeof tokenizedUrl === "object" && tokenizedUrl.id ? tokenizedUrl.id || finalDefaultTitle : finalDefaultTitle);
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
// just return the title of an URL
|
|
197
|
+
if (getTitle) {
|
|
198
|
+
return title;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// return the url itself
|
|
202
|
+
const
|
|
203
|
+
url = typeof tokenizedUrl === "string"
|
|
204
|
+
? tokenizedUrl
|
|
205
|
+
: (typeof tokenizedUrl === "object" && tokenizedUrl.url ? tokenizedUrl.url : null);
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
return tokenizeStrict(
|
|
209
|
+
url,
|
|
210
|
+
parameters || {},
|
|
211
|
+
"..."
|
|
212
|
+
);
|
|
213
|
+
} catch (e) {
|
|
214
|
+
console.log(TAG, e.message);
|
|
215
|
+
return message || "(not enough parameters)";
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export {
|
|
220
|
+
tokenize,
|
|
221
|
+
tokenizeStrict,
|
|
222
|
+
tokenizeObject,
|
|
223
|
+
tokenizeKeep,
|
|
224
|
+
tokenizeWithDefault,
|
|
225
|
+
tokenizeUrl,
|
|
226
|
+
getPointedData
|
|
227
|
+
};
|