@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.
- package/@types/validation.d.ts +43 -0
- package/LICENSE +21 -0
- package/README.md +88 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/validation.d.ts +48 -0
- package/dist/validation.js +287 -0
- package/package.json +31 -0
- package/src/index.ts +3 -0
- package/src/validation.ts +341 -0
- package/tsconfig.json +18 -0
|
@@ -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
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -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,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
|
+
}
|