@nuka9510/simple-validation 1.0.4

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.
@@ -0,0 +1,43 @@
1
+ export = validation;
2
+ export as namespace validation;
3
+
4
+ declare namespace validation {
5
+ type InputElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
6
+
7
+ /** 결과 값 객체 */
8
+ interface result {
9
+ /** #default `true` */
10
+ flag: boolean;
11
+ /** #default `null` */
12
+ alertMsg: string | null;
13
+ /** #default `null` */
14
+ el: InputElement | null;
15
+ }
16
+
17
+ interface dateEl {
18
+ S?: InputElement;
19
+ E?: InputElement;
20
+ }
21
+
22
+ /** validation check할 Element를 담는 객체 */
23
+ interface el {
24
+ el?: InputElement[];
25
+ date?: {
26
+ [date: string]: dateEl;
27
+ };
28
+ }
29
+
30
+ interface radio {
31
+ [required: string]: InputElement[];
32
+ }
33
+
34
+ /** validation에 사용할 정규식을 담은 객체 */
35
+ interface regex {
36
+ [pattern: string]: RegExp;
37
+ }
38
+
39
+ /** validation 초기화를 위한 객체 */
40
+ interface config {
41
+ regex?: regex;
42
+ }
43
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jong Won Kim
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,88 @@
1
+ [![GITHUB][github]][github-url]
2
+ [![NPM][npm]][npm-url]
3
+
4
+ # simple-validation
5
+ ## Installation
6
+ ```
7
+ npm i @nuka9510/simple-validation
8
+ ```
9
+ ## Usage
10
+ ```
11
+ root
12
+ ├── dist
13
+ │ ├── index.js
14
+ │ └── validation.js
15
+ ├── example
16
+ │ ├── js
17
+ │ │ └── index.js
18
+ │ └── view
19
+ │ └── index.html
20
+ └── node_modules
21
+ └── @nuka9510
22
+ └── js-util
23
+ └── dist
24
+ ├── index.js
25
+ └── util.js
26
+ ```
27
+ * example/js/index.js
28
+ ```
29
+ import { SValidation } from "@nuka9501/simple-valication";
30
+
31
+ class Index {
32
+ constructor() {
33
+ this.onValidationCheckClick = this.onValidationCheckClick.bind(this);
34
+
35
+ this.init();
36
+ }
37
+
38
+ init() {
39
+ document.querySelectorAll('[data-action]').forEach((...arg) => { arg[0].addEventListener('click', this.onValidationCheckClick); });
40
+ }
41
+
42
+ onValidationCheckClick(ev) {
43
+ const validation = new SValidation({ regex: { test: /^test/ } }),
44
+ result = document.querySelector('[data-name="result"]');
45
+
46
+ validation.run(form);
47
+
48
+ console.log(validation.result);
49
+
50
+ result.innerHTML = JSON.stringify(validation.result);
51
+ }
52
+
53
+ }
54
+
55
+ new Index();
56
+ ```
57
+ * example/view/index.html
58
+ ```
59
+ <!DOCTYPE html>
60
+ <html lang="en">
61
+ <head>
62
+ <meta charset="UTF-8">
63
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
64
+ <title>Document</title>
65
+ </head>
66
+ <body>
67
+ <form name="form">
68
+ <input type="text" name="test" data-sv-pattern="test" required="test">
69
+ <button type="button" data-action="validation-check-click">validation-check</button>
70
+ </form>
71
+ <div data-name="result"></div>
72
+ </body>
73
+ <script type="importmap">
74
+ {
75
+ "imports": {
76
+ "@nuka9510/js-util": "/node_modules/@nuka9510/js-util/dist/index.js",
77
+ "@nuka9501/simple-valication": "/dist/index.js"
78
+ }
79
+ }
80
+ </script>
81
+ <script type="module" src="../js/index.js"></script>
82
+ </html>
83
+ ```
84
+
85
+ [github]: https://img.shields.io/badge/github-blue.svg?style=flat&logo=github
86
+ [github-url]: https://github.com/nuka9510/simple-validation
87
+ [npm]: https://img.shields.io/badge/npm-1.0.4-blue.svg?style=flat&logo=nodedotjs
88
+ [npm-url]: https://www.npmjs.com/package/@nuka9510/simple-validation
@@ -0,0 +1,2 @@
1
+ import Validation from "./validation.js";
2
+ export { Validation as SValidation };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import Validation from "./validation.js";
2
+ export { Validation as SValidation };
@@ -0,0 +1,48 @@
1
+ import { config, result } from "../@types/validation";
2
+ /**
3
+ * Validation Check를 위한 객체
4
+ */
5
+ export default class Validation {
6
+ #private;
7
+ /** 결과 값 객체 */
8
+ result: result;
9
+ /**
10
+ * Validation Check를 위한 객체
11
+ *
12
+ * ```
13
+ * <form name="form">
14
+ * <input type="text" name="text" data-sv-pattern="password" data-sv-input-name="비밀번호" minlength="0" maxlength="10">
15
+ * <input type="text" name="text" data-sv-pattern="password" minlength="0" maxlength="10" required="비밀번호">
16
+ * <input type="date" name="sdate1" data-sv-date="date1" data-sv-date-state="S" data-sv-input-name="검색일1">
17
+ * <input type="date" name="edate1" data-sv-date="date1" data-sv-date-state="E" data-sv-input-name="검색일1">
18
+ * <input type="date" name="sdate2" data-sv-date="date2" data-sv-date-state="S" required="검색일2">
19
+ * <input type="date" name="edate2" data-sv-date="date2" data-sv-date-state="E" required="검색일2">
20
+ * </form>
21
+ * <script type="importmap">
22
+ * {
23
+ * "imports": { "@nuka9510/simple-validation": "/node_modules/@nuka9510/simple-validation/dist/index.js" }
24
+ * }
25
+ * </script>
26
+ * <script type="module">
27
+ * import SValidation from "@nuka9510/simple-validation";
28
+ *
29
+ * const validation = new SValidation({regex: {password: /^[\S!?@#$%^&*():;+-=~{}<>\_\[\]\|\\\"\'\,\.\/\`]{6,10}$/}});
30
+ *
31
+ * validation.run(form);
32
+ *
33
+ * if (validation.result.flag) {
34
+ * form.submit();
35
+ * } else {
36
+ * alert(validation.result.alertMsg);
37
+ * validation.result.el.focus();
38
+ * }
39
+ * </script>
40
+ * ```
41
+ */
42
+ constructor(config?: config);
43
+ /** 객체 초기화 */
44
+ init(
45
+ /** validation 초기화를 위한 객체 */ config?: config | null): void;
46
+ /** validation을 실행한다. */
47
+ run(form: HTMLFormElement): void;
48
+ }
@@ -0,0 +1,287 @@
1
+ import { JUtil } from "@nuka9510/js-util";
2
+ /**
3
+ * Validation Check를 위한 객체
4
+ */
5
+ export default class Validation {
6
+ /** 결과 값 객체 */
7
+ result;
8
+ /** validation check할 Element를 담는 객체 */
9
+ #el;
10
+ /** validation check할 radio Element를 담는 객체 */
11
+ #radio;
12
+ /** validation check에 사용할 정규식을 담은 객체 */
13
+ #regex;
14
+ /**
15
+ * Validation Check를 위한 객체
16
+ *
17
+ * ```
18
+ * <form name="form">
19
+ * <input type="text" name="text" data-sv-pattern="password" data-sv-input-name="비밀번호" minlength="0" maxlength="10">
20
+ * <input type="text" name="text" data-sv-pattern="password" minlength="0" maxlength="10" required="비밀번호">
21
+ * <input type="date" name="sdate1" data-sv-date="date1" data-sv-date-state="S" data-sv-input-name="검색일1">
22
+ * <input type="date" name="edate1" data-sv-date="date1" data-sv-date-state="E" data-sv-input-name="검색일1">
23
+ * <input type="date" name="sdate2" data-sv-date="date2" data-sv-date-state="S" required="검색일2">
24
+ * <input type="date" name="edate2" data-sv-date="date2" data-sv-date-state="E" required="검색일2">
25
+ * </form>
26
+ * <script type="importmap">
27
+ * {
28
+ * "imports": { "@nuka9510/simple-validation": "/node_modules/@nuka9510/simple-validation/dist/index.js" }
29
+ * }
30
+ * </script>
31
+ * <script type="module">
32
+ * import SValidation from "@nuka9510/simple-validation";
33
+ *
34
+ * const validation = new SValidation({regex: {password: /^[\S!?@#$%^&*():;+-=~{}<>\_\[\]\|\\\"\'\,\.\/\`]{6,10}$/}});
35
+ *
36
+ * validation.run(form);
37
+ *
38
+ * if (validation.result.flag) {
39
+ * form.submit();
40
+ * } else {
41
+ * alert(validation.result.alertMsg);
42
+ * validation.result.el.focus();
43
+ * }
44
+ * </script>
45
+ * ```
46
+ */
47
+ constructor(config) { this.init(config); }
48
+ /** 객체 초기화 */
49
+ init(
50
+ /** validation 초기화를 위한 객체 */ config = null) {
51
+ this.#resultInit();
52
+ this.#elInit();
53
+ this.#radioInit();
54
+ this.#regexInit(config?.regex);
55
+ }
56
+ /** 결과 값 초기화 */
57
+ #resultInit() {
58
+ this.result = {
59
+ flag: true,
60
+ alertMsg: null,
61
+ el: null
62
+ };
63
+ }
64
+ /** validation check할 Element를 담는 객체 초기화 */
65
+ #elInit() { this.#el = {}; }
66
+ /** validation check할 radio Element를 담는 객체 초기화 */
67
+ #radioInit() { this.#radio = {}; }
68
+ /** validation check에 사용할 정규식을 담은 객체 초기화 */
69
+ #regexInit(regex = null) {
70
+ this.#regex = (!JUtil.empty(regex) &&
71
+ JUtil.isObject(regex))
72
+ ? {
73
+ ...this.#regex,
74
+ ...regex
75
+ }
76
+ : { ...this.#regex };
77
+ }
78
+ /** el에 있는 Element들을 required check한다. */
79
+ #required(el) {
80
+ const required = el.getAttribute('required');
81
+ if (!JUtil.empty(required)) {
82
+ if (el.type == 'radio') {
83
+ this.#setRadio(el);
84
+ }
85
+ else if (JUtil.empty(el.value)) {
86
+ this.result.flag = false;
87
+ this.result.alertMsg = `'${required}'을/를 입력해 주세요.`;
88
+ this.result.el = el;
89
+ }
90
+ }
91
+ }
92
+ /** radio에 있는 Element들을 required check한다. */
93
+ #requiredRadio() {
94
+ for (const i in this.#radio) {
95
+ const el = this.#radio[i][0], flag = this.#radio[i].some((...arg) => arg[0].checked);
96
+ if (!flag) {
97
+ this.result.flag = false;
98
+ this.result.alertMsg = `'${i}'을/를 선택해주세요.`;
99
+ this.result.el = el;
100
+ break;
101
+ }
102
+ }
103
+ }
104
+ /** el에 Element를 담는다. */
105
+ #setEl(el) {
106
+ const pattern = el.dataset['svPattern'], date = el.dataset['svDate'];
107
+ if (!JUtil.empty(pattern)) {
108
+ if (JUtil.empty(this.#el.el)) {
109
+ this.#el.el = [];
110
+ }
111
+ this.#el.el?.push(el);
112
+ }
113
+ if (!JUtil.empty(date)) {
114
+ const state = el.dataset['svDateState'];
115
+ switch (state) {
116
+ case 'S':
117
+ case 'E':
118
+ if (JUtil.empty(this.#el.date)) {
119
+ this.#el.date = {};
120
+ }
121
+ if (JUtil.empty(this.#el.date[date])) {
122
+ this.#el.date[date] = {};
123
+ }
124
+ this.#el.date[date][state] = el;
125
+ break;
126
+ }
127
+ }
128
+ }
129
+ /** `#radio`에 type이 'radio'인 Element를 담는다. */
130
+ #setRadio(el) {
131
+ const required = el.getAttribute('required');
132
+ if (!JUtil.empty(required)) {
133
+ if (JUtil.empty(this.#radio[required])) {
134
+ this.#radio[required] = [el];
135
+ }
136
+ else {
137
+ this.#radio[required].push(el);
138
+ }
139
+ }
140
+ }
141
+ /**
142
+ * Element들을 validation check 한다.
143
+ * ```
144
+ * -----------------------
145
+ * date : isDate
146
+ * -----------------------
147
+ * el : isPattern
148
+ * ```
149
+ */
150
+ #match() {
151
+ for (const i in this.#el) {
152
+ if (this.result.flag) {
153
+ switch (i) {
154
+ case 'date':
155
+ this.#isDate(this.#el[i]);
156
+ break;
157
+ case 'el':
158
+ this.#isPattern(this.#el[i]);
159
+ break;
160
+ }
161
+ }
162
+ else {
163
+ break;
164
+ }
165
+ }
166
+ }
167
+ /** date check */
168
+ #isDate(el) {
169
+ for (const i in el) {
170
+ if (this.result.flag) {
171
+ const sdate = el[i].S.value, edate = el[i].E.value;
172
+ if (!JUtil.empty(sdate) &&
173
+ !JUtil.empty(edate)) {
174
+ const inputName = el[i].S.dataset['svInputName'] ||
175
+ el[i].E.dataset['svInputName'], required = el[i].S.getAttribute('required') ||
176
+ el[i].E.getAttribute('required');
177
+ if ((new Date(sdate)).getTime() > (new Date(edate)).getTime()) {
178
+ this.result.flag = false;
179
+ this.result.alertMsg = `'${inputName || required}'의 시작일이 종료일 보다 늦습니다.`;
180
+ this.result.el = el[i].S;
181
+ }
182
+ }
183
+ }
184
+ else {
185
+ break;
186
+ }
187
+ }
188
+ }
189
+ /** regex check */
190
+ #isPattern(el) {
191
+ if (Array.isArray(el)) {
192
+ for (const i of el) {
193
+ const pattern = i.dataset['svPattern'], inputName = i.dataset['svInputName'], required = i.getAttribute('required'), val = i.value;
194
+ if (Object.keys(this.#regex).includes(pattern)) {
195
+ if (!JUtil.empty(val) &&
196
+ !this.#regex[pattern].test(val)) {
197
+ this.result.flag = false;
198
+ this.result.alertMsg = `'${inputName || required}'의 형식이 올바르지 않습니다.`;
199
+ this.result.el = i;
200
+ break;
201
+ }
202
+ }
203
+ }
204
+ }
205
+ else {
206
+ const pattern = el.dataset['svPattern'], inputName = el.dataset['svInputName'], required = el.getAttribute('required'), val = el.value;
207
+ if (Object.keys(this.#regex).includes(pattern)) {
208
+ if (!JUtil.empty(val) &&
209
+ !this.#regex[pattern].test(val)) {
210
+ this.result.flag = false;
211
+ this.result.alertMsg = `'${inputName || required}'의 형식이 올바르지 않습니다.`;
212
+ this.result.el = el;
213
+ }
214
+ }
215
+ }
216
+ }
217
+ /** Element value의 length를 check 한다. */
218
+ #length() {
219
+ for (const i in this.#el) {
220
+ if (i == 'el' &&
221
+ this.result.flag) {
222
+ for (const j of this.#el[i]) {
223
+ const inputName = j.dataset['svInputName'], required = j.getAttribute('required'), val = j.value.length;
224
+ if (!(j instanceof HTMLSelectElement)) {
225
+ if (j.minLength >= 0 &&
226
+ j.maxLength >= 0) {
227
+ if (val < j.minLength ||
228
+ val > j.maxLength) {
229
+ this.result.flag = false;
230
+ this.result.alertMsg = `'${inputName || required}'은/는 ${j.minLength}~${j.maxLength}자 이내로 입력해주세요.`;
231
+ this.result.el = j;
232
+ break;
233
+ }
234
+ }
235
+ else if (j.minLength >= 0 &&
236
+ j.maxLength < 0) {
237
+ if (val < j.minLength) {
238
+ this.result.flag = false;
239
+ this.result.alertMsg = `'${inputName || required}'은/는 ${j.minLength}자 이상으로 입력해주세요.`;
240
+ this.result.el = j;
241
+ break;
242
+ }
243
+ }
244
+ else if (j.minLength < 0 &&
245
+ j.maxLength >= 0) {
246
+ if (val > j.maxLength) {
247
+ this.result.flag = false;
248
+ this.result.alertMsg = `'${inputName || required}'은/는 ${j.maxLength}자 이하로 입력해주세요.`;
249
+ this.result.el = j;
250
+ break;
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ else if (!this.result.flag) {
257
+ break;
258
+ }
259
+ }
260
+ }
261
+ /** validation을 실행한다. */
262
+ run(form) {
263
+ this.init();
264
+ for (const el of form.elements) {
265
+ if (this.result.flag) {
266
+ if (['INPUT', 'SELECT', 'TEXTAREA'].includes(el.tagName)) {
267
+ if (!el.disabled) {
268
+ this.#required(el);
269
+ this.#setEl(el);
270
+ }
271
+ }
272
+ }
273
+ else {
274
+ break;
275
+ }
276
+ }
277
+ if (this.result.flag) {
278
+ this.#requiredRadio();
279
+ }
280
+ if (this.result.flag) {
281
+ this.#match();
282
+ }
283
+ if (this.result.flag) {
284
+ this.#length();
285
+ }
286
+ }
287
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@nuka9510/simple-validation",
3
+ "version": "1.0.4",
4
+ "description": "simple validation util for web front-end",
5
+ "main": "dist/index.js",
6
+ "directories": {
7
+ "example": "example"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/nuka9510/simple-validation.git"
15
+ },
16
+ "keywords": [
17
+ "web",
18
+ "front-end",
19
+ "util",
20
+ "validation"
21
+ ],
22
+ "author": "nuka9510",
23
+ "license": "MIT",
24
+ "bugs": {
25
+ "url": "https://github.com/nuka9510/simple-validation/issues"
26
+ },
27
+ "homepage": "https://github.com/nuka9510/simple-validation",
28
+ "dependencies": {
29
+ "@nuka9510/js-util": "^1.0.21"
30
+ }
31
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ import Validation from "./validation.js";
2
+
3
+ export { Validation as SValidation };
@@ -0,0 +1,341 @@
1
+ import { JUtil } from "@nuka9510/js-util";
2
+ import { config, el, InputElement, radio, regex, result } from "../@types/validation";
3
+
4
+ /**
5
+ * Validation Check를 위한 객체
6
+ */
7
+ export default class Validation {
8
+ /** 결과 값 객체 */
9
+ result: result;
10
+
11
+ /** validation check할 Element를 담는 객체 */
12
+ #el: el;
13
+
14
+ /** validation check할 radio Element를 담는 객체 */
15
+ #radio: radio;
16
+
17
+ /** validation check에 사용할 정규식을 담은 객체 */
18
+ #regex: regex;
19
+
20
+ /**
21
+ * Validation Check를 위한 객체
22
+ *
23
+ * ```
24
+ * <form name="form">
25
+ * <input type="text" name="text" data-sv-pattern="password" data-sv-input-name="비밀번호" minlength="0" maxlength="10">
26
+ * <input type="text" name="text" data-sv-pattern="password" minlength="0" maxlength="10" required="비밀번호">
27
+ * <input type="date" name="sdate1" data-sv-date="date1" data-sv-date-state="S" data-sv-input-name="검색일1">
28
+ * <input type="date" name="edate1" data-sv-date="date1" data-sv-date-state="E" data-sv-input-name="검색일1">
29
+ * <input type="date" name="sdate2" data-sv-date="date2" data-sv-date-state="S" required="검색일2">
30
+ * <input type="date" name="edate2" data-sv-date="date2" data-sv-date-state="E" required="검색일2">
31
+ * </form>
32
+ * <script type="importmap">
33
+ * {
34
+ * "imports": { "@nuka9510/simple-validation": "/node_modules/@nuka9510/simple-validation/dist/index.js" }
35
+ * }
36
+ * </script>
37
+ * <script type="module">
38
+ * import SValidation from "@nuka9510/simple-validation";
39
+ *
40
+ * const validation = new SValidation({regex: {password: /^[\S!?@#$%^&*():;+-=~{}<>\_\[\]\|\\\"\'\,\.\/\`]{6,10}$/}});
41
+ *
42
+ * validation.run(form);
43
+ *
44
+ * if (validation.result.flag) {
45
+ * form.submit();
46
+ * } else {
47
+ * alert(validation.result.alertMsg);
48
+ * validation.result.el.focus();
49
+ * }
50
+ * </script>
51
+ * ```
52
+ */
53
+ constructor(
54
+ config?: config
55
+ ) { this.init(config); }
56
+
57
+ /** 객체 초기화 */
58
+ init(
59
+ /** validation 초기화를 위한 객체 */ config: config | null = null
60
+ ): void {
61
+ this.#resultInit();
62
+ this.#elInit();
63
+ this.#radioInit();
64
+ this.#regexInit(config?.regex);
65
+ }
66
+
67
+ /** 결과 값 초기화 */
68
+ #resultInit(): void {
69
+ this.result = {
70
+ flag: true,
71
+ alertMsg: null,
72
+ el: null
73
+ };
74
+ }
75
+
76
+ /** validation check할 Element를 담는 객체 초기화 */
77
+ #elInit(): void { this.#el = {}; }
78
+
79
+ /** validation check할 radio Element를 담는 객체 초기화 */
80
+ #radioInit(): void { this.#radio = {}; }
81
+
82
+ /** validation check에 사용할 정규식을 담은 객체 초기화 */
83
+ #regexInit(
84
+ regex: regex | null = null
85
+ ): void {
86
+ this.#regex = (
87
+ !JUtil.empty(regex) &&
88
+ JUtil.isObject(regex)
89
+ )
90
+ ? {
91
+ ...this.#regex,
92
+ ...regex
93
+ }
94
+ : { ...this.#regex };
95
+ }
96
+
97
+ /** el에 있는 Element들을 required check한다. */
98
+ #required(
99
+ el: InputElement
100
+ ): void {
101
+ const required = el.getAttribute('required');
102
+
103
+ if (!JUtil.empty(required)) {
104
+ if (el.type == 'radio') {
105
+ this.#setRadio(el);
106
+ } else if (JUtil.empty(el.value)) {
107
+ this.result.flag = false;
108
+ this.result.alertMsg = `'${required}'을/를 입력해 주세요.`;
109
+ this.result.el = el;
110
+ }
111
+ }
112
+ }
113
+
114
+ /** radio에 있는 Element들을 required check한다. */
115
+ #requiredRadio(): void {
116
+ for (const i in this.#radio) {
117
+ const el = this.#radio[i][0],
118
+ flag = this.#radio[i].some((...arg) => (arg[0] as HTMLInputElement).checked);
119
+
120
+ if (!flag) {
121
+ this.result.flag = false;
122
+ this.result.alertMsg = `'${i}'을/를 선택해주세요.`;
123
+ this.result.el = el;
124
+ break;
125
+ }
126
+ }
127
+ }
128
+
129
+ /** el에 Element를 담는다. */
130
+ #setEl(
131
+ el: InputElement
132
+ ): void {
133
+ const pattern = el.dataset['svPattern'],
134
+ date = el.dataset['svDate'];
135
+
136
+ if (!JUtil.empty(pattern)) {
137
+ if (JUtil.empty(this.#el.el)) { this.#el.el = []; }
138
+
139
+ this.#el.el?.push(el);
140
+ }
141
+
142
+ if (!JUtil.empty(date)) {
143
+ const state = el.dataset['svDateState'];
144
+
145
+ switch (state) {
146
+ case 'S':
147
+ case 'E':
148
+ if (JUtil.empty(this.#el.date)) { this.#el.date = {}; }
149
+ if (JUtil.empty((this.#el.date as NonNullable<el['date']>)[date as string])) { (this.#el.date as NonNullable<el['date']>)[date as string] = {}; }
150
+
151
+ (this.#el.date as NonNullable<el['date']>)[date as string][state] = el;
152
+ break;
153
+ }
154
+ }
155
+ }
156
+
157
+ /** `#radio`에 type이 'radio'인 Element를 담는다. */
158
+ #setRadio(
159
+ el: InputElement
160
+ ): void {
161
+ const required = el.getAttribute('required');
162
+
163
+ if (!JUtil.empty(required)) {
164
+ if (JUtil.empty(this.#radio[required as string])) {
165
+ this.#radio[required as string] = [el];
166
+ } else { this.#radio[required as string].push(el); }
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Element들을 validation check 한다.
172
+ * ```
173
+ * -----------------------
174
+ * date : isDate
175
+ * -----------------------
176
+ * el : isPattern
177
+ * ```
178
+ */
179
+ #match(): void {
180
+ for (const i in this.#el) {
181
+ if (this.result.flag) {
182
+ switch (i) {
183
+ case 'date':
184
+ this.#isDate(this.#el[i]);
185
+ break;
186
+ case 'el':
187
+ this.#isPattern(this.#el[i]);
188
+ break;
189
+ }
190
+ } else { break; }
191
+ }
192
+ }
193
+
194
+ /** date check */
195
+ #isDate(
196
+ el: el['date']
197
+ ): void {
198
+ for (const i in el) {
199
+ if (this.result.flag) {
200
+ const sdate = (el[i].S as InputElement).value,
201
+ edate = (el[i].E as InputElement).value;
202
+
203
+ if (
204
+ !JUtil.empty(sdate) &&
205
+ !JUtil.empty(edate)
206
+ ) {
207
+ const inputName = (el[i].S as InputElement).dataset['svInputName'] ||
208
+ (el[i].E as InputElement).dataset['svInputName'],
209
+ required = (el[i].S as InputElement).getAttribute('required') ||
210
+ (el[i].E as InputElement).getAttribute('required');
211
+
212
+ if ((new Date(sdate)).getTime() > (new Date(edate)).getTime()) {
213
+ this.result.flag = false;
214
+ this.result.alertMsg = `'${inputName || required}'의 시작일이 종료일 보다 늦습니다.`;
215
+ this.result.el = el[i].S as InputElement;
216
+ }
217
+ }
218
+ } else { break; }
219
+ }
220
+ }
221
+
222
+ /** regex check */
223
+ #isPattern(
224
+ el: el['el'] | InputElement
225
+ ): void {
226
+ if (Array.isArray(el)) {
227
+ for (const i of el) {
228
+ const pattern = i.dataset['svPattern'] as string,
229
+ inputName = i.dataset['svInputName'],
230
+ required = i.getAttribute('required'),
231
+ val = i.value;
232
+
233
+ if (Object.keys(this.#regex).includes(pattern)) {
234
+ if (
235
+ !JUtil.empty(val) &&
236
+ !this.#regex[pattern].test(val)
237
+ ) {
238
+ this.result.flag = false;
239
+ this.result.alertMsg = `'${inputName || required}'의 형식이 올바르지 않습니다.`;
240
+ this.result.el = i;
241
+ break;
242
+ }
243
+ }
244
+ }
245
+ } else {
246
+ const pattern = (el as InputElement).dataset['svPattern'] as string,
247
+ inputName = (el as InputElement).dataset['svInputName'],
248
+ required = (el as InputElement).getAttribute('required'),
249
+ val = (el as InputElement).value;
250
+
251
+ if (Object.keys(this.#regex).includes(pattern)) {
252
+ if (
253
+ !JUtil.empty(val) &&
254
+ !this.#regex[pattern].test(val)
255
+ ) {
256
+ this.result.flag = false;
257
+ this.result.alertMsg = `'${inputName || required}'의 형식이 올바르지 않습니다.`;
258
+ this.result.el = el as InputElement;
259
+ }
260
+ }
261
+ }
262
+ }
263
+
264
+ /** Element value의 length를 check 한다. */
265
+ #length(): void {
266
+ for (const i in this.#el) {
267
+ if (
268
+ i == 'el' &&
269
+ this.result.flag
270
+ ) {
271
+ for (const j of (this.#el[i] as NonNullable<el['el']>)) {
272
+ const inputName = j.dataset['svInputName'],
273
+ required = j.getAttribute('required'),
274
+ val = j.value.length;
275
+
276
+ if (!(j instanceof HTMLSelectElement)) {
277
+ if (
278
+ j.minLength >= 0 &&
279
+ j.maxLength >= 0
280
+ ) {
281
+ if (
282
+ val < j.minLength ||
283
+ val > j.maxLength
284
+ ) {
285
+ this.result.flag = false;
286
+ this.result.alertMsg = `'${inputName || required}'은/는 ${j.minLength}~${j.maxLength}자 이내로 입력해주세요.`;
287
+ this.result.el = j;
288
+ break;
289
+ }
290
+ } else if (
291
+ j.minLength >= 0 &&
292
+ j.maxLength < 0
293
+ ) {
294
+ if (val < j.minLength) {
295
+ this.result.flag = false;
296
+ this.result.alertMsg = `'${inputName || required}'은/는 ${j.minLength}자 이상으로 입력해주세요.`;
297
+ this.result.el = j;
298
+ break;
299
+ }
300
+ } else if (
301
+ j.minLength < 0 &&
302
+ j.maxLength >= 0
303
+ ) {
304
+ if (val > j.maxLength) {
305
+ this.result.flag = false;
306
+ this.result.alertMsg = `'${inputName || required}'은/는 ${j.maxLength}자 이하로 입력해주세요.`;
307
+ this.result.el = j;
308
+ break;
309
+ }
310
+ }
311
+ }
312
+ }
313
+ } else if (!this.result.flag) { break; }
314
+ }
315
+ }
316
+
317
+ /** validation을 실행한다. */
318
+ run(
319
+ form: HTMLFormElement
320
+ ): void {
321
+ this.init();
322
+
323
+ for (const el of form.elements) {
324
+ if (this.result.flag) {
325
+ if (['INPUT', 'SELECT', 'TEXTAREA'].includes(el.tagName)) {
326
+ if (!(el as InputElement).disabled) {
327
+ this.#required(el as InputElement);
328
+ this.#setEl(el as InputElement);
329
+ }
330
+ }
331
+ } else { break; }
332
+ }
333
+
334
+ if (this.result.flag) { this.#requiredRadio(); }
335
+
336
+ if (this.result.flag) { this.#match(); }
337
+
338
+ if (this.result.flag) { this.#length(); }
339
+ }
340
+
341
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "typeRoots": ["@types"],
4
+ "checkJs": true,
5
+ "strictNullChecks": false,
6
+ "noPropertyAccessFromIndexSignature": true,
7
+ "noUncheckedIndexedAccess": true,
8
+ "moduleResolution": "node",
9
+ "useDefineForClassFields": true,
10
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
11
+ "target": "ESNext",
12
+ "declaration": true,
13
+ "outDir": "dist"
14
+ },
15
+ "include": [
16
+ "src/index.ts"
17
+ ]
18
+ }