@schukai/monster 4.148.2 → 4.148.3
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/package.json +1 -1
- package/source/components/datatable/filter/date-presets.mjs +13 -0
- package/source/components/datatable/filter/date-range.mjs +12 -0
- package/source/components/datatable/filter/date-time.mjs +14 -1
- package/source/components/datatable/filter/date.mjs +14 -1
- package/source/components/datatable/filter/input.mjs +14 -1
- package/source/components/datatable/filter/range.mjs +11 -0
- package/source/components/datatable/filter/text-operator.mjs +19 -0
- package/source/components/datatable/filter/time.mjs +14 -1
- package/source/components/form/buy-box.mjs +2 -0
- package/source/components/form/cart-control.mjs +2 -0
- package/source/components/state/state.mjs +2 -0
- package/source/data/extend.mjs +7 -1
- package/source/dom/customcontrol.mjs +28 -23
- package/source/dom/customelement.mjs +105 -39
- package/source/dom/util/extract-keys.mjs +2 -1
- package/source/dom/util/init-options-from-attributes.mjs +1 -1
- package/source/dom/util/set-option-from-attribute.mjs +14 -3
- package/test/cases/components/datatable/filter-form-value.mjs +98 -0
- package/test/cases/components/form/non-value-form-association.mjs +53 -0
- package/test/cases/data/extend.mjs +27 -1
- package/test/cases/dom/customcontrol.mjs +188 -6
- package/test/cases/dom/customelement-initfromscripthost.mjs +62 -0
- package/test/cases/dom/customelement.mjs +123 -2
- package/test/cases/dom/util/extract-keys.mjs +14 -0
- package/test/cases/dom/util/init-options-from-attributes.mjs +18 -0
- package/test/cases/dom/util/set-option-from-attribute.mjs +151 -0
|
@@ -280,6 +280,25 @@ describe('DOM', function () {
|
|
|
280
280
|
expect(monster.getOption('demotest')).is.eql(1425);
|
|
281
281
|
|
|
282
282
|
});
|
|
283
|
+
|
|
284
|
+
it('should not pollute Object.prototype through data-monster-options issue #499', function () {
|
|
285
|
+
delete Object.prototype.monsterCustomElementPolluted;
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
const element = document.createElement('monster-testclass2');
|
|
289
|
+
element.setAttribute(
|
|
290
|
+
'data-monster-options',
|
|
291
|
+
'{"__proto__":{"monsterCustomElementPolluted":"yes"},"demotest":42}',
|
|
292
|
+
);
|
|
293
|
+
document.getElementById('test1').appendChild(element);
|
|
294
|
+
|
|
295
|
+
expect(Object.prototype.monsterCustomElementPolluted).to.equal(undefined);
|
|
296
|
+
expect(({}).monsterCustomElementPolluted).to.equal(undefined);
|
|
297
|
+
expect(element.getOption('demotest')).to.equal(42);
|
|
298
|
+
} finally {
|
|
299
|
+
delete Object.prototype.monsterCustomElementPolluted;
|
|
300
|
+
}
|
|
301
|
+
});
|
|
283
302
|
});
|
|
284
303
|
|
|
285
304
|
describe('create', function () {
|
|
@@ -402,6 +421,50 @@ describe('DOM', function () {
|
|
|
402
421
|
}
|
|
403
422
|
}, 10);
|
|
404
423
|
});
|
|
424
|
+
|
|
425
|
+
it('should keep runtime option attributes typed and reversible issue #504', async function () {
|
|
426
|
+
const htmlTAG = 'monster-testclass-runtime-options';
|
|
427
|
+
|
|
428
|
+
class RuntimeOptionsComponent extends CustomElement {
|
|
429
|
+
static getTag() {
|
|
430
|
+
return htmlTAG;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
get defaults() {
|
|
434
|
+
return Object.assign({}, super.defaults, {
|
|
435
|
+
shadowMode: false,
|
|
436
|
+
count: 1,
|
|
437
|
+
config: {
|
|
438
|
+
enabled: true,
|
|
439
|
+
},
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
registerCustomElement(RuntimeOptionsComponent);
|
|
445
|
+
const element = document.createElement(htmlTAG);
|
|
446
|
+
document.getElementById('test1').appendChild(element);
|
|
447
|
+
|
|
448
|
+
element.setOption('count', null);
|
|
449
|
+
element.setAttribute('data-monster-option-count', '5');
|
|
450
|
+
element.setOption('config', null);
|
|
451
|
+
element.setAttribute(
|
|
452
|
+
'data-monster-option-config',
|
|
453
|
+
'{"enabled":false}',
|
|
454
|
+
);
|
|
455
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
456
|
+
|
|
457
|
+
expect(element.getOption('count')).to.equal(5);
|
|
458
|
+
expect(typeof element.getOption('count')).to.equal('number');
|
|
459
|
+
expect(element.getOption('config')).to.deep.equal({ enabled: false });
|
|
460
|
+
|
|
461
|
+
element.removeAttribute('data-monster-option-count');
|
|
462
|
+
element.removeAttribute('data-monster-option-config');
|
|
463
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
464
|
+
|
|
465
|
+
expect(element.getOption('count')).to.equal(1);
|
|
466
|
+
expect(element.getOption('config')).to.deep.equal({ enabled: true });
|
|
467
|
+
});
|
|
405
468
|
});
|
|
406
469
|
|
|
407
470
|
describe('Options change', function () {
|
|
@@ -796,7 +859,7 @@ describe('DOM', function () {
|
|
|
796
859
|
|
|
797
860
|
})
|
|
798
861
|
|
|
799
|
-
|
|
862
|
+
describe('mutation observer lifecycle', function () {
|
|
800
863
|
it('should not rerun linked updaters after disconnect', function (done) {
|
|
801
864
|
let mocks = document.getElementById('mocks');
|
|
802
865
|
mocks.innerHTML = `<monster-testclass-mutation id="mutation-case"></monster-testclass-mutation>`;
|
|
@@ -843,7 +906,65 @@ describe('DOM', function () {
|
|
|
843
906
|
done(e);
|
|
844
907
|
}
|
|
845
908
|
}, 20);
|
|
846
|
-
|
|
909
|
+
})
|
|
910
|
+
|
|
911
|
+
describe('dynamic disabled synchronization issue #505', function () {
|
|
912
|
+
it('should synchronize late controls and preserve child-owned disabled state', async function () {
|
|
913
|
+
const htmlTAG = 'monster-testclass-dynamic-disabled';
|
|
914
|
+
|
|
915
|
+
class DynamicDisabledComponent extends CustomElement {
|
|
916
|
+
static getTag() {
|
|
917
|
+
return htmlTAG;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
get defaults() {
|
|
921
|
+
return Object.assign({}, super.defaults, {
|
|
922
|
+
templates: {
|
|
923
|
+
main: '<input id="initial"><slot></slot>',
|
|
924
|
+
},
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
registerCustomElement(DynamicDisabledComponent);
|
|
930
|
+
const element = document.createElement(htmlTAG);
|
|
931
|
+
const childOwned = document.createElement('input');
|
|
932
|
+
childOwned.setAttribute('disabled', '');
|
|
933
|
+
element.appendChild(childOwned);
|
|
934
|
+
document.getElementById('test1').appendChild(element);
|
|
935
|
+
|
|
936
|
+
const initial = element.shadowRoot.querySelector('#initial');
|
|
937
|
+
element.setOption('disabled', true);
|
|
938
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
939
|
+
expect(initial.disabled).to.equal(true);
|
|
940
|
+
expect(childOwned.disabled).to.equal(true);
|
|
941
|
+
|
|
942
|
+
const lateSlotted = document.createElement('input');
|
|
943
|
+
element.appendChild(lateSlotted);
|
|
944
|
+
const lateShadow = document.createElement('input');
|
|
945
|
+
element.shadowRoot.appendChild(lateShadow);
|
|
946
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
947
|
+
|
|
948
|
+
expect(lateSlotted.disabled).to.equal(true);
|
|
949
|
+
expect(lateShadow.disabled).to.equal(true);
|
|
950
|
+
|
|
951
|
+
lateSlotted.remove();
|
|
952
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
953
|
+
expect(lateSlotted.disabled).to.equal(false);
|
|
954
|
+
|
|
955
|
+
element.appendChild(lateSlotted);
|
|
956
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
957
|
+
expect(lateSlotted.disabled).to.equal(true);
|
|
958
|
+
|
|
959
|
+
element.setOption('disabled', false);
|
|
960
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
961
|
+
|
|
962
|
+
expect(initial.disabled).to.equal(false);
|
|
963
|
+
expect(lateSlotted.disabled).to.equal(false);
|
|
964
|
+
expect(lateShadow.disabled).to.equal(false);
|
|
965
|
+
expect(childOwned.disabled).to.equal(true);
|
|
966
|
+
});
|
|
967
|
+
});
|
|
847
968
|
})
|
|
848
969
|
|
|
849
970
|
});
|
|
@@ -19,6 +19,7 @@ describe('extractKeys', () => {
|
|
|
19
19
|
expect(result.get('first-name')).to.equal('firstName');
|
|
20
20
|
expect(result.get('lastname')).to.equal('lastName');
|
|
21
21
|
expect(result.get('last-name')).to.equal('lastName');
|
|
22
|
+
expect(result.get('address')).to.equal('address');
|
|
22
23
|
expect(result.get('address-street')).to.equal('address.street');
|
|
23
24
|
expect(result.get('address-city')).to.equal('address.city');
|
|
24
25
|
});
|
|
@@ -67,9 +68,22 @@ describe('extractKeys', () => {
|
|
|
67
68
|
|
|
68
69
|
const result = extractKeys(obj);
|
|
69
70
|
|
|
71
|
+
expect(result.get('popper')).to.equal('popper');
|
|
70
72
|
expect(result.get('popper-contentoverflow')).to.equal('popper.contentOverflow');
|
|
71
73
|
expect(result.get('popper-content-overflow')).to.equal('popper.contentOverflow');
|
|
74
|
+
expect(result.get('message-width')).to.equal('message.width');
|
|
72
75
|
expect(result.get('message-width-viewportratio')).to.equal('message.width.viewportRatio');
|
|
73
76
|
expect(result.get('message-width-viewport-ratio')).to.equal('message.width.viewportRatio');
|
|
74
77
|
});
|
|
78
|
+
|
|
79
|
+
it('should ignore inherited option keys issue #504', () => {
|
|
80
|
+
const obj = Object.assign(Object.create({ inherited: true }), {
|
|
81
|
+
own: true,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const result = extractKeys(obj);
|
|
85
|
+
|
|
86
|
+
expect(result.get('own')).to.equal('own');
|
|
87
|
+
expect(result.has('inherited')).to.equal(false);
|
|
88
|
+
});
|
|
75
89
|
});
|
|
@@ -199,4 +199,22 @@ describe('initOptionsFromAttributes', () => {
|
|
|
199
199
|
expect(result.popper.contentOverflow).to.equal('visible');
|
|
200
200
|
});
|
|
201
201
|
|
|
202
|
+
[
|
|
203
|
+
Object.assign(Object.create(null), {
|
|
204
|
+
url: (value) => `https://${value}.example`,
|
|
205
|
+
}),
|
|
206
|
+
{
|
|
207
|
+
hasOwnProperty: true,
|
|
208
|
+
url: (value) => `https://${value}.example`,
|
|
209
|
+
},
|
|
210
|
+
].forEach((mapping) => {
|
|
211
|
+
it('should support mappings without a callable hasOwnProperty issue #504', () => {
|
|
212
|
+
element.setAttribute('data-monster-option-url', 'monster');
|
|
213
|
+
|
|
214
|
+
const result = initOptionsFromAttributes(element, options, mapping);
|
|
215
|
+
|
|
216
|
+
expect(result.url).to.equal('https://monster.example');
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
202
220
|
});
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
import { initJSDOM } from '../../../util/jsdom.mjs';
|
|
5
|
+
|
|
6
|
+
describe('setOptionFromAttribute issue #504', function () {
|
|
7
|
+
let element;
|
|
8
|
+
let setOptionFromAttribute;
|
|
9
|
+
|
|
10
|
+
before(async function () {
|
|
11
|
+
await initJSDOM();
|
|
12
|
+
({ setOptionFromAttribute } = await import('../../../../source/dom/util/set-option-from-attribute.mjs'));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
beforeEach(function () {
|
|
16
|
+
element = document.createElement('div');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should use the default schema when the current number is null', function () {
|
|
20
|
+
const options = { count: null };
|
|
21
|
+
const defaults = { count: 1 };
|
|
22
|
+
element.setAttribute('data-monster-option-count', '5');
|
|
23
|
+
|
|
24
|
+
setOptionFromAttribute(
|
|
25
|
+
element,
|
|
26
|
+
'data-monster-option-count',
|
|
27
|
+
options,
|
|
28
|
+
{},
|
|
29
|
+
'data-monster-option-',
|
|
30
|
+
defaults,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(options.count).to.equal(5);
|
|
34
|
+
expect(typeof options.count).to.equal('number');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should use the default schema when the current object is null', function () {
|
|
38
|
+
const options = { config: null };
|
|
39
|
+
const defaults = { config: { enabled: true } };
|
|
40
|
+
element.setAttribute('data-monster-option-config', '{"enabled":false}');
|
|
41
|
+
|
|
42
|
+
setOptionFromAttribute(
|
|
43
|
+
element,
|
|
44
|
+
'data-monster-option-config',
|
|
45
|
+
options,
|
|
46
|
+
{},
|
|
47
|
+
'data-monster-option-',
|
|
48
|
+
defaults,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
expect(options.config).to.deep.equal({ enabled: false });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should restore the default when the attribute is removed', function () {
|
|
55
|
+
const options = { count: 5 };
|
|
56
|
+
const defaults = { count: 1 };
|
|
57
|
+
|
|
58
|
+
setOptionFromAttribute(
|
|
59
|
+
element,
|
|
60
|
+
'data-monster-option-count',
|
|
61
|
+
options,
|
|
62
|
+
{},
|
|
63
|
+
'data-monster-option-',
|
|
64
|
+
defaults,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(options.count).to.equal(1);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should preserve all declared default types and nested kebab-case paths', function () {
|
|
71
|
+
const options = {
|
|
72
|
+
enabled: null,
|
|
73
|
+
label: null,
|
|
74
|
+
tags: null,
|
|
75
|
+
popper: {
|
|
76
|
+
contentOverflow: null,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
const defaults = {
|
|
80
|
+
enabled: false,
|
|
81
|
+
label: '',
|
|
82
|
+
tags: [],
|
|
83
|
+
popper: {
|
|
84
|
+
contentOverflow: 'both',
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
const attributes = {
|
|
88
|
+
'data-monster-option-enabled': 'true',
|
|
89
|
+
'data-monster-option-label': 'monster',
|
|
90
|
+
'data-monster-option-tags': 'one::two',
|
|
91
|
+
'data-monster-option-popper-content-overflow': 'horizontal',
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
for (const [name, value] of Object.entries(attributes)) {
|
|
95
|
+
element.setAttribute(name, value);
|
|
96
|
+
setOptionFromAttribute(
|
|
97
|
+
element,
|
|
98
|
+
name,
|
|
99
|
+
options,
|
|
100
|
+
{},
|
|
101
|
+
'data-monster-option-',
|
|
102
|
+
defaults,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
expect(options).to.deep.equal({
|
|
107
|
+
enabled: true,
|
|
108
|
+
label: 'monster',
|
|
109
|
+
tags: ['one', 'two'],
|
|
110
|
+
popper: {
|
|
111
|
+
contentOverflow: 'horizontal',
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should clone object defaults when an attribute is removed', function () {
|
|
117
|
+
const options = { config: { enabled: false } };
|
|
118
|
+
const defaults = { config: { enabled: true } };
|
|
119
|
+
|
|
120
|
+
setOptionFromAttribute(
|
|
121
|
+
element,
|
|
122
|
+
'data-monster-option-config',
|
|
123
|
+
options,
|
|
124
|
+
{},
|
|
125
|
+
'data-monster-option-',
|
|
126
|
+
defaults,
|
|
127
|
+
);
|
|
128
|
+
options.config.enabled = false;
|
|
129
|
+
|
|
130
|
+
expect(defaults.config.enabled).to.equal(true);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
[
|
|
134
|
+
Object.assign(Object.create(null), {
|
|
135
|
+
count: (value) => Number(value) + 1,
|
|
136
|
+
}),
|
|
137
|
+
{
|
|
138
|
+
hasOwnProperty: true,
|
|
139
|
+
count: (value) => Number(value) + 1,
|
|
140
|
+
},
|
|
141
|
+
].forEach((mapping) => {
|
|
142
|
+
it('should support mappings without a callable hasOwnProperty', function () {
|
|
143
|
+
const options = { count: 1 };
|
|
144
|
+
element.setAttribute('data-monster-option-count', '5');
|
|
145
|
+
|
|
146
|
+
setOptionFromAttribute(element, 'data-monster-option-count', options, mapping);
|
|
147
|
+
|
|
148
|
+
expect(options.count).to.equal(6);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|