@pageboard/html 0.10.16 → 0.11.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/elements/card.js +6 -6
- package/elements/fieldsets.js +46 -11
- package/elements/input-date.js +2 -2
- package/elements/input-property.js +10 -1
- package/elements/inputs.js +6 -5
- package/elements/menu.js +2 -2
- package/elements/page.js +3 -2
- package/elements/paragraph.js +6 -7
- package/elements/sitemap.js +5 -4
- package/package.json +1 -1
- package/ui/fieldset-list.js +160 -61
- package/ui/fieldset.js +2 -2
- package/ui/form.js +28 -34
- package/ui/pagination.js +3 -2
- package/ui/tab.js +1 -1
package/elements/card.js
CHANGED
|
@@ -159,14 +159,14 @@ exports.card_header = {
|
|
|
159
159
|
contents: "inline*",
|
|
160
160
|
html: '<div class="header">Header</div>'
|
|
161
161
|
};
|
|
162
|
-
exports.card_header_nolink =
|
|
162
|
+
exports.card_header_nolink = { ...exports.card_header,
|
|
163
163
|
context: 'cardlink//',
|
|
164
164
|
contents: {
|
|
165
165
|
nodes: "inline*",
|
|
166
166
|
marks: "nolink"
|
|
167
167
|
},
|
|
168
168
|
html: '<div class="header">Header</div>'
|
|
169
|
-
}
|
|
169
|
+
};
|
|
170
170
|
|
|
171
171
|
exports.card_meta = {
|
|
172
172
|
title: 'meta',
|
|
@@ -177,14 +177,14 @@ exports.card_meta = {
|
|
|
177
177
|
contents: "inline*",
|
|
178
178
|
html: '<div class="meta">Meta</div>'
|
|
179
179
|
};
|
|
180
|
-
exports.card_meta_nolink =
|
|
180
|
+
exports.card_meta_nolink = { ...exports.card_meta,
|
|
181
181
|
context: 'cardlink//',
|
|
182
182
|
contents: {
|
|
183
183
|
nodes: "inline*",
|
|
184
184
|
marks: "nolink"
|
|
185
185
|
},
|
|
186
186
|
html: '<div class="meta">Meta</div>'
|
|
187
|
-
}
|
|
187
|
+
};
|
|
188
188
|
|
|
189
189
|
exports.card_description = {
|
|
190
190
|
title: 'description',
|
|
@@ -195,9 +195,9 @@ exports.card_description = {
|
|
|
195
195
|
contents: "paragraph+",
|
|
196
196
|
html: '<div class="description"></div>'
|
|
197
197
|
};
|
|
198
|
-
exports.card_description_nolink =
|
|
198
|
+
exports.card_description_nolink = { ...exports.card_description,
|
|
199
199
|
context: 'cardlink//',
|
|
200
200
|
contents: "paragraph_nolink+",
|
|
201
201
|
html: '<div class="description"></div>'
|
|
202
|
-
}
|
|
202
|
+
};
|
|
203
203
|
|
package/elements/fieldsets.js
CHANGED
|
@@ -42,10 +42,10 @@ exports.fieldset_legend = {
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
exports.fieldset_list = {
|
|
45
|
-
title: '
|
|
45
|
+
title: 'Field List',
|
|
46
46
|
menu: "form",
|
|
47
47
|
icon: '<i class="icons"><i class="folder outline icon"></i><i class="corner add icon"></i></i>',
|
|
48
|
-
group:
|
|
48
|
+
group: 'block template',
|
|
49
49
|
context: 'form//',
|
|
50
50
|
priority: 0,
|
|
51
51
|
properties: {
|
|
@@ -54,23 +54,58 @@ exports.fieldset_list = {
|
|
|
54
54
|
type: "integer",
|
|
55
55
|
minimum: 0,
|
|
56
56
|
default: 1
|
|
57
|
-
},
|
|
58
|
-
prefix: {
|
|
59
|
-
title: 'Prefix',
|
|
60
|
-
description: '',
|
|
61
|
-
type: "string",
|
|
62
|
-
format: 'singleline',
|
|
63
|
-
nullable: true
|
|
64
57
|
}
|
|
65
58
|
},
|
|
66
59
|
contents: [{
|
|
67
60
|
id: 'template',
|
|
68
|
-
nodes: 'block+'
|
|
61
|
+
nodes: 'block+',
|
|
62
|
+
expressions: true
|
|
69
63
|
}],
|
|
70
|
-
html: `<element-fieldset-list data-size="[size]"
|
|
64
|
+
html: `<element-fieldset-list data-size="[size]">
|
|
71
65
|
<template block-content="template"></template>
|
|
72
66
|
<div class="view"></div>
|
|
73
67
|
</element-fieldset-list>`,
|
|
74
68
|
scripts: ['../ui/fieldset-list.js'],
|
|
75
69
|
stylesheets: ['../ui/fieldset-list.css']
|
|
76
70
|
};
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
exports.fieldlist_button = {
|
|
74
|
+
title: 'Field List Button',
|
|
75
|
+
menu: "form",
|
|
76
|
+
icon: '<i class="icons"><i class="folder outline icon"></i><i class="corner hand pointer icon"></i></i>',
|
|
77
|
+
group: 'block',
|
|
78
|
+
context: 'fieldset_list//',
|
|
79
|
+
properties: {
|
|
80
|
+
type: {
|
|
81
|
+
title: 'Type',
|
|
82
|
+
default: 'add',
|
|
83
|
+
anyOf: [{
|
|
84
|
+
title: 'Add',
|
|
85
|
+
const: 'add'
|
|
86
|
+
}, {
|
|
87
|
+
title: 'Delete',
|
|
88
|
+
const: 'del'
|
|
89
|
+
}, {
|
|
90
|
+
title: 'Up',
|
|
91
|
+
const: 'up'
|
|
92
|
+
}, {
|
|
93
|
+
title: 'Down',
|
|
94
|
+
const: 'down'
|
|
95
|
+
}]
|
|
96
|
+
},
|
|
97
|
+
full: {
|
|
98
|
+
title: 'Full width',
|
|
99
|
+
type: 'boolean',
|
|
100
|
+
default: false
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
contents: {
|
|
104
|
+
nodes: "inline*",
|
|
105
|
+
marks: "nolink"
|
|
106
|
+
},
|
|
107
|
+
html: '<button type="button" class="ui [full|?:fluid:] button" value="[type]">Label</button>',
|
|
108
|
+
stylesheets: [
|
|
109
|
+
'../lib/components/button.css',
|
|
110
|
+
]
|
|
111
|
+
};
|
package/elements/input-date.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
exports.input_date_time = {
|
|
2
|
-
title: '
|
|
2
|
+
title: 'Date Time',
|
|
3
3
|
icon: '<i class="calendar outline icon"></i>',
|
|
4
4
|
menu: "form",
|
|
5
5
|
required: ["name"],
|
|
@@ -89,7 +89,7 @@ exports.input_date_time = {
|
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
exports.input_date_slot = {
|
|
92
|
-
title: '
|
|
92
|
+
title: 'Date Slot',
|
|
93
93
|
icon: '<i class="calendar outline icon"></i>',
|
|
94
94
|
menu: "form",
|
|
95
95
|
required: ["nameStart", "nameEnd"],
|
|
@@ -59,16 +59,25 @@ exports.input_property = {
|
|
|
59
59
|
let propKey;
|
|
60
60
|
let required = false;
|
|
61
61
|
let cases = null;
|
|
62
|
+
let discKey = null;
|
|
62
63
|
for (let i = 0; i < list.length; i++) {
|
|
63
64
|
propKey = list[i];
|
|
64
65
|
required = prop.required && prop.required.indexOf(propKey) >= 0;
|
|
65
66
|
if (cases) {
|
|
66
|
-
|
|
67
|
+
if (Array.isArray(cases)) {
|
|
68
|
+
prop = cases.find(obj => obj.properties?.[discKey]?.const == propKey);
|
|
69
|
+
} else {
|
|
70
|
+
prop = cases[propKey];
|
|
71
|
+
}
|
|
67
72
|
name = list.slice(0, i - 1).concat(list.slice(i + 1)).join('.');
|
|
68
73
|
cases = null;
|
|
74
|
+
discKey = null;
|
|
69
75
|
} else {
|
|
70
76
|
if (prop.select && prop.select.$data == `0/${propKey}`) {
|
|
71
77
|
cases = prop.selectCases;
|
|
78
|
+
} else if (prop.discriminator && prop.discriminator.propertyName == propKey) {
|
|
79
|
+
cases = prop.oneOf;
|
|
80
|
+
discKey = propKey;
|
|
72
81
|
}
|
|
73
82
|
prop = (prop.items && prop.items.properties || prop.properties || {})[propKey] || null;
|
|
74
83
|
}
|
package/elements/inputs.js
CHANGED
|
@@ -156,8 +156,8 @@ exports.input_text = {
|
|
|
156
156
|
nodes: 'inline*'
|
|
157
157
|
},
|
|
158
158
|
patterns: {
|
|
159
|
-
tel: /^(\(\d+\))? *\d+([
|
|
160
|
-
email: /^[\w.!#$%&'
|
|
159
|
+
tel: /^(\(\d+\))? *\d+([ .-]?\d+)*$/.source,
|
|
160
|
+
email: /^[\w.!#$%&'*+/=?^`{|}~-]+@\w(?:[\w-]{0,61}\w)?(?:\.\w(?:[\w-]{0,61}\w)?)*$/.source
|
|
161
161
|
},
|
|
162
162
|
html: `<div class="[width|num: wide] field [type|eq:hidden:hidden:]">
|
|
163
163
|
<label block-content="label">Label</label>
|
|
@@ -233,7 +233,7 @@ exports.input_range = {
|
|
|
233
233
|
menu: "form",
|
|
234
234
|
group: "block",
|
|
235
235
|
context: 'form//',
|
|
236
|
-
properties:
|
|
236
|
+
properties: {
|
|
237
237
|
multiple: {
|
|
238
238
|
title: 'Multiple',
|
|
239
239
|
type: 'boolean',
|
|
@@ -243,8 +243,9 @@ exports.input_range = {
|
|
|
243
243
|
title: 'Pips',
|
|
244
244
|
type: 'boolean',
|
|
245
245
|
default: true
|
|
246
|
-
}
|
|
247
|
-
|
|
246
|
+
},
|
|
247
|
+
...exports.input_number.properties
|
|
248
|
+
},
|
|
248
249
|
contents: {
|
|
249
250
|
id: 'label',
|
|
250
251
|
nodes: 'inline*'
|
package/elements/menu.js
CHANGED
|
@@ -102,14 +102,14 @@ exports.menu_item_link = {
|
|
|
102
102
|
html: '<a class="[labeled|?] item" href="[url|autolink]">Link</a>'
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
-
exports.menu_item_block =
|
|
105
|
+
exports.menu_item_block = { ...exports.menu_item_link,
|
|
106
106
|
title: 'Block',
|
|
107
107
|
priority: 11,
|
|
108
108
|
contents: {
|
|
109
109
|
nodes: "block+",
|
|
110
110
|
marks: "nolink"
|
|
111
111
|
}
|
|
112
|
-
}
|
|
112
|
+
};
|
|
113
113
|
|
|
114
114
|
exports.menu_item_text = {
|
|
115
115
|
priority: 11,
|
package/elements/page.js
CHANGED
|
@@ -5,9 +5,10 @@ exports.page.stylesheets = [
|
|
|
5
5
|
'../ui/transition.css'
|
|
6
6
|
];
|
|
7
7
|
|
|
8
|
-
exports.page.scripts =
|
|
8
|
+
exports.page.scripts = [
|
|
9
|
+
...exports.page.scripts,
|
|
9
10
|
'../ui/transition.js'
|
|
10
|
-
]
|
|
11
|
+
];
|
|
11
12
|
|
|
12
13
|
exports.page.properties.transition = {
|
|
13
14
|
title: 'Transition',
|
package/elements/paragraph.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
exports.paragraph_nolink =
|
|
1
|
+
exports.paragraph_nolink = { ...exports.paragraph,
|
|
2
2
|
priority: exports.paragraph.priority - 1,
|
|
3
3
|
group: null,
|
|
4
4
|
contents: {
|
|
5
5
|
nodes: "inline*",
|
|
6
6
|
marks: "nolink"
|
|
7
7
|
}
|
|
8
|
-
}
|
|
8
|
+
};
|
|
9
9
|
|
|
10
10
|
exports.segment = {
|
|
11
11
|
title: "Segment",
|
|
@@ -159,13 +159,12 @@ exports.heading = {
|
|
|
159
159
|
};
|
|
160
160
|
|
|
161
161
|
|
|
162
|
-
exports.heading_nolink =
|
|
162
|
+
exports.heading_nolink = {
|
|
163
|
+
...exports.heading,
|
|
163
164
|
priority: exports.heading.priority - 1,
|
|
164
165
|
group: null,
|
|
165
|
-
contents:
|
|
166
|
-
|
|
167
|
-
})
|
|
168
|
-
});
|
|
166
|
+
contents: { ...exports.heading.contents, marks: "nolink" }
|
|
167
|
+
};
|
|
169
168
|
|
|
170
169
|
exports.divider = {
|
|
171
170
|
title: "Divider",
|
package/elements/sitemap.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
exports.sitemap = {
|
|
2
|
-
title: "
|
|
2
|
+
title: "Sitemap",
|
|
3
3
|
group: "block",
|
|
4
4
|
icon: '<i class="sitemap icon"></i>',
|
|
5
5
|
menu: 'link',
|
|
@@ -30,12 +30,13 @@ exports.sitemap = {
|
|
|
30
30
|
title: schema.title,
|
|
31
31
|
icon: schema.icon,
|
|
32
32
|
standalone: true,
|
|
33
|
-
properties:
|
|
33
|
+
properties: {
|
|
34
34
|
leaf: {
|
|
35
35
|
type: 'boolean',
|
|
36
36
|
default: Boolean(leaf)
|
|
37
|
-
}
|
|
38
|
-
|
|
37
|
+
},
|
|
38
|
+
...schema.properties
|
|
39
|
+
},
|
|
39
40
|
menu: "link",
|
|
40
41
|
group: 'sitemap_item',
|
|
41
42
|
virtual: true,
|
package/package.json
CHANGED
package/ui/fieldset-list.js
CHANGED
|
@@ -1,62 +1,145 @@
|
|
|
1
|
+
class WalkIndex {
|
|
2
|
+
#walk;
|
|
3
|
+
#find;
|
|
4
|
+
#index;
|
|
5
|
+
constructor(root, fn) {
|
|
6
|
+
this.#find = fn;
|
|
7
|
+
this.#walk = root.ownerDocument.createTreeWalker(
|
|
8
|
+
root,
|
|
9
|
+
NodeFilter.SHOW_ELEMENT,
|
|
10
|
+
this
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
acceptNode(node) {
|
|
14
|
+
const index = this.#find(node);
|
|
15
|
+
if (index != null) {
|
|
16
|
+
this.#index = index;
|
|
17
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
18
|
+
} else {
|
|
19
|
+
return NodeFilter.FILTER_SKIP;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
findBefore(node) {
|
|
23
|
+
this.#index = null;
|
|
24
|
+
this.#walk.currentNode = node;
|
|
25
|
+
this.#walk.previousNode();
|
|
26
|
+
return this.#index;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
1
30
|
class HTMLElementFieldsetList extends VirtualHTMLElement {
|
|
31
|
+
#size;
|
|
32
|
+
#prefix;
|
|
33
|
+
#model;
|
|
34
|
+
#walk;
|
|
35
|
+
|
|
2
36
|
fill(values, scope) {
|
|
3
|
-
const list = this
|
|
4
|
-
this
|
|
37
|
+
const list = this.#listFromValues({ ...values });
|
|
38
|
+
this.#resize(list.length, scope);
|
|
5
39
|
}
|
|
6
40
|
|
|
7
|
-
|
|
41
|
+
#prepare() {
|
|
8
42
|
this.ownTpl.prerender();
|
|
9
43
|
if (this.isContentEditable) return;
|
|
10
|
-
|
|
44
|
+
for (const node of this.ownTpl.content.querySelectorAll('[block-id]')) {
|
|
45
|
+
node.removeAttribute('block-id');
|
|
46
|
+
}
|
|
47
|
+
const keys = new Set();
|
|
48
|
+
const inputs = this.ownTpl.content.querySelectorAll('[name]');
|
|
49
|
+
for (const node of inputs) {
|
|
50
|
+
keys.add(node.name);
|
|
51
|
+
}
|
|
52
|
+
const splits = Array.from(keys).map(name => name.split('.'));
|
|
53
|
+
const coms = [];
|
|
54
|
+
let pos = 0, com = null;
|
|
55
|
+
while (splits.every(list => {
|
|
56
|
+
if (com == null) {
|
|
57
|
+
if (pos < list.length) {
|
|
58
|
+
com = list[pos];
|
|
59
|
+
return true;
|
|
60
|
+
} else {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
return list[pos] == com;
|
|
65
|
+
}
|
|
66
|
+
})) {
|
|
67
|
+
coms.push(com);
|
|
68
|
+
com = null;
|
|
69
|
+
pos++;
|
|
70
|
+
}
|
|
71
|
+
if (coms.length) coms.push('');
|
|
72
|
+
const prefix = coms.join('.');
|
|
73
|
+
this.#prefix = prefix;
|
|
74
|
+
const model = {};
|
|
75
|
+
for (const key of keys) {
|
|
76
|
+
if (key.startsWith(prefix)) model[key.substring(prefix.length)] = null;
|
|
77
|
+
}
|
|
78
|
+
this.#model = model;
|
|
11
79
|
}
|
|
12
80
|
|
|
13
|
-
|
|
14
|
-
this
|
|
81
|
+
patch(state) {
|
|
82
|
+
this.#prepare();
|
|
83
|
+
if (!this.#size) this.#resize(0, state.scope);
|
|
15
84
|
}
|
|
16
85
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.size = len;
|
|
86
|
+
setup() {
|
|
87
|
+
this.#prepare();
|
|
88
|
+
}
|
|
21
89
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
const anc = tpl.querySelectorAll('[name]:not(button)').ancestor();
|
|
90
|
+
#selector(name) {
|
|
91
|
+
return `[block-type="fieldlist_button"][value="${name}"]`;
|
|
92
|
+
}
|
|
27
93
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
94
|
+
#resize(size, scope) {
|
|
95
|
+
if (this.isContentEditable) return;
|
|
96
|
+
const len = Math.max(Number(this.dataset.size) || 0, size);
|
|
97
|
+
if (this.#size === len) return;
|
|
98
|
+
this.#size = len;
|
|
99
|
+
let tpl = this.ownTpl.content.cloneNode(true);
|
|
100
|
+
const $fieldset = Array.from(Array(len)).map((x, i) => {
|
|
101
|
+
return { index: i };
|
|
102
|
+
});
|
|
103
|
+
const inputs = tpl.querySelectorAll('[name]');
|
|
104
|
+
const prefix = this.#prefix;
|
|
105
|
+
for (const node of inputs) {
|
|
106
|
+
if (node.name.startsWith(prefix)) {
|
|
107
|
+
node.name = `${prefix}[$field.index].${node.name.substring(prefix.length)}`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const subtpl = inputs.ancestor();
|
|
111
|
+
if (!subtpl) {
|
|
112
|
+
console.warn("fieldset-list should contain input[name]", this);
|
|
113
|
+
return;
|
|
32
114
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
115
|
+
subtpl.appendChild(
|
|
116
|
+
subtpl.ownerDocument.createTextNode('[$fieldset|repeat:*:$field|]')
|
|
117
|
+
);
|
|
118
|
+
if (len == 0) {
|
|
119
|
+
let node = tpl.querySelector(this.#selector('add'));
|
|
120
|
+
while (node != null && node != tpl && node != subtpl) {
|
|
121
|
+
while (node.nextSibling) node.nextSibling.remove();
|
|
122
|
+
while (node.previousSibling) node.previousSibling.remove();
|
|
123
|
+
node = node.parentNode;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
tpl = tpl.fuse({ $fieldset }, scope);
|
|
127
|
+
|
|
36
128
|
const view = this.ownView;
|
|
37
129
|
view.textContent = '';
|
|
38
130
|
view.appendChild(tpl);
|
|
39
|
-
}
|
|
40
131
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
132
|
+
view.querySelectorAll(this.#selector('up')).forEach((node, i) => {
|
|
133
|
+
node.disabled = i == 0;
|
|
134
|
+
});
|
|
135
|
+
view.querySelectorAll(this.#selector('down')).forEach((node, i, arr) => {
|
|
136
|
+
node.disabled = i == arr.length - 1;
|
|
137
|
+
});
|
|
47
138
|
}
|
|
48
139
|
|
|
49
|
-
|
|
50
|
-
const obj = {};
|
|
51
|
-
for (const node of this.ownTpl.content.querySelectorAll('[name]:not(button)')) {
|
|
52
|
-
obj[node.name] = null;
|
|
53
|
-
}
|
|
54
|
-
return obj;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
listFromValues(values) {
|
|
140
|
+
#listFromValues(values) {
|
|
58
141
|
const list = [];
|
|
59
|
-
const prefix = this
|
|
142
|
+
const prefix = this.#prefix;
|
|
60
143
|
// just unflatten the array
|
|
61
144
|
for (const [key, val] of Object.entries(values)) {
|
|
62
145
|
if (!key.startsWith(prefix)) continue;
|
|
@@ -71,8 +154,8 @@ class HTMLElementFieldsetList extends VirtualHTMLElement {
|
|
|
71
154
|
return list;
|
|
72
155
|
}
|
|
73
156
|
|
|
74
|
-
listToValues(values, list) {
|
|
75
|
-
const prefix = this
|
|
157
|
+
#listToValues(values, list) {
|
|
158
|
+
const prefix = this.#prefix;
|
|
76
159
|
for (let i = 0; i < list.length; i++) {
|
|
77
160
|
const obj = list[i];
|
|
78
161
|
for (const [key, val] of Object.entries(obj)) {
|
|
@@ -83,23 +166,47 @@ class HTMLElementFieldsetList extends VirtualHTMLElement {
|
|
|
83
166
|
|
|
84
167
|
handleClick(e, state) {
|
|
85
168
|
if (this.isContentEditable) return;
|
|
86
|
-
const btn = e.target.closest('button
|
|
169
|
+
const btn = e.target.closest('button');
|
|
87
170
|
if (!btn) return;
|
|
88
|
-
|
|
171
|
+
const action = btn.value;
|
|
172
|
+
if (["add", "del", "up", "down"].includes(action) == false) return;
|
|
89
173
|
|
|
90
174
|
const form = this.closest('form');
|
|
91
175
|
const values = form.read(true);
|
|
92
|
-
const list = this
|
|
93
|
-
const
|
|
94
|
-
if (!
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
176
|
+
const list = this.#listFromValues(values);
|
|
177
|
+
const prefix = this.#prefix;
|
|
178
|
+
if (!this.#walk) this.#walk = new WalkIndex(this, (node) => {
|
|
179
|
+
if (node.name?.startsWith(prefix)) {
|
|
180
|
+
const index = Number(node.name.substring(prefix.length).split('.').shift());
|
|
181
|
+
if (Number.isInteger(index) || index >= 0 || index < list.length) {
|
|
182
|
+
return index;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
});
|
|
187
|
+
let index;
|
|
188
|
+
|
|
189
|
+
switch (action) {
|
|
190
|
+
case "add":
|
|
191
|
+
list.splice((this.#walk.findBefore(btn) ?? -1) + 1, 0, this.#model);
|
|
192
|
+
break;
|
|
193
|
+
case "del":
|
|
194
|
+
list.splice(this.#walk.findBefore(btn) ?? 0, 1);
|
|
195
|
+
break;
|
|
196
|
+
case "up":
|
|
197
|
+
index = this.querySelectorAll(this.#selector('up')).indexOf(btn);
|
|
198
|
+
if (index > 0) {
|
|
199
|
+
list.splice(index - 1, 0, list.splice(index, 1).pop());
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
202
|
+
case "down":
|
|
203
|
+
index = this.querySelectorAll(this.#selector('down')).indexOf(btn);
|
|
204
|
+
if (index < list.length - 1) {
|
|
205
|
+
list.splice(index + 1, 0, list.splice(index, 1).pop());
|
|
206
|
+
}
|
|
207
|
+
break;
|
|
101
208
|
}
|
|
102
|
-
this
|
|
209
|
+
this.#listToValues(values, list);
|
|
103
210
|
form.fill(values, state.scope);
|
|
104
211
|
}
|
|
105
212
|
|
|
@@ -111,14 +218,6 @@ class HTMLElementFieldsetList extends VirtualHTMLElement {
|
|
|
111
218
|
get ownView() {
|
|
112
219
|
return this.children.find(node => node.matches('.view'));
|
|
113
220
|
}
|
|
114
|
-
get prefix() {
|
|
115
|
-
const prefix = this.dataset.prefix;
|
|
116
|
-
if (prefix) return prefix + ".";
|
|
117
|
-
else return "";
|
|
118
|
-
}
|
|
119
221
|
}
|
|
120
222
|
|
|
121
223
|
VirtualHTMLElement.define('element-fieldset-list', HTMLElementFieldsetList);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
package/ui/fieldset.js
CHANGED
|
@@ -15,8 +15,8 @@ class HTMLCustomFieldSetElement extends HTMLFieldSetElement {
|
|
|
15
15
|
this.disabled = this.hidden = val != this.options.value;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
patch() {
|
|
19
|
-
this.#update();
|
|
18
|
+
patch(state) {
|
|
19
|
+
state.finish(() => this.#update());
|
|
20
20
|
}
|
|
21
21
|
setup() {
|
|
22
22
|
this.form?.addEventListener('change', this);
|
package/ui/form.js
CHANGED
|
@@ -108,18 +108,15 @@ class HTMLCustomFormElement extends HTMLFormElement {
|
|
|
108
108
|
return query;
|
|
109
109
|
}
|
|
110
110
|
fill(query, scope) {
|
|
111
|
-
//
|
|
112
|
-
const
|
|
113
|
-
const FieldSet = VirtualHTMLElement.define(tagList);
|
|
114
|
-
for (const node of this.querySelectorAll(tagList)) {
|
|
115
|
-
if (!node.fill) Object.setPrototypeOf(node, FieldSet.prototype);
|
|
111
|
+
// fieldset-list are not custom inputs yet
|
|
112
|
+
for (const node of this.querySelectorAll("element-fieldset-list")) {
|
|
116
113
|
node.fill(query, scope);
|
|
117
114
|
}
|
|
118
115
|
const vars = [];
|
|
119
116
|
for (const elem of this.elements) {
|
|
120
117
|
const name = elem.name;
|
|
121
118
|
if (!name) continue;
|
|
122
|
-
if (
|
|
119
|
+
if (name in query && !vars.includes(name)) vars.push(name);
|
|
123
120
|
const val = query[name];
|
|
124
121
|
const str = ((v) => {
|
|
125
122
|
if (v == null) return "";
|
|
@@ -228,7 +225,7 @@ class HTMLCustomFormElement extends HTMLFormElement {
|
|
|
228
225
|
const loc = Page.parse(redirect);
|
|
229
226
|
Object.assign(loc.query, this.read(false));
|
|
230
227
|
if (loc.samePathname(state)) {
|
|
231
|
-
loc.query =
|
|
228
|
+
loc.query = { ...state.query, ...loc.query };
|
|
232
229
|
}
|
|
233
230
|
let status = 200;
|
|
234
231
|
const p = this.ignoreInputChange
|
|
@@ -430,7 +427,7 @@ Page.setup((state) => {
|
|
|
430
427
|
}
|
|
431
428
|
});
|
|
432
429
|
|
|
433
|
-
Page.
|
|
430
|
+
Page.patch(state => {
|
|
434
431
|
const filters = state.scope.$filters;
|
|
435
432
|
|
|
436
433
|
function linearizeValues(query, obj = {}, prefix) {
|
|
@@ -461,35 +458,32 @@ Page.ready((state) => {
|
|
|
461
458
|
if (action == "toggle") {
|
|
462
459
|
action = val ? "enable" : "disable";
|
|
463
460
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
if (
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
461
|
+
|
|
462
|
+
state.finish(() => {
|
|
463
|
+
if (action == "enable") {
|
|
464
|
+
form.enable();
|
|
465
|
+
} else if (action == "disable") {
|
|
466
|
+
form.disable();
|
|
467
|
+
} else if (action == "fill") {
|
|
468
|
+
if (val == null) {
|
|
469
|
+
form.reset();
|
|
470
|
+
} else if (typeof val == "object") {
|
|
471
|
+
let values = val;
|
|
472
|
+
if (val.id && val.data) {
|
|
473
|
+
// old way
|
|
474
|
+
values = { ...val.data };
|
|
475
|
+
for (const key of Object.keys(val)) {
|
|
476
|
+
if (key != "data") values['$' + key] = val[key];
|
|
477
|
+
}
|
|
478
|
+
} else {
|
|
479
|
+
// new way
|
|
479
480
|
}
|
|
480
|
-
|
|
481
|
-
|
|
481
|
+
form.fill(linearizeValues(values), state.scope);
|
|
482
|
+
form.save();
|
|
482
483
|
}
|
|
483
|
-
HTMLCustomFormElement.prototype.fill.call(form, linearizeValues(values), state.scope);
|
|
484
|
-
HTMLCustomFormElement.prototype.save.call(form);
|
|
485
484
|
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
for (const [key, kval] of Object.entries(val)) {
|
|
489
|
-
if (form.querySelector(`[name="${key}"]`)) obj[key] = kval;
|
|
490
|
-
}
|
|
491
|
-
return obj;
|
|
492
|
-
}
|
|
485
|
+
});
|
|
486
|
+
|
|
493
487
|
return val;
|
|
494
488
|
};
|
|
495
489
|
});
|
package/ui/pagination.js
CHANGED
|
@@ -27,9 +27,10 @@ class HTMLElementPagination extends HTMLAnchorElement {
|
|
|
27
27
|
} else {
|
|
28
28
|
this.setAttribute('href', Page.format({
|
|
29
29
|
pathname: state.pathname,
|
|
30
|
-
query:
|
|
30
|
+
query: {
|
|
31
|
+
...state.query,
|
|
31
32
|
[name]: cur || undefined
|
|
32
|
-
}
|
|
33
|
+
}
|
|
33
34
|
}));
|
|
34
35
|
}
|
|
35
36
|
state.finish(() => {
|
package/ui/tab.js
CHANGED
|
@@ -14,7 +14,7 @@ class HTMLElementTabs extends VirtualHTMLElement {
|
|
|
14
14
|
const id = this.id;
|
|
15
15
|
|
|
16
16
|
this.items.children.forEach((item, i) => {
|
|
17
|
-
const query =
|
|
17
|
+
const query = { ...state.query };
|
|
18
18
|
const key = `${id}.index`;
|
|
19
19
|
if (i == 0) delete query[key];
|
|
20
20
|
else query[key] = i;
|