@nebularstreams/libmui 2.0.13 → 2.0.15

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.
@@ -0,0 +1,31 @@
1
+ import m from "mithril";
2
+
3
+ let
4
+ gTainted = false;
5
+
6
+ function taint() {
7
+ gTainted = true;
8
+ }
9
+
10
+ function taintRedraw() {
11
+ const r = gTainted;
12
+ gTainted = true;
13
+ // eslint-disable-next-line no-unused-expressions
14
+ r && m.redraw();
15
+ }
16
+
17
+ function isTainted() {
18
+ return gTainted;
19
+ }
20
+
21
+ function untaint() {
22
+ gTainted = false;
23
+ m.redraw();
24
+ }
25
+
26
+ export {
27
+ taint,
28
+ taintRedraw,
29
+ isTainted,
30
+ untaint
31
+ };
@@ -216,6 +216,37 @@ function tokenizeUrl(tokenizedUrl, parameters, options) {
216
216
  }
217
217
  }
218
218
 
219
+ function sanitizeFilename(filename) {
220
+ return filename ? filename.trim()
221
+ .toLowerCase()
222
+ .replace(/[^0-9A-Z.-]+/gi, "") : null;
223
+ }
224
+
225
+
226
+ const generateFilename = (url, prefix = undefined) => {
227
+
228
+ const
229
+ dateCode = parseInt(md5(url)
230
+ .substring(24), 16)
231
+ .toString(32);
232
+
233
+ return (prefix ? sanitizeFilename(prefix) + "-" : "") + dateCode;
234
+
235
+ }; // 2025 --- 24 years layer i'm 50 ! I wonder about my past self ...
236
+
237
+ const Tokenizer = {
238
+ tokenize,
239
+ tokenizeStrict,
240
+ tokenizeObject,
241
+ tokenizeKeep,
242
+ tokenizeWithDefault,
243
+ tokenizeUrl,
244
+ getPointedData,
245
+ sanitizeFilename,
246
+ generateFilename
247
+ };
248
+
249
+ export default Tokenizer;
219
250
  export {
220
251
  tokenize,
221
252
  tokenizeStrict,
@@ -223,5 +254,7 @@ export {
223
254
  tokenizeKeep,
224
255
  tokenizeWithDefault,
225
256
  tokenizeUrl,
226
- getPointedData
257
+ getPointedData,
258
+ sanitizeFilename,
259
+ generateFilename
227
260
  };
@@ -0,0 +1,72 @@
1
+ import m from "mithril";
2
+ import {ButtonNew, defineWidget} from "./Basic";
3
+ import Separator from "./Separator"
4
+
5
+ const
6
+
7
+ /*
8
+ SizeChoices = {
9
+ "1080p": {width: 1920, height: 1080, value: "1080p"},
10
+ "720p": {width: 1280, height: 720, value: "720p"},
11
+ "Fluid": {width: null, height: null, value: "Fluid"},
12
+ "Custom": {value: ""}
13
+ }
14
+ */
15
+
16
+ ButtonChoiceWidget = defineWidget(
17
+ ({attrs}) => {
18
+
19
+ const
20
+ {value, field, toggle, element, emptyMessage, chooseKey, chooseDict} = attrs,
21
+ choose = (!attrs.choose && chooseKey && chooseDict) ? chooseDict[chooseKey] : attrs.choose,
22
+ choices = choose
23
+ ? choose.map((choice) => ({value: choice, caption: choice}))
24
+ : attrs.choices || {};
25
+
26
+ const
27
+ keys = Object.keys(choices),
28
+ has = keys.length,
29
+ clase = (attrs.class || "") + (attrs.subclass ? " " + attrs.subclass : " scaff scaff-b1");
30
+
31
+ return has || emptyMessage
32
+ ? [
33
+ ...attrs.label ? [m(Separator, {text: attrs.label, class: attrs.labelClass || ""})] : [],
34
+ m(
35
+ (element || "div") + ".buttonchoice.flexrow.ohidden",
36
+ {
37
+ class: clase + (attrs.icon ? " withicon fa-" + attrs.icon : ""),
38
+ title: attrs.title
39
+ },
40
+ m(
41
+ ".flexrow.grows.ohidden.wrap" + (attrs.icon ? " scaff-left" : ""),
42
+ keys.length
43
+ ? keys.map((choicekey) => {
44
+
45
+ const
46
+ choice = choices[choicekey],
47
+ choicevalue = attrs.raw && field ? choice : choice.value,
48
+ finalchoicevalue = field ? choicevalue[field] : choicevalue,
49
+ current = finalchoicevalue === value;
50
+
51
+ // noinspection EqualityComparisonWithCoercionJS
52
+ return m(ButtonNew, {
53
+
54
+ icon: choice.icon || undefined,
55
+ class: "grows scaff-b0 " + (attrs.buttonClass ? attrs.buttonClass + " " : "rectbutton unitheightsmall ") + (choice.class ? choice.class + " " : "") + (current ? "accent" : ""),
56
+ title: choice.current ? choice.titleOn || choice.title : choice.titleOff || choice.title,
57
+ onClick: (e) => {
58
+ attrs.onchange(toggle ? current ? undefined : choice : choice, choicekey, e);
59
+ m.redraw();
60
+ }
61
+ }, attrs.render ? attrs.render(choice) : choice.caption || choicekey);
62
+ })
63
+ : [m(".emptychoice.grows.al-center.align-self-center.unitheightsmall", attrs.emptyMessage)]
64
+ )
65
+ )
66
+ ]
67
+ : [];
68
+ }
69
+ );
70
+
71
+ export default ButtonChoiceWidget;
72
+
@@ -0,0 +1,144 @@
1
+ import m from "mithril";
2
+ import defineWidget from "../util/widgets.utils";
3
+ import {popupMessage} from "../util/widgets"
4
+
5
+ const
6
+ colorjoe = require("colorjoe");
7
+ // TODO
8
+ // ColorProbeButton = require("ColorProbeButton");
9
+
10
+ const
11
+ ColorJoe = defineWidget(
12
+ () => m(".colorjoe-frame.absolute"),
13
+ null,
14
+ ({attrs, dom}) => {
15
+
16
+ window.SCALE = 1;
17
+
18
+ attrs.state.joe = (attrs.hsl ? colorjoe.hsl : colorjoe.rgb)(
19
+ dom,
20
+ attrs.color,
21
+ attrs.noalpha
22
+ ? []
23
+ : [
24
+ // "currentColor",
25
+ "alpha"
26
+ ]
27
+ );
28
+
29
+ attrs.state.joe.on("change", (c) => {
30
+ attrs.onColor(attrs.noalpha ? c.css() : c.cssa(), c);
31
+ })
32
+ .update();
33
+ }
34
+ ),
35
+ FAVORITES = [],
36
+ ColorJoeWrapper = defineWidget(
37
+ ({attrs, state, children}) => m(".colorjoe-popper.flexcol", {
38
+ class: attrs.noalpha ? "no-alpha" : ""
39
+ }, [
40
+ m(ColorJoe, {...attrs, state}),
41
+ ...children,
42
+ m(".flexrow.extended.w-100.scaff-top.pad-2.wrap", [
43
+
44
+ [0, 1, 2, 3, 4, 5, 6, 7, 8].map((i) => m("button.scaff.scaff-b1.marg-1.unitheightsmall.grows", {
45
+ class: FAVORITES[i] ? "" : "chequered",
46
+ style: {
47
+ ...FAVORITES[i] && {backgroundColor: FAVORITES[i]}
48
+ },
49
+ onclick: (e) => {
50
+ if (e.shiftKey) {
51
+ FAVORITES[i] = state.joe.get()
52
+ .css();
53
+ } else {
54
+ if (FAVORITES[i]) state.joe.set(FAVORITES[i]);
55
+ }
56
+ if (attrs.onRedraw) attrs.onRedraw(); else m.redraw();
57
+ }
58
+ })),
59
+ m(".flexbreak"),
60
+ /* TODO ELECTRON
61
+ m(ColorProbeButton, {
62
+ class: "grows marg-1 scaff scaff-b1 unitheightsmall",
63
+ icon: "magic",
64
+ title: "Pick a color from the scene",
65
+ onColor: (color) => state.joe.set(color)
66
+ }),
67
+ */
68
+ ...attrs.onRemove ? [m("button.scaff.scaff-b1.unitheightsmall.marg-1.pad-2.pad-h.grows.fabf.transp.bg-accent.fa-trash", {
69
+ onclick: () => attrs.onRemove(state.joe.get())
70
+ })] : []
71
+ ])
72
+ ])
73
+ ),
74
+ popupColor = (vnode) => popupMessage(
75
+ () => m(ColorJoeWrapper, {
76
+ noalpha: vnode.attrs.noalpha,
77
+ color: vnode.state.color,
78
+ hsl: vnode.attrs.hsl,
79
+ onColor: (parsedColor, colorObject) => {
80
+ vnode.state.color = parsedColor;
81
+ if (vnode.attrs.onchange) vnode.attrs.onchange(parsedColor, colorObject);
82
+ m.redraw();
83
+ },
84
+ onRemove: () => {
85
+ if (vnode.attrs.onchange) vnode.attrs.onchange(null, null);
86
+ popupMessage(null);
87
+ },
88
+ onRedraw: () => {
89
+ popupMessage.redraw();
90
+ m.redraw();
91
+ }
92
+ }, vnode.children),
93
+
94
+ () => {
95
+ },
96
+
97
+ ".modal-content-popper"
98
+ );
99
+
100
+ const ColorJoeWidget = defineWidget(
101
+ (vnode) => {
102
+ const {attrs, state} = vnode;
103
+ return [
104
+ m(
105
+ ".colorjoe-cell.chequered",
106
+ {
107
+ class: (attrs.class || "") + (state.shown ? " open" : ""),
108
+ title: attrs.title,
109
+ ...attrs.style && {style: attrs.style}
110
+ },
111
+ [
112
+ m(".inset", {
113
+ style: {
114
+ backgroundColor: state.color
115
+ },
116
+ ...attrs.caption && {"data-caption": attrs.caption, class: "titled"},
117
+ onclick: (e) => {
118
+ if (attrs.onshiftclick && (e.shiftKey || e.ctrlKey)) {
119
+ attrs.onshiftclick();
120
+ } else {
121
+ popupColor(vnode);
122
+ }
123
+ }
124
+ })
125
+ ])
126
+ ];
127
+ },
128
+ ({attrs, state}) => {
129
+ state.original = attrs.color;
130
+ state.color = state.original || "rgba(0,0,0,0)";
131
+ },
132
+ null,
133
+ null,
134
+ ({attrs, state}) => {
135
+ if (state.original !== attrs.color) {
136
+ state.original = attrs.color;
137
+ state.color = state.original || "rgba(0,0,0,0)";
138
+ m.redraw();
139
+ }
140
+ }
141
+ );
142
+
143
+
144
+ export default ColorJoeWidget;
@@ -0,0 +1,155 @@
1
+ import m from "mithril";
2
+
3
+ const
4
+ PropGroup = {
5
+ view: ({attrs}) => attrs.items.map(({name}, index) => m(
6
+ "option",
7
+ {
8
+ ...(attrs.state.index === index + (attrs.offset || 0)) && {selected: true}
9
+ },
10
+ name
11
+ ))
12
+ };
13
+
14
+ let
15
+ __timer;
16
+
17
+ function parseGroups(attrs, state) {
18
+
19
+ if (attrs.groups) {
20
+
21
+ state.groups = {};
22
+ state.allItems = [];
23
+
24
+ attrs.parsed = true;
25
+
26
+ const
27
+ groupKeys = Object.keys(attrs.groups);
28
+
29
+ groupKeys.forEach((groupKey) => {
30
+ state.groups[groupKey] = {
31
+ label: groupKey,
32
+ len: attrs.groups[groupKey].length,
33
+ items: attrs.groups[groupKey]
34
+ };
35
+ });
36
+
37
+ const
38
+ groupValues = Object.values(state.groups);
39
+
40
+ groupValues
41
+ .forEach((group, index) => {
42
+
43
+ if (attrs.value) {
44
+ state.index = 0;
45
+ }
46
+
47
+ group.offset = index ? groupValues[index - 1].offset + groupValues[index - 1].len : 0;
48
+ state.allItems = state.allItems.concat(group.items);
49
+ if (attrs.value) {
50
+
51
+ group.items.forEach((item, itemIndex) => {
52
+ const
53
+ itemValue = item.value,
54
+ parsedValue = attrs.parser ? attrs.parser(itemValue) : itemValue;
55
+ if (parsedValue === attrs.value) {
56
+ state.index = itemIndex + group.offset;
57
+ }
58
+ });
59
+ }
60
+ });
61
+ } else if (attrs.items) {
62
+ state.index = 0;
63
+ for (let i = 0, l = attrs.items.length; i < l; i++) {
64
+ const
65
+ itemValue = attrs.items[i].value,
66
+ parsedValue = attrs.parser ? attrs.parser(itemValue) : itemValue;
67
+ if (parsedValue === attrs.value) {
68
+ state.index = i;
69
+ break;
70
+ }
71
+ }
72
+ state.allItems = attrs.items;
73
+ } else {
74
+ state.allItems = [];
75
+ }
76
+
77
+ }
78
+
79
+ const ComboWidget = {
80
+
81
+ /**
82
+ * Creates the Widget View
83
+ * @param vnode
84
+ * @param {SelectAttrs} vnode.attrs
85
+ * @param {Object} vnode.state
86
+ * @return {*}
87
+ * @private
88
+ */
89
+
90
+
91
+ view: ({attrs, state}) => {
92
+ const {groups} = state;
93
+ return m(
94
+ "select",
95
+ {
96
+ "aria-label": attrs.caption,
97
+ class: attrs.class,
98
+ oninput: (ev) => {
99
+
100
+ // el desincronismo es si se camian los items y el state no se entera
101
+ // esto asegura que estan synchro
102
+ parseGroups(attrs, state);
103
+
104
+ const
105
+ index = state.index = ev.target.selectedIndex,
106
+ item = index >= 0 ? state.allItems[index] : null;
107
+
108
+ if (attrs.onchange && item) {
109
+ attrs.onchange(item.value, item, index);
110
+ }
111
+
112
+ m.redraw();
113
+ }
114
+ },
115
+ groups
116
+ ? Object.values(groups)
117
+ .map((group) => m("optgroup", {label: group.label}, m(PropGroup, {
118
+ items: group.items,
119
+ offset: group.offset,
120
+ state
121
+ })))
122
+ : m(PropGroup, {items: (attrs.items != null ? attrs.items : []), state}));
123
+ },
124
+
125
+ oninit: ({attrs, state}) => {
126
+ Object.assign(state, {
127
+ index: attrs.index || 0,
128
+ initial: attrs.value
129
+ });
130
+ parseGroups(attrs, state);
131
+ },
132
+
133
+ oncreate: () => {
134
+ },
135
+
136
+ onupdate: ({attrs, state}) => {
137
+
138
+ const refresh = (attrs.value !== undefined && state.initial !== attrs.value);
139
+
140
+ if (!state.groups && !state.allItems || refresh) {
141
+
142
+ // sets index from attrs.value
143
+ parseGroups(attrs, state);
144
+
145
+ if (refresh) {
146
+ state.initial = attrs.value;
147
+ clearTimeout(__timer);
148
+ __timer = setTimeout(() => m.redraw(), 50);
149
+ }
150
+ }
151
+
152
+ }
153
+ };
154
+
155
+ export default ComboWidget;
@@ -0,0 +1,239 @@
1
+ import {defineWidget, ButtonNew} from "./Basic.js"
2
+ import {promptName} from "./OverflowUtils"
3
+ import {confirmPromise} from "../util/fuckingconfirm"
4
+
5
+ const
6
+ ThematicWrapper = defineWidget(
7
+ ({attrs, children}) => m(
8
+ ".buttonchoice.withicon.flexrow.scaff.scaff-b1.fadein.ohidden.fa-" + (attrs.icon || "gear"),
9
+ {class: (attrs.containerClass || "col-11 grows marg-1"), title: attrs.title},
10
+ m(
11
+ ".flexrow.wrap.grows.col-11.ohidden.scaff-left.bg-inputs",
12
+ {class: attrs.class},
13
+ children
14
+ )
15
+ )
16
+ ),
17
+ optionsPrompt = (items, index, onAdd, onDelete, onEdit, allowUpdate) => {
18
+
19
+ const item = items[index];
20
+
21
+ confirmPromise(
22
+ null,
23
+
24
+ "Choose an action for this preset",
25
+
26
+ onAdd && allowUpdate
27
+ ? ["DELETE", "RENAME", "UPDATE", "CANCEL"]
28
+ : ["DELETE", "RENAME", "CANCEL"]
29
+ )
30
+ .then(({idx}) => {
31
+
32
+ if (idx === 0) {
33
+ items.splice(index, 1);
34
+ if (onDelete) onDelete(index);
35
+ m.redraw();
36
+ } else if (idx === 1) {
37
+ setTimeout(() => promptName(
38
+ "Rename Preset",
39
+ item.title || "",
40
+ "type a name for this preset",
41
+ (newName) => {
42
+ if (newName) {
43
+ newName = newName.trim();
44
+ if (newName) {
45
+ item.title = newName.substring(0, 24);
46
+ m.redraw();
47
+ }
48
+ }
49
+ }
50
+ ), 10);
51
+ } else if (onAdd && idx === 2) {
52
+ onAdd(false, index);
53
+ }
54
+ });
55
+ },
56
+ GenericButtonTicker = defineWidget(
57
+ ({attrs, children}) => {
58
+
59
+ const
60
+ {
61
+ title, noUpdate, items = [], current, altIndex, onEdit, emptyText,
62
+ onAdd, onSelect, onDelete, addText = "Add New",
63
+ unconfirm, buttonClass, themeIcon, themeTitle
64
+ } = attrs,
65
+
66
+ allItems = [
67
+
68
+ ...items.map(
69
+ (item, index) => m(
70
+ "button.grows.marg-1.ellipsis.ohidden.hasShift",
71
+ {
72
+
73
+ class: (buttonClass ? buttonClass : "unitheightsmall scaff-b1")
74
+ + (index === current ? " accent" : "")
75
+ + (index === altIndex ? " alt-accent" : ""),
76
+
77
+ title,
78
+ onclick: (e) => {
79
+ if (e.metaKey && onEdit) {
80
+ onEdit(item);
81
+ } else if (onAdd && e.shiftKey) {
82
+ if (unconfirm) {
83
+ items.splice(index, 1);
84
+ if (onDelete) onDelete(index);
85
+ m.redraw();
86
+ } else {
87
+ optionsPrompt(items, index, onAdd, onDelete, undefined, !noUpdate);
88
+ }
89
+ } else {
90
+ onSelect(item, index, e.metaKey, e.shiftKey);
91
+ }
92
+ }
93
+ },
94
+ (item.title || item.name || item.text || String(1 + index)).substring(0, 32)
95
+ )
96
+ ),
97
+
98
+ ...!items.length && emptyText
99
+ ? [
100
+ m(".grows.marg-1.ellipsis.ohidden.al-center", emptyText)
101
+ ] : [],
102
+
103
+ ...onAdd
104
+ ? [
105
+ m(ButtonNew, {
106
+ tabIndex: -1,
107
+ icon: attrs.icon || "plus",
108
+ title: attrs.addTitle || "Add a new item",
109
+ class: "pad-2 pad-h al-center unitheightsmall transp addbut scaff-left bg-window-lo grows",
110
+ onClick: (e) => onAdd(e.ctrlKey || e.metaKey),
111
+ text: items?.length ? "" : addText
112
+ })
113
+ ]
114
+ : [],
115
+
116
+ ...!themeIcon && attrs.currentWidget && current >= 0 && items[current]
117
+ ? attrs.currentWidget(items[current], current) || []
118
+ : [],
119
+
120
+ ...children
121
+ ];
122
+
123
+ return themeIcon
124
+ ? [
125
+ m(ThematicWrapper, {
126
+ title: themeTitle,
127
+ containerClass: attrs.containerClass,
128
+ icon: themeIcon
129
+ }, allItems),
130
+ ...attrs.currentWidget && current >= 0 && items[current] ? attrs.currentWidget(items[current], current) || [] : []
131
+ ] : allItems;
132
+ }
133
+ ),
134
+ CoolGenericTicker = defineWidget(
135
+ ({attrs, children}) => {
136
+
137
+ const
138
+ {
139
+ nocontainer,
140
+ emptyText,
141
+ title,
142
+ addTitle,
143
+ items,
144
+ currentIndex,
145
+ altIndex,
146
+ onEdit,
147
+ onDelta,
148
+ onSelect,
149
+ onAdd,
150
+ addText,
151
+ icon,
152
+ buttonClass
153
+ } = attrs,
154
+ itemz = ((items && items.length <= (attrs.max || 15)) || !onDelta)
155
+ ? m(GenericButtonTicker, {
156
+ addTitle,
157
+ emptyText,
158
+ title,
159
+ items,
160
+ current: currentIndex,
161
+ altIndex,
162
+ onSelect,
163
+ onAdd,
164
+ onEdit,
165
+ addText,
166
+ icon,
167
+ buttonClass
168
+ }, children)
169
+ : [
170
+ m(ButtonNew, {
171
+ tabIndex: -1,
172
+ icon: "caret-right",
173
+ class: "unitheightsmall grows marg-1 no-marg-left",
174
+ onClick: () => onDelta(-1)
175
+ }),
176
+ ...items
177
+ ? [
178
+ m(
179
+ ".scaff.unitheightsmall.value.al-center.bg-window-lo.grows.marg-1.no-marg-left ",
180
+ (1 + currentIndex) + " / " + items.length
181
+ )
182
+ ]
183
+ : [],
184
+ m(ButtonNew, {
185
+ tabIndex: -1,
186
+ icon: "caret-left",
187
+ class: "unitheightsmall grows marg-1 marg-v",
188
+ onClick: () => onDelta(1)
189
+ }),
190
+ ...onAdd
191
+ ? [
192
+ m(ButtonNew, {
193
+ tabIndex: -1,
194
+ icon: attrs.icon || "plus",
195
+ class: "unitheightsmall marg-1 marg-v",
196
+ onClick: () => onAdd()
197
+ })
198
+ ] : []
199
+ ];
200
+
201
+ return nocontainer
202
+ ? itemz
203
+ : items.length || !onAdd ? m(
204
+ ".flexrow.wrap.max.minusbar",
205
+ {class: (attrs.dynclass ? attrs.dynclass() + " " : "") + attrs.class},
206
+ itemz
207
+ ) : [];
208
+ }
209
+ ),
210
+
211
+ CoolContentTicker = defineWidget(
212
+ ({attrs}) => {
213
+
214
+ if (!attrs.layer.items) return [];
215
+
216
+ const
217
+ {global, layer, remoteFirst: isRemote, isCue} = attrs,
218
+ {storyWrapper} = global,
219
+ {id, items} = layer,
220
+
221
+ currentIndex = storyWrapper.getTickerIndex(id, isRemote),
222
+ altIndex = isRemote ? storyWrapper.getTickerIndex(id, false) : undefined;
223
+
224
+ // noinspection JSUnusedGlobalSymbols
225
+ return m(CoolGenericTicker, {
226
+ title: attrs.title,
227
+ onAdd: attrs.onAdd,
228
+ class: "marg-1 marg-h grows",
229
+ items,
230
+ currentIndex,
231
+ altIndex,
232
+ current: items[currentIndex] || undefined,
233
+ onDelta: (direction) => storyWrapper.tickLayer(layer, direction, isRemote, isCue),
234
+ onSelect: (item, index, force) => storyWrapper.setTickerIndex(layer, index, force, isRemote, isCue)
235
+ });
236
+ }
237
+ );
238
+
239
+ export {CoolContentTicker, CoolGenericTicker, GenericButtonTicker, optionsPrompt};