@nebularstreams/libmui 2.0.13 → 2.0.14
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.css +1 -1
- package/dist/libui.esm.js +1 -1
- package/dist/libui.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/index.js +53 -4
- package/src/meta/Emojis.js +32136 -0
- package/src/meta/FontAwesome.js +8012 -0
- package/src/meta/InputTemplates.js +3 -0
- package/src/util/colorjoe.js +1371 -0
- package/src/util/tainter.js +31 -0
- package/src/util/util.tokenizer.js +7 -1
- package/src/widgets/ButtonChoiceWidget.js +72 -0
- package/src/widgets/ColorJoeWidget.js +144 -0
- package/src/widgets/ComboWidget.js +155 -0
- package/src/widgets/FontSelectorButton.js +36 -0
- package/src/widgets/PlusMinusWidget.js +55 -0
- package/src/widgets/SelectFileMiniButton.js +194 -0
- package/src/widgets/SmileysButton.js +18 -0
- package/src/widgets/SmileysPanel.js +20 -0
- package/src/widgets/SmileysWidget.js +199 -0
- package/src/widgets/TemplatedInputWidget.js +1219 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* A Button to read a text file
|
|
4
|
+
* @typedef {{ root:string, key:string, format:string, type:string, onUpload:function(boolean,Error?), quality:number}} UploadImageAttrs
|
|
5
|
+
*
|
|
6
|
+
* @author Rodolfo Lopez Pintor, 2019
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import m from "mithril";
|
|
11
|
+
import {defineWidget, Icon, ButtonNew, Notification} from "./Basic";
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
function processDataUrl(file) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
|
|
17
|
+
const reader = new FileReader();
|
|
18
|
+
reader.onload = function (evt) {
|
|
19
|
+
|
|
20
|
+
const
|
|
21
|
+
data = evt.target.result;
|
|
22
|
+
|
|
23
|
+
if (data) resolve({name: file.name, url: data}); else reject(new Error("no data"));
|
|
24
|
+
|
|
25
|
+
};
|
|
26
|
+
reader.readAsDataURL(file);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function processImage(file) {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
|
|
34
|
+
const reader = new FileReader();
|
|
35
|
+
reader.onload = function (evt) {
|
|
36
|
+
|
|
37
|
+
const
|
|
38
|
+
data = evt.target.result,
|
|
39
|
+
pict = new Image();
|
|
40
|
+
|
|
41
|
+
pict.onerror = function (error) {
|
|
42
|
+
evt.target.value = "";
|
|
43
|
+
reject(error);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
pict.onload = function () {
|
|
47
|
+
resolve(pict);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// noinspection JSValidateTypes
|
|
51
|
+
pict.src = data;
|
|
52
|
+
|
|
53
|
+
};
|
|
54
|
+
reader.readAsDataURL(file);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const
|
|
60
|
+
MediaSelectButton = defineWidget(
|
|
61
|
+
({attrs}) => m(ButtonNew, {
|
|
62
|
+
class: "unitsizesmall rectbutton ohidden",
|
|
63
|
+
icon: "images",
|
|
64
|
+
onClick: () => attrs.state.setTransState("image", undefined, {
|
|
65
|
+
giphyQuery: "frame",
|
|
66
|
+
onOverride: (global, item) => {
|
|
67
|
+
const translated = item ? attrs.parse ? attrs.parse(item) : item : undefined;
|
|
68
|
+
if (translated) {
|
|
69
|
+
attrs.onImage(translated);
|
|
70
|
+
m.redraw();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// noinspection JSValidateTypes
|
|
78
|
+
const
|
|
79
|
+
FileSelectButton = defineWidget(
|
|
80
|
+
(vnode) => {
|
|
81
|
+
|
|
82
|
+
const {attrs} = vnode;
|
|
83
|
+
|
|
84
|
+
return m(
|
|
85
|
+
"button.selectfile.relative",
|
|
86
|
+
{
|
|
87
|
+
...attrs.class && {class: attrs.class}
|
|
88
|
+
},
|
|
89
|
+
[
|
|
90
|
+
m(Icon, {icon: attrs.icon || "upload", iconClass: attrs.iconClass}),
|
|
91
|
+
...attrs.text ? [m("span.text", {class: attrs.textClass}, attrs.text)] : [],
|
|
92
|
+
m("input", {
|
|
93
|
+
class: "absolute w-100 h-100 ohidden",
|
|
94
|
+
type: "file",
|
|
95
|
+
accept: attrs.accept || null,
|
|
96
|
+
title: attrs.title,
|
|
97
|
+
onchange: (event) => {
|
|
98
|
+
if (event.target.files && event.target.files.length) {
|
|
99
|
+
attrs.onFile(event.target.files[0]);
|
|
100
|
+
event.target.value = "";
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
]
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
|
|
110
|
+
ImageSelectButton = defineWidget(
|
|
111
|
+
({attrs}) => m(FileSelectButton, {
|
|
112
|
+
class: attrs.class,
|
|
113
|
+
accept: attrs.accept || "image/*",
|
|
114
|
+
icon: attrs.icon || "image",
|
|
115
|
+
iconClass: attrs.iconClass,
|
|
116
|
+
textClass: attrs.textClass,
|
|
117
|
+
text: attrs.text,
|
|
118
|
+
onFile: (file) => attrs.onImageFiles([{type: "image", file}])
|
|
119
|
+
})
|
|
120
|
+
),
|
|
121
|
+
|
|
122
|
+
VideoUploadButton = defineWidget(
|
|
123
|
+
({attrs}) => m(FileSelectButton, {
|
|
124
|
+
class: attrs.class,
|
|
125
|
+
accept: attrs.accept || ".mp4,.webm",
|
|
126
|
+
icon: attrs.icon || "video",
|
|
127
|
+
iconClass: attrs.iconClass,
|
|
128
|
+
textClass: attrs.textClass,
|
|
129
|
+
text: attrs.text,
|
|
130
|
+
|
|
131
|
+
onFile: (file) => {
|
|
132
|
+
if (file) {
|
|
133
|
+
attrs.entity.saveBlob(file.name, file, "video", undefined, false)
|
|
134
|
+
.then(() => {
|
|
135
|
+
if (attrs.onVideo) {
|
|
136
|
+
attrs.onVideo(attrs.path);
|
|
137
|
+
} else {
|
|
138
|
+
m.redraw();
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
.catch((e) => Notification.add(e.message));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
),
|
|
146
|
+
|
|
147
|
+
ImageProcessButton = defineWidget(
|
|
148
|
+
({attrs}) => m(ImageSelectButton, {
|
|
149
|
+
class: attrs.class,
|
|
150
|
+
icon: attrs.icon,
|
|
151
|
+
text: attrs.text,
|
|
152
|
+
accept: attrs.accept,
|
|
153
|
+
iconClass: attrs.iconClass,
|
|
154
|
+
textClass: attrs.textClass,
|
|
155
|
+
onImageFiles: (files) => {
|
|
156
|
+
if (files.length) {
|
|
157
|
+
processImage(files[0].file)
|
|
158
|
+
.then(attrs.onImage)
|
|
159
|
+
.catch((e) => {
|
|
160
|
+
if (attrs.onError) attrs.onError(e);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
),
|
|
166
|
+
ImageDataButton = defineWidget(
|
|
167
|
+
({attrs}) => m(ImageSelectButton, {
|
|
168
|
+
class: attrs.class,
|
|
169
|
+
icon: attrs.icon,
|
|
170
|
+
text: attrs.text,
|
|
171
|
+
accept: attrs.accept,
|
|
172
|
+
iconClass: attrs.iconClass,
|
|
173
|
+
textClass: attrs.textClass,
|
|
174
|
+
onImageFiles: (files) => {
|
|
175
|
+
if (files.length) {
|
|
176
|
+
processDataUrl(files[0].file)
|
|
177
|
+
.then(attrs.onImageUrl)
|
|
178
|
+
.catch((e) => {
|
|
179
|
+
if (attrs.onError) attrs.onError(e);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
export {
|
|
187
|
+
VideoUploadButton,
|
|
188
|
+
FileSelectButton,
|
|
189
|
+
ImageDataButton,
|
|
190
|
+
ImageSelectButton,
|
|
191
|
+
ImageProcessButton,
|
|
192
|
+
MediaSelectButton,
|
|
193
|
+
processImage
|
|
194
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import m from "mithril";
|
|
2
|
+
import {defineWidget, ButtonNew} from "./Basic";
|
|
3
|
+
|
|
4
|
+
const
|
|
5
|
+
SmileysButton = defineWidget(
|
|
6
|
+
({attrs}) => {
|
|
7
|
+
const {icon, onchange, icons, state} = attrs;
|
|
8
|
+
return m(ButtonNew, {
|
|
9
|
+
title: "Click to select icon or emoji for this marker",
|
|
10
|
+
class: "chequered " + (attrs.class || "font-200"),
|
|
11
|
+
icon: icon && icon.icon,
|
|
12
|
+
text: icon && icon.glyph,
|
|
13
|
+
onClick: () => state.setTransState("emoji", onchange, {icons})
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export default SmileysButton;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import m from "mithril";
|
|
2
|
+
import {defineWidget} from "./Basic";
|
|
3
|
+
import TitleBarWidget from "./TitleBarWidget";
|
|
4
|
+
import SmileysWidget from "./SmileysWidget";
|
|
5
|
+
|
|
6
|
+
export default defineWidget(
|
|
7
|
+
({attrs}) => [
|
|
8
|
+
...attrs.toggle ? [] : [
|
|
9
|
+
m(TitleBarWidget, {
|
|
10
|
+
onClick: attrs.onClose,
|
|
11
|
+
title: "Add an emoji"
|
|
12
|
+
})
|
|
13
|
+
],
|
|
14
|
+
m(SmileysWidget, {
|
|
15
|
+
horizontal: true,
|
|
16
|
+
onClick: attrs.onClick,
|
|
17
|
+
icons: attrs.icons
|
|
18
|
+
})
|
|
19
|
+
]
|
|
20
|
+
);
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import m from "mithril";
|
|
2
|
+
import {defineWidget, Empty} from "./Basic";
|
|
3
|
+
import InputWidget from "./InputWidget";
|
|
4
|
+
import EMOJIS from "../meta/EMOJIS";
|
|
5
|
+
import FONTAWESOME from "../meta/FONTAWESOME";
|
|
6
|
+
|
|
7
|
+
const
|
|
8
|
+
|
|
9
|
+
FAVOLEGEND = "⭐️",
|
|
10
|
+
FAVORITES = {},
|
|
11
|
+
BLACKLIST = {Component: true};
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
"codes": "1F3F4 E0067 E0062 E0077 E006C E0073 E007F",
|
|
17
|
+
"char": "🏴",
|
|
18
|
+
"name": "flag: Wales",
|
|
19
|
+
"category": "Flags (subdivision-flag)",
|
|
20
|
+
"group": "Flags",
|
|
21
|
+
"subgroup": "subdivision-flag"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
let
|
|
27
|
+
favorites,
|
|
28
|
+
groups,
|
|
29
|
+
filtered,
|
|
30
|
+
filterText,
|
|
31
|
+
ICONSET;
|
|
32
|
+
|
|
33
|
+
function filter(text, minlen = 2) {
|
|
34
|
+
if (text && text.length >= minlen) {
|
|
35
|
+
filtered = ICONSET.filter((smiley) => (smiley.name.toLowerCase()
|
|
36
|
+
.indexOf(text) >= 0));
|
|
37
|
+
m.redraw();
|
|
38
|
+
} else if (filtered) {
|
|
39
|
+
filtered = null;
|
|
40
|
+
m.redraw();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function setIconset(emojis, icons) {
|
|
45
|
+
ICONSET = [
|
|
46
|
+
...emojis ? EMOJIS : [],
|
|
47
|
+
...icons ? FONTAWESOME : []
|
|
48
|
+
];
|
|
49
|
+
calc();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function calc() {
|
|
53
|
+
favorites = FAVORITES || {};
|
|
54
|
+
const favkeys = ObjectKeys(favorites);
|
|
55
|
+
groups = ICONSET.reduce((total, item) => {
|
|
56
|
+
const {
|
|
57
|
+
char,
|
|
58
|
+
group,
|
|
59
|
+
name,
|
|
60
|
+
icon,
|
|
61
|
+
class: clase
|
|
62
|
+
} = item;
|
|
63
|
+
if (!BLACKLIST[group]) {
|
|
64
|
+
if (total[group]) {
|
|
65
|
+
total[group].push({
|
|
66
|
+
char,
|
|
67
|
+
name,
|
|
68
|
+
icon,
|
|
69
|
+
class: clase
|
|
70
|
+
});
|
|
71
|
+
} else {
|
|
72
|
+
total[group] = [{
|
|
73
|
+
char,
|
|
74
|
+
name,
|
|
75
|
+
icon,
|
|
76
|
+
class: clase
|
|
77
|
+
}
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return total;
|
|
82
|
+
},
|
|
83
|
+
favkeys.length
|
|
84
|
+
? {
|
|
85
|
+
|
|
86
|
+
favorites: favkeys.map((char) => ({
|
|
87
|
+
name: favorites[char].name,
|
|
88
|
+
char
|
|
89
|
+
}))
|
|
90
|
+
}
|
|
91
|
+
: {});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function del(item) {
|
|
95
|
+
if (item && item.char && favorites[item.char]) {
|
|
96
|
+
delete favorites[item.char];
|
|
97
|
+
calc();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function save(item) {
|
|
102
|
+
if (item && item.char && item.name && !item.icon) {
|
|
103
|
+
favorites[item.char] = item.name;
|
|
104
|
+
calc();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const SmileysWidget = defineWidget(
|
|
109
|
+
({attrs, state}) => m("widget.ohidden",
|
|
110
|
+
{
|
|
111
|
+
class: (attrs.mainclass ? attrs.mainclass : "smileyswidget") + " " + (attrs.horizontal ? "flexcol" : "flexrow")
|
|
112
|
+
},
|
|
113
|
+
[
|
|
114
|
+
m(InputWidget, {
|
|
115
|
+
hint: "search emoji ...",
|
|
116
|
+
containerClass: "bottombox forinputs unitheight col-12 font-125 order-end",
|
|
117
|
+
class: "font-125 transparent",
|
|
118
|
+
autofocus: true,
|
|
119
|
+
value: filterText,
|
|
120
|
+
oninput: (value) => {
|
|
121
|
+
filterText = value.toLowerCase();
|
|
122
|
+
filter(filterText);
|
|
123
|
+
},
|
|
124
|
+
onchange: () => {
|
|
125
|
+
}
|
|
126
|
+
}),
|
|
127
|
+
|
|
128
|
+
...filtered
|
|
129
|
+
? [
|
|
130
|
+
m(
|
|
131
|
+
"icons.flexrow.wrap.scrolly.grows",
|
|
132
|
+
filtered.length
|
|
133
|
+
? filtered.map(
|
|
134
|
+
(smiley) => m(".smiley", {
|
|
135
|
+
onclick: (e) => {
|
|
136
|
+
if (state.current === "favorites" && e.shiftKey) {
|
|
137
|
+
del(smiley);
|
|
138
|
+
} else {
|
|
139
|
+
save(smiley);
|
|
140
|
+
}
|
|
141
|
+
attrs.onClick(smiley.char, smiley);
|
|
142
|
+
},
|
|
143
|
+
class: smiley.class || ""
|
|
144
|
+
}, smiley.char))
|
|
145
|
+
: [
|
|
146
|
+
m(Empty, {
|
|
147
|
+
icon: "smile",
|
|
148
|
+
message: "No icons found",
|
|
149
|
+
size: 2
|
|
150
|
+
})
|
|
151
|
+
]
|
|
152
|
+
)
|
|
153
|
+
]
|
|
154
|
+
: [
|
|
155
|
+
m(
|
|
156
|
+
".categories.noshrink",
|
|
157
|
+
{
|
|
158
|
+
class: attrs.horizontal ? "flexrow wrap" : "flexcol"
|
|
159
|
+
},
|
|
160
|
+
Object.keys(groups)
|
|
161
|
+
.map((group) => m(".grows.cat", {
|
|
162
|
+
className: (state.current === group ? "accent" : "") + " " + (group === "favorites" ? "isfav" : ""),
|
|
163
|
+
onclick: () => {
|
|
164
|
+
state.current = group;
|
|
165
|
+
m.redraw();
|
|
166
|
+
}
|
|
167
|
+
}, group === "favorites"
|
|
168
|
+
? FAVOLEGEND : group))
|
|
169
|
+
),
|
|
170
|
+
m(
|
|
171
|
+
"icons.flexrow.wrap.scrolly.grows",
|
|
172
|
+
groups[state.current]
|
|
173
|
+
? groups[state.current].map((smiley) => m(".smiley", {
|
|
174
|
+
onclick: (e) => {
|
|
175
|
+
if (state.current === "favorites" && e.shiftKey) {
|
|
176
|
+
del(smiley);
|
|
177
|
+
} else {
|
|
178
|
+
save(smiley);
|
|
179
|
+
}
|
|
180
|
+
attrs.onClick(smiley.char, smiley);
|
|
181
|
+
},
|
|
182
|
+
class: smiley.class || ""
|
|
183
|
+
}, smiley.char))
|
|
184
|
+
: []
|
|
185
|
+
)
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
]
|
|
190
|
+
),
|
|
191
|
+
({attrs, state}) => {
|
|
192
|
+
setIconset(!attrs.noemojis, attrs.icons);
|
|
193
|
+
[state.current] = Object.keys(groups);
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
export default SmileysWidget;
|
|
198
|
+
|
|
199
|
+
|