@epa-wg/custom-element-dist 0.0.21 → 0.0.23
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/.idea/.gitignore +8 -0
- package/README.md +4 -4
- package/coverage/coverage-final.json +13 -11
- package/coverage/index.html +30 -30
- package/coverage/src/custom-element/coverage.svg +1 -1
- package/coverage/src/custom-element/custom-element.js/coverage.svg +1 -1
- package/coverage/src/custom-element/custom-element.js.html +603 -420
- package/coverage/src/custom-element/http-request.js.html +10 -10
- package/coverage/src/custom-element/index.html +18 -18
- package/coverage/src/custom-element/local-storage.js.html +2 -2
- package/coverage/src/custom-element/location-element.js.html +1 -1
- package/coverage/src/index.html +1 -1
- package/coverage/src/mocks/handlers.ts.html +1 -1
- package/coverage/src/mocks/index.html +1 -1
- package/coverage/src/stories/{css.stories.ts → attributes.test.stories.ts}/coverage.svg +1 -1
- package/coverage/src/stories/{attributes.stories.ts.html → attributes.test.stories.ts.html} +113 -83
- package/coverage/src/stories/coverage.svg +1 -1
- package/coverage/src/stories/css.test.stories.ts/coverage.svg +10 -0
- package/coverage/src/stories/{css.stories.ts.html → css.test.stories.ts.html} +122 -65
- package/coverage/src/stories/dom-merge.test.stories.ts/coverage.svg +10 -0
- package/coverage/src/stories/{dom-merge.stories.ts.html → dom-merge.test.stories.ts.html} +118 -70
- package/coverage/src/stories/external-template.test.stories.ts/coverage.svg +10 -0
- package/coverage/src/stories/{external-template.stories.ts.html → external-template.test.stories.ts.html} +180 -150
- package/coverage/src/stories/form.test.stories.ts/coverage.svg +10 -0
- package/coverage/src/stories/form.test.stories.ts.html +655 -0
- package/coverage/src/stories/http-request.stories.ts.html +7 -7
- package/coverage/src/stories/index.html +118 -88
- package/coverage/src/stories/{dom-merge.stories.ts → local-storage.test.stories.ts}/coverage.svg +1 -1
- package/coverage/src/stories/{local-storage.stories.ts.html → local-storage.test.stories.ts.html} +475 -439
- package/coverage/src/stories/{external-template.stories.ts → location-element.test.stories.ts}/coverage.svg +1 -1
- package/coverage/src/stories/{location-element.stories.ts.html → location-element.test.stories.ts.html} +134 -98
- package/coverage/src/stories/slice-events.test.stories.ts/coverage.svg +10 -0
- package/coverage/src/stories/slice-events.test.stories.ts.html +685 -0
- package/coverage/src/stories/slots.test.stories.ts/coverage.svg +10 -0
- package/coverage/src/stories/slots.test.stories.ts.html +736 -0
- package/coverage/src/stories/{renderPlay.ts.html → testStoryBook.ts.html} +44 -26
- package/coverage/src/sum.ts.html +1 -1
- package/dist/custom-element-BISbI4SU.js +463 -0
- package/dist/custom-element-N-sWiqGK.cjs +53 -0
- package/dist/custom-element-bundle.cjs +1 -1
- package/dist/custom-element-bundle.js +2 -2
- package/dist/mockServiceWorker.js +1 -1
- package/package.json +4 -4
- package/public/mockServiceWorker.js +1 -1
- package/src/custom-element/custom-element.d.ts +4 -0
- package/src/custom-element/custom-element.js +103 -42
- package/src/custom-element/demo/a.html +38 -41
- package/src/custom-element/demo/b.html +13 -0
- package/src/custom-element/demo/data-slices.html +32 -0
- package/src/custom-element/demo/form.html +240 -0
- package/src/custom-element/demo/s.xml +11 -14
- package/src/custom-element/demo/s.xslt +22 -38
- package/src/custom-element/demo/s1.xslt +60 -0
- package/src/custom-element/ide/customData-dce.json +14 -1
- package/src/custom-element/ide/web-types-dce.json +6 -1
- package/src/custom-element/ide/web-types-xsl.json +1 -1
- package/src/custom-element/index.html +1 -0
- package/src/custom-element.test.ts +24 -8
- package/src/stories/{attributes.stories.ts → attributes.test.stories.ts} +19 -9
- package/src/stories/{css.stories.ts → css.test.stories.ts} +28 -9
- package/src/stories/{dom-merge.stories.ts → dom-merge.test.stories.ts} +19 -3
- package/src/stories/{external-template.stories.ts → external-template.test.stories.ts} +13 -3
- package/src/stories/form.test.stories.ts +190 -0
- package/src/stories/http-request.stories.ts +6 -6
- package/src/stories/http-request.test.ts +0 -9
- package/src/stories/{local-storage.stories.ts → local-storage.test.stories.ts} +24 -12
- package/src/stories/{location-element.stories.ts → location-element.test.stories.ts} +21 -9
- package/src/stories/{slice-events.stories.ts → slice-events.test.stories.ts} +88 -5
- package/src/stories/slots.test.stories.ts +217 -0
- package/src/stories/testStoryBook.ts +28 -0
- package/storybook-static/assets/{Color-RQJUDNI5-C4yZhNbM.js → Color-PRSJMWNM-BD_Ds9NW.js} +1 -1
- package/storybook-static/assets/{Configure-C7d36rng.js → Configure-70I_VApa.js} +1 -1
- package/storybook-static/assets/DocsRenderer-K4EAMTCU-9dn0-HCP.js +2 -0
- package/storybook-static/assets/WithTooltip-KJL26V4Q-C6g5GOU9.js +1 -0
- package/storybook-static/assets/{attributes.stories-ZB0RTY1d.js → attributes.test.stories-BEOraI4E.js} +22 -21
- package/storybook-static/assets/css.test.stories-D9WaxrEv.js +96 -0
- package/storybook-static/assets/custom-element-BV8-hRQS.js +219 -0
- package/storybook-static/assets/{dom-merge.stories-CgHZUABU.js → dom-merge.test.stories-BhbNeum_.js} +5 -6
- package/storybook-static/assets/{entry-preview-CQqNFx4W.js → entry-preview-DrgzXgwT.js} +1 -1
- package/storybook-static/assets/{entry-preview-docs-CWgqLfd3.js → entry-preview-docs-Bxv0qQWs.js} +1 -1
- package/storybook-static/assets/{external-template.stories-DtSLMxvg.js → external-template.test.stories-Bpr_wxBo.js} +23 -24
- package/storybook-static/assets/form.test.stories-3tURbEdv.js +250 -0
- package/storybook-static/assets/{formatter-B5HCVTEV-tKeEfJA9.js → formatter-2WMMO6ZP-6IvBq34u.js} +5 -5
- package/storybook-static/assets/http-request.stories-8K_qSs8C.js +300 -0
- package/storybook-static/assets/iframe-zdt9kuj6.js +2 -0
- package/storybook-static/assets/index-B3oZkK3F.js +1 -0
- package/storybook-static/assets/index-C30JwJMK.js +548 -0
- package/storybook-static/assets/index-CVRyq5ci.js +27 -0
- package/storybook-static/assets/index-DXimoRZY.js +1 -0
- package/storybook-static/assets/{index-DnEJ_bKa.js → index-DhXZyjEd.js} +1 -1
- package/storybook-static/assets/index-DuIEV_9C.js +13 -0
- package/storybook-static/assets/{lit-element-B4_0akdT.js → lit-element-CenEXOuS.js} +2 -2
- package/storybook-static/assets/{local-storage.stories-BkO6djDz.js → local-storage.test.stories-CtisAQBB.js} +28 -24
- package/storybook-static/assets/{location-element.stories-DCIOUd0D.js → location-element.test.stories-5O_t_m4Y.js} +11 -11
- package/storybook-static/assets/preview-4Up_z4Em.js +7 -0
- package/storybook-static/assets/preview-BKCN0mOr.js +1 -0
- package/storybook-static/assets/{preview-CkgAD_DE.js → preview-D0eCfQft.js} +2 -2
- package/storybook-static/assets/preview-DRnyIGXK.js +48 -0
- package/storybook-static/assets/preview-FpHGYA1q.js +1 -0
- package/storybook-static/assets/{preview-PxUn-cIn.js → preview-TCN6m6T-.js} +1 -1
- package/storybook-static/assets/slice-events.test.stories-BSXCLIA5.js +231 -0
- package/storybook-static/assets/slots.test.stories-B1vqfHmN.js +214 -0
- package/storybook-static/assets/syntaxhighlighter-BP7B2CQK-DpPBKyTO.js +1 -0
- package/storybook-static/iframe.html +153 -10
- package/storybook-static/index.html +1 -1
- package/storybook-static/index.json +1 -1
- package/storybook-static/mockServiceWorker.js +1 -1
- package/storybook-static/project.json +1 -1
- package/storybook-static/sb-addons/chromatic-com-storybook-9/manager-bundle.js +35 -29
- package/storybook-static/sb-addons/chromatic-com-storybook-9/manager-bundle.js.LEGAL.txt +1 -1
- package/storybook-static/sb-addons/essentials-actions-3/manager-bundle.js +1 -1
- package/storybook-static/sb-addons/essentials-backgrounds-4/manager-bundle.js +5 -5
- package/storybook-static/sb-addons/essentials-controls-2/manager-bundle.js +35 -35
- package/storybook-static/sb-addons/essentials-measure-7/manager-bundle.js +1 -1
- package/storybook-static/sb-addons/essentials-outline-8/manager-bundle.js +1 -1
- package/storybook-static/sb-addons/essentials-toolbars-6/manager-bundle.js +1 -1
- package/storybook-static/sb-addons/essentials-viewport-5/manager-bundle.js +1 -1
- package/storybook-static/sb-addons/interactions-10/manager-bundle.js +18 -16
- package/storybook-static/sb-addons/links-1/manager-bundle.js +1 -1
- package/storybook-static/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +1 -1
- package/storybook-static/sb-manager/WithTooltip-KJL26V4Q-5LS5AN27.js +1 -0
- package/storybook-static/sb-manager/{chunk-S4VOIVUE.js → chunk-B3YDJJJH.js} +9 -9
- package/storybook-static/sb-manager/{chunk-FEE35O7J.js → chunk-BLWCBWKL.js} +3 -3
- package/storybook-static/sb-manager/{chunk-XCO5HRLK.js → chunk-GUVK2GTO.js} +3 -3
- package/storybook-static/sb-manager/chunk-LFRML3ZV.js +186 -0
- package/storybook-static/sb-manager/chunk-MC7RAF2B.js +274 -0
- package/storybook-static/sb-manager/{chunk-XP3HGWTR.js → chunk-ZR5JZWHI.js} +1 -1
- package/storybook-static/sb-manager/{formatter-B5HCVTEV-7DCBOGO6.js → formatter-2WMMO6ZP-JI7RHVTW.js} +1 -1
- package/storybook-static/sb-manager/globals-module-info.js +1 -1
- package/storybook-static/sb-manager/globals-runtime.js +1 -1
- package/storybook-static/sb-manager/index.js +1 -1
- package/storybook-static/sb-manager/runtime.js +1 -1
- package/storybook-static/sb-manager/{syntaxhighlighter-JOJW2KGS-VF6EEVPI.js → syntaxhighlighter-BP7B2CQK-WOJYHKQR.js} +1 -1
- package/storybook-static/sb-preview/runtime.js +28 -11
- package/tsconfig.json +31 -21
- package/vite.config.js +5 -5
- package/yarn.lock +10242 -0
- package/.vscode/settings.json +0 -24
- package/coverage/src/stories/local-storage.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/location-element.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/renderPlay.ts/coverage.svg +0 -10
- package/coverage/src/stories/slice-events.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/slice-events.stories.ts.html +0 -436
- package/dist/custom-element-B4v-KaIh.cjs +0 -53
- package/dist/custom-element-_g0GTup2.js +0 -436
- package/src/stories/attributes.test.ts +0 -14
- package/src/stories/css.test.ts +0 -12
- package/src/stories/dom-merge.test.ts +0 -12
- package/src/stories/external-template.test.ts +0 -12
- package/src/stories/local-storage.test.ts +0 -12
- package/src/stories/location-element.test.ts +0 -14
- package/src/stories/renderPlay.ts +0 -22
- package/src/stories/slice-events.test.ts +0 -12
- package/storybook-static/assets/DocsRenderer-K4EAMTCU-BLMupvSb.js +0 -2
- package/storybook-static/assets/WithTooltip-Y7J54OF7-BAQSPSFk.js +0 -1
- package/storybook-static/assets/css.stories-CLSX-Xxd.js +0 -86
- package/storybook-static/assets/custom-element-BLZZ00dz.js +0 -53
- package/storybook-static/assets/http-request.stories-CUzlXO89.js +0 -300
- package/storybook-static/assets/iframe-gCvlWuoC.js +0 -2
- package/storybook-static/assets/index-CBQwM6ST.js +0 -508
- package/storybook-static/assets/index-CDavW7r9.js +0 -193
- package/storybook-static/assets/index-CQA5dlr6.js +0 -13
- package/storybook-static/assets/index-DgaNIR0t.js +0 -1
- package/storybook-static/assets/index-Dkj0J1ds.js +0 -1
- package/storybook-static/assets/preview-C6t8KBFr.js +0 -1
- package/storybook-static/assets/preview-CYD85dwb.js +0 -7
- package/storybook-static/assets/preview-D8LadFCz.js +0 -48
- package/storybook-static/assets/preview-DNpCpRPf.js +0 -1
- package/storybook-static/assets/slice-events.stories-DXKjXI37.js +0 -115
- package/storybook-static/assets/syntaxhighlighter-JOJW2KGS-C04pIVD3.js +0 -1
- package/storybook-static/sb-manager/WithTooltip-Y7J54OF7-CEHQ77YF.js +0 -1
- package/storybook-static/sb-manager/chunk-E3WK6ZOZ.js +0 -234
- package/storybook-static/sb-manager/chunk-E6ABNH5R.js +0 -183
- /package/coverage/src/stories/{attributes.stories.ts → testStoryBook.ts}/coverage.svg +0 -0
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
// noinspection DuplicatedCode
|
|
2
2
|
|
|
3
|
-
import type { StoryObj }
|
|
3
|
+
import type { StoryObj } from '@storybook/web-components';
|
|
4
4
|
import {expect, getByTestId, within, userEvent} from '@storybook/test';
|
|
5
5
|
|
|
6
6
|
import '../custom-element/custom-element.js';
|
|
7
|
+
import {
|
|
8
|
+
ByIdWithinXsltFile, EmbeddingInAnotherFile,
|
|
9
|
+
ExternalHtmlFile, ExternalHtmlFileInline, ExternalSvg, ExternalXsltFile, HtmlWithinHtmlFile, MathMLWithinHtmlFile,
|
|
10
|
+
MissingIdWithinXsltFile,
|
|
11
|
+
NoTag,
|
|
12
|
+
SvgWithinHtmlFile, TemplateInPage
|
|
13
|
+
} from './external-template.test.stories';
|
|
7
14
|
|
|
8
15
|
type TProps = { title: string; body:string};
|
|
9
16
|
|
|
@@ -55,7 +62,6 @@ export const CharsCountInTextarea:Story =
|
|
|
55
62
|
await userEvent.keyboard(titleText);
|
|
56
63
|
expect(textarea.value).toEqual(titleText);
|
|
57
64
|
expect(textarea.value.length).toEqual(titleText.length);
|
|
58
|
-
debugger;
|
|
59
65
|
canvas.getByTestId('refocus-id').focus();
|
|
60
66
|
await sleep(10);
|
|
61
67
|
expect(canvas.getByTestId('counter-id').textContent).toEqual(''+titleText?.length,'counter of symbols');
|
|
@@ -80,7 +86,7 @@ export const WordCountOnType:Story =
|
|
|
80
86
|
<code data-testid="words-id"
|
|
81
87
|
>{
|
|
82
88
|
string-length(normalize-space(//slice/txt)) -
|
|
83
|
-
string-length(translate(normalize-space(//slice/txt), ' ', '')) + 1
|
|
89
|
+
string-length(translate(normalize-space(//slice/txt), ' ', '')) + 1
|
|
84
90
|
}</code>
|
|
85
91
|
<!-- The expression first normalizes the string by removing leading and trailing whitespace and
|
|
86
92
|
collapsing internal whitespace into a single space. It then subtracts the length of the string
|
|
@@ -111,3 +117,13 @@ export const WordCountOnType:Story =
|
|
|
111
117
|
expect(canvas.getByTestId('words-id').textContent.trim()).toEqual('6', 'counter of words in render');
|
|
112
118
|
},
|
|
113
119
|
};
|
|
120
|
+
|
|
121
|
+
/* istanbul ignore else -- @preserve */
|
|
122
|
+
if( 'test' === import.meta.env.MODE &&
|
|
123
|
+
!import.meta.url.includes('skiptest') )
|
|
124
|
+
{
|
|
125
|
+
const mod = await import('./dom-merge.test.stories.ts?skiptest');
|
|
126
|
+
const { testStoryBook } = await import('./testStoryBook')
|
|
127
|
+
const { describe } = await import('vitest')
|
|
128
|
+
describe(meta.title, () => testStoryBook( mod, meta ) );
|
|
129
|
+
}
|
|
@@ -4,6 +4,7 @@ import type { StoryObj } from '@storybook/web-components';
|
|
|
4
4
|
import {expect, getByTestId, within} from '@storybook/test';
|
|
5
5
|
|
|
6
6
|
import '../custom-element/custom-element.js';
|
|
7
|
+
import {Demo, SrcAttribute} from './location-element.test.stories';
|
|
7
8
|
|
|
8
9
|
type TProps = { title: string; body:string};
|
|
9
10
|
|
|
@@ -32,10 +33,10 @@ export const TemplateInPage:Story =
|
|
|
32
33
|
<template id="template1">
|
|
33
34
|
<slot>Hello</slot> World!
|
|
34
35
|
</template>
|
|
35
|
-
|
|
36
|
+
|
|
36
37
|
<custom-element tag="dce-internal" src="#template1"></custom-element>
|
|
37
38
|
<!-- no need for loading fallback as the template exists -->
|
|
38
|
-
|
|
39
|
+
|
|
39
40
|
<dce-internal data-testid="slot-override">👋</dce-internal>
|
|
40
41
|
<dce-internal data-testid="slot-default"></dce-internal>
|
|
41
42
|
`}
|
|
@@ -194,7 +195,6 @@ export const MathMLWithinHtmlFile:Story =
|
|
|
194
195
|
const canvas = within(canvasElement);
|
|
195
196
|
await canvas.findByText(MathMLWithinHtmlFile.args!.title as string);
|
|
196
197
|
const ml = await canvas.findByTestId('ml-test');
|
|
197
|
-
debugger;
|
|
198
198
|
expect(ml.firstElementChild.localName).toEqual('mrow');
|
|
199
199
|
},
|
|
200
200
|
};
|
|
@@ -243,3 +243,13 @@ export const EmbeddingInAnotherFile:Story =
|
|
|
243
243
|
expect(canvas.getByTestId('wave').innerHTML).toEqual('🖖');
|
|
244
244
|
},
|
|
245
245
|
};
|
|
246
|
+
|
|
247
|
+
/* istanbul ignore else -- @preserve */
|
|
248
|
+
if( 'test' === import.meta.env.MODE &&
|
|
249
|
+
!import.meta.url.includes('skiptest') )
|
|
250
|
+
{
|
|
251
|
+
const mod = await import('./external-template.test.stories.ts?skiptest');
|
|
252
|
+
const { testStoryBook } = await import('./testStoryBook')
|
|
253
|
+
const { describe } = await import('vitest')
|
|
254
|
+
describe(meta.title, () => testStoryBook( mod, meta ) );
|
|
255
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// noinspection DuplicatedCode
|
|
2
|
+
|
|
3
|
+
import type { StoryObj } from '@storybook/web-components';
|
|
4
|
+
import {expect, within, userEvent} from '@storybook/test';
|
|
5
|
+
|
|
6
|
+
import '../custom-element/custom-element.js';
|
|
7
|
+
|
|
8
|
+
type TProps = { title: string; body:string};
|
|
9
|
+
|
|
10
|
+
type Story = StoryObj<TProps>;
|
|
11
|
+
|
|
12
|
+
function render(args: TProps)
|
|
13
|
+
{
|
|
14
|
+
const {title, body} = args;
|
|
15
|
+
return `
|
|
16
|
+
<fieldset>
|
|
17
|
+
<legend>${ title }</legend>
|
|
18
|
+
${ body }
|
|
19
|
+
</fieldset>
|
|
20
|
+
`;
|
|
21
|
+
}
|
|
22
|
+
const meta =
|
|
23
|
+
{ title: 'form'
|
|
24
|
+
, render
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default meta;
|
|
28
|
+
|
|
29
|
+
export const SystemMessage:Story =
|
|
30
|
+
{ args : {title: 'custom-validity boolean', body:`
|
|
31
|
+
<p>type and then clear test in input should lead to system validation message shown next to input field.
|
|
32
|
+
Something like <q>Please fill out this field</q>.</p>
|
|
33
|
+
<custom-element>
|
|
34
|
+
<template>
|
|
35
|
+
<form>
|
|
36
|
+
<label> Email
|
|
37
|
+
<input slice="username" slice-event="input" placeholder="non-empty" required data-testid="input-1">
|
|
38
|
+
</label>
|
|
39
|
+
<if test="//username/@validation-message">
|
|
40
|
+
<var data-testid="validation-msg">{//username/@validation-message}</var>
|
|
41
|
+
</if>
|
|
42
|
+
<button>Next</button>
|
|
43
|
+
</form>
|
|
44
|
+
</template>
|
|
45
|
+
</custom-element>
|
|
46
|
+
`}
|
|
47
|
+
, play: async ({canvasElement}) =>
|
|
48
|
+
{
|
|
49
|
+
const titleText = SystemMessage.args!.title as string;
|
|
50
|
+
const canvas = within(canvasElement);
|
|
51
|
+
|
|
52
|
+
await expect( canvas.queryByTestId('validation-msg')).toBeNull();
|
|
53
|
+
const input = await canvas.findByTestId('input-1');
|
|
54
|
+
input.focus();
|
|
55
|
+
await userEvent.keyboard('abc');
|
|
56
|
+
|
|
57
|
+
await userEvent.clear(input);
|
|
58
|
+
await expect( canvas.queryByTestId('validation-msg')).toBeInTheDocument();
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const FormData:Story =
|
|
63
|
+
{ args : {title: 'form-data populated', body:`
|
|
64
|
+
<p>type and then clear test in input should lead to system validation message shown next to input field.
|
|
65
|
+
Something like <q>Please fill out this field</q>.</p>
|
|
66
|
+
<custom-element>
|
|
67
|
+
<template>
|
|
68
|
+
<form slice="signin-form" >
|
|
69
|
+
<input name="f1" placeholder="non-empty" required data-testid="input-1"/>
|
|
70
|
+
<input name="f2" placeholder="non-empty" required data-testid="input-2"/>
|
|
71
|
+
<input name="f3" placeholder="non-empty" required data-testid="input-3"/>
|
|
72
|
+
|
|
73
|
+
<button data-testid="next-button">Next</button><br/>
|
|
74
|
+
f1: <code data-testid="c1">{ /datadom/slice/signin-form/form-data/f1 }</code><br/>
|
|
75
|
+
f2: <code data-testid="c2">{ //form-data/f2 }</code><br/>
|
|
76
|
+
f3: <code data-testid="c3">{/datadom/slice/signin-form/form-data/f3}</code><br/>
|
|
77
|
+
</form>
|
|
78
|
+
</template>
|
|
79
|
+
</custom-element>
|
|
80
|
+
`}
|
|
81
|
+
, play: async ({canvasElement}) =>
|
|
82
|
+
{
|
|
83
|
+
const canvas = within(canvasElement);
|
|
84
|
+
await userEvent.type(canvas.getByTestId('input-1'), 'ABC');
|
|
85
|
+
await userEvent.click(canvas.getByRole('button'));
|
|
86
|
+
await expect( await canvas.findByText('ABC')).toBeInTheDocument();
|
|
87
|
+
await userEvent.type(canvas.getByTestId('input-2'), 'DCE');
|
|
88
|
+
await userEvent.click(canvas.getByRole('button'));
|
|
89
|
+
await expect( await canvas.findByText('DCE')).toBeInTheDocument();
|
|
90
|
+
await userEvent.type(canvas.getByTestId('input-3'), 'XYZ');
|
|
91
|
+
canvas.getByTestId('input-1').focus();
|
|
92
|
+
await expect( await canvas.findByText('XYZ')).toBeInTheDocument();
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
export const SetValidityMessage:Story =
|
|
96
|
+
{ args : {title: 'setCustomValidity', body:`
|
|
97
|
+
<p><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/setCustomValidity">setCustomValidity()</a>
|
|
98
|
+
invoked by <code>custom-validity</code> attribute. Type in the input fiels to observe the chars count in
|
|
99
|
+
text, click "next" and observe same message in dropdown.
|
|
100
|
+
</p>
|
|
101
|
+
<custom-element>
|
|
102
|
+
<template>
|
|
103
|
+
<form>
|
|
104
|
+
<input slice="s1" slice-event="input keyup" placeholder="type to see the custom error"
|
|
105
|
+
custom-validity=" concat( 'char count ', string-length(//s1) ) "
|
|
106
|
+
data-testid="input-1"/><br/>
|
|
107
|
+
s1: <code data-testid="c1">{ //s1 }</code><br/>
|
|
108
|
+
@validation-message: <var data-testid="validation-msg">{//s1/@validation-message}</var>
|
|
109
|
+
<button>next</button>
|
|
110
|
+
</form>
|
|
111
|
+
</template>
|
|
112
|
+
</custom-element>
|
|
113
|
+
`}
|
|
114
|
+
, play: async ({canvasElement}) =>
|
|
115
|
+
{
|
|
116
|
+
const canvas = within(canvasElement);
|
|
117
|
+
await userEvent.type(canvas.getByTestId('input-1'), 'ABC');
|
|
118
|
+
await expect( canvas.getByText('ABC')).toBeInTheDocument();
|
|
119
|
+
await expect( canvas.getByText('char count 3')).toBeInTheDocument();
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const FormCustomValidityBoolean:Story =
|
|
124
|
+
{ args : {title: 'form custom-validity, boolean', body:`
|
|
125
|
+
<p> Form is valid only when input text length longer of 3 characters. </p>
|
|
126
|
+
<custom-element>
|
|
127
|
+
<template>
|
|
128
|
+
<form slice="form-1" custom-validity=" string-length(//form-1//f1) > 3 "
|
|
129
|
+
data-testid="form-1"
|
|
130
|
+
>
|
|
131
|
+
<input name="f1" data-testid="input-1"/><br/>
|
|
132
|
+
|
|
133
|
+
<input type="hidden" name="id" value="form--form-custom-validity-boolean"/>
|
|
134
|
+
<input type="hidden" name="viewMode" value="story"/>
|
|
135
|
+
//form-1//f1: <code data-testid="c1">{ //form-1//f1 }</code><br/>
|
|
136
|
+
<button>next</button>
|
|
137
|
+
</form>
|
|
138
|
+
</template>
|
|
139
|
+
</custom-element>
|
|
140
|
+
`}
|
|
141
|
+
, play: async ({canvasElement}) =>
|
|
142
|
+
{
|
|
143
|
+
const canvas = within(canvasElement);
|
|
144
|
+
await userEvent.type(canvas.getByTestId('input-1'), 'AB');
|
|
145
|
+
await userEvent.click(canvas.getByRole('button'));
|
|
146
|
+
|
|
147
|
+
await expect( canvas.getByText('AB')).toBeInTheDocument(); // i.e. not reloaded by form submit
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
export const FormCustomValidityString:Story =
|
|
151
|
+
{ args : {title: 'form custom-validity, string', body:`
|
|
152
|
+
<p> Form is valid only when input text is longer of 3 characters, @validation-message propagated in form slot </p>
|
|
153
|
+
<custom-element>
|
|
154
|
+
<template>
|
|
155
|
+
<form slice="form-1"
|
|
156
|
+
custom-validity=" string-length(//form-1//f1) > 3 ?? concat('should be more than 3 characters, now is ',string-length(//form-1//f1) ) "
|
|
157
|
+
data-testid="form-1"
|
|
158
|
+
>
|
|
159
|
+
<input name="f1" data-testid="input-1"/><br/>
|
|
160
|
+
|
|
161
|
+
<input type="hidden" name="id" value="form--form-custom-validity-string"/>
|
|
162
|
+
<input type="hidden" name="viewMode" value="story"/>
|
|
163
|
+
//form-1//f1: <code data-testid="c1">{ //form-1//f1 }</code><br/>
|
|
164
|
+
//form-1/@validation-message: <code data-testid="c1">{ //@validation-message }</code><br/>
|
|
165
|
+
<button>next</button>
|
|
166
|
+
</form>
|
|
167
|
+
</template>
|
|
168
|
+
</custom-element>
|
|
169
|
+
`}
|
|
170
|
+
, play: async ({canvasElement}) =>
|
|
171
|
+
{
|
|
172
|
+
const canvas = within(canvasElement);
|
|
173
|
+
await userEvent.type(canvas.getByTestId('input-1'), 'AB');
|
|
174
|
+
await userEvent.click(canvas.getByRole('button'));
|
|
175
|
+
|
|
176
|
+
await expect( canvas.getByText('AB')).toBeInTheDocument(); // i.e. not reloaded by form submit
|
|
177
|
+
await expect( canvas.getByText('should be more than 3 characters, now is 2')).toBeInTheDocument();
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
// custom validity rules on form : boolean and string values
|
|
181
|
+
|
|
182
|
+
/* istanbul ignore else -- @preserve */
|
|
183
|
+
if( 'test' === import.meta.env.MODE &&
|
|
184
|
+
!import.meta.url.includes('skiptest') )
|
|
185
|
+
{
|
|
186
|
+
const mod = await import('./form.test.stories.ts?skiptest');
|
|
187
|
+
const { testStoryBook } = await import('./testStoryBook')
|
|
188
|
+
const { describe } = await import('vitest')
|
|
189
|
+
describe(meta.title, () => testStoryBook( mod, meta ) );
|
|
190
|
+
}
|
|
@@ -28,12 +28,12 @@ function Template({title, slice, url}: TProps)
|
|
|
28
28
|
slice="${slice}"
|
|
29
29
|
></http-request>
|
|
30
30
|
<input placeholder="URL for fetch" slice="url" value="{ //url ?? '${ url }' }"/>
|
|
31
|
-
<button>set</button>
|
|
32
|
-
<button slice="url" slice-value="''" slice-event="click">set blank</button>
|
|
33
|
-
<button slice="url" slice-value="'/reflect'" slice-event="click">/reflect</button>
|
|
34
|
-
<button slice="url" slice-value="'/pokemon'" slice-event="click">/pokemon</button>
|
|
35
|
-
<button slice="url" slice-value="'/pokemon?limit=6'" slice-event="click">/pokemon?limit=6</button>
|
|
36
|
-
<button slice="url" slice-value="'/pokemon?limit=3'" slice-event="click">/pokemon?limit=3</button>
|
|
31
|
+
<button>set</button>
|
|
32
|
+
<button slice="url" slice-value="''" slice-event="click">set blank</button>
|
|
33
|
+
<button slice="url" slice-value="'/reflect'" slice-event="click">/reflect</button>
|
|
34
|
+
<button slice="url" slice-value="'/pokemon'" slice-event="click">/pokemon</button>
|
|
35
|
+
<button slice="url" slice-value="'/pokemon?limit=6'" slice-event="click">/pokemon?limit=6</button>
|
|
36
|
+
<button slice="url" slice-value="'/pokemon?limit=3'" slice-event="click">/pokemon?limit=3</button>
|
|
37
37
|
|
|
38
38
|
<p>Pokemon Count: {count(/datadom/slice/${slice}//results)}</p>
|
|
39
39
|
<if test="count(/datadom/slice/${slice}//results) < 0">
|
|
@@ -12,15 +12,6 @@ import {handlers} from '../mocks/handlers.ts';
|
|
|
12
12
|
export const worker = setupWorker(...handlers);
|
|
13
13
|
await worker.start();
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
// worker.start({serviceWorker: { url: '/public/mockServiceWorker.js' } });
|
|
17
|
-
// worker.use(...handlers);
|
|
18
|
-
|
|
19
|
-
// beforeAll( () => {worker.start()});//{ onUnhandledRequest: 'error' }));
|
|
20
|
-
//
|
|
21
|
-
// afterAll(() => worker.stop());
|
|
22
|
-
|
|
23
|
-
|
|
24
15
|
const {renderPlay} = meta;
|
|
25
16
|
describe('http-request', () => {
|
|
26
17
|
for (let story of Object.values(Stories) as StoryObj[] )
|
|
@@ -27,13 +27,13 @@ function render(args: TProps)
|
|
|
27
27
|
|
|
28
28
|
<custom-element>
|
|
29
29
|
<template><!-- wrapping into template to prevent images loading within DCE declaration -->
|
|
30
|
-
<local-storage
|
|
31
|
-
key="${ key }"
|
|
32
|
-
slice="${ slice }"
|
|
33
|
-
${ live ? `live="${live }"`:''}
|
|
34
|
-
${ value ? `value="${value }"`:''}
|
|
30
|
+
<local-storage
|
|
31
|
+
key="${ key }"
|
|
32
|
+
slice="${ slice }"
|
|
33
|
+
${ live ? `live="${live }"`:''}
|
|
34
|
+
${ value ? `value="${value }"`:''}
|
|
35
35
|
></local-storage>
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
<br/>
|
|
38
38
|
<var>${key}</var>:<code data-testid="slice-value">{ //slice/${slice} }</code>
|
|
39
39
|
<br/>
|
|
@@ -53,12 +53,12 @@ export default meta;
|
|
|
53
53
|
export const Demo:Story =
|
|
54
54
|
{ args : {title: 'live value', live:'live', body:`
|
|
55
55
|
<input placeholder="value for localStorage" id="textinput"
|
|
56
|
-
slice="${defs.slice}"
|
|
56
|
+
slice="${defs.slice}"
|
|
57
57
|
value="{ //${defs.slice} ?? '${ defs.value }' }"/>
|
|
58
58
|
<button onclick="localStorage.setItem('${defs.key}',textinput.value )">set</button>
|
|
59
59
|
<button onclick="localStorage.setItem('${defs.key}','text value' )">text value</button>
|
|
60
|
-
<button onclick="localStorage.setItem('${defs.key}','another text')">another text</button>
|
|
61
|
-
<button onclick="localStorage.removeItem('${defs.key}' )">set blank</button>
|
|
60
|
+
<button onclick="localStorage.setItem('${defs.key}','another text')">another text</button>
|
|
61
|
+
<button onclick="localStorage.removeItem('${defs.key}' )">set blank</button>
|
|
62
62
|
`}
|
|
63
63
|
, play: async ({canvasElement}) =>
|
|
64
64
|
{
|
|
@@ -94,8 +94,8 @@ export const Demo:Story =
|
|
|
94
94
|
export const AlwaysOverride:Story =
|
|
95
95
|
{ args : {title: 'AlwaysOverride', live:'', value:'ABC', body:`
|
|
96
96
|
buttons are changing the localStorage value, but without 'live' attribute slice ^^ from <i>local-storage</i> is not updated<br/>
|
|
97
|
-
<button onclick="localStorage.setItem('${defs.key}','text value' )">text value</button>
|
|
98
|
-
<button onclick="localStorage.removeItem('${defs.key}' )">set blank</button>
|
|
97
|
+
<button onclick="localStorage.setItem('${defs.key}','text value' )">text value</button>
|
|
98
|
+
<button onclick="localStorage.removeItem('${defs.key}' )">set blank</button>
|
|
99
99
|
`}
|
|
100
100
|
, play: async ({canvasElement}) =>
|
|
101
101
|
{
|
|
@@ -168,7 +168,7 @@ export const FromStorageWithDefault:Story =
|
|
|
168
168
|
|
|
169
169
|
export const TypeAttribute:Story =
|
|
170
170
|
{ args : {title: 'local-storage type attribute variations', body:`
|
|
171
|
-
|
|
171
|
+
|
|
172
172
|
<local-storage key="textKey" slice="text-key" type="text" live="live"></local-storage>
|
|
173
173
|
<local-storage key="dateKey" slice="date-key" type="date" live="live"></local-storage>
|
|
174
174
|
<local-storage key="timeKey" slice="time-key" type="time" live="live"></local-storage>
|
|
@@ -218,6 +218,8 @@ export const TypeAttribute:Story =
|
|
|
218
218
|
`}
|
|
219
219
|
, play: async ({canvasElement}) =>
|
|
220
220
|
{
|
|
221
|
+
window['JsonSample'] = {a:1,b:'B'};
|
|
222
|
+
|
|
221
223
|
const canvas = within(canvasElement);
|
|
222
224
|
await canvas.findByText(TypeAttribute.args!.title as string);
|
|
223
225
|
const byText = txt => canvas.getByText(txt)
|
|
@@ -386,3 +388,13 @@ export const TypeAttribute:Story =
|
|
|
386
388
|
expectVal('json-key' ,'\na : 1b : B' );
|
|
387
389
|
},
|
|
388
390
|
};
|
|
391
|
+
|
|
392
|
+
/* istanbul ignore else -- @preserve */
|
|
393
|
+
if( 'test' === import.meta.env.MODE &&
|
|
394
|
+
!import.meta.url.includes('skiptest') )
|
|
395
|
+
{
|
|
396
|
+
const mod = await import('./local-storage.test.stories.ts?skiptest');
|
|
397
|
+
const { testStoryBook } = await import('./testStoryBook')
|
|
398
|
+
const { describe } = await import('vitest')
|
|
399
|
+
describe(meta.title, () => testStoryBook( mod, meta ) );
|
|
400
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// noinspection DuplicatedCode
|
|
2
2
|
|
|
3
|
-
import type { StoryObj }
|
|
4
|
-
import {expect, getByTestId, within}
|
|
3
|
+
import type { StoryObj } from '@storybook/web-components';
|
|
4
|
+
import {expect, getByTestId, within} from '@storybook/test';
|
|
5
5
|
|
|
6
6
|
import '../custom-element/custom-element.js';
|
|
7
7
|
import '../custom-element/location-element.js';
|
|
8
|
+
import {RealtimeEventInSlice, SliceInitChangeEvent} from './slice-events.test.stories';
|
|
8
9
|
|
|
9
10
|
type TProps = { title: string; slice: string; href: string; live:string; body:string};
|
|
10
11
|
const defs: TProps =
|
|
@@ -26,13 +27,13 @@ function render(args: TProps)
|
|
|
26
27
|
|
|
27
28
|
<custom-element>
|
|
28
29
|
<template><!-- wrapping into template to prevent images loading within DCE declaration -->
|
|
29
|
-
<location-element
|
|
30
|
-
slice="${ slice }"
|
|
31
|
-
${ href ? `href="${ href }"`:''}
|
|
30
|
+
<location-element
|
|
31
|
+
slice="${ slice }"
|
|
32
|
+
${ href ? `href="${ href }"`:''}
|
|
32
33
|
live="${ live }"
|
|
33
34
|
></location-element>
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
|
|
36
|
+
|
|
36
37
|
${ body }
|
|
37
38
|
<xhtml:table>
|
|
38
39
|
<xhtml:tbody>
|
|
@@ -40,12 +41,12 @@ function render(args: TProps)
|
|
|
40
41
|
<xhtml:th><h3> URL properties </h3></xhtml:th>
|
|
41
42
|
<xhtml:td>{count(//value/@*)}</xhtml:td>
|
|
42
43
|
</xhtml:tr>
|
|
43
|
-
<apply-templates mode="attrs" select="
|
|
44
|
+
<apply-templates mode="attrs" select="//${ slice }/value/@*"></apply-templates>
|
|
44
45
|
</xhtml:tbody>
|
|
45
46
|
</xhtml:table>
|
|
46
47
|
<xhtml:table>
|
|
47
48
|
<h3> URL parameters </h3>
|
|
48
|
-
<apply-templates mode="attrs" select="
|
|
49
|
+
<apply-templates mode="attrs" select="//${ slice }/value/params/*/*"></apply-templates>
|
|
49
50
|
</xhtml:table>
|
|
50
51
|
<xsl:template mode="attrs" match="*|@*">
|
|
51
52
|
<xhtml:tr>
|
|
@@ -131,3 +132,14 @@ export const SrcAttribute:Story =
|
|
|
131
132
|
|
|
132
133
|
},
|
|
133
134
|
};
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
/* istanbul ignore else -- @preserve */
|
|
138
|
+
if( 'test' === import.meta.env.MODE &&
|
|
139
|
+
!import.meta.url.includes('skiptest') )
|
|
140
|
+
{
|
|
141
|
+
const mod = await import('./location-element.test.stories.ts?skiptest');
|
|
142
|
+
const { testStoryBook } = await import('./testStoryBook')
|
|
143
|
+
const { describe } = await import('vitest')
|
|
144
|
+
describe(meta.title, () => testStoryBook( mod, meta ) );
|
|
145
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// noinspection DuplicatedCode
|
|
2
2
|
|
|
3
|
-
import type { StoryObj }
|
|
4
|
-
import {
|
|
3
|
+
import type { StoryObj } from '@storybook/web-components';
|
|
4
|
+
import {expect, userEvent, within, spyOn} from '@storybook/test';
|
|
5
5
|
|
|
6
6
|
import '../custom-element/custom-element.js';
|
|
7
7
|
|
|
@@ -74,7 +74,7 @@ export const RealtimeEventInSlice:Story =
|
|
|
74
74
|
<p>move the mouse over TEXTAREA and click to see slice and slice event changed</p>
|
|
75
75
|
<custom-element>
|
|
76
76
|
<template>
|
|
77
|
-
<textarea slice="s" slice-value="concat('x:', //@pageX)" slice-event="mousemove click"
|
|
77
|
+
<textarea slice="s" slice-value="concat('x:', //@pageX)" slice-event="mousemove click"
|
|
78
78
|
style="width:16rem;height:16rem;box-shadow: inset {//@offsetX}px {//@offsetY}px gold;"></textarea><br/>
|
|
79
79
|
//slice/s : <code data-testid="//slice/s" >{ //slice/s }</code> <br/>
|
|
80
80
|
//slice/s/event/@offsetY : <code data-testid="//slice/s/event/@offsetY" >{ //slice/s/event/@offsetY }</code> <br/>
|
|
@@ -108,10 +108,93 @@ export const RealtimeEventInSlice:Story =
|
|
|
108
108
|
input.dispatchEvent( ev );
|
|
109
109
|
};
|
|
110
110
|
|
|
111
|
-
emitXy(
|
|
111
|
+
emitXy(20,20,'click');
|
|
112
112
|
await sleep(10);
|
|
113
|
-
expect( sliceText() ).to.equal('x:
|
|
113
|
+
expect( sliceText() ).to.equal('x:20', 'click slot value 20');
|
|
114
114
|
expect( Number(offsetY()) ).to.be.lessThan(0, 'offsetY click');
|
|
115
115
|
expect( eventType() ).to.equal('click', 'click event type');
|
|
116
116
|
},
|
|
117
117
|
};
|
|
118
|
+
|
|
119
|
+
export const DoubleEventInSlice:Story =
|
|
120
|
+
{ args : {title: 'slice-event="change submit change submit" ', body:`
|
|
121
|
+
<p> double same event should be treated as one.</p>
|
|
122
|
+
<custom-element>
|
|
123
|
+
<template>
|
|
124
|
+
<form slice-event="submit submit change change" slice="form-1">
|
|
125
|
+
<input slice-event="change change" required slice="field-1" data-testid="f1" name="f1"/>
|
|
126
|
+
<input name="f2" value="populated in form-data"/>
|
|
127
|
+
<button>next</button> <code>slices count {count(/datadom/slice/*)}</code>
|
|
128
|
+
</form>
|
|
129
|
+
</template>
|
|
130
|
+
</custom-element>
|
|
131
|
+
`}
|
|
132
|
+
, play: async ({canvasElement}) =>
|
|
133
|
+
{
|
|
134
|
+
const canvas = within(canvasElement);
|
|
135
|
+
const input = await canvas.findByTestId('f1');
|
|
136
|
+
input.focus();
|
|
137
|
+
await userEvent.type ( input, 'AB');
|
|
138
|
+
canvas.getByRole('button').focus()
|
|
139
|
+
await userEvent.clear( input );
|
|
140
|
+
await userEvent.click( canvas.getByRole('button'));
|
|
141
|
+
expect( await canvas.findByText('slices count 2')).toBeInTheDocument();
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
export const MultipleSlices:Story =
|
|
145
|
+
{ args : {title: 'slice="/datadom/attributes/emotion | s1" ', body:`
|
|
146
|
+
<p> double same event should be treated as one.</p>
|
|
147
|
+
<custom-element>
|
|
148
|
+
<template>
|
|
149
|
+
<input slice="s1|s2"
|
|
150
|
+
slice-event="input"
|
|
151
|
+
data-testid="f1"
|
|
152
|
+
/><br/>
|
|
153
|
+
Type to update s1 and s2 slices <br/>
|
|
154
|
+
slice <code>s1: {//slice/s1}</code><br/>
|
|
155
|
+
slice <code>s2: {//slice/s2}</code><br/>
|
|
156
|
+
</template>
|
|
157
|
+
</custom-element>
|
|
158
|
+
`}
|
|
159
|
+
, play: async ({canvasElement}) =>
|
|
160
|
+
{
|
|
161
|
+
const canvas = within(canvasElement);
|
|
162
|
+
const input = await canvas.findByTestId('f1');
|
|
163
|
+
input.focus();
|
|
164
|
+
await userEvent.type ( input, 'AB');
|
|
165
|
+
await expect( await canvas.findByText('s1: AB')).toBeInTheDocument();
|
|
166
|
+
await expect( await canvas.findByText('s2: AB')).toBeInTheDocument();
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
export const SlicesInAttrAndName:Story =
|
|
170
|
+
{ args : {title: 'slice="/datadom/attributes/emotion | s1" ', body:`
|
|
171
|
+
<p> double same event should be treated as one.</p>
|
|
172
|
+
<custom-element>
|
|
173
|
+
<template>
|
|
174
|
+
<attribute name="emotion">😃</attribute>
|
|
175
|
+
<input slice-event="input" slice="/datadom/attributes/emotion | s1" data-testid="f1"/>
|
|
176
|
+
<p>Type to update </p>
|
|
177
|
+
<p>emotion attribute: {emotion}</p>
|
|
178
|
+
<p>slice: {//slice/s1}</p>
|
|
179
|
+
</template>
|
|
180
|
+
</custom-element>
|
|
181
|
+
`}
|
|
182
|
+
, play: async ({canvasElement}) =>
|
|
183
|
+
{
|
|
184
|
+
const canvas = within(canvasElement);
|
|
185
|
+
const input = await canvas.findByTestId('f1');
|
|
186
|
+
input.focus();
|
|
187
|
+
await userEvent.type ( input, 'AB');
|
|
188
|
+
await expect( await canvas.findByText( 'emotion attribute: AB')).toBeInTheDocument();
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/* istanbul ignore else -- @preserve */
|
|
193
|
+
if( 'test' === import.meta.env.MODE &&
|
|
194
|
+
!import.meta.url.includes('skiptest') )
|
|
195
|
+
{
|
|
196
|
+
const mod = await import('./slice-events.test.stories.ts?skiptest');
|
|
197
|
+
const { testStoryBook } = await import('./testStoryBook')
|
|
198
|
+
const { describe } = await import('vitest')
|
|
199
|
+
describe(meta.title, () => testStoryBook( mod, meta ) );
|
|
200
|
+
}
|