@pageboard/html 0.15.14 → 0.16.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/consent.js +56 -8
- package/elements/embed.js +5 -0
- package/elements/form.js +14 -10
- package/elements/image.js +1 -2
- package/elements/inlines.js +1 -1
- package/elements/inputs.js +90 -4
- package/elements/link.js +6 -2
- package/elements/menu.js +3 -1
- package/elements/page.js +6 -10
- package/package.json +6 -6
- package/ui/consent.css +10 -3
- package/ui/consent.js +47 -55
- package/ui/embed.js +6 -3
- package/ui/form.js +18 -13
- package/ui/inlines.css +3 -0
- package/ui/storage.js +18 -33
- package/lib/formdata.js +0 -21
- package/lib/nouislider.css +0 -304
- package/lib/nouislider.js +0 -2341
- package/lib/object-fit-images.js +0 -243
- package/lib/stickyfill.js +0 -546
package/elements/consent.js
CHANGED
|
@@ -2,7 +2,7 @@ exports.consent_form = {
|
|
|
2
2
|
priority: 11,
|
|
3
3
|
title: 'Consent',
|
|
4
4
|
icon: '<i class="handshake icon"></i>',
|
|
5
|
-
group: "block",
|
|
5
|
+
group: "block form",
|
|
6
6
|
menu: 'form',
|
|
7
7
|
properties: {
|
|
8
8
|
transient: {
|
|
@@ -17,44 +17,92 @@ exports.consent_form = {
|
|
|
17
17
|
nodes: "block+"
|
|
18
18
|
},
|
|
19
19
|
html: `<form is="element-consent" class="ui form" data-transient="[transient]">
|
|
20
|
-
<
|
|
20
|
+
<template block-content="content"></template>
|
|
21
|
+
<div class="view"></div>
|
|
21
22
|
</form>`,
|
|
22
23
|
scripts: ['../ui/storage.js', '../ui/consent.js'],
|
|
23
24
|
stylesheets: ['../ui/consent.css']
|
|
24
25
|
};
|
|
25
26
|
|
|
27
|
+
const consents = [];
|
|
28
|
+
|
|
29
|
+
exports.input_radio_consent = {
|
|
30
|
+
title: 'Consent custom',
|
|
31
|
+
icon: '<i class="hand scissors icon"></i>',
|
|
32
|
+
menu: "form",
|
|
33
|
+
group: "block",
|
|
34
|
+
context: 'consent_form//',
|
|
35
|
+
properties: {
|
|
36
|
+
value: {
|
|
37
|
+
title: 'Consent',
|
|
38
|
+
anyOf: [{
|
|
39
|
+
const: 'custom',
|
|
40
|
+
title: 'Custom'
|
|
41
|
+
}, {
|
|
42
|
+
const: 'yes',
|
|
43
|
+
title: 'All'
|
|
44
|
+
}, {
|
|
45
|
+
const: 'no',
|
|
46
|
+
title: 'None'
|
|
47
|
+
}]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
contents: {
|
|
51
|
+
id: 'label',
|
|
52
|
+
nodes: 'inline*'
|
|
53
|
+
},
|
|
54
|
+
html: `<div class="field">
|
|
55
|
+
<div class="ui radio checkbox">
|
|
56
|
+
<input type="radio" name="consent" value="[value]" id="for-consent-[value]" />
|
|
57
|
+
<label block-content="label" for="for-consent-[value]">Custom</label>
|
|
58
|
+
</div>
|
|
59
|
+
</div>`
|
|
60
|
+
};
|
|
61
|
+
|
|
26
62
|
exports.input_radio_yes = {
|
|
27
|
-
title: '
|
|
63
|
+
title: 'Consent yes',
|
|
28
64
|
icon: '<i class="thumbs up icon"></i>',
|
|
29
65
|
menu: "form",
|
|
30
66
|
group: "block",
|
|
31
67
|
context: 'consent_form//',
|
|
68
|
+
properties: {
|
|
69
|
+
consent: {
|
|
70
|
+
title: 'Consent',
|
|
71
|
+
anyOf: consents
|
|
72
|
+
}
|
|
73
|
+
},
|
|
32
74
|
contents: {
|
|
33
75
|
id: 'label',
|
|
34
76
|
nodes: 'inline*'
|
|
35
77
|
},
|
|
36
78
|
html: `<div class="field">
|
|
37
79
|
<div class="ui radio checkbox">
|
|
38
|
-
<input type="radio" name="consent" value="yes" id="for-consent-yes" />
|
|
39
|
-
<label block-content="label" for="for-consent-yes">Yes</label>
|
|
80
|
+
<input type="radio" name="consent.[consent]" value="yes" id="for-consent-yes-[consent]" />
|
|
81
|
+
<label block-content="label" for="for-consent-yes-[consent]">Yes</label>
|
|
40
82
|
</div>
|
|
41
83
|
</div>`
|
|
42
84
|
};
|
|
43
85
|
|
|
44
86
|
exports.input_radio_no = {
|
|
45
|
-
title: '
|
|
87
|
+
title: 'Consent no',
|
|
46
88
|
icon: '<i class="thumbs down icon"></i>',
|
|
47
89
|
menu: "form",
|
|
48
90
|
group: "block",
|
|
49
91
|
context: 'consent_form//',
|
|
92
|
+
properties: {
|
|
93
|
+
consent: {
|
|
94
|
+
title: 'Consent',
|
|
95
|
+
anyOf: consents
|
|
96
|
+
}
|
|
97
|
+
},
|
|
50
98
|
contents: {
|
|
51
99
|
id: 'label',
|
|
52
100
|
nodes: 'inline*'
|
|
53
101
|
},
|
|
54
102
|
html: `<div class="field">
|
|
55
103
|
<div class="ui radio checkbox">
|
|
56
|
-
<input type="radio" name="consent" value="no" id="for-consent-no" />
|
|
57
|
-
<label block-content="label" for="for-consent-no">No</label>
|
|
104
|
+
<input type="radio" name="consent.[consent]" value="no" id="for-consent-no-[consent]" />
|
|
105
|
+
<label block-content="label" for="for-consent-no-[consent]">No</label>
|
|
58
106
|
</div>
|
|
59
107
|
</div>`
|
|
60
108
|
};
|
package/elements/embed.js
CHANGED
package/elements/form.js
CHANGED
|
@@ -31,15 +31,20 @@ exports.query_form = {
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
redirection: {
|
|
34
|
-
title: 'Target
|
|
34
|
+
title: 'Target',
|
|
35
35
|
type: 'object',
|
|
36
36
|
properties: {
|
|
37
37
|
url: {
|
|
38
|
-
title: '
|
|
38
|
+
title: 'Address',
|
|
39
39
|
nullable: true,
|
|
40
40
|
type: "string",
|
|
41
|
-
format:
|
|
42
|
-
$helper:
|
|
41
|
+
format: 'uri-reference',
|
|
42
|
+
$helper: {
|
|
43
|
+
name: 'href',
|
|
44
|
+
filter: {
|
|
45
|
+
type: ["link", "file", "archive"]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
43
48
|
},
|
|
44
49
|
parameters: {
|
|
45
50
|
title: 'Parameters',
|
|
@@ -89,8 +94,7 @@ exports.api_form = {
|
|
|
89
94
|
title: 'Hidden',
|
|
90
95
|
description: 'Hidden and disabled\nShown by $query.toggle',
|
|
91
96
|
type: 'boolean',
|
|
92
|
-
default: false
|
|
93
|
-
context: 'template'
|
|
97
|
+
default: false
|
|
94
98
|
},
|
|
95
99
|
action: {
|
|
96
100
|
title: 'Action',
|
|
@@ -177,10 +181,10 @@ exports.api_form = {
|
|
|
177
181
|
id="[name|else:$id]"
|
|
178
182
|
action="/@api/form/[$id]"
|
|
179
183
|
parameters="[action?.request|as:expressions]"
|
|
180
|
-
success="[redirection.parameters|as:query]"
|
|
181
|
-
badrequest="[badrequest.parameters|as:query]"
|
|
182
|
-
unauthorized="[unauthorized.parameters|as:query]"
|
|
183
|
-
notfound="[notfound.parameters|as:query]"
|
|
184
|
+
success="[redirection.parameters|as:query|as:null]"
|
|
185
|
+
badrequest="[badrequest.parameters|as:query|as:null]"
|
|
186
|
+
unauthorized="[unauthorized.parameters|as:query|as:null]"
|
|
187
|
+
notfound="[notfound.parameters|as:query|as:null]"
|
|
184
188
|
class="ui form"></form>`,
|
|
185
189
|
stylesheets: [
|
|
186
190
|
'../ui/components/form.css',
|
package/elements/image.js
CHANGED
|
@@ -128,14 +128,13 @@ exports.image = {
|
|
|
128
128
|
}, {
|
|
129
129
|
id: 'alt',
|
|
130
130
|
title: 'Alternative Text',
|
|
131
|
-
$attr: 'data-alt',
|
|
132
131
|
$helper: {
|
|
133
132
|
name: 'describe'
|
|
134
133
|
}
|
|
135
134
|
}],
|
|
136
135
|
html: `<element-image
|
|
137
136
|
class="[display.fit|or:none] [display.horizontal?] [display.vertical?]"
|
|
138
|
-
data-src="[url]"
|
|
137
|
+
data-src="[url]" data-alt="[$content.alt]"
|
|
139
138
|
data-crop="[crop.x|or:50];[crop.y|or:50];[crop.width|or:100];[crop.height|or:100];[crop.zoom|or:100]"
|
|
140
139
|
>
|
|
141
140
|
<div block-content="legend"></div>
|
package/elements/inlines.js
CHANGED
package/elements/inputs.js
CHANGED
|
@@ -13,8 +13,7 @@ exports.input_button = {
|
|
|
13
13
|
title: 'Type',
|
|
14
14
|
default: 'submit',
|
|
15
15
|
anyOf: [{
|
|
16
|
-
|
|
17
|
-
const: 'submit'
|
|
16
|
+
const: 'submit' // deprecated
|
|
18
17
|
}, {
|
|
19
18
|
title: 'Reset',
|
|
20
19
|
const: 'reset'
|
|
@@ -90,6 +89,93 @@ exports.input_button = {
|
|
|
90
89
|
]
|
|
91
90
|
};
|
|
92
91
|
|
|
92
|
+
exports.input_submit = {
|
|
93
|
+
title: 'Submit',
|
|
94
|
+
icon: '<i class="icons"><i class="hand pointer icon"></i><i class="corner write icon"></i></i>',
|
|
95
|
+
menu: "form",
|
|
96
|
+
group: "block input_field",
|
|
97
|
+
context: 'form//',
|
|
98
|
+
contents: {
|
|
99
|
+
nodes: "inline*",
|
|
100
|
+
marks: "nolink"
|
|
101
|
+
},
|
|
102
|
+
properties: {
|
|
103
|
+
action: {
|
|
104
|
+
title: 'Action',
|
|
105
|
+
type: 'string',
|
|
106
|
+
format: 'pathname',
|
|
107
|
+
nullable: true,
|
|
108
|
+
$helper: {
|
|
109
|
+
name: 'datalist',
|
|
110
|
+
url: '/@api/block/search?type=api_form&limit=20&data.name:not&order=data.name',
|
|
111
|
+
value: '/@api/form/[data.name]',
|
|
112
|
+
title: '[$services.[data.action.method|enc:path].title] / [data.name|else:id]'
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
name: {
|
|
116
|
+
title: "Name",
|
|
117
|
+
description: "The form object key",
|
|
118
|
+
type: "string",
|
|
119
|
+
format: "singleline"
|
|
120
|
+
},
|
|
121
|
+
value: {
|
|
122
|
+
title: "Default value",
|
|
123
|
+
nullable: true,
|
|
124
|
+
type: "string",
|
|
125
|
+
format: "singleline"
|
|
126
|
+
},
|
|
127
|
+
form: {
|
|
128
|
+
title: 'Target form',
|
|
129
|
+
type: 'string',
|
|
130
|
+
format: 'name',
|
|
131
|
+
nullable: true,
|
|
132
|
+
$filter: {
|
|
133
|
+
name: 'action',
|
|
134
|
+
action: 'write'
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
disabled: {
|
|
138
|
+
title: 'Disabled',
|
|
139
|
+
type: 'boolean',
|
|
140
|
+
default: false
|
|
141
|
+
},
|
|
142
|
+
full: {
|
|
143
|
+
title: 'Fluid',
|
|
144
|
+
type: 'boolean',
|
|
145
|
+
default: false
|
|
146
|
+
},
|
|
147
|
+
icon: {
|
|
148
|
+
title: 'Icon',
|
|
149
|
+
type: 'boolean',
|
|
150
|
+
default: false
|
|
151
|
+
},
|
|
152
|
+
compact: {
|
|
153
|
+
title: 'Compact',
|
|
154
|
+
type: 'boolean',
|
|
155
|
+
default: false
|
|
156
|
+
},
|
|
157
|
+
float: {
|
|
158
|
+
title: 'Float',
|
|
159
|
+
anyOf: [{
|
|
160
|
+
type: 'null',
|
|
161
|
+
title: 'No'
|
|
162
|
+
}, {
|
|
163
|
+
const: 'left',
|
|
164
|
+
title: 'Left'
|
|
165
|
+
}, {
|
|
166
|
+
const: 'right',
|
|
167
|
+
title: 'Right'
|
|
168
|
+
}],
|
|
169
|
+
default: null
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
html: '<button type="submit" formaction="[action]" form="[form]" disabled="[disabled]" class="ui [full|alt:fluid:] [icon] [compact] [float|post:%20floated] button" name="[name]" value="[value]">Submit</button>',
|
|
173
|
+
stylesheets: [
|
|
174
|
+
'../ui/components/button.css',
|
|
175
|
+
'../ui/button.css'
|
|
176
|
+
]
|
|
177
|
+
};
|
|
178
|
+
|
|
93
179
|
exports.input_fields = {
|
|
94
180
|
title: 'Input Fields',
|
|
95
181
|
icon: '<i class="icon columns"></i>',
|
|
@@ -206,8 +292,8 @@ exports.input_text = {
|
|
|
206
292
|
nodes: 'inline*'
|
|
207
293
|
},
|
|
208
294
|
patterns: {
|
|
209
|
-
tel: /^(\(\d+\))? *\d+([
|
|
210
|
-
email:
|
|
295
|
+
tel: /^(\(\d+\))? *\d+([ .\-]?\d+)*$/v.source,
|
|
296
|
+
email: /[\w.!#$%&'*+\/=?^`\{\|\}~\-]+@\w(?:[\w\-]{0,61}\w)?(?:\.\w(?:[\w\-]{0,61}\w)?)*/v.source
|
|
211
297
|
},
|
|
212
298
|
html: `<div class="[width|as:colnums|post: wide] field [type|if:eq:hidden]">
|
|
213
299
|
<label block-content="label">Label</label>
|
package/elements/link.js
CHANGED
|
@@ -29,7 +29,9 @@ exports.link = {
|
|
|
29
29
|
nullable: true,
|
|
30
30
|
$helper: {
|
|
31
31
|
name: 'datalist',
|
|
32
|
-
url: '/@api/translate/languages'
|
|
32
|
+
url: '/@api/translate/languages',
|
|
33
|
+
value: '[data.lang]',
|
|
34
|
+
title: '[content.]'
|
|
33
35
|
}
|
|
34
36
|
},
|
|
35
37
|
id: {
|
|
@@ -75,7 +77,9 @@ exports.link_button = {
|
|
|
75
77
|
nullable: true,
|
|
76
78
|
$helper: {
|
|
77
79
|
name: 'datalist',
|
|
78
|
-
url: '/@api/translate/languages'
|
|
80
|
+
url: '/@api/translate/languages',
|
|
81
|
+
value: '[data.lang]',
|
|
82
|
+
title: '[content.]'
|
|
79
83
|
}
|
|
80
84
|
},
|
|
81
85
|
full: {
|
package/elements/menu.js
CHANGED
package/elements/page.js
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
exports.page.stylesheets
|
|
2
|
-
...exports.page.stylesheets,
|
|
1
|
+
exports.page.stylesheets.push(
|
|
3
2
|
'../ui/components/reset.css',
|
|
4
3
|
'../ui/site.css',
|
|
5
4
|
'../ui/page.css',
|
|
6
5
|
'../ui/transition.css'
|
|
7
|
-
|
|
6
|
+
);
|
|
8
7
|
|
|
9
|
-
exports.page.resources =
|
|
10
|
-
|
|
11
|
-
site: '../ui/site.css'
|
|
12
|
-
};
|
|
8
|
+
exports.page.resources.reset = '../ui/components/reset.css';
|
|
9
|
+
exports.page.resources.site = '../ui/site.css';
|
|
13
10
|
|
|
14
|
-
exports.page.scripts
|
|
15
|
-
...exports.page.scripts,
|
|
11
|
+
exports.page.scripts.push(
|
|
16
12
|
'../ui/transition.js'
|
|
17
|
-
|
|
13
|
+
);
|
|
18
14
|
|
|
19
15
|
exports.page.properties.transition = {
|
|
20
16
|
title: 'Transition',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pageboard/html",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
"dependencies": {},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"nouislider": "^15.8.1",
|
|
19
|
-
"postinstall": "^0.
|
|
19
|
+
"postinstall": "^0.11.0"
|
|
20
20
|
},
|
|
21
|
-
"postinstall": {
|
|
22
|
-
|
|
23
|
-
"nouislider/dist/nouislider.
|
|
24
|
-
"nouislider/dist/nouislider.css": "copy lib/"
|
|
21
|
+
"postinstall": {
|
|
22
|
+
"nouislider/dist/nouislider.js": "link lib/",
|
|
23
|
+
"nouislider/dist/nouislider.css": "link lib/"
|
|
25
24
|
},
|
|
26
25
|
"pageboard": {
|
|
26
|
+
"version": "^0.16",
|
|
27
27
|
"priority": -10,
|
|
28
28
|
"directories": [
|
|
29
29
|
"elements",
|
package/ui/consent.css
CHANGED
|
@@ -13,9 +13,16 @@ footer [block-type="consent_form"][data-transient="true"] {
|
|
|
13
13
|
[block-type="consent_form"][data-transient="true"]:not(.visible) {
|
|
14
14
|
display:none;
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
|
|
17
|
+
[block-type="consent_form"] > [block-content="content"] {
|
|
18
|
+
display:none;
|
|
19
|
+
}
|
|
20
|
+
[block-type="consent_form"] > .view {
|
|
21
|
+
position:relative;
|
|
22
|
+
}
|
|
23
|
+
[contenteditable] [block-type="consent_form"] > [block-content="content"] {
|
|
24
|
+
display:block;
|
|
25
|
+
min-height:1em;
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
[contenteditable] [block-focused="last"] > .form[block-type="consent_form"][data-transient="true"],
|
package/ui/consent.js
CHANGED
|
@@ -3,51 +3,62 @@ class HTMLElementConsent extends Page.create(HTMLFormElement) {
|
|
|
3
3
|
dataTransient: false
|
|
4
4
|
};
|
|
5
5
|
|
|
6
|
-
static
|
|
7
|
-
|
|
6
|
+
static explicits = new Set();
|
|
7
|
+
|
|
8
|
+
static ask(state, consent) {
|
|
8
9
|
let tacit = true;
|
|
9
|
-
|
|
10
|
+
const forms = document.querySelectorAll('[block-type="consent_form"]');
|
|
11
|
+
const consents = state.scope.storage.all();
|
|
12
|
+
for (const node of forms) {
|
|
13
|
+
window.HTMLElementForm.prototype.fill.call(node, consents);
|
|
10
14
|
node.classList.add('visible');
|
|
11
|
-
tacit = false;
|
|
15
|
+
tacit = consent && !node.querySelector(`[name="${consent}"]`) || false;
|
|
12
16
|
}
|
|
13
|
-
|
|
17
|
+
if (!tacit) this.explicits.add(consent);
|
|
18
|
+
return tacit ? "yes" : null;
|
|
14
19
|
}
|
|
15
20
|
setup(state) {
|
|
16
21
|
if (state.scope.$write) return;
|
|
22
|
+
this.constructor.explicits = new Set();
|
|
23
|
+
const view = this.ownView;
|
|
24
|
+
view.textContent = '';
|
|
25
|
+
const tmpl = this.ownTpl.prerender();
|
|
26
|
+
view.appendChild(tmpl.content.cloneNode(true));
|
|
27
|
+
state.chain('consent', this);
|
|
28
|
+
}
|
|
29
|
+
chainConsent(state) {
|
|
17
30
|
if (this.options.transient) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
31
|
+
this.classList.remove('visible');
|
|
32
|
+
} else {
|
|
33
|
+
window.HTMLElementForm.prototype.fill.call(this, state.scope.storage.all());
|
|
22
34
|
}
|
|
23
|
-
state.consent(this);
|
|
24
35
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
if (this.options.transient) this.classList.remove('visible');
|
|
36
|
+
handleChange(e, state) {
|
|
37
|
+
if (e.type == "submit" || !this.elements.find(item => item.type == "submit")) {
|
|
38
|
+
this.handleSubmit(e, state);
|
|
39
|
+
}
|
|
30
40
|
}
|
|
31
41
|
handleSubmit(e, state) {
|
|
32
42
|
if (e.type == "submit") e.preventDefault();
|
|
33
43
|
if (state.scope.$write) return;
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
44
|
+
const consents = window.HTMLElementForm.prototype.read.call(this);
|
|
45
|
+
const list = Array.from(this.constructor.explicits);
|
|
46
|
+
const def = consents.consent;
|
|
47
|
+
for (const consent of list) {
|
|
48
|
+
if (def != "custom") consents[consent] = def;
|
|
49
|
+
}
|
|
50
|
+
if (list.some(c => consents[c] == null)) {
|
|
51
|
+
// not all explicit consents have been answered
|
|
37
52
|
return;
|
|
38
53
|
}
|
|
39
|
-
|
|
40
|
-
|
|
54
|
+
for (const [key, val] of Object.entries(consents)) {
|
|
55
|
+
state.scope.storage.set(key, val);
|
|
56
|
+
}
|
|
41
57
|
state.copy().runChain('consent');
|
|
42
58
|
}
|
|
43
|
-
handleChange(e, state) {
|
|
44
|
-
this.handleSubmit(e, state);
|
|
45
|
-
}
|
|
46
59
|
patch(state) {
|
|
47
60
|
if (state.scope.$write) return;
|
|
48
|
-
|
|
49
|
-
this.ownTpl.prerender();
|
|
50
|
-
}
|
|
61
|
+
this.ownTpl.prerender();
|
|
51
62
|
}
|
|
52
63
|
get ownTpl() {
|
|
53
64
|
return this.children.find(
|
|
@@ -59,31 +70,17 @@ class HTMLElementConsent extends Page.create(HTMLFormElement) {
|
|
|
59
70
|
}
|
|
60
71
|
}
|
|
61
72
|
|
|
62
|
-
Page.constructor.prototype.consent = function (
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
this.chain('consent', fn);
|
|
68
|
-
if (consent === undefined) {
|
|
69
|
-
HTMLElementConsent.waiting = true;
|
|
70
|
-
} else if (consent === null) {
|
|
71
|
-
// setup finished but no consent is done yet, ask consent
|
|
72
|
-
this.reconsent();
|
|
73
|
+
Page.constructor.prototype.consent = function (listener, ask) {
|
|
74
|
+
const { consent } = listener.constructor;
|
|
75
|
+
if (!consent) {
|
|
76
|
+
console.warn("Expected a static consent field", listener);
|
|
77
|
+
return;
|
|
73
78
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (fn) this.consent(fn);
|
|
78
|
-
const consent = this.scope.$consent;
|
|
79
|
-
let asking = false;
|
|
80
|
-
if (consent != "yes") {
|
|
81
|
-
asking = HTMLElementConsent.ask();
|
|
79
|
+
const cur = this.scope.storage.get(consent);
|
|
80
|
+
if (cur == null || ask) {
|
|
81
|
+
this.scope.storage.set(consent, HTMLElementConsent.ask(this, consent));
|
|
82
82
|
}
|
|
83
|
-
|
|
84
|
-
if (consent == null) this.scope.$consent = "yes";
|
|
85
|
-
}
|
|
86
|
-
return asking;
|
|
83
|
+
this.chain('consent', listener);
|
|
87
84
|
};
|
|
88
85
|
|
|
89
86
|
Page.define(`element-consent`, HTMLElementConsent, 'form');
|
|
@@ -91,12 +88,7 @@ Page.define(`element-consent`, HTMLElementConsent, 'form');
|
|
|
91
88
|
|
|
92
89
|
Page.paint(state => {
|
|
93
90
|
state.finish(() => {
|
|
94
|
-
|
|
95
|
-
if (HTMLElementConsent.waiting) {
|
|
96
|
-
if (state.reconsent()) run = false;
|
|
97
|
-
}
|
|
98
|
-
if (run) {
|
|
99
|
-
// do not change current state stage
|
|
91
|
+
if (!HTMLElementConsent.explicits.size) {
|
|
100
92
|
state.copy().runChain('consent');
|
|
101
93
|
}
|
|
102
94
|
});
|
package/ui/embed.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
class HTMLElementEmbed extends Page.Element {
|
|
2
|
+
static consent = "consent.embed";
|
|
2
3
|
static defaults = {
|
|
3
4
|
src: null,
|
|
4
5
|
query: null,
|
|
@@ -11,7 +12,7 @@ class HTMLElementEmbed extends Page.Element {
|
|
|
11
12
|
state.consent(this);
|
|
12
13
|
}
|
|
13
14
|
get currentSrc() {
|
|
14
|
-
return this.querySelector('iframe')?.src
|
|
15
|
+
return this.querySelector('iframe')?.getAttribute('src');
|
|
15
16
|
}
|
|
16
17
|
patch(state) {
|
|
17
18
|
const { src } = this.options;
|
|
@@ -21,7 +22,7 @@ class HTMLElementEmbed extends Page.Element {
|
|
|
21
22
|
if (width && height) this.style.paddingBottom = `calc(${height} / ${width} * 100%)`;
|
|
22
23
|
}
|
|
23
24
|
consent(state) {
|
|
24
|
-
const consent = state.scope
|
|
25
|
+
const consent = state.scope.storage.get(this.constructor.consent);
|
|
25
26
|
this.classList.toggle('denied', consent == "no");
|
|
26
27
|
this.classList.toggle('waiting', consent == null);
|
|
27
28
|
|
|
@@ -57,7 +58,9 @@ class HTMLElementEmbed extends Page.Element {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
captureClick(e, state) {
|
|
60
|
-
if (this.matches('.denied'))
|
|
61
|
+
if (this.matches('.denied')) {
|
|
62
|
+
state.consent(this, true);
|
|
63
|
+
}
|
|
61
64
|
}
|
|
62
65
|
captureLoad() {
|
|
63
66
|
this.classList.remove('loading');
|
package/ui/form.js
CHANGED
|
@@ -98,16 +98,19 @@ class HTMLElementForm extends Page.create(HTMLFormElement) {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
paint(state) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
101
|
+
if (state.scope.$write) return;
|
|
102
|
+
const name = state.query.submit; // explicit auto-submit
|
|
103
|
+
if (name && name == this.name || this.elements.length == 0 && this.action != state.toString()) {
|
|
104
|
+
if (state.scope.$read) {
|
|
105
|
+
console.info("form#paint would auto-submit:", this.action);
|
|
106
|
+
} else {
|
|
107
|
+
delete state.query.submit;
|
|
108
|
+
state.finish(() => {
|
|
109
|
+
if (state.status != 200) return;
|
|
110
|
+
state.dispatch(this, 'submit');
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
111
114
|
}
|
|
112
115
|
read(withDefaults = false, submitter) {
|
|
113
116
|
const fd = new FormData(this, submitter);
|
|
@@ -322,7 +325,9 @@ class HTMLElementForm extends Page.create(HTMLFormElement) {
|
|
|
322
325
|
form.disable();
|
|
323
326
|
form.classList.add('loading');
|
|
324
327
|
scope.$response = await state.fetch(
|
|
325
|
-
form.method,
|
|
328
|
+
form.method,
|
|
329
|
+
e.submitter?.getAttribute('formaction') || form.action,
|
|
330
|
+
scope.$request
|
|
326
331
|
);
|
|
327
332
|
} catch (err) {
|
|
328
333
|
scope.$response = err;
|
|
@@ -416,8 +421,8 @@ HTMLButtonElement.prototype.fill = HTMLInputElement.prototype.fill = function (v
|
|
|
416
421
|
this.checked = true;
|
|
417
422
|
} else {
|
|
418
423
|
this.checked = (Array.isArray(val) ? val : [val]).some(str => {
|
|
419
|
-
if (str == false && this.value == "") return true;
|
|
420
|
-
return str.toString() == this.value;
|
|
424
|
+
if ((str == false || str == null) && this.value == "") return true;
|
|
425
|
+
return (str ?? '').toString() == this.value;
|
|
421
426
|
});
|
|
422
427
|
}
|
|
423
428
|
} else {
|