@pageboard/html 0.10.15 → 0.11.1
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 +8 -9
- package/elements/fieldsets.js +46 -11
- package/elements/form.js +1 -1
- package/elements/grid.js +4 -3
- package/elements/image.js +4 -2
- package/elements/input-date.js +2 -2
- package/elements/input-property.js +16 -1
- package/elements/inputs.js +6 -5
- package/elements/layout.js +6 -5
- package/elements/media.js +4 -2
- package/elements/menu.js +2 -5
- package/elements/page.js +5 -6
- package/elements/paragraph.js +7 -8
- package/elements/rating.js +1 -1
- 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
|
@@ -18,7 +18,7 @@ exports.cards = {
|
|
|
18
18
|
shape: {
|
|
19
19
|
title: 'Shape',
|
|
20
20
|
anyOf: [{
|
|
21
|
-
|
|
21
|
+
const: null,
|
|
22
22
|
title: 'Default',
|
|
23
23
|
}, {
|
|
24
24
|
const: "square",
|
|
@@ -33,9 +33,8 @@ exports.cards = {
|
|
|
33
33
|
},
|
|
34
34
|
responsive: {
|
|
35
35
|
title: 'Responsive',
|
|
36
|
-
nullable: true,
|
|
37
36
|
anyOf: [{
|
|
38
|
-
title: '
|
|
37
|
+
title: 'No',
|
|
39
38
|
const: null
|
|
40
39
|
}, {
|
|
41
40
|
title: 'Stackable',
|
|
@@ -160,14 +159,14 @@ exports.card_header = {
|
|
|
160
159
|
contents: "inline*",
|
|
161
160
|
html: '<div class="header">Header</div>'
|
|
162
161
|
};
|
|
163
|
-
exports.card_header_nolink =
|
|
162
|
+
exports.card_header_nolink = { ...exports.card_header,
|
|
164
163
|
context: 'cardlink//',
|
|
165
164
|
contents: {
|
|
166
165
|
nodes: "inline*",
|
|
167
166
|
marks: "nolink"
|
|
168
167
|
},
|
|
169
168
|
html: '<div class="header">Header</div>'
|
|
170
|
-
}
|
|
169
|
+
};
|
|
171
170
|
|
|
172
171
|
exports.card_meta = {
|
|
173
172
|
title: 'meta',
|
|
@@ -178,14 +177,14 @@ exports.card_meta = {
|
|
|
178
177
|
contents: "inline*",
|
|
179
178
|
html: '<div class="meta">Meta</div>'
|
|
180
179
|
};
|
|
181
|
-
exports.card_meta_nolink =
|
|
180
|
+
exports.card_meta_nolink = { ...exports.card_meta,
|
|
182
181
|
context: 'cardlink//',
|
|
183
182
|
contents: {
|
|
184
183
|
nodes: "inline*",
|
|
185
184
|
marks: "nolink"
|
|
186
185
|
},
|
|
187
186
|
html: '<div class="meta">Meta</div>'
|
|
188
|
-
}
|
|
187
|
+
};
|
|
189
188
|
|
|
190
189
|
exports.card_description = {
|
|
191
190
|
title: 'description',
|
|
@@ -196,9 +195,9 @@ exports.card_description = {
|
|
|
196
195
|
contents: "paragraph+",
|
|
197
196
|
html: '<div class="description"></div>'
|
|
198
197
|
};
|
|
199
|
-
exports.card_description_nolink =
|
|
198
|
+
exports.card_description_nolink = { ...exports.card_description,
|
|
200
199
|
context: 'cardlink//',
|
|
201
200
|
contents: "paragraph_nolink+",
|
|
202
201
|
html: '<div class="description"></div>'
|
|
203
|
-
}
|
|
202
|
+
};
|
|
204
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/form.js
CHANGED
package/elements/grid.js
CHANGED
|
@@ -17,8 +17,10 @@ exports.grid = {
|
|
|
17
17
|
},
|
|
18
18
|
responsive: {
|
|
19
19
|
title: 'Responsive',
|
|
20
|
-
nullable: true,
|
|
21
20
|
anyOf: [{
|
|
21
|
+
title: 'No',
|
|
22
|
+
const: null
|
|
23
|
+
}, {
|
|
22
24
|
title: 'Stackable',
|
|
23
25
|
const: 'stackable'
|
|
24
26
|
}, {
|
|
@@ -67,9 +69,8 @@ exports.grid_row = {
|
|
|
67
69
|
properties: {
|
|
68
70
|
responsive: {
|
|
69
71
|
title: 'Responsive',
|
|
70
|
-
nullable: true,
|
|
71
72
|
anyOf: [{
|
|
72
|
-
title: '
|
|
73
|
+
title: 'No',
|
|
73
74
|
const: null
|
|
74
75
|
}, {
|
|
75
76
|
title: 'Stackable',
|
package/elements/image.js
CHANGED
|
@@ -12,8 +12,9 @@ exports.image = {
|
|
|
12
12
|
url: {
|
|
13
13
|
title: 'Address',
|
|
14
14
|
description: 'Local or remote URL',
|
|
15
|
-
nullable: true,
|
|
16
15
|
anyOf: [{
|
|
16
|
+
type: "null"
|
|
17
|
+
}, {
|
|
17
18
|
type: "string",
|
|
18
19
|
format: "uri"
|
|
19
20
|
}, {
|
|
@@ -156,8 +157,9 @@ exports.inlineImage = {
|
|
|
156
157
|
url: {
|
|
157
158
|
title: 'Address',
|
|
158
159
|
description: 'Local or remote URL',
|
|
159
|
-
nullable: true,
|
|
160
160
|
anyOf: [{
|
|
161
|
+
type: "null"
|
|
162
|
+
}, {
|
|
161
163
|
type: "string",
|
|
162
164
|
format: "uri"
|
|
163
165
|
}, {
|
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,31 @@ 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 => {
|
|
69
|
+
if (obj.properties && obj.properties[discKey] && obj.properties[discKey].const == propKey) {
|
|
70
|
+
return true;
|
|
71
|
+
} else {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
} else {
|
|
76
|
+
prop = cases[propKey];
|
|
77
|
+
}
|
|
67
78
|
name = list.slice(0, i - 1).concat(list.slice(i + 1)).join('.');
|
|
68
79
|
cases = null;
|
|
80
|
+
discKey = null;
|
|
69
81
|
} else {
|
|
70
82
|
if (prop.select && prop.select.$data == `0/${propKey}`) {
|
|
71
83
|
cases = prop.selectCases;
|
|
84
|
+
} else if (prop.discriminator && prop.discriminator.propertyName == propKey) {
|
|
85
|
+
cases = prop.oneOf;
|
|
86
|
+
discKey = propKey;
|
|
72
87
|
}
|
|
73
88
|
prop = (prop.items && prop.items.properties || prop.properties || {})[propKey] || null;
|
|
74
89
|
}
|
package/elements/inputs.js
CHANGED
|
@@ -156,8 +156,8 @@ exports.input_text = {
|
|
|
156
156
|
nodes: 'inline*'
|
|
157
157
|
},
|
|
158
158
|
patterns: {
|
|
159
|
-
tel:
|
|
160
|
-
email:
|
|
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/layout.js
CHANGED
|
@@ -106,8 +106,9 @@ exports.layout = {
|
|
|
106
106
|
image: {
|
|
107
107
|
title: 'Image',
|
|
108
108
|
description: 'Local or remote URL',
|
|
109
|
-
nullable: true,
|
|
110
109
|
anyOf: [{
|
|
110
|
+
type: "null"
|
|
111
|
+
}, {
|
|
111
112
|
type: "string",
|
|
112
113
|
format: "uri"
|
|
113
114
|
}, {
|
|
@@ -168,7 +169,7 @@ exports.layout = {
|
|
|
168
169
|
size: {
|
|
169
170
|
title: 'Size',
|
|
170
171
|
anyOf: [{
|
|
171
|
-
|
|
172
|
+
const: null,
|
|
172
173
|
title: 'Auto'
|
|
173
174
|
}, {
|
|
174
175
|
const: 'cover',
|
|
@@ -181,7 +182,7 @@ exports.layout = {
|
|
|
181
182
|
position: {
|
|
182
183
|
title: 'Position',
|
|
183
184
|
anyOf: [{
|
|
184
|
-
|
|
185
|
+
const: null,
|
|
185
186
|
title: 'Top Left'
|
|
186
187
|
}, {
|
|
187
188
|
const: 'top center',
|
|
@@ -212,7 +213,7 @@ exports.layout = {
|
|
|
212
213
|
repeat: {
|
|
213
214
|
title: 'Repeat',
|
|
214
215
|
anyOf: [{
|
|
215
|
-
|
|
216
|
+
const: null,
|
|
216
217
|
title: 'Repeat'
|
|
217
218
|
}, {
|
|
218
219
|
const: 'no-repeat',
|
|
@@ -234,7 +235,7 @@ exports.layout = {
|
|
|
234
235
|
attachment: {
|
|
235
236
|
title: 'Attachment',
|
|
236
237
|
anyOf: [{
|
|
237
|
-
|
|
238
|
+
const: null,
|
|
238
239
|
title: 'Local'
|
|
239
240
|
}, {
|
|
240
241
|
const: 'scroll',
|
package/elements/media.js
CHANGED
|
@@ -8,8 +8,9 @@ exports.video = {
|
|
|
8
8
|
url: {
|
|
9
9
|
title: 'Address',
|
|
10
10
|
description: 'Local or remote URL',
|
|
11
|
-
nullable: true,
|
|
12
11
|
anyOf: [{
|
|
12
|
+
type: "null"
|
|
13
|
+
}, {
|
|
13
14
|
type: "string",
|
|
14
15
|
format: "uri"
|
|
15
16
|
}, {
|
|
@@ -88,8 +89,9 @@ exports.audio = {
|
|
|
88
89
|
url: {
|
|
89
90
|
title: 'Address',
|
|
90
91
|
description: 'Local or remote URL',
|
|
91
|
-
nullable: true,
|
|
92
92
|
anyOf: [{
|
|
93
|
+
type: "null"
|
|
94
|
+
}, {
|
|
93
95
|
type: "string",
|
|
94
96
|
format: "uri"
|
|
95
97
|
}, {
|
package/elements/menu.js
CHANGED
|
@@ -9,7 +9,6 @@ exports.menu = {
|
|
|
9
9
|
properties: {
|
|
10
10
|
direction: {
|
|
11
11
|
title: 'Direction',
|
|
12
|
-
nullable: true,
|
|
13
12
|
anyOf: [{
|
|
14
13
|
const: null,
|
|
15
14
|
title: "Horizontal"
|
|
@@ -37,7 +36,6 @@ exports.menu_group = {
|
|
|
37
36
|
properties: {
|
|
38
37
|
position: {
|
|
39
38
|
title: 'Position',
|
|
40
|
-
nullable: true,
|
|
41
39
|
anyOf: [{
|
|
42
40
|
const: null,
|
|
43
41
|
title: "Left"
|
|
@@ -104,14 +102,14 @@ exports.menu_item_link = {
|
|
|
104
102
|
html: '<a class="[labeled|?] item" href="[url|autolink]">Link</a>'
|
|
105
103
|
};
|
|
106
104
|
|
|
107
|
-
exports.menu_item_block =
|
|
105
|
+
exports.menu_item_block = { ...exports.menu_item_link,
|
|
108
106
|
title: 'Block',
|
|
109
107
|
priority: 11,
|
|
110
108
|
contents: {
|
|
111
109
|
nodes: "block+",
|
|
112
110
|
marks: "nolink"
|
|
113
111
|
}
|
|
114
|
-
}
|
|
112
|
+
};
|
|
115
113
|
|
|
116
114
|
exports.menu_item_text = {
|
|
117
115
|
priority: 11,
|
|
@@ -153,7 +151,6 @@ exports.menu_item_dropdown = {
|
|
|
153
151
|
properties: {
|
|
154
152
|
position: {
|
|
155
153
|
title: 'Position',
|
|
156
|
-
nullable: true,
|
|
157
154
|
anyOf: [{
|
|
158
155
|
const: null,
|
|
159
156
|
title: "Left"
|
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',
|
|
@@ -16,9 +17,8 @@ exports.page.properties.transition = {
|
|
|
16
17
|
properties: {
|
|
17
18
|
close: {
|
|
18
19
|
title: 'Close',
|
|
19
|
-
nullable: true,
|
|
20
20
|
anyOf: [{
|
|
21
|
-
|
|
21
|
+
const: null,
|
|
22
22
|
title: 'None'
|
|
23
23
|
}, {
|
|
24
24
|
const: 'tr-up',
|
|
@@ -39,9 +39,8 @@ exports.page.properties.transition = {
|
|
|
39
39
|
},
|
|
40
40
|
open: {
|
|
41
41
|
title: 'Open',
|
|
42
|
-
nullable: true,
|
|
43
42
|
anyOf: [{
|
|
44
|
-
|
|
43
|
+
const: null,
|
|
45
44
|
title: 'None'
|
|
46
45
|
}, {
|
|
47
46
|
const: 'tr-up',
|
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",
|
|
@@ -128,7 +128,7 @@ exports.heading = {
|
|
|
128
128
|
id: {
|
|
129
129
|
nullable: true,
|
|
130
130
|
type: 'string',
|
|
131
|
-
pattern:
|
|
131
|
+
pattern: /^[a-z0-9-]*$/.source
|
|
132
132
|
}
|
|
133
133
|
},
|
|
134
134
|
contents: {
|
|
@@ -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/rating.js
CHANGED
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;
|