@nuka9510/simple-validation 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,38 +4,46 @@ import Phase from "./enums/phase.js";
4
4
  * Validation Check를 위한 객체
5
5
  */
6
6
  export default class Validation {
7
- /** 결과 값 객체 */
8
7
  result;
9
- /** validation check할 Element를 담는 객체 */
10
- #el;
11
- /** validation check할 radio Element를 담는 객체 */
8
+ #input;
9
+ #date;
10
+ #checkbox;
12
11
  #radio;
13
- /** validation check에 사용할 정규식을 담은 객체 */
14
12
  #regex;
15
13
  /**
16
14
  * Validation Check를 위한 객체
17
15
  *
18
16
  * ```
19
17
  * <form name="form">
20
- * <input type="text" name="text" data-sv-pattern="password" data-sv-input-name="비밀번호" minlength="0" maxlength="10">
21
- * <input type="text" name="text" data-sv-pattern="password" minlength="0" maxlength="10" required="비밀번호">
22
- * <input type="date" name="sdate1" data-sv-date="date1" data-sv-date-state="S" data-sv-input-name="검색일1">
23
- * <input type="date" name="edate1" data-sv-date="date1" data-sv-date-state="E" data-sv-input-name="검색일1">
24
- * <input type="date" name="sdate2" data-sv-date="date2" data-sv-date-state="S" required="검색일2">
25
- * <input type="date" name="edate2" data-sv-date="date2" data-sv-date-state="E" required="검색일2">
18
+ * <input type="text" name="text" minlength="0" maxlength="10" data-sv-pattern="password" data-sv-input="비밀번호">
19
+ * <input type="text" name="text" minlength="0" maxlength="10" data-sv-pattern="password" required="비밀번호">
20
+ *
21
+ * <input type="date" name="sdate1" data-sv-name="date1" data-sv-state="S" data-sv-date="검색일1">
22
+ * <input type="date" name="edate1" data-sv-name="date1" data-sv-state="E" data-sv-date="검색일1">
23
+ * <input type="date" name="sdate2" data-sv-name="date2" data-sv-state="S" required="검색일2">
24
+ * <input type="date" name="edate2" data-sv-name="date2" data-sv-state="E" required="검색일2">
25
+ *
26
+ * <input type="checkbox" data-sv-name="checkbox1" required="옵션">
27
+ * <input type="checkbox" data-sv-name="checkbox1" required="옵션">
28
+ * <input type="checkbox" name="checkbox2" required="옵션">
29
+ * <input type="checkbox" name="checkbox2" required="옵션">
30
+ *
31
+ * <input type="radio" data-sv-name="radio1" required="옵션">
32
+ * <input type="radio" data-sv-name="radio1" required="옵션">
33
+ * <input type="radio" name="radio2" required="옵션">
34
+ * <input type="radio" name="radio2" required="옵션">
26
35
  * </form>
27
36
  * <script type="importmap">
28
37
  * {
29
38
  * "imports": {
30
- * "@nuka9510/js-util": "https://cdn.jsdelivr.net/npm/@nuka9510/js-util/dist/index.js",
31
- * "@nuka9510/simple-validation": "https://cdn.jsdelivr.net/npm/@nuka9510/simple-validation/dist/index.js"
39
+ * "@nuka9510/simple-validation": "https://cdn.jsdelivr.net/npm/@nuka9510/simple-validation/dist/esm/index.min.mjs"
32
40
  * }
33
41
  * }
34
42
  * </script>
35
43
  * <script type="module">
36
- * import { SValidation } from "@nuka9510/simple-validation";
44
+ * import { Validation } from "@nuka9510/simple-validation";
37
45
  *
38
- * const validation = new SValidation({regex: {password: /^[\S!?@#$%^&*():;+-=~{}<>\_\[\]\|\\\"\'\,\.\/\`]{6,10}$/}});
46
+ * const validation = new Validation({regex: {password: /^[\S!?@#$%^&*():;+-=~{}<>\_\[\]\|\\\"\'\,\.\/\`]{6,10}$/}});
39
47
  *
40
48
  * validation.run(form);
41
49
  *
@@ -48,16 +56,16 @@ export default class Validation {
48
56
  * </script>
49
57
  * ```
50
58
  */
51
- constructor(config) { this.init(config); }
52
- /** 객체 초기화 */
53
- init(
54
- /** validation 초기화를 위한 객체 */ config = null) {
59
+ constructor(
60
+ /** validation 초기화를 위한 객체 */ config) { this.#init(config); }
61
+ #init(config = null) {
55
62
  this.#resultInit();
56
- this.#elInit();
63
+ this.#inputInit();
64
+ this.#dateInit();
65
+ this.#checkboxInit();
57
66
  this.#radioInit();
58
67
  this.#regexInit(config?.regex);
59
68
  }
60
- /** 결과 값 초기화 */
61
69
  #resultInit() {
62
70
  this.result = {
63
71
  flag: true,
@@ -66,235 +74,272 @@ export default class Validation {
66
74
  phase: Phase.INIT
67
75
  };
68
76
  }
69
- /** validation check할 Element를 담는 객체 초기화 */
70
- #elInit() { this.#el = {}; }
71
- /** validation check할 radio Element를 담는 객체 초기화 */
77
+ #inputInit() { this.#input = []; }
78
+ #dateInit() { this.#date = {}; }
79
+ #checkboxInit() { this.#checkbox = {}; }
72
80
  #radioInit() { this.#radio = {}; }
73
- /** validation check에 사용할 정규식을 담은 객체 초기화 */
74
81
  #regexInit(regex = null) {
75
82
  this.#regex = (!Util.empty(regex) &&
76
83
  Util.isObject(regex))
77
84
  ? {
78
- ...this.#regex,
85
+ ...(this.#regex ?? {}),
79
86
  ...regex
80
87
  }
81
- : { ...this.#regex };
88
+ : { ...(this.#regex ?? {}) };
82
89
  }
83
- /** el 있는 Element들을 required check한다. */
84
- #required(el) {
85
- const required = el.getAttribute('required');
86
- if (!Util.empty(required)) {
87
- if (el.type == 'radio') {
90
+ #setEl(el) {
91
+ const type = el.getAttribute('type');
92
+ switch (type) {
93
+ case 'date':
94
+ case 'time':
95
+ case 'datetime-local':
96
+ case 'month':
97
+ case 'week':
98
+ this.#setDate(el);
99
+ break;
100
+ case 'checkbox':
101
+ this.#setCheckbox(el);
102
+ break;
103
+ case 'radio':
88
104
  this.#setRadio(el);
89
- }
90
- else if (Util.empty(el.value)) {
91
- this.result.flag = false;
92
- this.result.alertMsg = `'${required}'을/를 입력해 주세요.`;
93
- this.result.el = el;
94
- this.result.phase = Phase.REQUIRED;
95
- }
96
- }
97
- }
98
- /** radio에 있는 Element들을 required check한다. */
99
- #requiredRadio() {
100
- for (const i in this.#radio) {
101
- const el = this.#radio[i][0], flag = this.#radio[i].some((...arg) => arg[0].checked);
102
- if (!flag) {
103
- this.result.flag = false;
104
- this.result.alertMsg = `'${i}'을/를 선택해주세요.`;
105
- this.result.el = el;
106
- this.result.phase = Phase.REQUIRED;
107
105
  break;
108
- }
106
+ default:
107
+ this.#setInput(el);
108
+ break;
109
109
  }
110
110
  }
111
- /** el Element를 담는다. */
112
- #setEl(el) {
113
- const pattern = el.dataset['svPattern'], date = el.dataset['svDate'];
114
- if (!Util.empty(pattern)) {
115
- if (Util.empty(this.#el.el)) {
116
- this.#el.el = [];
117
- }
118
- this.#el.el?.push(el);
119
- }
120
- if (!Util.empty(date)) {
121
- const state = el.dataset['svDateState'];
111
+ #setInput(el) { this.#input.push(el); }
112
+ #setDate(el) {
113
+ const name = el.getAttribute('data-sv-name');
114
+ if (!Util.empty(name)) {
115
+ const state = el.getAttribute('data-sv-state');
122
116
  switch (state) {
123
117
  case 'S':
124
118
  case 'E':
125
- if (Util.empty(this.#el.date)) {
126
- this.#el.date = {};
127
- }
128
- if (Util.empty(this.#el.date[date])) {
129
- this.#el.date[date] = {};
119
+ if (Util.empty(this.#date[name])) {
120
+ this.#date[name] = {};
130
121
  }
131
- this.#el.date[date][state] = el;
122
+ this.#date[name][state] = el;
132
123
  break;
124
+ default:
125
+ this.#input.push(el);
126
+ break;
127
+ }
128
+ }
129
+ else {
130
+ this.#input.push(el);
131
+ }
132
+ }
133
+ #setCheckbox(el) {
134
+ const name = el.getAttribute('name') || el.getAttribute('data-sv-name');
135
+ if (!Util.empty(name)) {
136
+ if (Util.empty(this.#checkbox[name])) {
137
+ this.#checkbox[name] = [];
133
138
  }
139
+ this.#checkbox[name].push(el);
134
140
  }
135
141
  }
136
- /** `#radio`에 type이 'radio'인 Element를 담는다. */
137
142
  #setRadio(el) {
138
- const required = el.getAttribute('required');
139
- if (!Util.empty(required)) {
140
- if (Util.empty(this.#radio[required])) {
141
- this.#radio[required] = [el];
143
+ const name = el.getAttribute('name') || el.getAttribute('data-sv-name');
144
+ if (!Util.empty(name)) {
145
+ if (Util.empty(this.#radio[name])) {
146
+ this.#radio[name] = [];
142
147
  }
143
- else {
144
- this.#radio[required].push(el);
148
+ this.#radio[name].push(el);
149
+ }
150
+ }
151
+ #requiredEl() {
152
+ if (this.result.flag) {
153
+ this.#requiredInput();
154
+ }
155
+ if (this.result.flag) {
156
+ this.#requiredDate();
157
+ }
158
+ if (this.result.flag) {
159
+ this.#requiredCheckbox();
160
+ }
161
+ if (this.result.flag) {
162
+ this.#requiredRadio();
163
+ }
164
+ }
165
+ #requiredInput() {
166
+ for (const input of this.#input) {
167
+ const required = input.getAttribute('required');
168
+ if (!Util.empty(required) &&
169
+ Util.empty(input.value)) {
170
+ this.result = {
171
+ flag: false,
172
+ alertMsg: `'${required}'을/를 입력해 주세요.`,
173
+ el: input,
174
+ phase: Phase.REQUIRED
175
+ };
176
+ break;
145
177
  }
146
178
  }
147
179
  }
148
- /**
149
- * Element들을 validation check 한다.
150
- * ```
151
- * -----------------------
152
- * date : isDate
153
- * -----------------------
154
- * el : isPattern
155
- * ```
156
- */
157
- #match() {
158
- for (const i in this.#el) {
159
- if (this.result.flag) {
160
- switch (i) {
161
- case 'date':
162
- this.#isDate(this.#el[i]);
163
- break;
164
- case 'el':
165
- this.#isPattern(this.#el[i]);
166
- break;
180
+ #requiredDate() {
181
+ for (const name in this.#date) {
182
+ for (const state in this.#date[name]) {
183
+ const date = this.#date[name][state], required = date.getAttribute('required');
184
+ if (!Util.empty(required) &&
185
+ Util.empty(date.value)) {
186
+ this.result = {
187
+ flag: false,
188
+ alertMsg: `'${required}'을/를 입력해 주세요.`,
189
+ el: date,
190
+ phase: Phase.REQUIRED
191
+ };
192
+ break;
167
193
  }
168
194
  }
169
- else {
195
+ }
196
+ }
197
+ #requiredCheckbox() {
198
+ for (const name in this.#checkbox) {
199
+ const checkboxList = this.#checkbox[name].filter((...arg) => !Util.empty(arg[0].getAttribute('required')));
200
+ if (!Util.empty(checkboxList) &&
201
+ checkboxList.some((...arg) => !arg[0].checked)) {
202
+ const checkbox = checkboxList.find((...arg) => !arg[0].checked), required = checkbox.getAttribute('required');
203
+ this.result = {
204
+ flag: false,
205
+ alertMsg: `'${required}'을/를 선택해주세요.`,
206
+ el: checkbox,
207
+ phase: Phase.REQUIRED
208
+ };
170
209
  break;
171
210
  }
172
211
  }
173
212
  }
174
- /** date check */
175
- #isDate(el) {
176
- for (const i in el) {
177
- if (this.result.flag) {
178
- const sdate = el[i].S.value, edate = el[i].E.value;
179
- if (!Util.empty(sdate) &&
180
- !Util.empty(edate)) {
181
- const inputName = el[i].S.dataset['svInputName'] ||
182
- el[i].E.dataset['svInputName'], required = el[i].S.getAttribute('required') ||
183
- el[i].E.getAttribute('required');
184
- if ((new Date(sdate)).getTime() > (new Date(edate)).getTime()) {
185
- this.result.flag = false;
186
- this.result.alertMsg = `'${inputName || required}'의 시작일이 종료일 보다 늦습니다.`;
187
- this.result.el = el[i].S;
188
- this.result.phase = Phase.MATCH;
189
- }
190
- }
191
- }
192
- else {
213
+ #requiredRadio() {
214
+ for (const name in this.#radio) {
215
+ const radioList = this.#radio[name].filter((...arg) => !Util.empty(arg[0].getAttribute('required')));
216
+ if (!Util.empty(radioList) &&
217
+ radioList.every((...arg) => !arg[0].checked)) {
218
+ const radio = radioList.find((...arg) => !arg[0].checked), required = radio.getAttribute('required');
219
+ this.result = {
220
+ flag: false,
221
+ alertMsg: `'${required}'을/를 선택해주세요.`,
222
+ el: radio,
223
+ phase: Phase.REQUIRED
224
+ };
193
225
  break;
194
226
  }
195
227
  }
196
228
  }
197
- /** regex check */
198
- #isPattern(el) {
199
- if (Array.isArray(el)) {
200
- for (const i of el) {
201
- const pattern = i.dataset['svPattern'], inputName = i.dataset['svInputName'], required = i.getAttribute('required'), val = i.value;
202
- if (Object.keys(this.#regex).includes(pattern)) {
203
- if (!Util.empty(val) &&
204
- !this.#regex[pattern].test(val)) {
205
- this.result.flag = false;
206
- this.result.alertMsg = `'${inputName || required}'의 형식이 올바르지 않습니다.`;
207
- this.result.el = i;
208
- this.result.phase = Phase.MATCH;
229
+ #length() {
230
+ for (const input of this.#input) {
231
+ const input_ = input.getAttribute('data-sv-input') || input.getAttribute('required'), length = input.value.length;
232
+ if (!(input instanceof HTMLSelectElement)) {
233
+ if (input.minLength >= 0 &&
234
+ input.maxLength >= 0) {
235
+ if (length < input.minLength ||
236
+ length > input.maxLength) {
237
+ this.result = {
238
+ flag: false,
239
+ alertMsg: `'${input_}'은/는 ${input.minLength}~${input.maxLength}자 이내로 입력해주세요.`,
240
+ el: input,
241
+ phase: Phase.LENGTH
242
+ };
243
+ break;
244
+ }
245
+ }
246
+ else if (input.minLength >= 0 &&
247
+ input.maxLength < 0) {
248
+ if (length < input.minLength) {
249
+ this.result = {
250
+ flag: false,
251
+ alertMsg: `'${input_}'은/는 ${input.minLength}자 이상으로 입력해주세요.`,
252
+ el: input,
253
+ phase: Phase.LENGTH
254
+ };
255
+ break;
256
+ }
257
+ }
258
+ else if (input.minLength < 0 &&
259
+ input.maxLength >= 0) {
260
+ if (length > input.maxLength) {
261
+ this.result = {
262
+ flag: false,
263
+ alertMsg: `'${input_}'은/는 ${input.maxLength}자 이하로 입력해주세요.`,
264
+ el: input,
265
+ phase: Phase.LENGTH
266
+ };
209
267
  break;
210
268
  }
211
269
  }
212
270
  }
213
271
  }
214
- else {
215
- const pattern = el.dataset['svPattern'], inputName = el.dataset['svInputName'], required = el.getAttribute('required'), val = el.value;
216
- if (Object.keys(this.#regex).includes(pattern)) {
217
- if (!Util.empty(val) &&
218
- !this.#regex[pattern].test(val)) {
219
- this.result.flag = false;
220
- this.result.alertMsg = `'${inputName || required}'의 형식이 올바르지 않습니다.`;
221
- this.result.el = el;
222
- this.result.phase = Phase.MATCH;
272
+ }
273
+ #match(regex) {
274
+ if (this.result.flag) {
275
+ this.#isPattern(regex);
276
+ }
277
+ if (this.result.flag) {
278
+ this.#isDate();
279
+ }
280
+ }
281
+ #isPattern(regex = null) {
282
+ const regex_ = {
283
+ ...this.#regex,
284
+ ...(regex ?? {})
285
+ };
286
+ for (const input of this.#input) {
287
+ const pattern = input.getAttribute('data-sv-pattern');
288
+ if (Object.keys(regex_).includes(pattern)) {
289
+ const input_ = input.getAttribute('data-sv-input') || input.getAttribute('required'), value = input.value;
290
+ if (!Util.empty(value) &&
291
+ !regex_[pattern].test(value)) {
292
+ this.result = {
293
+ flag: false,
294
+ alertMsg: `'${input_}'의 형식이 올바르지 않습니다.`,
295
+ el: input,
296
+ phase: Phase.MATCH
297
+ };
298
+ break;
223
299
  }
224
300
  }
225
301
  }
226
302
  }
227
- /** Element value의 length를 check 한다. */
228
- #length() {
229
- for (const i in this.#el) {
230
- if (i == 'el' &&
231
- this.result.flag) {
232
- for (const j of this.#el[i]) {
233
- const inputName = j.dataset['svInputName'], required = j.getAttribute('required'), val = j.value.length;
234
- if (!(j instanceof HTMLSelectElement)) {
235
- if (j.minLength >= 0 &&
236
- j.maxLength >= 0) {
237
- if (val < j.minLength ||
238
- val > j.maxLength) {
239
- this.result.flag = false;
240
- this.result.alertMsg = `'${inputName || required}'은/는 ${j.minLength}~${j.maxLength}자 이내로 입력해주세요.`;
241
- this.result.el = j;
242
- this.result.phase = Phase.LENGTH;
243
- break;
244
- }
245
- }
246
- else if (j.minLength >= 0 &&
247
- j.maxLength < 0) {
248
- if (val < j.minLength) {
249
- this.result.flag = false;
250
- this.result.alertMsg = `'${inputName || required}'은/는 ${j.minLength}자 이상으로 입력해주세요.`;
251
- this.result.el = j;
252
- this.result.phase = Phase.LENGTH;
253
- break;
254
- }
255
- }
256
- else if (j.minLength < 0 &&
257
- j.maxLength >= 0) {
258
- if (val > j.maxLength) {
259
- this.result.flag = false;
260
- this.result.alertMsg = `'${inputName || required}'은/는 ${j.maxLength}자 이하로 입력해주세요.`;
261
- this.result.el = j;
262
- this.result.phase = Phase.LENGTH;
263
- break;
264
- }
265
- }
266
- }
303
+ #isDate() {
304
+ for (const name in this.#date) {
305
+ const date = this.#date[name], sdate = date.S, edate = date.E;
306
+ if (!Util.empty(sdate) &&
307
+ !Util.empty(edate)) {
308
+ const input_ = sdate.getAttribute('data-sv-date') ||
309
+ edate.getAttribute('data-sv-date') ||
310
+ sdate.getAttribute('required') ||
311
+ edate.getAttribute('required');
312
+ if (sdate.valueAsNumber > edate.valueAsNumber) {
313
+ this.result = {
314
+ flag: false,
315
+ alertMsg: `'${input_}'의 시작일이 종료일 보다 늦습니다.`,
316
+ el: sdate,
317
+ phase: Phase.MATCH
318
+ };
319
+ break;
267
320
  }
268
321
  }
269
- else if (!this.result.flag) {
270
- break;
271
- }
272
322
  }
273
323
  }
274
324
  /** validation을 실행한다. */
275
- run(form) {
276
- this.init();
325
+ run(form,
326
+ /** validation 추가 설정*/ config) {
327
+ this.#init();
277
328
  for (const el of form.elements) {
278
- if (this.result.flag) {
279
- if (['INPUT', 'SELECT', 'TEXTAREA'].includes(el.tagName)) {
280
- if (!el.disabled) {
281
- this.#required(el);
282
- this.#setEl(el);
283
- }
329
+ if (['INPUT', 'SELECT', 'TEXTAREA'].includes(el.tagName)) {
330
+ if (!el.disabled) {
331
+ this.#setEl(el);
284
332
  }
285
333
  }
286
- else {
287
- break;
288
- }
289
334
  }
290
335
  if (this.result.flag) {
291
- this.#requiredRadio();
336
+ this.#requiredEl();
292
337
  }
293
338
  if (this.result.flag) {
294
- this.#match();
339
+ this.#length();
295
340
  }
296
341
  if (this.result.flag) {
297
- this.#length();
342
+ this.#match(config?.regex);
298
343
  }
299
344
  if (this.result.flag) {
300
345
  this.result.phase = Phase.DONE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuka9510/simple-validation",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "simple validation util for web front-end",
5
5
  "type": "module",
6
6
  "exports": {