@frikimirinda/picture 1.0.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.
package/src/picture.js ADDED
@@ -0,0 +1,1167 @@
1
+ /**
2
+ * picture.js
3
+ * A powerful JavaScript class for formatting, deformatting, and validating data using "picture strings"
4
+ * (compact format descriptors for strings, numbers, dates, times, and patterns).
5
+ *
6
+ * Picture is a static-only JavaScript class. All methods are called directly on the class, no instantiation needed.
7
+ * It provides three core capabilities:
8
+ *
9
+ * 1. Formatting — Transform raw data into display-ready strings.
10
+ * 2. Deformatting — Extract raw data back from formatted strings.
11
+ * 3. Validation — Check whether a value matches the constraints defined by a picture string.
12
+ *
13
+ * Additionally, Picture can bind directly to DOM <input> elements, providing real-time keystroke validation, formatting on blur, and deformatting on focus.
14
+ *
15
+ * You can follow the project on: https://github.com/frikimirinda/picture
16
+ *
17
+ * This class also uses the function NUMBER_FORMAT taken from https://github.com/locutusjs/locutus/tree/main by Kevin van Zonneveld and other authors.
18
+ *
19
+ *
20
+ * This Source Code Form is subject to the terms of the Mozilla Public
21
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
22
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
23
+ *
24
+ */
25
+ export class Picture {
26
+ static version = '1.0.0';
27
+ static re_isPic = /^(?<TYPE>[SNDTEP]){1}(?<FORMAT>.+)/;
28
+ static re_formats = {
29
+ 'S':/^(?<SIZE>[0-9]+)(?<CASE>[ULCA]?)(~REAC~(?<REAC>[^~]*))?(~REVA~(?<REVA>[^~]*))?(~RETY~(?<RETY>[^~]*))?/,
30
+ 'N':/^(?<CURRENCY>[$€£¥%]?|(~.{1,10}~)?)(?<CURRENCY_POS>\<|\>?)(?<THOUSANDS_SEP>[,\._]?)(?<SIGN>[\[\(+-]?)(?<SIGN_POS>\<|\>?)(?<FILL>[0_\*]?)(?<SIZE>[0-9]{1,})(?<DECIMALS_SEP>[,\._]?)(?<DECIMALS>[0-9]*)(?<BLANK_IF_ZERO>B?)(?<ALIGN>[LCR]?)/,
31
+ 'D':/^(?<FORMAT>[0-9]+|.+)(?<SEPARATOR>[\/,\-\.\_]?)/,
32
+ 'T':/^(?<FORMAT>[0-9]+|.+)(?<SEPARATOR>[:,\-\.\_]?)/,
33
+ 'I':/^(?<PARAM1>(?<DATEORTIME1>[DT]{1})(?<FORMAT1>[0-9]+)(?<SEPARATOR1>[:,\/\-\.\_]?)){1}(?<SEPARATOR>.*)(?<PARAM2>(?<DATEORTIME2>[DT]{1})(?<FORMAT2>[0-9]+)(?<SEPARATOR2>[:,\/\-\.\_]?)){1}/,
34
+ 'P':/^(?<FORMAT>.*)/
35
+ };
36
+ /*
37
+ The date format is the same as in PHP:
38
+ d Day of the month with leading zeros 01-31
39
+ j Day of the month without leading zeros 1-31
40
+ m Month number with leading zeros 01-12
41
+ n Month number without zeros 1-12
42
+ Y Year with 4 digits
43
+ y Year with 2 digits
44
+ z Day of the year 0-365
45
+ D Day of the week Sun(0)=>Sat(6)
46
+ l Day of the week Sunday(0)=>Saturday(6)
47
+ N Day of the week 1 (Monday)=>7 (Sunday)
48
+ w Day of the week 0 (Sun)=>6 (Sat)
49
+ W Week of the year
50
+ F Full name of the month
51
+ M Name of the month (Jan)=>(Dec)
52
+ t Number of days in the given month 28=>31
53
+ L (1) If it is a leap year
54
+ To inject text, put it in "~" for example ~week~ (0126)
55
+
56
+ El formato de fechas es el mismo que en PHP:
57
+ d Día del mes con ceros por la izquierda 01-31
58
+ j Día del mes sin ceros iniciales 1-31
59
+ m Número del mes con cero por la izquierda 01-12
60
+ n Número del mes sin ceros 1-12
61
+ Y Año con 4 dígitos
62
+ y Año con 2 dígitos
63
+ z Día del año 0-365
64
+ D Día de la semana Sun(0)=>Sat(6)
65
+ l Día de la semana Sunday(0)=>Saturday(6)
66
+ N Día de la semana 1(lunes)=>7(domingo)
67
+ w Día de la semana 0(Sun)=>6(Sat)
68
+ W Semana del año
69
+ F Nombre completo del mes
70
+ M Nombre del mes (Ene)=>(Dic)
71
+ t Número de días del mes dado 28=>31
72
+ L (1)Si es un año bisiesto
73
+ Para inyectar texto ponerlo entre "~" por ejemplo ~semana~ (0126)
74
+ */
75
+ static re_date = {
76
+ '1':{'FORMAT':'d/m/Y'},
77
+ '2':{'FORMAT':'d/m/y'},
78
+ '3':{'FORMAT':'m/d/Y'},
79
+ '4':{'FORMAT':'m/d/y'},
80
+ '5':{'FORMAT':'Y/m/d'},
81
+ '6':{'FORMAT':'Y/d/m'},
82
+ '7':{'FORMAT':"l d ~d~e F ~d~e Y"},
83
+ '8':{'FORMAT':"l d ~d~e F Y ~(semana ~W)"},
84
+ '9':{'FORMAT':"F j, Y"},
85
+ '10':{'FORMAT':"j F Y"},
86
+ '11':{'FORMAT':"l, F j, Y"},
87
+ };
88
+
89
+ static re_date_formats = {
90
+ 'd':'(?<DAY1>[0-3]{1})(?<DAY2>[0-9]{1})',
91
+ 'm':'(?<MONTH1>[0-1]{1})(?<MONTH2>[0-9]{1})',
92
+ 'Y':'(?<YEAR>[0-9]{4})'
93
+ };
94
+
95
+ static re_time = {
96
+ '1':{'FORMAT':'H:i:s'},
97
+ '2':{'FORMAT':'H:i'},
98
+ };
99
+ static re_time_formats = {
100
+ 'H':'(?<HOUR>[0-2]{1})(?<HOUR2>[0-9]{1})',
101
+ 'i':'(?<MIN1>[0-5]{1})(?<MIN2>[0-9]{1})',
102
+ 's':'(?<SEC1>[0-5]{1})(?<SEC2>[0-9]{1})'
103
+ };
104
+ static CURRENCY_POS = '>';
105
+ static THOUSANDS_SEP = '';
106
+ static DECIMALS_SEP = ',';
107
+ static SIGN = '-';
108
+ static SIGN_POS = '<';
109
+ static DATE_SEPARATOR = '/';
110
+ static TIME_SEPARATOR = ':';
111
+ static DATE_CONFIG = {
112
+ 'EN':{
113
+ 'D':['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
114
+ 'l':['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
115
+ 'N':[1,2,3,4,5,6,7],
116
+ 'w':[0,1,2,3,4,5,6],
117
+ 'F':['January','February','March','April','May','June','July','August','September','October','November','December'],
118
+ 'M':['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
119
+ },
120
+ 'ES':{
121
+ 'D':['Dom','Lun','Mar','Mie','Jue','Vie','Sáb'],
122
+ 'l':['Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado'],
123
+ 'N':[7,1,2,3,4,5,6],
124
+ 'w':[0,1,2,3,4,5,6],
125
+ 'F':['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'],
126
+ 'M':['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic'],
127
+ }
128
+ };
129
+ static DATE_LNG = 'ES';
130
+ static STRING_LNG = 'ES';
131
+ // For the Patterns
132
+ static STRING = {
133
+ 'EN':{
134
+ 'a':'a-z',
135
+ 'A':'A-Z',
136
+ },
137
+ 'ES': {
138
+ 'a':'a-zñ',
139
+ 'A':'A-ZÑ',
140
+ }
141
+ }
142
+
143
+ // Get picture info
144
+ static picInfo(picture){
145
+ return this.getData(picture);
146
+ }
147
+ // Format a value
148
+ static format(data,picture){
149
+ picture = this.getData(picture);
150
+ if(!picture) return false;
151
+ return this[ 'format_'+picture.TYPE ](data,picture);
152
+ }
153
+ // Return the value without the format
154
+ static deformat( data, picture ){
155
+ picture = this.getData(picture);
156
+ if(!picture) return false;
157
+ return this[ 'deformat_'+picture.TYPE ](data,picture);
158
+ }
159
+ // Capitalize a string (if all==null only capitalize the first word)
160
+ static capitalize(s,all){
161
+ if(all==null) return s.charAt(0).toUpperCase()+s.slice(1);
162
+ return s.replace(/\b\w/g, function(l){ return l.toUpperCase() })
163
+ }
164
+ // Remove padding from the left
165
+ static removeFill( data, picture ){
166
+ picture = this.getData(picture);
167
+ if(!picture) return false;
168
+ if( picture.FILL!='' )
169
+ return data.replace( new RegExp("^"+picture.FILL+"+"), '')*1;
170
+ return data*1;
171
+ }
172
+ // Test if a value is valid
173
+ static isValid( data, picture ){
174
+ picture = this.getData(picture);
175
+ if(!picture) return false;
176
+ return picture.PATTERNVALRE.test(data);
177
+ }
178
+
179
+
180
+
181
+ static getData(picture){
182
+ if( !this.re_isPic.test(picture) ) return false;
183
+ let r0 = this.re_isPic.exec(picture);
184
+ let groups=null;
185
+ try{
186
+ groups = this.re_formats[ r0.groups.TYPE ].exec( r0.groups.FORMAT ).groups;
187
+ groups.TYPE = r0.groups.TYPE;
188
+ groups.PICTURE = picture;
189
+ if(groups.TYPE=='x' && groups.REAC||null!=null ){
190
+ groups.PATTERN = groups.REAC;
191
+ groups.PATTERNRE = new RegExp( groups.PATTERN );
192
+ groups.PATTERNVAL = '^'+groups.REVA+'{,'+groups.SIZE+'}$';
193
+ groups.PATTERNVALRE = new RegExp( groups.PATTERNVAL );
194
+ groups.PATTERNTYPING = groups.RETY;
195
+ groups.PATTERNTYPINGRE = new RegExp( groups.PATTERNTYPING );
196
+ }else if(groups.TYPE=='P'){
197
+ let tp = this[ 'getTypingRexExp_'+groups.TYPE ]( groups );
198
+ groups.PATTERN = this[ 'getAllowedChars_'+groups.TYPE ]( groups ); // all the characters that the field can have
199
+ groups.PATTERNRE = new RegExp( groups.PATTERN );
200
+ groups.PATTERNVALRE = groups.PATTERNRE;
201
+ groups.PATTERNTYPING = tp.PATTERNTYPING; // while the user is typing, what can be pressed
202
+ groups.PATTERNTYPINGRE = new RegExp( groups.PATTERNTYPING );
203
+ groups.TYPINGARRAY = tp.TYPINGARRAY;
204
+ groups.TYPINGARRAY2 = tp.TYPINGARRAY2;
205
+ groups.TYPINGARRAYRE = tp.TYPINGARRAYRE;
206
+ }else{
207
+ groups.PATTERN = this[ 'getAllowedChars_'+groups.TYPE ]( groups ); // all the characters that the field can have
208
+ groups.PATTERNVAL = this[ 'getValidationRexExp_'+groups.TYPE ]( groups ); // regular exp when leaving the field to validate the content
209
+ groups.PATTERNTYPING = this[ 'getTypingRexExp_'+groups.TYPE ]( groups ); // while the user is typing, what can be pressed
210
+ groups.PATTERNTYPINGRE = new RegExp( groups.PATTERNTYPING );
211
+ groups.PATTERNRE = new RegExp( groups.PATTERN );
212
+ groups.PATTERNVALRE = new RegExp( groups.PATTERNVAL );
213
+ }
214
+ if( groups.TYPE=='D' ){
215
+ if( this.re_date[groups.FORMAT]==undefined ){
216
+ groups.re_date = {'FORMAT':groups.FORMAT};
217
+ groups.SEPARATOR= null;
218
+ }else{
219
+ groups.re_date = this.re_date[groups.FORMAT];
220
+ if( groups.SEPARATOR=='' ) groups.SEPARATOR=this.DATE_SEPARATOR;
221
+ }
222
+ }else if( groups.TYPE=='T' ){
223
+ if( this.re_time[groups.FORMAT]==undefined ){
224
+ groups.re_time = {'FORMAT':groups.FORMAT};
225
+ groups.SEPARATOR= null;
226
+ }else{
227
+ groups.re_time = this.re_time[groups.FORMAT];
228
+ if( groups.SEPARATOR=='' ) groups.SEPARATOR=this.TIME_SEPARATOR;
229
+ }
230
+ }
231
+ }catch(e){
232
+ console.log('Picture getData error: '+picture+' => '+e.message);
233
+ return false;
234
+ }
235
+ return groups;
236
+ }
237
+
238
+
239
+ /* --------------------------------------------------------------------------
240
+ TYPE => N Number
241
+ -------------------------------------------------------------------------- */
242
+ static format_N( data, pic ){
243
+ pic.THOUSANDS_SEP = ( pic.THOUSANDS_SEP=='' )? this.THOUSANDS_SEP : pic.THOUSANDS_SEP;
244
+ pic.DECIMALS_SEP = ( pic.DECIMALS_SEP =='' )? this.DECIMALS_SEP : pic.DECIMALS_SEP;
245
+ pic.DECIMALS = ( pic.DECIMALS =='' )? 0 : pic.DECIMALS;
246
+ pic.SIGN = ( pic.SIGN =='' )? this.SIGN : pic.SIGN;
247
+ pic.SIGN_POS = ( pic.SIGN_POS=='' )? this.SIGN_POS : pic.SIGN_POS;
248
+ if( pic.SIGN!='' && pic.SIGN_POS=='>' && (data+'').indexOf('-')>-1 ){
249
+ data = (data+'').replace(/\-/,'');
250
+ data = Number(data)*-1;
251
+ }
252
+ if( pic.BLANK_IF_ZERO=='B' && data==0 ) return '';
253
+ let v = this.number_format( data, pic.DECIMALS, pic.DECIMALS_SEP, pic.THOUSANDS_SEP );
254
+ // FILL - Fill from the left
255
+ if( pic.FILL!='' ){
256
+ let f =( pic.THOUSANDS_SEP=='' )? 0 : (v.match(new RegExp( "\\"+pic.THOUSANDS_SEP, "g")) || []).length;
257
+ f+=( pic.DECIMALS_SEP=='' )? 0 : (v.match(new RegExp( "\\"+pic.DECIMALS_SEP, "g")) || []).length;
258
+ v = v.padStart( Number(pic.SIZE)+f, pic.FILL );
259
+ }else{
260
+ v = this.number_format( data, pic.DECIMALS, pic.DECIMALS_SEP, pic.THOUSANDS_SEP );
261
+ }
262
+ // SIGN - Negative sign
263
+ if(data<0){
264
+ if( pic.SIGN=='[' ){
265
+ v = v.replace(/\-/,'[');
266
+ v += ']';
267
+ }else if( pic.SIGN=='(' ){
268
+ v = v.replace(/\-/,'(');
269
+ v += ')';
270
+ }else if( pic.SIGN=='+' ){
271
+ v = v.replace(/\-/,'');
272
+ }else if( pic.SIGN_POS=='>' ){
273
+ v = v.replace(/\-/,'');
274
+ v += pic.SIGN;
275
+ }
276
+ }
277
+ // CURRENCY
278
+ if( pic.CURRENCY!='' ){
279
+ pic.CURRENCY_POS = ( pic.CURRENCY_POS=='' )? this.CURRENCY_POS : pic.CURRENCY_POS;
280
+ pic.CURRENCY = pic.CURRENCY.replace(/~/g,'');
281
+ v = ( pic.CURRENCY_POS=='>' )? (v+pic.CURRENCY+'') : (pic.CURRENCY+v+'');
282
+ }
283
+ return v;
284
+ }
285
+ static deformat_N( data, pic ){
286
+ let v=data+'';
287
+ // Currency
288
+ if( pic.CURRENCY!='' ){
289
+ pic.CURRENCY = pic.CURRENCY.replace(/~/g,'');
290
+ v = data.replace(pic.CURRENCY,'');
291
+ }
292
+ // Negative sign
293
+ pic.SIGN = ( pic.SIGN =='' )? this.SIGN : pic.SIGN;
294
+ pic.SIGN_POS = ( pic.SIGN_POS=='' )? this.SIGN_POS : pic.SIGN_POS;
295
+ v = v.replace(/\]|\)/g,'');
296
+ v = v.replace(/\[|\(/g,'-');
297
+ if( v.indexOf('-')>-1 && pic.SIGN_POS=='>' ){
298
+ v = v.replace('-','');
299
+ v = '-'+v;
300
+ }
301
+ pic.THOUSANDS_SEP = ( pic.THOUSANDS_SEP=='' )? this.THOUSANDS_SEP : pic.THOUSANDS_SEP;
302
+ pic.DECIMALS_SEP = ( pic.DECIMALS_SEP =='' )? this.DECIMALS_SEP : pic.DECIMALS_SEP;
303
+ pic.DECIMALS = ( pic.DECIMALS =='' )? 0 : pic.DECIMALS;
304
+ // Thousands and decimals
305
+ if( pic.DECIMALS_SEP!='' ) v = v.replace( new RegExp('\\'+pic.DECIMALS_SEP, 'g'), '~');
306
+ if( pic.THOUSANDS_SEP!='' ) v = v.replace( new RegExp('\\'+pic.THOUSANDS_SEP,'g'), '');
307
+ v = v.replace( new RegExp('~+','g') ,'.');
308
+ // If it has padding on the left it is returned as is
309
+ if( pic.FILL!='' ){
310
+ v = v.replace( new RegExp('[0\_\*]+','g') ,'');
311
+ return v;
312
+ }
313
+ // Since it is a number, a number is returned
314
+ return Number(v);
315
+ }
316
+ // Obtain RegExp that is used to validate each key pressed in OnKeyPress (the characters that can be typed)
317
+ static getAllowedChars_N(pic){
318
+ let r = '0-9';
319
+ pic.SIGN = ( pic.SIGN =='' )? this.SIGN : pic.SIGN;
320
+ if( pic.SIGN!='' && pic.SIGN!='+' )
321
+ r += "\\-";
322
+ if( pic.DECIMALS!=0 )
323
+ r += '\\.';
324
+ return '['+r+']';
325
+ }
326
+ // Obtain RegExp that is used to validate the data in OnChange
327
+ static getValidationRexExp_N(pic){
328
+ let r = '^';
329
+ let e = '$';
330
+ pic.SIGN = ( pic.SIGN =='' )? this.SIGN : pic.SIGN;
331
+ pic.SIGN_POS = ( pic.SIGN_POS=='' )? this.SIGN_POS : pic.SIGN_POS;
332
+ if( pic.SIGN!='' && pic.SIGN!='+' ){
333
+ if( pic.SIGN_POS=='>' ){
334
+ e = '\\-?$';
335
+ }else{
336
+ r = "^\\-?";
337
+ }
338
+ }
339
+ if( pic.DECIMALS!=0 ){
340
+ let enteros = pic.SIZE - pic.DECIMALS;
341
+ r += '(([0-9]{0,'+enteros+'}\\.{1}[0-9]{0,'+pic.DECIMALS+'})|([0-9]{0,'+enteros+'})|(\\.{1}[0-9]{0,'+pic.DECIMALS+'}))' + e;
342
+ }else{
343
+ r += '[0-9]{0,'+pic.SIZE+'}'+e;
344
+ }
345
+ return r;
346
+ }
347
+ // Obtain RegExp that is used to validate the data in OnKeypress
348
+ static getTypingRexExp_N(pic){
349
+ let r = '';
350
+ let e = '';
351
+ pic.SIGN = ( pic.SIGN =='' )? this.SIGN : pic.SIGN;
352
+ pic.SIGN_POS = ( pic.SIGN_POS=='' )? this.SIGN_POS : pic.SIGN_POS;
353
+ if( pic.SIGN!='' && pic.SIGN!='+' ){
354
+ if( pic.SIGN_POS=='>' ){
355
+ e = '\\-?';
356
+ }else{
357
+ r = "^\\-?";
358
+ }
359
+ }
360
+ if( pic.DECIMALS!=0 ){
361
+ let enteros = pic.SIZE - pic.DECIMALS;
362
+ r += '[0-9]{0,'+enteros+'}\\.?[0-9]{0,'+pic.DECIMALS+'}' + e;
363
+ }else{
364
+ r += '[0-9]{0,'+pic.SIZE+'}'+e;
365
+ }
366
+ return r+'$';
367
+ }
368
+
369
+ /* --------------------------------------------------------------------------
370
+ TYPE => S String
371
+ -------------------------------------------------------------------------- */
372
+ static format_S( data, pic ){
373
+ data+='';
374
+ switch(pic.CASE){
375
+ case 'U':data=data.toUpperCase();break;
376
+ case 'L':data=data.toLowerCase();break;
377
+ case 'C':data=this.capitalize( data.toLowerCase() );break;
378
+ case 'A':data=this.capitalize( data.toLowerCase(),1 );break;
379
+ }
380
+ return data.substring(0,pic.SIZE);
381
+ }
382
+ static deformat_S( data, pic ){
383
+ data+='';
384
+ switch(pic.CASE){
385
+ case 'U': data=data.toUpperCase();break;
386
+ case 'L': data=data.toLowerCase();break;
387
+ case 'C': data=this.capitalize( data.toLowerCase() );break;
388
+ case 'A': data=this.capitalize( data.toLowerCase(),1 );break;
389
+ }
390
+ return String(data);
391
+ }
392
+ // Obtain RegExp that is used to validate each key pressed in OnKeyPress (the characters that can be typed)
393
+ static getAllowedChars_S(pic){
394
+ if(pic.REAC||null!==null)return pic.REAC;
395
+ return '.';
396
+ }
397
+ // Obtain RegExp that is used to validate the data in OnChange
398
+ static getValidationRexExp_S(pic){
399
+ if( pic.REVA||null!=null)return '^'+pic.REVA+'$';
400
+ return '^.{0,'+pic.SIZE+'}$';
401
+ }
402
+ // Obtain RegExp that is used to validate the data in OnKeypress
403
+ static getTypingRexExp_S(pic){
404
+ if( pic.RETY||null!=null)return '^'+pic.REAC+'$';
405
+ return '^.{0,'+pic.SIZE+'}$';
406
+ }
407
+
408
+ /* --------------------------------------------------------------------------
409
+ TYPE => D DATE - ^(?<FORMAT>[0-9]+)(?<SEPARATOR>[\/,\-\.\_]?)
410
+ -------------------------------------------------------------------------- */
411
+ static deformat_D( data, pic ){
412
+ return data+'';
413
+ }
414
+ // ***********************************************************************
415
+ static _format_D_item(item,amd,dia,mes,ano){
416
+ if( /d/.test(item) ) return dia.padStart(2,0); // Day of the month with leading zeros 01-31
417
+ if( /j/.test(item) ) return Number(dia); // Day of the month without leading zeros 1-31
418
+ if( /m/.test(item) ) return mes.padStart(2,0); // Month number with leading zero 01-12
419
+ if( /n/.test(item) ) return Number(mes) // Month number without zeros 1-12
420
+ if( /Y/.test(item) ) return ano; // Year with 4 digits
421
+ if( /y/.test(item) ) return ano.substring(2); // Year with 2 digits
422
+ if( /z/.test(item) ) return this.getDayOfYear(dia,mes); // Day of the year 0-365
423
+ if( /D/.test(item) ) return this.getDayOfWeek(amd,'D'); // Day of the week Sun(0)=>Sat(6)
424
+ if( /l/.test(item) ) return this.getDayOfWeek(amd,'l'); // Day of the week Sunday(0)=>Saturday(6)
425
+ if( /N/.test(item) ) return this.getDayOfWeek(amd,'N'); // Day of the week 1(Monday)=>7(Sunday)
426
+ if( /w/.test(item) ) return this.getDayOfWeek(amd,'w'); // Day of the week 0(Sun)=>6(Sat)
427
+ if( /W/.test(item) ) return this.getWeekOfYear(amd); // Week of the year
428
+ if( /F/.test(item) ) return this.getMonth(amd,'F'); // Full name of the month
429
+ if( /M/.test(item) ) return this.getMonth(amd,'M'); // Short name of the month (Jan)=>(Dec)
430
+ if( /t/.test(item) ) return this.getDaysInMonth(amd); // Number of days in the given month 28=>31
431
+ if( /L/.test(item) ) return Number(this.isLeapYear(ano)); // (1)If it is a leap year
432
+ return item;
433
+ }
434
+ static format_D( data, pic ){
435
+ let v=data+'';
436
+ if(v=='') return '';
437
+ const x=v.split('-');
438
+ let ano=x[0];
439
+ let mes=x[1];
440
+ let dia=x[2];
441
+ const regex = /(?<VAR>[^~])|(?<CONST>(~[^~]*~))/g;
442
+ v='';
443
+ let m=null;
444
+ while ((m = regex.exec(pic.re_date.FORMAT)) !== null) {
445
+ if(m.index === regex.lastIndex)regex.lastIndex++; // avoid infinite loops
446
+ if( m.groups.CONST!=undefined ){
447
+ v += m.groups.CONST.replace(/~/g,'');
448
+ continue;
449
+ }
450
+ if( pic.SEPARATOR!=null && /\//.test(m.groups.VAR) ){
451
+ v+=pic.SEPARATOR;
452
+ continue;
453
+ }
454
+ v+=this._format_D_item(m.groups.VAR,data,dia,mes,ano);
455
+ }
456
+ return String(v);
457
+ }
458
+ // Obtain RegExp that is used to validate each key pressed in OnKeyPress (the characters that can be typed)
459
+ static getAllowedChars_D(pic){
460
+ pic.SEPARATOR = (pic.SEPARATOR=='')?this.DATE_SEPARATOR:pic.SEPARATOR;
461
+ const vali='[0-9·]';
462
+ return vali.replace( new RegExp(/·/,'g'),pic.SEPARATOR);
463
+ }
464
+ // Obtain RegExp that is used to validate the data in OnChange
465
+ static getValidationRexExp_D(pic){
466
+ if(this.re_date[pic.FORMAT]==undefined)return '^.+$';
467
+ let vali=this.re_date[pic.FORMAT].VALIDATION;
468
+ if( vali==undefined ){
469
+ let f=this.re_date[ pic.FORMAT ].FORMAT.split('/');
470
+ vali=new Array();
471
+ for(var x in f)
472
+ vali.push( this.re_date_formats[f[x]] );
473
+ pic.SEPARATOR = (pic.SEPARATOR=='')?this.DATE_SEPARATOR:pic.SEPARATOR;
474
+ vali = '^'+vali.join( pic.SEPARATOR )+'$';
475
+ }
476
+ return vali.replace( new RegExp(/·/,'g'),pic.SEPARATOR);
477
+ }
478
+ // Obtain RegExp that is used to validate the data in OnKeypress
479
+ static getTypingRexExp_D(pic){
480
+ return '';
481
+ }
482
+
483
+
484
+
485
+ /* --------------------------------------------------------------------------
486
+ TYPE => T TIME - ^(?<FORMAT>[0-9]+|.+)(?<SEPARATOR>[:,\-\.\_]?)
487
+ -------------------------------------------------------------------------- */
488
+ static deformat_T( data, pic ){
489
+ return data+'';
490
+ }
491
+ // ***********************************************************************
492
+ static _format_T_item(item,hms,h,m,s){
493
+ if( /a/.test(item) ) return this.getampm(h,m,s); // am or pm (lowercase)
494
+ if( /A/.test(item) ) return this.getAMPM(h,m,s); // AM or PM (in capital letters)
495
+ if( /g/.test(item) ) return (Number(h)%12)||12; // time in 12h format without leading zeros
496
+ if( /G/.test(item) ) return Number(h); // time in 24h format without leading zeros
497
+ if( /g/.test(item) ) return ((Number(h)%12)||12).padStart(2,0); // time in 12h format with leading zeros
498
+ if( /H/.test(item) ) return h.padStart(2,0); // time in 24h format with leading zeros
499
+ if( /i/.test(item) ) return m.padStart(2,0); // minutes with leading zeros
500
+ if( /s/.test(item) ) return s.padStart(2,0); // seconds with leading zeros
501
+ return item;
502
+ }
503
+ static format_T( data, pic ){
504
+ let v=data+'';
505
+ if(v=='') return '';
506
+ let x=v.split(':');
507
+ if(x[0].length>2){
508
+ x[1]=x[0].substring(2);
509
+ x[0]=x[0].substring(0,2);
510
+ }
511
+ const hor=x[0];
512
+ if(x[1].length>2){
513
+ x[2]=x[1].substring(2);
514
+ x[1]=x[1].substring(0,2);
515
+ }
516
+ const min=x[1];
517
+ const seg=x[2]||'00';
518
+ const regex = /(?<VAR>[^~])|(?<CONST>(~[^~]*~))/g;
519
+ v='';
520
+ let m=null;
521
+ while ((m = regex.exec(pic.re_time.FORMAT)) !== null) {
522
+ if(m.index === regex.lastIndex)regex.lastIndex++; // avoid infinite loops
523
+ if( m.groups.CONST!=undefined ){
524
+ v += m.groups.CONST.replace(/~/g,'');
525
+ continue;
526
+ }
527
+ if( pic.SEPARATOR!=null && /:/.test(m.groups.VAR) ){
528
+ v+=pic.SEPARATOR;
529
+ continue;
530
+ }
531
+ v+=this._format_T_item(m.groups.VAR,data,hor,min,seg);
532
+ }
533
+ return String(v);
534
+ }
535
+ // Obtain RegExp that is used to validate each key pressed in OnKeyPress (the characters that can be typed)
536
+ static getAllowedChars_T(pic){
537
+ pic.SEPARATOR = (pic.SEPARATOR=='')?this.TIME_SEPARATOR:pic.SEPARATOR;
538
+ const vali='[0-9·]';
539
+ return vali.replace( new RegExp(/·/,'g'),pic.SEPARATOR);
540
+ }
541
+ // Obtain RegExp that is used to validate the data in OnChange
542
+ static getValidationRexExp_T(pic){
543
+ if(this.re_time[pic.FORMAT]==undefined){
544
+ return '^.+$';
545
+ }
546
+ let vali=this.re_time[pic.FORMAT].VALIDATION;
547
+ if( vali==undefined ){
548
+ let f=this.re_time[ pic.FORMAT ].FORMAT.split(':');
549
+ vali=new Array();
550
+ for(var x in f){
551
+ vali.push( this.re_time_formats[f[x]] );
552
+ }
553
+ pic.SEPARATOR = (pic.SEPARATOR=='')?this.TIME_SEPARATOR:pic.SEPARATOR;
554
+ vali = '^'+vali.join( pic.SEPARATOR )+'$';
555
+ }
556
+ return vali.replace( new RegExp(/·/,'g'),pic.SEPARATOR);
557
+ }
558
+ // Obtener RegExp que sirve para validar el dato en el OnKeypress
559
+ static getTypingRexExp_T(pic){
560
+ return '';
561
+ }
562
+
563
+ /* --------------------------------------------------------------------------
564
+ TYPE => P Pattern
565
+ -------------------------------------------------------------------------- */
566
+ static format_P( data, pic ){
567
+ data+='';
568
+ let ret='',ixdata=0;
569
+ for(var x in pic.TYPINGARRAY){
570
+ if(pic.TYPINGARRAY[x]!=''){
571
+ ret+=pic.TYPINGARRAY[x];
572
+ }else{
573
+ let c=data[ixdata]||'';
574
+ const ta2=pic.TYPINGARRAY2[x];
575
+ if(ta2=='#' && (c=='' ||c==' ') ){
576
+ c='0';
577
+ }else if(ta2=='a' || ta2=='â'){
578
+ c=c.toLowerCase();
579
+ }else if(ta2=='A' || ta2=='Â'){
580
+ c=c.toUpperCase();
581
+ }else if(c!='' && (ta2=='<' || ta2=='#') ){
582
+ if(!Number.isInteger(Number(c)))
583
+ c=' ';
584
+ }
585
+ if(c=='') c=' ';
586
+ ret+=c;
587
+ ixdata+=1;
588
+ }
589
+ }
590
+ return ret;
591
+ }
592
+ // ***********************************************************************
593
+ static deformat_P( data, pic ){
594
+ data+='';
595
+ let ret='';
596
+ for(var x in pic.TYPINGARRAY){
597
+ if(pic.TYPINGARRAY[x]=='')
598
+ ret+=data[x]||'';
599
+ }
600
+ return ret;
601
+ }
602
+ // Obtain RegExp that is used to validate each key pressed in OnKeyPress (the characters that can be typed)
603
+ static escapeRegExp(str){
604
+ return str.replace(/[.*+?^${}()|[\]\\\/\-]/g, '\\$&');
605
+ }
606
+ static getAllowedChars_P(pic){
607
+ let r='',m=null;
608
+ const regex = /(?<VAR>[^~])|(?<CONST>(~[^~]*~))/g;
609
+ while ((m = regex.exec(pic.FORMAT)) !== null) {
610
+ if(m.index === regex.lastIndex)regex.lastIndex++; // avoid infinite loops
611
+ if( m.groups.CONST!=undefined ){
612
+ r += this.escapeRegExp( m.groups.CONST.replace(/~/g,'') );
613
+ continue;
614
+ }
615
+ /*
616
+ for(var x in m.groups.VAR){
617
+ x=m.groups.VAR[x];
618
+ if(x=='<' || x=='#'){
619
+ r += '0-9';
620
+ }else if( x=='A'){
621
+ r += this.STRING[this.STRING_LNG]['A']+' ';
622
+ }else if( x=='Â'){
623
+ r += this.STRING[this.STRING_LNG]['A'];
624
+ }else if( x=='a'){
625
+ r += this.STRING[this.STRING_LNG]['a']+' ';
626
+ }else if( x=='â'){
627
+ r += this.STRING[this.STRING_LNG]['a'];
628
+ }else if( x=='*'){
629
+ r += '.';
630
+ }else{
631
+ r += '\\'+x;
632
+ }
633
+ }
634
+ */
635
+
636
+ for(var x in m.groups.VAR){
637
+ x=m.groups.VAR[x];
638
+ if(x=='<'){
639
+ r += '[0-9 ]?';
640
+ }else if(x=='#'){
641
+ r += '[0-9]';
642
+ }else if( x=='A'){
643
+ r += '['+this.STRING[this.STRING_LNG]['A']+']';
644
+ }else if( x=='Â'){
645
+ r += '['+this.STRING[this.STRING_LNG]['A']+' ]';
646
+ }else if( x=='a'){
647
+ r += '['+this.STRING[this.STRING_LNG]['a']+']';
648
+ }else if( x=='â'){
649
+ r += '['+this.STRING[this.STRING_LNG]['a']+' ]';
650
+ }else if( x=='*'){
651
+ r += '.';
652
+ }else{
653
+ r += '\\'+x;
654
+ }
655
+ }
656
+ }
657
+ return r;
658
+ }
659
+
660
+
661
+ // Obtain RegExp that is used to validate the data in OnChange
662
+ static getValidationRexExp_P(pic){
663
+ let r='',m=null;
664
+ const regex = /(?<VAR>[^~])|(?<CONST>(~[^~]*~))/g;
665
+ while ((m = regex.exec(pic.FORMAT)) !== null) {
666
+ if(m.index === regex.lastIndex)regex.lastIndex++; // avoid infinite loops
667
+ if( m.groups.CONST!=undefined ){
668
+ r += this.escapeRegExp( m.groups.CONST.replace(/~/g,'') );
669
+ continue;
670
+ }
671
+ for(var x in m.groups.VAR){
672
+ x=m.groups.VAR[x];
673
+ if(x=='<'){
674
+ r += '[0-9 ]?';
675
+ }else if( x=='#'){
676
+ r += '[0-9]{1}';
677
+ }else if( x=='A'){
678
+ r += '['+this.STRING[this.STRING_LNG]['A']+' ]{1}';
679
+ }else if( x=='Â'){
680
+ r += '['+this.STRING[this.STRING_LNG]['A']+']{1}';
681
+ }else if( x=='a'){
682
+ r += '['+this.STRING[this.STRING_LNG]['a']+' ]{1}';
683
+ }else if( x=='â'){
684
+ r += '['+this.STRING[this.STRING_LNG]['a']+']{1}';
685
+ }else if( x=='*'){
686
+ r += '.{1}';
687
+ }else{
688
+ r += '\\'+x;
689
+ }
690
+ }
691
+ }
692
+ return '^'+r+'$';
693
+ }
694
+ // Obtain RegExp that is used to validate the data in OnKeypress
695
+ static getTypingRexExp_P(pic){
696
+ let a=[],b=[],c=[],r='',m=null;
697
+ const regex = /(?<VAR>[^~])|(?<CONST>(~[^~]*~))/g;
698
+ while ((m = regex.exec(pic.FORMAT)) !== null) {
699
+ if(m.index === regex.lastIndex)regex.lastIndex++; // avoid infinite loops
700
+ let str1='';
701
+ let str2='';
702
+ if( m.groups.CONST!=undefined ){
703
+ let z=m.groups.CONST.replace(/~/g,'').split('');
704
+ for(var x in z ){
705
+ a.push( new RegExp( '\\x'+ z[x].charCodeAt(0).toString(16), 'g') );
706
+ b.push( z[x] );
707
+ r += this.escapeRegExp( z[x] );
708
+ c.push( '' );
709
+ }
710
+ continue;
711
+ }
712
+ for(var x in m.groups.VAR){
713
+ x=m.groups.VAR[x];
714
+ if(x=='<'){
715
+ str1 = '[0-9 ]{1}';
716
+ }else if( x=='#'){
717
+ str1 = '[0-9]{1}';
718
+ }else if( x=='A'){
719
+ str1 = '['+this.STRING[this.STRING_LNG]['A']+' ]{1}';
720
+ }else if( x=='Â'){
721
+ str1 = '['+this.STRING[this.STRING_LNG]['A']+']{1}';
722
+ }else if( x=='a'){
723
+ str1 = '['+this.STRING[this.STRING_LNG]['a']+' ]{1}';
724
+ }else if( x=='â'){
725
+ str1 = '['+this.STRING[this.STRING_LNG]['a']+']{1}';
726
+ }else if( x=='*'){
727
+ str1 = '.{1}';
728
+ }else{
729
+ str1 = '\\x'+ x.charCodeAt(0).toString(16);
730
+ str2 = x;
731
+ }
732
+ a.push( new RegExp(str1) );
733
+ b.push( str2 );
734
+ c.push(x);
735
+ }
736
+ }
737
+ return {PATTERNTYPING:r, TYPINGARRAYRE:a, TYPINGARRAY:b, TYPINGARRAY2:c };
738
+ }
739
+
740
+ /**
741
+ * NUMBER_FORMAT taken from https://github.com/locutusjs/locutus/tree/main
742
+ * by Kevin van Zonneveld and other authors.
743
+ *
744
+ **/
745
+ static number_format(number, decimals, decPoint, thousandsSep) {
746
+ number = (number + '').replace(/[^0-9+\-Ee.]/g, '')
747
+ const n = !isFinite(+number) ? 0 : +number
748
+ const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
749
+ const sep = (typeof thousandsSep === 'undefined') ? ',' : thousandsSep
750
+ const dec = (typeof decPoint === 'undefined') ? '.' : decPoint
751
+ let s = ''
752
+ const toFixedFix = function (n, prec) {
753
+ if (('' + n).indexOf('e') === -1) {
754
+ return +(Math.round(n + 'e+' + prec) + 'e-' + prec)
755
+ } else {
756
+ const arr = ('' + n).split('e')
757
+ let sig = ''
758
+ if (+arr[1] + prec > 0) {
759
+ sig = '+'
760
+ }
761
+ return (+(Math.round(+arr[0] + 'e' + sig + (+arr[1] + prec)) + 'e-' + prec)).toFixed(prec)
762
+ }
763
+ }
764
+ // @todo: for IE parseFloat(0.55).toFixed(0) = 0;
765
+ s = (prec ? toFixedFix(n, prec).toString() : '' + Math.round(n)).split('.')
766
+ if (s[0].length > 3) {
767
+ s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep)
768
+ }
769
+ if ((s[1] || '').length < prec) {
770
+ s[1] = s[1] || ''
771
+ s[1] += new Array(prec - s[1].length + 1).join('0')
772
+ }
773
+ return s.join(dec)
774
+ }
775
+
776
+
777
+ /**
778
+ * DATE FUNCTIONS
779
+ *
780
+ **/
781
+ static isLeapYear(y){ // es año bisiesto ?
782
+ y=Number(y);
783
+ return ((y&3)!=0)? false : ((y%100)!= 0||(y%400)==0);
784
+ }
785
+ // Get Day of Year
786
+ static getDayOfYear(d,m){
787
+ d=Number(d);
788
+ m=Number(m);
789
+ const dayCount = [0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
790
+ const dayOfYear = dayCount[m] + d;
791
+ return (m>2 && this.isLeapYear())? dayOfYear++ : dayOfYear;
792
+ }
793
+ static getDayOfWeek(v,format){
794
+ return this.DATE_CONFIG[this.DATE_LNG][format][ new Date(v).getDay() ];
795
+ }
796
+ static getMonth(v,format){
797
+ return this.DATE_CONFIG[this.DATE_LNG][format][ new Date(v).getMonth() ];
798
+ }
799
+ static getWeekOfYear(v){ // ISO-8601
800
+ let d=new Date(v);
801
+ d=new Date( Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
802
+ let dayNum = d.getUTCDay() || 7;
803
+ d.setUTCDate(d.getUTCDate() + 4 - dayNum);
804
+ var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
805
+ return Math.ceil((((d-yearStart)/86400000)+1)/7)
806
+ }
807
+ static getDaysInMonth(v){
808
+ let d=new Date(v);
809
+ return new Date(d.getFullYear(), d.getMonth()+1, 0).getDate();
810
+ }
811
+
812
+
813
+ /**
814
+ * HOUR FUNCTIONS
815
+ *
816
+ **/
817
+ static getAMPM(h,m,s){
818
+ s=s||'00';
819
+ if(m==undefined){
820
+ var x=h.split(':');h=x[0];m=x[1];s=x[2]||'00';
821
+ }
822
+ return (h>=12)? 'PM':'AM';
823
+ }
824
+ static getampm(h,m,s){
825
+ s=s||'00';
826
+ if(m==undefined){
827
+ var x=h.split(':');h=x[0];m=x[1];s=x[2]||'00';
828
+ }
829
+ return (h>=12)? 'pm':'am';
830
+ }
831
+ /**
832
+ * INIT DOM ELEMENT
833
+ *
834
+ **/
835
+ static initElement( el, pic ){
836
+
837
+ var pic = pic||el.getAttribute('pic');
838
+ if( !this.re_isPic.test(pic) ) return false;
839
+ try{
840
+ var iv = el.val();
841
+ }catch(e){
842
+ var iv = el.value;
843
+ }
844
+ el.value= this.format( iv, pic );
845
+ el.PIC = this.getData(pic);
846
+ if( el.PIC.PATTERN!='' ){
847
+ if( el.PIC.TYPE=='D' ){
848
+ el.addEventListener("blur" ,this.onblur);
849
+ }else if( el.PIC.TYPE=='D' ){
850
+ el.addEventListener("blur" ,this.onblur);
851
+ }else if( el.PIC.TYPE=='P' ){
852
+ this.initPatternValue(el);
853
+ el.addEventListener("keypress" ,this.onkeypressPattern);
854
+ el.addEventListener("keydown" ,this.onkeydownPattern);
855
+ el.addEventListener("click" ,this.onclickPattern);
856
+ el.addEventListener("blur" ,this.onblur);
857
+ }else{
858
+ el.addEventListener("blur" ,this.onblur);
859
+ el.addEventListener("change" ,this.onchange);
860
+ el.addEventListener("keypress" ,this.onkeypress);
861
+ }
862
+ el.addEventListener("focus" ,this.onfocus);
863
+ el.addEventListener("paste" ,this.onpaste);
864
+ }
865
+ if( el.PIC.TYPE=='S' && el.PIC.CASE!='' ){
866
+ el.style.textTransform = (el.PIC.CASE=='U')? 'uppercase': (el.PIC.CASE=='L')? 'lowercase' : (el.PIC.CASE=='C')? 'capitalize' : 'initial';
867
+ }
868
+ el.val = el.rval = function(v){
869
+ if(v==undefined){
870
+ //if(el.PIC.TYPE=='P')return this.value;
871
+ return Picture.deformat( this.value, this.PIC.PICTURE );
872
+ }
873
+ el.setAttribute('value',v);
874
+ this.value = Picture.format( v, this.PIC.PICTURE );
875
+ return this.value;
876
+ }
877
+ el.format = function(val,pic){
878
+ if(pic==undefined){
879
+ if(el.PIC.TYPE=='P'){
880
+ val = Picture.deformat(this.value, this.PIC.PICTURE);
881
+ }else{
882
+ val=val?? this.getAttribute('value');
883
+ }
884
+ return Picture.format( val , this.PIC.PICTURE );
885
+ }
886
+ val=val?? this.value;
887
+ el.PIC.PICTURE=pic;
888
+ return Picture.format( this.value, this.PIC.PICTURE );
889
+ }
890
+ el.isvalid = function(v){
891
+ if(v==undefined){
892
+ v = (el.PIC.TYPE=='P') ? this.value : this.val();
893
+ }
894
+ return this.PIC.PATTERNVALRE.test(v);
895
+ }
896
+ el.isempty = function(){
897
+ var v=this.val();
898
+ if(v=='')return true;
899
+ if(this.PIC.TYPE=='N'){
900
+ if(v*1==0)return true;
901
+ }
902
+ return false;
903
+ }
904
+ if( el.PIC.TYPE=='P' ){
905
+ // Return variable data without pattern
906
+ el.deformat = function(data){
907
+ data = (data==undefined)? this.value : data;
908
+ return Picture.deformat(data,el.PIC.PICTURE);
909
+ }
910
+ }
911
+ }
912
+
913
+
914
+
915
+ static initPatternValue (el){
916
+ var s='';
917
+ for(var x in el.PIC.TYPINGARRAY){
918
+ s+=(el.PIC.TYPINGARRAY[x]=='')? ' ': el.PIC.TYPINGARRAY[x];
919
+ }
920
+ el.value=s;
921
+ }
922
+
923
+ static onfocus(event){
924
+ var e = event || window.event;
925
+ var o = e.currentTarget;
926
+ if( o.PIC.TYPE!='D' && o.PIC.TYPE!='P')
927
+ o.value = o.val();
928
+ if( o.PIC.TYPE=='N'){
929
+ o.style.textAlign = ( o.PIC.ALIGN=='R' )? 'right' : ( o.PIC.ALIGN=='C' )? 'center' : 'left';
930
+ o.select();
931
+ }else if( o.PIC.TYPE=='P'){
932
+ o.value = o.format();
933
+ for(var x in o.PIC.TYPINGARRAY){
934
+ if(o.PIC.TYPINGARRAY[x]==''){
935
+ e.target.selectionStart = e.target.selectionEnd = x;
936
+ break;
937
+ }
938
+ }
939
+ }else{
940
+ o.select();
941
+ }
942
+ }
943
+
944
+ static onblur(event){
945
+ const e = event || window.event;
946
+ const o = e.currentTarget;
947
+ const pic = o.getAttribute('pic');
948
+ const val = o.value;
949
+ if( o.PIC.TYPE!='D' && o.PIC.TYPE!='T'){
950
+ if( o.PIC.TYPE=='P' ){
951
+ o.value = Picture.format( Picture.deformat(val, pic), pic );
952
+ }else{
953
+ o.value = o.format(val,pic);
954
+ }
955
+ }else{
956
+ if( !o.PIC.PATTERNVALRE.test(o.val()) ){
957
+ o.setAttribute('isvalid',false);
958
+ }else{
959
+ o.setAttribute('isvalid',true);
960
+ }
961
+ }
962
+ if( o.PIC.TYPE=='N') o.style.textAlign = 'initial';
963
+ }
964
+
965
+
966
+ static onchange(event){
967
+ const e = event || window.event;
968
+ const o = e.currentTarget;
969
+ o.setAttribute('value',o.value);
970
+ if( o.PIC.TYPE=='D' ){
971
+ e.returnValue = false;
972
+ if( e.preventDefault )
973
+ e.preventDefault();
974
+ }
975
+ if( o.PIC.TYPE!='D' && o.PIC.TYPE!='T' && !o.PIC.PATTERNVALRE.test(o.value) ){
976
+ o.setAttribute('isvalid',false);
977
+ return;
978
+ }
979
+ o.setAttribute('isvalid',true);
980
+ }
981
+
982
+
983
+ static onkeypress(event){
984
+ const e = event || window.event;
985
+ let key = e.keyCode || e.which;
986
+ const o = e.currentTarget;
987
+ key = String.fromCharCode(key);
988
+ if( !o.PIC.PATTERNRE.test(key) ){
989
+ e.returnValue = false;
990
+ if( e.preventDefault )
991
+ e.preventDefault();
992
+ }
993
+ const ss = e.target.selectionStart;
994
+ const v = o.value.substring(0,ss)+key+o.value.substring(ss);
995
+ if( e.target.selectionStart==0 && e.target.selectionEnd==o.value.length ) return true;
996
+ if( !o.PIC.PATTERNTYPINGRE.test( v ) ){
997
+ e.returnValue = false;
998
+ if( e.preventDefault )
999
+ e.preventDefault();
1000
+ }
1001
+ }
1002
+
1003
+
1004
+ static onclickPattern(event){
1005
+ const e = event || window.event;
1006
+ const o = e.currentTarget;
1007
+ for(var x=e.target.selectionStart ; x<o.PIC.TYPINGARRAY.length ;x++){
1008
+ if(o.PIC.TYPINGARRAY[x]==''){
1009
+ e.target.selectionStart = x;
1010
+ break;
1011
+ }
1012
+ }
1013
+
1014
+
1015
+ }
1016
+
1017
+
1018
+ static onkeypressPattern(event){
1019
+ const e = event || window.event;
1020
+ const keyc= e.keyCode || e.which;
1021
+ const o = e.currentTarget;
1022
+ const key = String.fromCharCode(keyc);
1023
+ // get old value
1024
+ const start = e.target.selectionStart;
1025
+ const end = e.target.selectionEnd;
1026
+ const oldValue = e.currentTarget.value;
1027
+ if( o.PIC.TYPINGARRAYRE[start]==undefined ){
1028
+ e.returnValue = false;
1029
+ if( e.preventDefault )
1030
+ e.preventDefault();
1031
+ return;
1032
+ }
1033
+ if( !o.PIC.TYPINGARRAYRE[start].test( key ) ){
1034
+ e.returnValue = false;
1035
+ if( e.preventDefault )
1036
+ e.preventDefault();
1037
+ return;
1038
+ }
1039
+ let append='';
1040
+ let xtart=start;
1041
+ let npos=0;
1042
+ while(1){
1043
+ xtart+=1;
1044
+ var nextChar = o.PIC.TYPINGARRAY[xtart];
1045
+ if(nextChar==undefined) break;
1046
+ if(nextChar!='' ){
1047
+ append += nextChar;
1048
+ npos+=1;
1049
+ }else{
1050
+ break;
1051
+ }
1052
+ }
1053
+ if( append!='' ){
1054
+ const newValue = oldValue.slice(0, start) + key + oldValue.slice(start+1)
1055
+ e.currentTarget.value = newValue;
1056
+ // replace cursor
1057
+ e.target.selectionStart = e.target.selectionEnd = start + npos +1;
1058
+ e.preventDefault();
1059
+ return;
1060
+ }
1061
+ const newValue = oldValue.slice(0, start) + key + oldValue.slice(start+1)
1062
+ e.currentTarget.value = newValue;
1063
+ // replace cursor
1064
+ e.target.selectionStart = e.target.selectionEnd = start + 1;
1065
+ e.returnValue = false;
1066
+ if( e.preventDefault )e.preventDefault();
1067
+ }
1068
+
1069
+
1070
+ static onkeydownPattern (event){
1071
+ const e = event || window.event;
1072
+ const key = e.keyCode || e.which;
1073
+ let o = e.currentTarget;
1074
+ const keys = String.fromCharCode(key);
1075
+ // get old value
1076
+ let start = e.target.selectionStart;
1077
+ let end = e.target.selectionEnd;
1078
+ let oldValue = e.currentTarget.value;
1079
+ if( key==8 ){ //Backspace
1080
+ if( o.PIC.TYPINGARRAY[start-1]!='' ){
1081
+ while( o.PIC.TYPINGARRAY[start-1]!=''){
1082
+ if(start-1<=1) break;
1083
+ start-=1;
1084
+ }
1085
+ }else{
1086
+ var newValue = oldValue.slice(0, start-1) + ' ' + oldValue.slice(start);
1087
+ e.currentTarget.value = newValue;
1088
+ start -=1;
1089
+ }
1090
+ e.target.selectionStart = e.target.selectionEnd = start;
1091
+ e.returnValue = false;
1092
+ if( e.preventDefault )e.preventDefault();
1093
+ }else if( key==46 ){ //Delete
1094
+ let ov = oldValue;
1095
+ let spc='';
1096
+ for(var x=start; x<=end; x++){
1097
+ if(o.PIC.TYPINGARRAY[x]!='')continue;
1098
+ ov = Picture.setCharAt(ov,x,'~');
1099
+ spc+=' ';
1100
+ }
1101
+ for( x=0; x<ov.length; x++ ){
1102
+ if( o.PIC.TYPINGARRAY[x]!='' ){
1103
+ ov = Picture.setCharAt(ov,x,'~');
1104
+ }
1105
+ }
1106
+ ov= ov.replace(/~/g,'')+spc;
1107
+ for( x=0; x<ov.length; x++ ){
1108
+ if( o.PIC.TYPINGARRAY[x]!='' ){
1109
+ ov = ov.substring(0,x)+o.PIC.TYPINGARRAY[x]+ov.substring(x);
1110
+ }
1111
+ }
1112
+ e.currentTarget.value = ov; //+spc;
1113
+ e.target.selectionStart = e.target.selectionEnd = start;
1114
+ e.returnValue = false; if( e.preventDefault )e.preventDefault();
1115
+ }else if( key==36 ){ //Init
1116
+ if(e.shiftKey){
1117
+ e.target.selectionEnd=e.target.selectionStart;
1118
+ e.target.selectionStart=0;
1119
+ e.returnValue = false; if( e.preventDefault )e.preventDefault();
1120
+ return;
1121
+ }
1122
+ for(var x in o.PIC.TYPINGARRAY){
1123
+ if(o.PIC.TYPINGARRAY[x]==''){
1124
+ e.returnValue = false; if( e.preventDefault )e.preventDefault();
1125
+ e.target.selectionStart = e.target.selectionEnd = x;
1126
+ return;
1127
+ }
1128
+ }
1129
+ }else if( key==37 ){ //Left
1130
+ let xtart=start-1;
1131
+ while(1){
1132
+ if( o.PIC.TYPINGARRAY[xtart]=='' )break;
1133
+ if(xtart<=1){
1134
+ e.target.selectionStart = e.target.selectionEnd = start;
1135
+ e.returnValue = false; if( e.preventDefault )e.preventDefault();
1136
+ break;
1137
+ }
1138
+ xtart-=1;
1139
+ e.target.selectionStart = e.target.selectionEnd = xtart+2;
1140
+ }
1141
+ }else if( key==39 ){ //Right
1142
+ let xtart=start;
1143
+ while(1){
1144
+ if( o.PIC.TYPINGARRAY[xtart]=='' )break;
1145
+ xtart+=1;
1146
+ e.target.selectionStart = e.target.selectionEnd = xtart-1;
1147
+ if(xtart>=e.currentTarget.value.length) break;
1148
+ }
1149
+ }
1150
+ }
1151
+
1152
+
1153
+ static onpaste(event){
1154
+ const e = event || window.event;
1155
+ const o = e.currentTarget;
1156
+ const clipboardData = e.clipboardData || window.clipboardData;
1157
+ const pastedData = clipboardData.getData('Text');
1158
+ if( o.PIC.TYPE=='S' ){
1159
+ navigator.clipboard.writeText(pastedData.substring(0,o.PIC.SIZE));
1160
+ }
1161
+ if( !o.PIC.PATTERNVALRE.test(pastedData) ){
1162
+ e.returnValue = false;
1163
+ if( e.preventDefault )
1164
+ e.preventDefault();
1165
+ }
1166
+ }
1167
+ }