@optionfactory/ful 0.102.0 → 0.104.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/ful.iife.js +154 -507
- package/dist/ful.iife.js.map +1 -1
- package/dist/ful.iife.min.js +1 -1
- package/dist/ful.iife.min.js.map +1 -1
- package/dist/ful.min.mjs +1 -1
- package/dist/ful.min.mjs.map +1 -1
- package/dist/ful.mjs +135 -477
- package/dist/ful.mjs.map +1 -1
- package/package.json +17 -8
package/dist/ful.iife.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var ful = (function (exports) {
|
|
1
|
+
var ful = (function (exports, ftl, TomSelect) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
class Base64 {
|
|
@@ -1034,473 +1034,158 @@ var ful = (function (exports) {
|
|
|
1034
1034
|
}
|
|
1035
1035
|
};
|
|
1036
1036
|
|
|
1037
|
-
class
|
|
1038
|
-
constructor() {
|
|
1039
|
-
this.promise = new Promise((resolve, reject) => {
|
|
1040
|
-
this.reject = reject;
|
|
1041
|
-
this.resolve = resolve;
|
|
1042
|
-
});
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1037
|
+
class Bindings {
|
|
1045
1038
|
|
|
1046
|
-
class Fragments {
|
|
1047
1039
|
/**
|
|
1048
|
-
*
|
|
1049
|
-
* @param
|
|
1050
|
-
* @
|
|
1040
|
+
* @param {{ [x: string]: any; }} obj
|
|
1041
|
+
* @param {string} prefix
|
|
1042
|
+
* @return {{ [x: string]: any; }}
|
|
1051
1043
|
*/
|
|
1052
|
-
static
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
static toHtml(fragment) {
|
|
1063
|
-
var el = document.createElement("template");
|
|
1064
|
-
el.content.appendChild(fragment);
|
|
1065
|
-
return el.innerHTML;
|
|
1066
|
-
}
|
|
1067
|
-
/**
|
|
1068
|
-
*
|
|
1069
|
-
* @param {...Node} nodes
|
|
1070
|
-
* @returns
|
|
1071
|
-
*/
|
|
1072
|
-
static from(...nodes) {
|
|
1073
|
-
const fragment = new DocumentFragment();
|
|
1074
|
-
fragment.append(...nodes);
|
|
1075
|
-
return fragment;
|
|
1076
|
-
}
|
|
1077
|
-
/**
|
|
1078
|
-
*
|
|
1079
|
-
* @param {HTMLElement} el
|
|
1080
|
-
* @returns
|
|
1081
|
-
*/
|
|
1082
|
-
static fromChildNodes(el) {
|
|
1083
|
-
const fragment = new DocumentFragment();
|
|
1084
|
-
fragment.append(...el.childNodes);
|
|
1085
|
-
return fragment;
|
|
1044
|
+
static flatten(obj, prefix) {
|
|
1045
|
+
return Object.keys(obj).reduce((acc, k) => {
|
|
1046
|
+
const pre = prefix.length ? prefix + '.' : '';
|
|
1047
|
+
if (typeof obj[k] === 'object' && obj[k] !== null) {
|
|
1048
|
+
Object.assign(acc, Bindings.flatten(obj[k], pre + k));
|
|
1049
|
+
} else {
|
|
1050
|
+
acc[pre + k] = obj[k];
|
|
1051
|
+
}
|
|
1052
|
+
return acc;
|
|
1053
|
+
}, {});
|
|
1086
1054
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
class Attributes {
|
|
1090
|
-
static id = 0;
|
|
1055
|
+
|
|
1091
1056
|
/**
|
|
1092
|
-
*
|
|
1093
|
-
* @param {string}
|
|
1094
|
-
* @
|
|
1057
|
+
* @param {any} result
|
|
1058
|
+
* @param {string} path
|
|
1059
|
+
* @param {any} value
|
|
1095
1060
|
*/
|
|
1096
|
-
static
|
|
1097
|
-
|
|
1061
|
+
static providePath(result, path, value) {
|
|
1062
|
+
const keys = path.split(".").map((k) => /^[0-9]+$/.test(k) ? +k : k);
|
|
1063
|
+
let current = result ?? {};
|
|
1064
|
+
let previous = null;
|
|
1065
|
+
for (let i = 0; ; ++i) {
|
|
1066
|
+
const ckey = keys[i];
|
|
1067
|
+
const pkey = keys[i - 1];
|
|
1068
|
+
if (Number.isInteger(ckey) && !Array.isArray(current)) {
|
|
1069
|
+
if (previous !== null) {
|
|
1070
|
+
previous[pkey] = current = [];
|
|
1071
|
+
} else {
|
|
1072
|
+
result = current = [];
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
if (i === keys.length - 1) {
|
|
1076
|
+
//when value is undefined we only want to define the property if it's not defined
|
|
1077
|
+
current[ckey] = value !== undefined ? value : (ckey in current ? current[ckey] : null);
|
|
1078
|
+
return result;
|
|
1079
|
+
}
|
|
1080
|
+
if (current[ckey] === undefined) {
|
|
1081
|
+
current[ckey] = {};
|
|
1082
|
+
}
|
|
1083
|
+
previous = current;
|
|
1084
|
+
current = current[ckey];
|
|
1085
|
+
}
|
|
1098
1086
|
}
|
|
1099
1087
|
/**
|
|
1100
1088
|
*
|
|
1101
|
-
* @param {
|
|
1102
|
-
* @param {string} k
|
|
1103
|
-
* @param {string} v
|
|
1089
|
+
* @param {Element & {dataset?: any} & {checked?: boolean} & {value?: any}} el
|
|
1104
1090
|
* @returns
|
|
1105
1091
|
*/
|
|
1106
|
-
static
|
|
1107
|
-
if (
|
|
1108
|
-
el.
|
|
1092
|
+
static extract(el) {
|
|
1093
|
+
if (el.getAttribute('type') === 'radio') {
|
|
1094
|
+
if (!el.checked) {
|
|
1095
|
+
return undefined;
|
|
1096
|
+
}
|
|
1097
|
+
return el.dataset['fulBindType'] === 'boolean' ? el.value === 'true' : el.value;
|
|
1109
1098
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
/**
|
|
1113
|
-
*
|
|
1114
|
-
* @param {string} prefix
|
|
1115
|
-
* @param {HTMLElement} from
|
|
1116
|
-
* @param {HTMLElement} to
|
|
1117
|
-
*/
|
|
1118
|
-
static forward(prefix, from, to) {
|
|
1119
|
-
from.getAttributeNames()
|
|
1120
|
-
.filter(a => a.startsWith(prefix))
|
|
1121
|
-
.forEach(a => {
|
|
1122
|
-
const target = a.substring(prefix.length);
|
|
1123
|
-
if (target === 'class') {
|
|
1124
|
-
const classes = from.getAttribute(prefix + "class")?.split(" ").filter(a => a.length) ?? [];
|
|
1125
|
-
to.classList.add(...classes);
|
|
1126
|
-
return;
|
|
1127
|
-
}
|
|
1128
|
-
// @ts-ignore
|
|
1129
|
-
to.setAttribute(target, from.getAttribute(a));
|
|
1130
|
-
});
|
|
1131
|
-
}
|
|
1132
|
-
/**
|
|
1133
|
-
*
|
|
1134
|
-
* @param {HTMLElement} el
|
|
1135
|
-
* @param {string} attr
|
|
1136
|
-
* @param {boolean} value
|
|
1137
|
-
*/
|
|
1138
|
-
static toggle(el, attr, value) {
|
|
1139
|
-
if (value) {
|
|
1140
|
-
el.setAttribute(attr, '');
|
|
1141
|
-
} else {
|
|
1142
|
-
el.removeAttribute(attr);
|
|
1099
|
+
if (el.getAttribute('type') === 'checkbox') {
|
|
1100
|
+
return el.checked;
|
|
1143
1101
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
if (el.hasAttribute(attr)) {
|
|
1147
|
-
el.removeAttribute(attr);
|
|
1148
|
-
} else {
|
|
1149
|
-
el.setAttribute(attr, '');
|
|
1102
|
+
if (el.dataset['fulBindType'] === 'boolean') {
|
|
1103
|
+
return !el.value ? null : el.value === 'true';
|
|
1150
1104
|
}
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
class LightSlots {
|
|
1156
|
-
/**
|
|
1157
|
-
*
|
|
1158
|
-
* @param {HTMLElement} el
|
|
1159
|
-
* @returns the slots
|
|
1160
|
-
*/
|
|
1161
|
-
static from(el) {
|
|
1162
|
-
/** @type [string, Element][] */
|
|
1163
|
-
const namedSlots = Array.from(el.children)
|
|
1164
|
-
.filter(el => el.matches('[slot]'))
|
|
1165
|
-
.map(el => {
|
|
1166
|
-
el.remove();
|
|
1167
|
-
const slot = el.getAttribute("slot");
|
|
1168
|
-
el.removeAttribute("slot");
|
|
1169
|
-
return [slot ?? 'unnamed', el];
|
|
1170
|
-
});
|
|
1171
|
-
const slots = {};
|
|
1172
|
-
slots.default = new DocumentFragment();
|
|
1173
|
-
slots.default.append(...el.childNodes);
|
|
1174
|
-
for (const [name, el] of namedSlots) {
|
|
1175
|
-
if (!(name in slots)) {
|
|
1176
|
-
slots[name] = new DocumentFragment();
|
|
1177
|
-
}
|
|
1178
|
-
slots[name].append(el);
|
|
1105
|
+
if (el.tagName === 'INPUT' || el.tagName === 'SELECT') {
|
|
1106
|
+
return el.value === '' || el.value === undefined ? null : el.value;
|
|
1179
1107
|
}
|
|
1180
|
-
return
|
|
1108
|
+
return el.value;
|
|
1181
1109
|
}
|
|
1182
|
-
}
|
|
1183
1110
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
for
|
|
1187
|
-
if (
|
|
1188
|
-
|
|
1111
|
+
static extractFrom(root, ignoredChildrenSelector){
|
|
1112
|
+
let result = {};
|
|
1113
|
+
for(const el of /** @type {NodeListOf<HTMLElement>} */(root.querySelectorAll('[name]'))){
|
|
1114
|
+
if (el.dataset['fulBindInclude'] === 'never') {
|
|
1115
|
+
continue;
|
|
1189
1116
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
}
|
|
1193
|
-
static queryChildren(node, selector) {
|
|
1194
|
-
for (const c of node.children) {
|
|
1195
|
-
if (c.matches(selector)) {
|
|
1196
|
-
return c;
|
|
1117
|
+
if(ignoredChildrenSelector && el.dataset['fulBindInclude'] !== 'always' && el.closest(ignoredChildrenSelector) !== null){
|
|
1118
|
+
continue;
|
|
1197
1119
|
}
|
|
1120
|
+
result = Bindings.providePath(result, /** @type {string} */(el.getAttribute('name')), Bindings.extract(el));
|
|
1198
1121
|
}
|
|
1199
|
-
return
|
|
1122
|
+
return result;
|
|
1200
1123
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
class TemplatesRegistry {
|
|
1213
|
-
#idToFragment = {};
|
|
1214
|
-
#idToTemplate = {};
|
|
1215
|
-
#ec;
|
|
1216
|
-
put(k, fragment) {
|
|
1217
|
-
if (this.#ec) {
|
|
1218
|
-
// @ts-ignore
|
|
1219
|
-
this.#idToTemplate[k] = ftl.Template.fromFragment(fragment, this.#ec);
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
*
|
|
1127
|
+
* @param {Element & {checked?: boolean} & {value?: any}} el
|
|
1128
|
+
* @returns
|
|
1129
|
+
*/
|
|
1130
|
+
static mutate(el, raw) {
|
|
1131
|
+
if (el.getAttribute('type') === 'radio') {
|
|
1132
|
+
el.checked = el.getAttribute('value') === raw;
|
|
1220
1133
|
return;
|
|
1221
1134
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
if (!this.#ec) {
|
|
1226
|
-
throw new Error("TemplatesRegistry is not configured");
|
|
1227
|
-
}
|
|
1228
|
-
const tpl = this.#idToTemplate[k];
|
|
1229
|
-
if (!tpl) {
|
|
1230
|
-
throw new Error(`missing template: '${k}'`);
|
|
1231
|
-
}
|
|
1232
|
-
return tpl;
|
|
1233
|
-
}
|
|
1234
|
-
configure(ec, ...data) {
|
|
1235
|
-
this.#ec = ec;
|
|
1236
|
-
for (const [k, fragment] of Object.entries(this.#idToFragment)) {
|
|
1237
|
-
delete this.#idToFragment[k];
|
|
1238
|
-
// @ts-ignore
|
|
1239
|
-
this.#idToTemplate[k] = ftl.Template.fromFragment(fragment, ec, ...data);
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
class ElementsRegistry {
|
|
1246
|
-
#templates;
|
|
1247
|
-
#tagToclass;
|
|
1248
|
-
#configured;
|
|
1249
|
-
#id = 0;
|
|
1250
|
-
constructor() {
|
|
1251
|
-
this.#templates = new TemplatesRegistry();
|
|
1252
|
-
this.#tagToclass = {};
|
|
1253
|
-
}
|
|
1254
|
-
defineTemplate(html) {
|
|
1255
|
-
if (html === null || html === undefined) {
|
|
1256
|
-
return undefined;
|
|
1257
|
-
}
|
|
1258
|
-
const name = `unnamed-${++this.#id}`;
|
|
1259
|
-
this.#templates.put(name, Fragments.fromHtml(html));
|
|
1260
|
-
return name;
|
|
1261
|
-
}
|
|
1262
|
-
define(tag, klass) {
|
|
1263
|
-
if (!this.#configured) {
|
|
1264
|
-
this.#tagToclass[tag] = klass;
|
|
1265
|
-
return this;
|
|
1266
|
-
}
|
|
1267
|
-
customElements.define(tag, klass);
|
|
1268
|
-
return this;
|
|
1269
|
-
}
|
|
1270
|
-
configure(ec, ...data) {
|
|
1271
|
-
this.#templates.configure(ec, ...data);
|
|
1272
|
-
for (const [tag, klass] of Object.entries(this.#tagToclass)) {
|
|
1273
|
-
customElements.define(tag, klass);
|
|
1274
|
-
delete this.#tagToclass[tag];
|
|
1275
|
-
}
|
|
1276
|
-
this.#configured = true;
|
|
1277
|
-
}
|
|
1278
|
-
template(k) {
|
|
1279
|
-
if (k === null || k === undefined) {
|
|
1280
|
-
return undefined;
|
|
1135
|
+
if (el.getAttribute('type') === 'checkbox') {
|
|
1136
|
+
el.checked = raw;
|
|
1137
|
+
return;
|
|
1281
1138
|
}
|
|
1282
|
-
|
|
1139
|
+
el.value = raw;
|
|
1283
1140
|
}
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
const elements = new ElementsRegistry();
|
|
1287
|
-
|
|
1288
1141
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
enqueue(el) {
|
|
1295
|
-
if (!this.#q.length) {
|
|
1296
|
-
requestAnimationFrame(this.dequeue.bind(this));
|
|
1142
|
+
static mutateIn(root, values){
|
|
1143
|
+
for (const [flattenedKey, value] of Object.entries(Bindings.flatten(values, ''))) {
|
|
1144
|
+
for(const el of root.querySelectorAll(`[name='${CSS.escape(flattenedKey)}']`)){
|
|
1145
|
+
Bindings.mutate(el, value);
|
|
1146
|
+
}
|
|
1297
1147
|
}
|
|
1298
|
-
this.#q.push(el);
|
|
1299
1148
|
}
|
|
1300
|
-
dequeue() {
|
|
1301
|
-
this.#q.splice(0).forEach(el => el.upgrade());
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
1149
|
|
|
1305
|
-
const upgradeQueue = new UpgradeQueue();
|
|
1306
1150
|
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
throw new Error(`unsupported attribute type: ${type}`);
|
|
1324
|
-
}
|
|
1325
|
-
return [attr.trim(), type];
|
|
1326
|
-
});
|
|
1327
|
-
|
|
1328
|
-
const attrsAndMappers = attrsAndTypes.map(([attr, type]) => [attr, mappers[type]]);
|
|
1329
|
-
|
|
1330
|
-
const attrToMapper = Object.fromEntries(attrsAndMappers);
|
|
1331
|
-
|
|
1332
|
-
const templateId = elements.defineTemplate(template);
|
|
1333
|
-
|
|
1334
|
-
const k = class extends HTMLElement {
|
|
1335
|
-
static get observedAttributes() {
|
|
1336
|
-
return Object.keys(attrToMapper);
|
|
1337
|
-
}
|
|
1338
|
-
#parsed;
|
|
1339
|
-
#initialized;
|
|
1340
|
-
#reflecting;
|
|
1341
|
-
#internals;
|
|
1342
|
-
constructor() {
|
|
1343
|
-
super();
|
|
1344
|
-
this.#internals = this.attachInternals();
|
|
1345
|
-
}
|
|
1346
|
-
get initialized() {
|
|
1347
|
-
return this.#initialized;
|
|
1348
|
-
}
|
|
1349
|
-
get internals() {
|
|
1350
|
-
return this.#internals;
|
|
1351
|
-
}
|
|
1352
|
-
connectedCallback() {
|
|
1353
|
-
if (this.#parsed) {
|
|
1354
|
-
return;
|
|
1355
|
-
}
|
|
1356
|
-
if (this.ownerDocument.readyState === 'complete' || Nodes.isParsed(this)) {
|
|
1357
|
-
upgradeQueue.enqueue(this);
|
|
1358
|
-
return;
|
|
1359
|
-
}
|
|
1360
|
-
this.ownerDocument.addEventListener('DOMContentLoaded', () => {
|
|
1361
|
-
observer.disconnect();
|
|
1362
|
-
upgradeQueue.enqueue(this);
|
|
1363
|
-
});
|
|
1364
|
-
const observer = new MutationObserver(() => {
|
|
1365
|
-
if (!Nodes.isParsed(this)) {
|
|
1366
|
-
return;
|
|
1367
|
-
}
|
|
1368
|
-
observer.disconnect();
|
|
1369
|
-
upgradeQueue.enqueue(this);
|
|
1151
|
+
static errors(root, es, invalidClass){
|
|
1152
|
+
const fieldErrors = es.filter(e => e.type === 'FIELD_ERROR' || e.type === 'INVALID_FORMAT');
|
|
1153
|
+
const globalErrors = es.filter(e => e.type !== 'FIELD_ERROR' && e.type !== 'INVALID_FORMAT');
|
|
1154
|
+
root.querySelectorAll(`.${CSS.escape(invalidClass)}`).forEach(el => el.classList.remove(invalidClass));
|
|
1155
|
+
root.querySelectorAll("ful-errors").forEach(el => {
|
|
1156
|
+
el.replaceChildren();
|
|
1157
|
+
el.setAttribute('hidden', '');
|
|
1158
|
+
});
|
|
1159
|
+
fieldErrors.forEach(e => {
|
|
1160
|
+
const name = e.context.replace("[", ".").replace("].", ".");
|
|
1161
|
+
const validationTargetsSelector = `[name='${CSS.escape(name)}'] [ful-validation-target],[name='${CSS.escape(name)}']:not(:has([ful-validation-target]))`;
|
|
1162
|
+
root.querySelectorAll(validationTargetsSelector).forEach(input => input.classList.add(invalidClass));
|
|
1163
|
+
const fieldErrorsSelector = `ful-field-error[field='${CSS.escape(name)}']`;
|
|
1164
|
+
root.querySelectorAll(fieldErrorsSelector).forEach(el => {
|
|
1165
|
+
const hel = /** @type HTMLElement} */ (el);
|
|
1166
|
+
hel.innerText = e.reason;
|
|
1370
1167
|
});
|
|
1371
|
-
// @ts-ignore
|
|
1372
|
-
observer.observe(this.parentNode, { childList: true, subtree: true });
|
|
1373
|
-
}
|
|
1374
|
-
attributeChangedCallback(attr, oldValue, newValue) {
|
|
1375
|
-
if (!this.#parsed || oldValue === newValue) {
|
|
1376
|
-
return;
|
|
1377
|
-
}
|
|
1378
|
-
if (this.#reflecting) {
|
|
1379
|
-
return;
|
|
1380
|
-
}
|
|
1381
|
-
const mapper = attrToMapper[attr];
|
|
1382
|
-
this[attr] = mapper(newValue);
|
|
1383
|
-
}
|
|
1384
|
-
reflect(fn) {
|
|
1385
|
-
this.#reflecting = true;
|
|
1386
|
-
try {
|
|
1387
|
-
fn();
|
|
1388
|
-
} finally {
|
|
1389
|
-
this.#reflecting = false;
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
async upgrade() {
|
|
1393
|
-
if (this.#parsed) {
|
|
1394
|
-
return;
|
|
1395
|
-
}
|
|
1396
|
-
this.#parsed = true;
|
|
1397
|
-
// @ts-ignore
|
|
1398
|
-
await this.render(elements.template(templateId), slots ? LightSlots.from(this) : undefined);
|
|
1399
|
-
|
|
1400
|
-
for (const [attr, mapper] of attrsAndMappers) {
|
|
1401
|
-
if (this.hasAttribute(attr)) {
|
|
1402
|
-
this[attr] = mapper(this.getAttribute(attr));
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
this.#initialized = true;
|
|
1406
|
-
}
|
|
1407
|
-
};
|
|
1408
|
-
|
|
1409
|
-
for (const [attr, type] of attrsAndTypes.filter(([a, t]) => t === 'state')) {
|
|
1410
|
-
Object.defineProperty(k.prototype, attr, {
|
|
1411
|
-
enumerable: true,
|
|
1412
|
-
configurable: true,
|
|
1413
|
-
get() {
|
|
1414
|
-
return this.internals.states ? this.internals.states.has(`--${attr}`) : this.hasAttribute(attr);
|
|
1415
|
-
},
|
|
1416
|
-
set(value) {
|
|
1417
|
-
this.internals.states?.[value ? 'add' : 'delete'](`--${attr}`);
|
|
1418
|
-
this.reflect(() => Attributes.toggle(this, attr, value));
|
|
1419
|
-
}
|
|
1420
1168
|
});
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
function flatten(obj, prefix) {
|
|
1427
|
-
return Object.keys(obj).reduce((acc, k) => {
|
|
1428
|
-
const pre = prefix.length ? prefix + '.' : '';
|
|
1429
|
-
if (typeof obj[k] === 'object' && obj[k] !== null) {
|
|
1430
|
-
Object.assign(acc, flatten(obj[k], pre + k));
|
|
1431
|
-
} else {
|
|
1432
|
-
acc[pre + k] = obj[k];
|
|
1433
|
-
}
|
|
1434
|
-
return acc;
|
|
1435
|
-
}, {});
|
|
1436
|
-
}
|
|
1437
|
-
|
|
1438
|
-
function providePath(result, path, value) {
|
|
1439
|
-
const keys = path.split(".").map((k) => k.match(/^[0-9]+$/) ? +k : k);
|
|
1440
|
-
let current = result;
|
|
1441
|
-
let previous = null;
|
|
1442
|
-
for (let i = 0; ; ++i) {
|
|
1443
|
-
const ckey = keys[i];
|
|
1444
|
-
const pkey = keys[i - 1];
|
|
1445
|
-
if (Number.isInteger(ckey) && !Array.isArray(current)) {
|
|
1446
|
-
if (previous !== null) {
|
|
1447
|
-
previous[pkey] = current = [];
|
|
1448
|
-
} else {
|
|
1449
|
-
result = current = [];
|
|
1169
|
+
root.querySelectorAll("ful-errors").forEach(el => {
|
|
1170
|
+
const hel = /** @type HTMLElement} */ (el);
|
|
1171
|
+
hel.innerText = globalErrors.map(e => e.reason).join("\n");
|
|
1172
|
+
if (globalErrors.length !== 0) {
|
|
1173
|
+
el.removeAttribute('hidden');
|
|
1450
1174
|
}
|
|
1451
|
-
}
|
|
1452
|
-
if (i === keys.length - 1) {
|
|
1453
|
-
//when value is undefined we only want to define the property if it's not defined
|
|
1454
|
-
current[ckey] = value !== undefined ? value : (ckey in current ? current[ckey] : null);
|
|
1455
|
-
return result;
|
|
1456
|
-
}
|
|
1457
|
-
if (current[ckey] === undefined) {
|
|
1458
|
-
current[ckey] = {};
|
|
1459
|
-
}
|
|
1460
|
-
previous = current;
|
|
1461
|
-
current = current[ckey];
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1175
|
+
});
|
|
1464
1176
|
|
|
1465
|
-
function extract(el) {
|
|
1466
|
-
if (el.getAttribute('type') === 'radio') {
|
|
1467
|
-
if (!el.checked) {
|
|
1468
|
-
return undefined;
|
|
1469
|
-
}
|
|
1470
|
-
return el.dataset['fulBindType'] === 'boolean' ? el.value === 'true' : el.value;
|
|
1471
|
-
}
|
|
1472
|
-
if (el.getAttribute('type') === 'checkbox') {
|
|
1473
|
-
return el.checked;
|
|
1474
|
-
}
|
|
1475
|
-
if (el.dataset['fulBindType'] === 'boolean') {
|
|
1476
|
-
return !el.value ? null : el.value === 'true';
|
|
1477
|
-
}
|
|
1478
|
-
if (el.tagName === 'INPUT' || el.tagName === 'SELECT'){
|
|
1479
|
-
return el.value === '' || el.value === undefined ? null : el.value;
|
|
1480
|
-
}
|
|
1481
|
-
return el.value;
|
|
1482
|
-
}
|
|
1483
1177
|
|
|
1484
|
-
function mutate(el, raw) {
|
|
1485
|
-
if (el.getAttribute('type') === 'radio') {
|
|
1486
|
-
el.checked = el.getAttribute('value') === raw;
|
|
1487
|
-
return;
|
|
1488
|
-
}
|
|
1489
|
-
if (el.getAttribute('type') === 'checkbox') {
|
|
1490
|
-
el.checked = raw;
|
|
1491
|
-
return;
|
|
1492
1178
|
}
|
|
1493
|
-
el.value = raw;
|
|
1494
1179
|
}
|
|
1495
1180
|
|
|
1496
|
-
class Form extends ParsedElement() {
|
|
1181
|
+
class Form extends ftl.ParsedElement() {
|
|
1497
1182
|
static IGNORED_CHILDREN_SELECTOR = '.d-none, [hidden]';
|
|
1498
1183
|
static SCROLL_OFFSET = 50;
|
|
1499
1184
|
static INVALID_CLASS = 'is-invalid';
|
|
1500
1185
|
submitter;
|
|
1501
1186
|
render() {
|
|
1502
1187
|
const form = document.createElement('form');
|
|
1503
|
-
Attributes.forward('form-', this, form);
|
|
1188
|
+
ftl.Attributes.forward('form-', this, form);
|
|
1504
1189
|
form.replaceChildren(...this.childNodes);
|
|
1505
1190
|
form.addEventListener('submit', async (e) => {
|
|
1506
1191
|
e.preventDefault();
|
|
@@ -1508,12 +1193,12 @@ var ful = (function (exports) {
|
|
|
1508
1193
|
await this.submitter?.(this.values, this);
|
|
1509
1194
|
});
|
|
1510
1195
|
});
|
|
1511
|
-
if(this.hasAttribute("clear-invalid-on-change")){
|
|
1196
|
+
if (this.hasAttribute("clear-invalid-on-change")) {
|
|
1512
1197
|
this.addEventListener('change', evt => {
|
|
1513
1198
|
const target = /** @type HTMLElement */ (evt.target);
|
|
1514
1199
|
target?.querySelectorAll(`.${CSS.escape(Form.INVALID_CLASS)}`).forEach(el => {
|
|
1515
1200
|
el.classList.remove(Form.INVALID_CLASS);
|
|
1516
|
-
});
|
|
1201
|
+
});
|
|
1517
1202
|
});
|
|
1518
1203
|
}
|
|
1519
1204
|
this.replaceChildren(form);
|
|
@@ -1542,7 +1227,7 @@ var ful = (function (exports) {
|
|
|
1542
1227
|
this.spinner(true);
|
|
1543
1228
|
try {
|
|
1544
1229
|
await this.remoting(fn);
|
|
1545
|
-
} catch(e) {
|
|
1230
|
+
} catch (e) {
|
|
1546
1231
|
this.spinner(false);
|
|
1547
1232
|
throw e;
|
|
1548
1233
|
}
|
|
@@ -1556,48 +1241,14 @@ var ful = (function (exports) {
|
|
|
1556
1241
|
}
|
|
1557
1242
|
}
|
|
1558
1243
|
set values(vs) {
|
|
1559
|
-
|
|
1560
|
-
this.querySelectorAll(`[name='${CSS.escape(flattenedKey)}']`).forEach(el => mutate(el, value));
|
|
1561
|
-
}
|
|
1244
|
+
Bindings.mutateIn(this, vs);
|
|
1562
1245
|
}
|
|
1563
1246
|
get values() {
|
|
1564
|
-
return
|
|
1565
|
-
.filter(el => {
|
|
1566
|
-
if (el.dataset['fulBindInclude'] === 'never') {
|
|
1567
|
-
return false;
|
|
1568
|
-
}
|
|
1569
|
-
return el.dataset['fulBindInclude'] === 'always' || el.closest(Form.IGNORED_CHILDREN_SELECTOR) === null;
|
|
1570
|
-
})
|
|
1571
|
-
.reduce((result, el) => {
|
|
1572
|
-
return providePath(result, el.getAttribute('name'), extract(el));
|
|
1573
|
-
}, {});
|
|
1247
|
+
return Bindings.extractFrom(this, Form.IGNORED_CHILDREN_SELECTOR);
|
|
1574
1248
|
}
|
|
1575
1249
|
set errors(es) {
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
this.querySelectorAll(`.${Form.INVALID_CLASS}`).forEach(el => el.classList.remove(Form.INVALID_CLASS));
|
|
1579
|
-
this.querySelectorAll("ful-errors").forEach(el => {
|
|
1580
|
-
el.replaceChildren();
|
|
1581
|
-
el.setAttribute('hidden', '');
|
|
1582
|
-
});
|
|
1583
|
-
fieldErrors.forEach(e => {
|
|
1584
|
-
const name = e.context.replace("[", ".").replace("].", ".");
|
|
1585
|
-
const validationTargetsSelector = `[name='${CSS.escape(name)}'] [ful-validation-target],[name='${CSS.escape(name)}']:not(:has([ful-validation-target]))`;
|
|
1586
|
-
this.querySelectorAll(validationTargetsSelector).forEach(input => input.classList.add(Form.INVALID_CLASS));
|
|
1587
|
-
const fieldErrorsSelector = `ful-field-error[field='${CSS.escape(name)}']`;
|
|
1588
|
-
this.querySelectorAll(fieldErrorsSelector).forEach(el => {
|
|
1589
|
-
const hel = /** @type HTMLElement} */ (el);
|
|
1590
|
-
hel.innerText = e.reason;
|
|
1591
|
-
});
|
|
1592
|
-
});
|
|
1593
|
-
this.querySelectorAll("ful-errors").forEach(el => {
|
|
1594
|
-
const hel = /** @type HTMLElement} */ (el);
|
|
1595
|
-
hel.innerText = globalErrors.map(e => e.reason).join("\n");
|
|
1596
|
-
if (globalErrors.length !== 0) {
|
|
1597
|
-
el.removeAttribute('hidden');
|
|
1598
|
-
}
|
|
1599
|
-
});
|
|
1600
|
-
if (!this.hasAttribute('scroll-on-error')) {
|
|
1250
|
+
Bindings.errors(this, es, Form.INVALID_CLASS);
|
|
1251
|
+
if (es.length == 0 || !this.hasAttribute('scroll-on-error')) {
|
|
1601
1252
|
return;
|
|
1602
1253
|
}
|
|
1603
1254
|
const ys = Array.from(this.querySelectorAll(`ful-errors:not([hidden]), [ful-validated-field]:has(.${Form.INVALID_CLASS}) ful-field-error`))
|
|
@@ -1641,23 +1292,23 @@ var ful = (function (exports) {
|
|
|
1641
1292
|
}
|
|
1642
1293
|
}));
|
|
1643
1294
|
});
|
|
1644
|
-
const id = input.getAttribute('id') ?? el.getAttribute('input-id') ?? Attributes.uid('ful-input');
|
|
1645
|
-
Attributes.forward('input-', el, slots.input);
|
|
1646
|
-
Attributes.defaultValue(slots.input, "id", id);
|
|
1647
|
-
Attributes.defaultValue(slots.input, "type", "text");
|
|
1648
|
-
Attributes.defaultValue(slots.input, "placeholder", " ");
|
|
1295
|
+
const id = input.getAttribute('id') ?? el.getAttribute('input-id') ?? ftl.Attributes.uid('ful-input');
|
|
1296
|
+
ftl.Attributes.forward('input-', el, slots.input);
|
|
1297
|
+
ftl.Attributes.defaultValue(slots.input, "id", id);
|
|
1298
|
+
ftl.Attributes.defaultValue(slots.input, "type", "text");
|
|
1299
|
+
ftl.Attributes.defaultValue(slots.input, "placeholder", " ");
|
|
1649
1300
|
const name = el.getAttribute('name');
|
|
1650
|
-
return template.
|
|
1301
|
+
return template.withOverlay(el, { id, name, slots }).render();
|
|
1651
1302
|
};
|
|
1652
1303
|
|
|
1653
|
-
class Input extends ParsedElement({
|
|
1304
|
+
class Input extends ftl.ParsedElement({
|
|
1654
1305
|
observed: ['value'],
|
|
1655
1306
|
slots: true,
|
|
1656
1307
|
template: INPUT_TEMPLATE
|
|
1657
1308
|
}){
|
|
1658
1309
|
input;
|
|
1659
|
-
render(
|
|
1660
|
-
const fragment = makeInputFragment(this, template, slots);
|
|
1310
|
+
render({slots}) {
|
|
1311
|
+
const fragment = makeInputFragment(this, this.template(), slots);
|
|
1661
1312
|
this.replaceChildren(fragment);
|
|
1662
1313
|
}
|
|
1663
1314
|
get value() {
|
|
@@ -1673,7 +1324,7 @@ var ful = (function (exports) {
|
|
|
1673
1324
|
* <link href="tom-select.bootstrap5.css" rel="stylesheet" />
|
|
1674
1325
|
*/
|
|
1675
1326
|
|
|
1676
|
-
class Select extends ParsedElement({
|
|
1327
|
+
class Select extends ftl.ParsedElement({
|
|
1677
1328
|
observed: ["value"],
|
|
1678
1329
|
slots: true,
|
|
1679
1330
|
template: `
|
|
@@ -1693,11 +1344,12 @@ var ful = (function (exports) {
|
|
|
1693
1344
|
}) {
|
|
1694
1345
|
shouldLoad;
|
|
1695
1346
|
_unwrappedRemoteLoad;
|
|
1347
|
+
ts;
|
|
1696
1348
|
constructor(tsConfig) {
|
|
1697
1349
|
super();
|
|
1698
1350
|
this.tsConfig = tsConfig;
|
|
1699
1351
|
}
|
|
1700
|
-
render(
|
|
1352
|
+
render({slots}) {
|
|
1701
1353
|
const type = this.getAttribute("type") ?? 'local';
|
|
1702
1354
|
const remote = type != 'local';
|
|
1703
1355
|
const loadOnce = this.getAttribute('load') != 'always';
|
|
@@ -1707,15 +1359,15 @@ var ful = (function (exports) {
|
|
|
1707
1359
|
})();
|
|
1708
1360
|
input.setAttribute('ful-validation-target', '');
|
|
1709
1361
|
|
|
1710
|
-
const id = input.getAttribute('id') ?? this.getAttribute('input-id') ?? Attributes.uid('ful-select');
|
|
1362
|
+
const id = input.getAttribute('id') ?? this.getAttribute('input-id') ?? ftl.Attributes.uid('ful-select');
|
|
1711
1363
|
const tsId = `${id}-ts-control`;
|
|
1712
|
-
Attributes.forward('input-', this, input);
|
|
1713
|
-
Attributes.defaultValue(input, "id", id);
|
|
1714
|
-
Attributes.defaultValue(input, "placeholder", " ");
|
|
1364
|
+
ftl.Attributes.forward('input-', this, input);
|
|
1365
|
+
ftl.Attributes.defaultValue(input, "id", id);
|
|
1366
|
+
ftl.Attributes.defaultValue(input, "placeholder", " ");
|
|
1715
1367
|
|
|
1716
1368
|
//tomselect needs the input to have a parent.
|
|
1717
1369
|
//se we move the input to a fragment
|
|
1718
|
-
slots.input = Fragments.from(input);
|
|
1370
|
+
slots.input = ftl.Fragments.from(input);
|
|
1719
1371
|
|
|
1720
1372
|
this.loaded = !remote;
|
|
1721
1373
|
|
|
@@ -1744,7 +1396,6 @@ var ful = (function (exports) {
|
|
|
1744
1396
|
}
|
|
1745
1397
|
callback(data);
|
|
1746
1398
|
};
|
|
1747
|
-
// @ts-ignore
|
|
1748
1399
|
this.ts = new TomSelect(input, Object.assign(remote ? {
|
|
1749
1400
|
preload: 'focus',
|
|
1750
1401
|
load: this._unwrappedRemoteLoad,
|
|
@@ -1764,7 +1415,7 @@ var ful = (function (exports) {
|
|
|
1764
1415
|
evt.stopPropagation();
|
|
1765
1416
|
});
|
|
1766
1417
|
input.remove();
|
|
1767
|
-
template.
|
|
1418
|
+
this.template().withOverlay({ id, tsId, name, input, slots }).renderTo(this);
|
|
1768
1419
|
}
|
|
1769
1420
|
#loader;
|
|
1770
1421
|
set loader(l) {
|
|
@@ -1789,8 +1440,8 @@ var ful = (function (exports) {
|
|
|
1789
1440
|
}
|
|
1790
1441
|
}
|
|
1791
1442
|
|
|
1792
|
-
class RadioGroup extends ParsedElement({
|
|
1793
|
-
observed: ['value', 'disabled:
|
|
1443
|
+
class RadioGroup extends ftl.ParsedElement({
|
|
1444
|
+
observed: ['value', 'disabled:presence'],
|
|
1794
1445
|
slots: true,
|
|
1795
1446
|
template: `
|
|
1796
1447
|
<fieldset ful-validated-field>
|
|
@@ -1815,14 +1466,14 @@ var ful = (function (exports) {
|
|
|
1815
1466
|
</fieldset>
|
|
1816
1467
|
`
|
|
1817
1468
|
}) {
|
|
1818
|
-
render(
|
|
1819
|
-
const name = this.getAttribute('name') ?? Attributes.uid('ful-radiogroup');
|
|
1469
|
+
render({slots}) {
|
|
1470
|
+
const name = this.getAttribute('name') ?? ftl.Attributes.uid('ful-radiogroup');
|
|
1820
1471
|
const radioEls = Array.from(slots.default.querySelectorAll('ful-radio'));
|
|
1821
1472
|
const inputsAndLabels = radioEls.map(el => {
|
|
1822
1473
|
const input = document.createElement('input');
|
|
1823
1474
|
input.setAttribute('type', 'radio');
|
|
1824
|
-
Attributes.forward('input-', this, input);
|
|
1825
|
-
Attributes.forward('', el, input);
|
|
1475
|
+
ftl.Attributes.forward('input-', this, input);
|
|
1476
|
+
ftl.Attributes.forward('', el, input);
|
|
1826
1477
|
input.setAttribute('name', `${name}-ignore`);
|
|
1827
1478
|
input.setAttribute('ful-validation-target', '');
|
|
1828
1479
|
input.dataset['fulBindInclude'] = 'never';
|
|
@@ -1837,13 +1488,19 @@ var ful = (function (exports) {
|
|
|
1837
1488
|
}
|
|
1838
1489
|
}));
|
|
1839
1490
|
});
|
|
1840
|
-
const label = Fragments.fromChildNodes(el);
|
|
1491
|
+
const label = ftl.Fragments.fromChildNodes(el);
|
|
1841
1492
|
return [input, label];
|
|
1842
1493
|
});
|
|
1843
1494
|
|
|
1844
1495
|
radioEls.forEach(el => el.remove());
|
|
1845
|
-
template.
|
|
1496
|
+
this.template().withOverlay({ name, slots, inputsAndLabels }).renderTo(this);
|
|
1497
|
+
}
|
|
1498
|
+
get disabled() {
|
|
1499
|
+
return this.hasAttribute('disabled');
|
|
1846
1500
|
}
|
|
1501
|
+
set disabled(value) {
|
|
1502
|
+
this.reflect(() => ftl.Attributes.toggle(this, 'disabled', value));
|
|
1503
|
+
}
|
|
1847
1504
|
get value() {
|
|
1848
1505
|
/** @type {HTMLInputElement|null} */
|
|
1849
1506
|
const checked = this.querySelector('input[type=radio]:checked');
|
|
@@ -1851,10 +1508,8 @@ var ful = (function (exports) {
|
|
|
1851
1508
|
}
|
|
1852
1509
|
set value(value) {
|
|
1853
1510
|
if (value === null) {
|
|
1854
|
-
/** @type {HTMLInputElement[]} */
|
|
1855
1511
|
this.querySelectorAll(`input[type=radio]`).forEach(el => {
|
|
1856
|
-
|
|
1857
|
-
el.checked = false;
|
|
1512
|
+
(/** @type {HTMLInputElement} */(el)).checked = false;
|
|
1858
1513
|
});
|
|
1859
1514
|
return;
|
|
1860
1515
|
}
|
|
@@ -1866,7 +1521,7 @@ var ful = (function (exports) {
|
|
|
1866
1521
|
}
|
|
1867
1522
|
}
|
|
1868
1523
|
|
|
1869
|
-
class Spinner extends ParsedElement({
|
|
1524
|
+
class Spinner extends ftl.ParsedElement({
|
|
1870
1525
|
slots: true,
|
|
1871
1526
|
template: `
|
|
1872
1527
|
<div class="ful-spinner-wrapper">
|
|
@@ -1875,42 +1530,34 @@ var ful = (function (exports) {
|
|
|
1875
1530
|
</div>
|
|
1876
1531
|
`
|
|
1877
1532
|
}) {
|
|
1878
|
-
render(
|
|
1879
|
-
template.
|
|
1533
|
+
render({slots}) {
|
|
1534
|
+
this.template().withOverlay({ slots }).renderTo(this);
|
|
1880
1535
|
}
|
|
1881
1536
|
}
|
|
1882
1537
|
|
|
1883
|
-
exports.Attributes = Attributes;
|
|
1884
1538
|
exports.AuthorizationCodeFlow = AuthorizationCodeFlow;
|
|
1885
1539
|
exports.AuthorizationCodeFlowInterceptor = AuthorizationCodeFlowInterceptor;
|
|
1886
1540
|
exports.AuthorizationCodeFlowSession = AuthorizationCodeFlowSession;
|
|
1887
1541
|
exports.Base64 = Base64;
|
|
1888
|
-
exports.
|
|
1889
|
-
exports.ElementsRegistry = ElementsRegistry;
|
|
1542
|
+
exports.Bindings = Bindings;
|
|
1890
1543
|
exports.Failure = Failure;
|
|
1891
1544
|
exports.Form = Form;
|
|
1892
|
-
exports.Fragments = Fragments;
|
|
1893
1545
|
exports.Hex = Hex;
|
|
1894
1546
|
exports.HttpClient = HttpClient;
|
|
1895
1547
|
exports.HttpClientError = HttpClientError;
|
|
1896
1548
|
exports.INPUT_TEMPLATE = INPUT_TEMPLATE;
|
|
1897
1549
|
exports.Input = Input;
|
|
1898
|
-
exports.LightSlots = LightSlots;
|
|
1899
1550
|
exports.LocalStorage = LocalStorage;
|
|
1900
1551
|
exports.MediaType = MediaType;
|
|
1901
|
-
exports.Nodes = Nodes;
|
|
1902
|
-
exports.ParsedElement = ParsedElement;
|
|
1903
1552
|
exports.RadioGroup = RadioGroup;
|
|
1904
1553
|
exports.Select = Select;
|
|
1905
1554
|
exports.SessionStorage = SessionStorage;
|
|
1906
1555
|
exports.Spinner = Spinner;
|
|
1907
|
-
exports.TemplatesRegistry = TemplatesRegistry;
|
|
1908
1556
|
exports.VersionedStorage = VersionedStorage;
|
|
1909
|
-
exports.elements = elements;
|
|
1910
1557
|
exports.makeInputFragment = makeInputFragment;
|
|
1911
1558
|
exports.timing = timing;
|
|
1912
1559
|
|
|
1913
1560
|
return exports;
|
|
1914
1561
|
|
|
1915
|
-
})({});
|
|
1562
|
+
})({}, ftl, window?.TomSelect || {});
|
|
1916
1563
|
//# sourceMappingURL=ful.iife.js.map
|