@lemonadejs/calendar 5.2.0 → 5.2.1
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/README.md +90 -88
- package/dist/index.js +140 -66
- package/dist/style.css +1 -0
- package/package.json +23 -23
package/README.md
CHANGED
|
@@ -1,88 +1,90 @@
|
|
|
1
|
-
# JavaScript Calendar
|
|
2
|
-
|
|
3
|
-
[Official JavaScript Calendar Documenation](https://lemonadejs.com/docs/plugins/calendar)
|
|
4
|
-
|
|
5
|
-
Compatible with Vanilla JavaScript, LemonadeJS, React, VueJS or Angular.
|
|
6
|
-
|
|
7
|
-
# JavaScript Calendar
|
|
8
|
-
|
|
9
|
-
Leverage the power of the LemonadeJS Calendar, a lightweight and versatile JavaScript component compatible with React, VueJS, and Angular. Designed to enhance web applications, it offers an embeddable calendar for easy date, time, and range selections. Key features include:
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
## Getting Started
|
|
17
|
-
|
|
18
|
-
You can install using NPM or using directly from a CDN.
|
|
19
|
-
|
|
20
|
-
### npm Installation
|
|
21
|
-
|
|
22
|
-
To install it in your project using npm, run the following command:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
$ npm install @lemonadejs/calendar
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### CDN
|
|
29
|
-
|
|
30
|
-
For immediate use without NPM, include these script tags in your HTML for access to the calendar and its dependencies:
|
|
31
|
-
|
|
32
|
-
```html
|
|
33
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/style.min.css" />
|
|
34
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/style.min.css" />
|
|
35
|
-
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
|
|
36
|
-
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
|
|
37
|
-
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/index.min.js"></script>
|
|
38
|
-
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/index.min.js"></script>
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Usage
|
|
42
|
-
|
|
43
|
-
Quick example with ReactJS.
|
|
44
|
-
|
|
45
|
-
```javascript
|
|
46
|
-
import React, { useRef } from 'react';
|
|
47
|
-
import Calendar from '@lemonadejs/calendar/dist/react';
|
|
48
|
-
|
|
49
|
-
import
|
|
50
|
-
import
|
|
51
|
-
|
|
52
|
-
export default function App() {
|
|
53
|
-
const calendarRef = useRef();
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
1
|
+
# JavaScript Calendar
|
|
2
|
+
|
|
3
|
+
[Official JavaScript Calendar Documenation](https://lemonadejs.com/docs/plugins/calendar)
|
|
4
|
+
|
|
5
|
+
Compatible with Vanilla JavaScript, LemonadeJS, React, VueJS or Angular.
|
|
6
|
+
|
|
7
|
+
# JavaScript Calendar
|
|
8
|
+
|
|
9
|
+
Leverage the power of the LemonadeJS Calendar, a lightweight and versatile JavaScript component compatible with React, VueJS, and Angular. Designed to enhance web applications, it offers an embeddable calendar for easy date, time, and range selections. Key features include:
|
|
10
|
+
|
|
11
|
+
- Intuitive keyboard navigation.
|
|
12
|
+
- A reactive and responsive design for seamless device adaptation.
|
|
13
|
+
- Flexible range selection for various applications.
|
|
14
|
+
- Customizable options to match your project needs.
|
|
15
|
+
|
|
16
|
+
## Getting Started
|
|
17
|
+
|
|
18
|
+
You can install using NPM or using directly from a CDN.
|
|
19
|
+
|
|
20
|
+
### npm Installation
|
|
21
|
+
|
|
22
|
+
To install it in your project using npm, run the following command:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
$ npm install @lemonadejs/calendar
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### CDN
|
|
29
|
+
|
|
30
|
+
For immediate use without NPM, include these script tags in your HTML for access to the calendar and its dependencies:
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/style.min.css" />
|
|
34
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/style.min.css" />
|
|
35
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
|
|
36
|
+
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
|
|
37
|
+
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/index.min.js"></script>
|
|
38
|
+
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/index.min.js"></script>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Usage
|
|
42
|
+
|
|
43
|
+
Quick example with ReactJS.
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
import React, { useRef } from 'react';
|
|
47
|
+
import Calendar from '@lemonadejs/calendar/dist/react';
|
|
48
|
+
|
|
49
|
+
import '@lemonadejs/calendar/dist/style.css';
|
|
50
|
+
import '@lemonadejs/modal/dist/style.css';
|
|
51
|
+
|
|
52
|
+
export default function App() {
|
|
53
|
+
const calendarRef = useRef();
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<>
|
|
57
|
+
<Calendar type={'inline'} ref={calendarRef} value={new Date()} />
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Configuration
|
|
64
|
+
|
|
65
|
+
You can configure things such as calendar starting date, calendar events, and customize functions.
|
|
66
|
+
|
|
67
|
+
#### Calendar Properties
|
|
68
|
+
|
|
69
|
+
| Attribute | Type | Description |
|
|
70
|
+
| --------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
71
|
+
| type? | string | Determines the rendering type for the calendar. Options: 'inline', 'default'. |
|
|
72
|
+
| range? | boolean | Enables the range mode for date selection. |
|
|
73
|
+
| value? | number or string | Represents the currently selected date. |
|
|
74
|
+
| numeric? | boolean | Enables the use of numeric dates, treating them as serial numbers. |
|
|
75
|
+
| input? | HTML element | An optional reference to control the calendar opening. The value is automatically bound when using this property. |
|
|
76
|
+
|
|
77
|
+
### Calendar Events
|
|
78
|
+
|
|
79
|
+
| Event | Description |
|
|
80
|
+
| -------------------------------- | ----------------------------------- |
|
|
81
|
+
| onchange?: (self, value) => void | Called when a new date is selected. |
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
The LemonadeJS [Reactive JavaScript Calendar](https://lemonadejs.com/docs/plugins/calendar) is released under the MIT.
|
|
86
|
+
|
|
87
|
+
## Other Tools
|
|
88
|
+
|
|
89
|
+
- [jSuites Plugins - JavaScript Calendar](https://jsuites.net/docs/javascript-calendar)
|
|
90
|
+
- [Jspreadsheet - JavaScript Spreadsheet](https://jspreadsheet.com/)
|
package/dist/index.js
CHANGED
|
@@ -304,7 +304,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
304
304
|
return component;
|
|
305
305
|
})();
|
|
306
306
|
|
|
307
|
-
const Mask = (function() {
|
|
307
|
+
const Mask = (function Mask() {
|
|
308
308
|
// Currency
|
|
309
309
|
const tokens = {
|
|
310
310
|
// Text
|
|
@@ -325,6 +325,33 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
325
325
|
general: [ 'A', '0', '\\?', '\\*', ',,M', ',,,B', '[0-9a-zA-Z\\$]+', '_\\(', '_\\)', '\\(', '\\)', '_-', '.']
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
// All expressions
|
|
329
|
+
const allExpressions = [].concat(tokens.fraction, tokens.currency, tokens.datetime, tokens.percentage, tokens.scientific, tokens.numeric, tokens.text, tokens.general).join('|');
|
|
330
|
+
|
|
331
|
+
// Pre-compile all regexes once at initialization for better performance
|
|
332
|
+
const compiledTokens = {};
|
|
333
|
+
const tokenPriority = ['fraction', 'currency', 'scientific', 'percentage', 'numeric', 'datetime', 'text', 'general'];
|
|
334
|
+
|
|
335
|
+
// Initialize compiled regexes
|
|
336
|
+
for (const type of tokenPriority) {
|
|
337
|
+
compiledTokens[type] = tokens[type].map(pattern => ({
|
|
338
|
+
regex: new RegExp('^' + pattern + '$', 'gi'),
|
|
339
|
+
method: pattern
|
|
340
|
+
}));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Pre-compile regex for getTokens function
|
|
344
|
+
const allExpressionsRegex = new RegExp(allExpressions, 'gi');
|
|
345
|
+
|
|
346
|
+
// Pre-compile currency symbol regexes for autoCastingCurrency
|
|
347
|
+
const knownSymbols = ['$', '€', '£', '¥', '₹', '₽', '₩', '₫', 'R$', 'CHF', 'AED'];
|
|
348
|
+
const currencyRegexes = knownSymbols.map(s => ({
|
|
349
|
+
symbol: s,
|
|
350
|
+
regex: new RegExp(`^${s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')}(\\s?)`)
|
|
351
|
+
}));
|
|
352
|
+
|
|
353
|
+
const hiddenCaret = "\u200B";
|
|
354
|
+
|
|
328
355
|
// Labels
|
|
329
356
|
const weekDaysFull = Helpers.weekdays;
|
|
330
357
|
const weekDays = Helpers.weekdaysShort;
|
|
@@ -333,6 +360,29 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
333
360
|
|
|
334
361
|
// Helpers
|
|
335
362
|
|
|
363
|
+
const focus = function(el) {
|
|
364
|
+
if (el.textContent.length) {
|
|
365
|
+
// Handle contenteditable elements
|
|
366
|
+
const range = document.createRange();
|
|
367
|
+
const sel = window.getSelection();
|
|
368
|
+
|
|
369
|
+
let node = el;
|
|
370
|
+
// Go as deep as possible to the last text node
|
|
371
|
+
while (node.lastChild) node = node.lastChild;
|
|
372
|
+
// Ensure it's a text node
|
|
373
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
374
|
+
range.setStart(node, node.length);
|
|
375
|
+
} else {
|
|
376
|
+
range.setStart(node, node.childNodes.length);
|
|
377
|
+
}
|
|
378
|
+
range.collapse(true);
|
|
379
|
+
sel.removeAllRanges();
|
|
380
|
+
sel.addRange(range);
|
|
381
|
+
|
|
382
|
+
el.scrollLeft = el.scrollWidth;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
336
386
|
/**
|
|
337
387
|
* Returns if the given value is considered blank
|
|
338
388
|
*/
|
|
@@ -461,7 +511,6 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
461
511
|
const setCaret = function(index) {
|
|
462
512
|
if (typeof index !== 'number') index = Number(index) || 0;
|
|
463
513
|
|
|
464
|
-
// Inputs/Textareas
|
|
465
514
|
if (this.tagName !== 'DIV' || this.isContentEditable !== true) {
|
|
466
515
|
const n = this.value ?? '';
|
|
467
516
|
if (index < 0) index = 0;
|
|
@@ -648,14 +697,18 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
648
697
|
}
|
|
649
698
|
} else {
|
|
650
699
|
if (this.values[this.index] == 1 && parseInt(v) < 3) {
|
|
651
|
-
this.
|
|
700
|
+
this.values[this.index] += v;
|
|
652
701
|
commit();
|
|
653
702
|
} else if (this.values[this.index] == 0 && parseInt(v) > 0 && parseInt(v) < 10) {
|
|
654
|
-
this.
|
|
703
|
+
this.values[this.index] += v;
|
|
655
704
|
commit();
|
|
656
705
|
} else {
|
|
657
706
|
let test = parseInt(this.values[this.index]);
|
|
658
707
|
if (test > 0 && test <= 12) {
|
|
708
|
+
if (! single) {
|
|
709
|
+
test = '0' + test;
|
|
710
|
+
}
|
|
711
|
+
this.values[this.index] = test;
|
|
659
712
|
commit();
|
|
660
713
|
return false;
|
|
661
714
|
}
|
|
@@ -706,6 +759,10 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
706
759
|
} else {
|
|
707
760
|
let test = parseInt(this.values[this.index]);
|
|
708
761
|
if (test > 0 && test <= 31) {
|
|
762
|
+
if (! single) {
|
|
763
|
+
test = '0' + test;
|
|
764
|
+
}
|
|
765
|
+
this.values[this.index] = test;
|
|
709
766
|
commit();
|
|
710
767
|
return false;
|
|
711
768
|
}
|
|
@@ -935,10 +992,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
935
992
|
}
|
|
936
993
|
this.values[this.index] += this.decimal;
|
|
937
994
|
}
|
|
938
|
-
} else if (v === "\u200B") {
|
|
939
|
-
this.values[this.index] += v;
|
|
940
995
|
}
|
|
941
|
-
|
|
942
996
|
},
|
|
943
997
|
'[0#]+([.,]{1}0*#*)?%': function(v) {
|
|
944
998
|
parseMethods['[0#]+([.,]{1}0*#*)?'].call(this, v);
|
|
@@ -1094,7 +1148,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1094
1148
|
// Add the value
|
|
1095
1149
|
this.values[this.index] += v;
|
|
1096
1150
|
// Only if caret is before the change
|
|
1097
|
-
let current = this.values[this.index]
|
|
1151
|
+
let current = this.values[this.index];
|
|
1098
1152
|
// Add token to the values
|
|
1099
1153
|
if (current !== word.substring(0,current.length)) {
|
|
1100
1154
|
this.values[this.index] = word;
|
|
@@ -1121,7 +1175,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1121
1175
|
this.index++;
|
|
1122
1176
|
}
|
|
1123
1177
|
},
|
|
1124
|
-
'\\*': function(
|
|
1178
|
+
'\\*': function() {
|
|
1125
1179
|
this.values[this.index] = '';
|
|
1126
1180
|
this.index++;
|
|
1127
1181
|
return false;
|
|
@@ -1160,17 +1214,17 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1160
1214
|
}
|
|
1161
1215
|
this.values[this.index] += v;
|
|
1162
1216
|
},
|
|
1163
|
-
'_\\(': function(
|
|
1217
|
+
'_\\(': function() {
|
|
1164
1218
|
this.values[this.index] = ' ';
|
|
1165
1219
|
this.index++;
|
|
1166
1220
|
return false;
|
|
1167
1221
|
},
|
|
1168
|
-
'_\\)': function(
|
|
1222
|
+
'_\\)': function() {
|
|
1169
1223
|
this.values[this.index] = ' ';
|
|
1170
1224
|
this.index++;
|
|
1171
1225
|
return false;
|
|
1172
1226
|
},
|
|
1173
|
-
'\\(': function(
|
|
1227
|
+
'\\(': function() {
|
|
1174
1228
|
if (this.type === 'currency' && this.parenthesisForNegativeNumbers) {
|
|
1175
1229
|
this.values[this.index] = '';
|
|
1176
1230
|
} else {
|
|
@@ -1179,7 +1233,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1179
1233
|
this.index++;
|
|
1180
1234
|
return false;
|
|
1181
1235
|
},
|
|
1182
|
-
'\\)': function(
|
|
1236
|
+
'\\)': function() {
|
|
1183
1237
|
if (this.type === 'currency' && this.parenthesisForNegativeNumbers) {
|
|
1184
1238
|
this.values[this.index] = '';
|
|
1185
1239
|
} else {
|
|
@@ -1188,17 +1242,17 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1188
1242
|
this.index++;
|
|
1189
1243
|
return false;
|
|
1190
1244
|
},
|
|
1191
|
-
'_-': function(
|
|
1245
|
+
'_-': function() {
|
|
1192
1246
|
this.values[this.index] = ' ';
|
|
1193
1247
|
this.index++;
|
|
1194
1248
|
return false;
|
|
1195
1249
|
},
|
|
1196
|
-
',,M': function(
|
|
1250
|
+
',,M': function() {
|
|
1197
1251
|
this.values[this.index] = 'M';
|
|
1198
1252
|
this.index++;
|
|
1199
1253
|
return false;
|
|
1200
1254
|
},
|
|
1201
|
-
',,,B': function(
|
|
1255
|
+
',,,B': function() {
|
|
1202
1256
|
this.values[this.index] = 'B';
|
|
1203
1257
|
this.index++;
|
|
1204
1258
|
return false;
|
|
@@ -1243,9 +1297,8 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1243
1297
|
// Types TODO: Generate types so we can garantee that text,scientific, numeric,percentage, current are not duplicates. If they are, it will be general or broken.
|
|
1244
1298
|
|
|
1245
1299
|
const getTokens = function(str) {
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
return str.match(new RegExp(expressions.join('|'), 'gi'));
|
|
1300
|
+
allExpressionsRegex.lastIndex = 0; // Reset for global regex
|
|
1301
|
+
return str.match(allExpressionsRegex);
|
|
1249
1302
|
}
|
|
1250
1303
|
|
|
1251
1304
|
/**
|
|
@@ -1253,35 +1306,23 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1253
1306
|
*/
|
|
1254
1307
|
const getMethod = function(str, temporary) {
|
|
1255
1308
|
str = str.toString().toUpperCase();
|
|
1256
|
-
const types = Object.keys(tokens);
|
|
1257
1309
|
|
|
1258
1310
|
// Check for datetime mask
|
|
1259
|
-
|
|
1260
|
-
for (let i = 0; i < temporary.length; i++) {
|
|
1261
|
-
let type = temporary[i].type;
|
|
1262
|
-
if (! (type === 'datetime' || type === 'general')) {
|
|
1263
|
-
datetime = false;
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
// Remove date time from the possible types
|
|
1268
|
-
if (datetime !== true) {
|
|
1269
|
-
let index = types.indexOf('datetime');
|
|
1270
|
-
types.splice(index, 1);
|
|
1271
|
-
}
|
|
1311
|
+
const datetime = temporary.every(t => t.type === 'datetime' || t.type === 'general');
|
|
1272
1312
|
|
|
1273
|
-
//
|
|
1274
|
-
for (
|
|
1275
|
-
|
|
1313
|
+
// Use priority order for faster matching with pre-compiled regexes
|
|
1314
|
+
for (const type of tokenPriority) {
|
|
1315
|
+
if (!datetime && type === 'datetime') continue;
|
|
1276
1316
|
|
|
1277
|
-
for (
|
|
1278
|
-
let
|
|
1279
|
-
|
|
1280
|
-
if (
|
|
1281
|
-
return { type: type, method:
|
|
1317
|
+
for (const compiled of compiledTokens[type]) {
|
|
1318
|
+
let regex = compiled.regex;
|
|
1319
|
+
regex.lastIndex = 0; // Reset regex state
|
|
1320
|
+
if (regex.test(str)) {
|
|
1321
|
+
return { type: type, method: compiled.method };
|
|
1282
1322
|
}
|
|
1283
1323
|
}
|
|
1284
1324
|
}
|
|
1325
|
+
return null;
|
|
1285
1326
|
}
|
|
1286
1327
|
|
|
1287
1328
|
const fixMinuteToken = function(t) {
|
|
@@ -1417,7 +1458,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1417
1458
|
|
|
1418
1459
|
const isNumber = function(num) {
|
|
1419
1460
|
if (typeof(num) === 'string') {
|
|
1420
|
-
num = num.
|
|
1461
|
+
num = num.trim();
|
|
1421
1462
|
}
|
|
1422
1463
|
return !isNaN(num) && num !== null && num !== '';
|
|
1423
1464
|
}
|
|
@@ -1711,7 +1752,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1711
1752
|
}
|
|
1712
1753
|
|
|
1713
1754
|
const extractDateAndTime = function(value) {
|
|
1714
|
-
value =
|
|
1755
|
+
value = value.toString().substring(0,19);
|
|
1715
1756
|
let splitStr = (value.indexOf('T') !== -1) ? 'T' : ' ';
|
|
1716
1757
|
value = value.split(splitStr);
|
|
1717
1758
|
|
|
@@ -1759,11 +1800,20 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1759
1800
|
// Walk every character on the value
|
|
1760
1801
|
let method;
|
|
1761
1802
|
while (method = getMethodByPosition(control)) {
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1803
|
+
let char = control.value[control.position];
|
|
1804
|
+
if (char === hiddenCaret) {
|
|
1805
|
+
control.caret = {
|
|
1806
|
+
index: control.index,
|
|
1807
|
+
position: control.values[control.index]?.length ?? 0,
|
|
1808
|
+
}
|
|
1766
1809
|
control.position++;
|
|
1810
|
+
} else {
|
|
1811
|
+
// Get the method name to handle the current token
|
|
1812
|
+
let ret = method.call(control, char);
|
|
1813
|
+
// Next position
|
|
1814
|
+
if (ret !== false) {
|
|
1815
|
+
control.position++;
|
|
1816
|
+
}
|
|
1767
1817
|
}
|
|
1768
1818
|
}
|
|
1769
1819
|
|
|
@@ -1785,6 +1835,13 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1785
1835
|
}
|
|
1786
1836
|
}
|
|
1787
1837
|
}
|
|
1838
|
+
if (control.caret) {
|
|
1839
|
+
let index = control.caret.index;
|
|
1840
|
+
let position = control.caret.position;
|
|
1841
|
+
let value = control.values[index] ?? '';
|
|
1842
|
+
// Re-apply the caret to the original position
|
|
1843
|
+
control.values[index] = value.substring(0, position) + hiddenCaret + value.substring(position);
|
|
1844
|
+
}
|
|
1788
1845
|
|
|
1789
1846
|
control.value = getValue(control);
|
|
1790
1847
|
|
|
@@ -1897,7 +1954,6 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
1897
1954
|
const parts = str.split('-');
|
|
1898
1955
|
const p1 = parseInt(parts[0]);
|
|
1899
1956
|
const p2 = parseInt(parts[1]);
|
|
1900
|
-
const p3 = parseInt(parts[2]);
|
|
1901
1957
|
|
|
1902
1958
|
if (p1 <= 12 && p2 <= 31 && p2 > 12) {
|
|
1903
1959
|
patterns.push('mm-dd-yyyy', 'mm-dd-yy', 'm-d-yyyy', 'm-d-yy');
|
|
@@ -2085,13 +2141,10 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
2085
2141
|
const hasParens = /^\s*\(.+\)\s*$/.test(original);
|
|
2086
2142
|
let value = original.replace(/[()\-]/g, '').trim();
|
|
2087
2143
|
|
|
2088
|
-
//
|
|
2089
|
-
const knownSymbols = ['$', '€', '£', '¥', '₹', '₽', '₩', '₫', 'R$', 'CHF', 'AED'];
|
|
2144
|
+
// Use pre-compiled currency regexes
|
|
2090
2145
|
let symbol = '';
|
|
2091
2146
|
|
|
2092
|
-
for (let s of
|
|
2093
|
-
const escaped = s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
2094
|
-
const regex = new RegExp(`^${escaped}(\\s?)`);
|
|
2147
|
+
for (let {symbol: s, regex} of currencyRegexes) {
|
|
2095
2148
|
const match = value.match(regex);
|
|
2096
2149
|
if (match) {
|
|
2097
2150
|
symbol = s + (match[1] || '');
|
|
@@ -2441,8 +2494,6 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
2441
2494
|
return returnObject ? o : result;
|
|
2442
2495
|
};
|
|
2443
2496
|
|
|
2444
|
-
// TODO: We have a large number like 1000000 and I want format it to 1,00 or 1M or… (display million/thousands/full numbers). In the excel we can do that with custom format cell “0,00..” However, when I tried applying similar formatting with the mask cell of Jspreadsheet, it didn't work. Could you advise how we can achieve this?
|
|
2445
|
-
|
|
2446
2497
|
Component.render = function(value, options, fullMask) {
|
|
2447
2498
|
// Nothing to render
|
|
2448
2499
|
if (value === '' || value === undefined || value === null) {
|
|
@@ -2531,7 +2582,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
2531
2582
|
} else {
|
|
2532
2583
|
options.input.value = value;
|
|
2533
2584
|
}
|
|
2534
|
-
|
|
2585
|
+
focus(options.input);
|
|
2535
2586
|
}
|
|
2536
2587
|
|
|
2537
2588
|
return value;
|
|
@@ -2564,6 +2615,11 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
2564
2615
|
return '';
|
|
2565
2616
|
}
|
|
2566
2617
|
|
|
2618
|
+
// Tokens
|
|
2619
|
+
const dateTokens = ['DAY', 'WD', 'DDDD', 'DDD', 'DD', 'D', 'Q', 'HH24', 'HH12', 'HH', '\\[H\\]', 'H', 'AM/PM', 'MI', 'SS', 'MS', 'YYYY', 'YYY', 'YY', 'Y', 'MONTH', 'MON', 'MMMMM', 'MMMM', 'MMM', 'MM', 'M', '.'];
|
|
2620
|
+
// All date tokens
|
|
2621
|
+
const allDateTokens = dateTokens.join('|')
|
|
2622
|
+
|
|
2567
2623
|
Component.getDateString = function(value, options) {
|
|
2568
2624
|
if (! options) {
|
|
2569
2625
|
options = {};
|
|
@@ -2595,11 +2651,9 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
2595
2651
|
value = Helpers.numToDate(value);
|
|
2596
2652
|
}
|
|
2597
2653
|
|
|
2598
|
-
// Tokens
|
|
2599
|
-
let tokens = ['DAY', 'WD', 'DDDD', 'DDD', 'DD', 'D', 'Q', 'HH24', 'HH12', 'HH', '\\[H\\]', 'H', 'AM/PM', 'MI', 'SS', 'MS', 'YYYY', 'YYY', 'YY', 'Y', 'MONTH', 'MON', 'MMMMM', 'MMMM', 'MMM', 'MM', 'M', '.'];
|
|
2600
2654
|
|
|
2601
2655
|
// Expression to extract all tokens from the string
|
|
2602
|
-
let e = new RegExp(
|
|
2656
|
+
let e = new RegExp(allDateTokens, 'gi');
|
|
2603
2657
|
// Extract
|
|
2604
2658
|
let t = format.match(e);
|
|
2605
2659
|
|
|
@@ -2793,7 +2847,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
2793
2847
|
// Keep the current caret position
|
|
2794
2848
|
let caret = getCaret(element);
|
|
2795
2849
|
if (caret) {
|
|
2796
|
-
value = value.substring(0, caret) +
|
|
2850
|
+
value = value.substring(0, caret) + hiddenCaret + value.substring(caret);
|
|
2797
2851
|
}
|
|
2798
2852
|
|
|
2799
2853
|
// Run mask
|
|
@@ -2804,15 +2858,17 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
2804
2858
|
// Apply the result back to the element
|
|
2805
2859
|
if (newValue !== value && ! e.inputType.includes('delete')) {
|
|
2806
2860
|
// Set the caret to the position before transformation
|
|
2807
|
-
let caret = newValue.indexOf(
|
|
2861
|
+
let caret = newValue.indexOf(hiddenCaret);
|
|
2808
2862
|
if (caret !== -1) {
|
|
2809
2863
|
// Apply value
|
|
2810
|
-
element[property] = newValue.replace(
|
|
2864
|
+
element[property] = newValue.replace(hiddenCaret, "");
|
|
2811
2865
|
// Set caret
|
|
2812
2866
|
setCaret.call(element, caret);
|
|
2813
2867
|
} else {
|
|
2814
2868
|
// Apply value
|
|
2815
2869
|
element[property] = newValue;
|
|
2870
|
+
// Make sure the caret is positioned in the end
|
|
2871
|
+
focus(element);
|
|
2816
2872
|
}
|
|
2817
2873
|
}
|
|
2818
2874
|
}
|
|
@@ -2822,7 +2878,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
2822
2878
|
Component.adjustPrecision = adjustPrecision;
|
|
2823
2879
|
|
|
2824
2880
|
return Component;
|
|
2825
|
-
}
|
|
2881
|
+
}());
|
|
2826
2882
|
|
|
2827
2883
|
const isNumber = function (num) {
|
|
2828
2884
|
if (typeof(num) === 'string') {
|
|
@@ -3385,12 +3441,18 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
3385
3441
|
let input = getInput();
|
|
3386
3442
|
let value = self.value;
|
|
3387
3443
|
if (input) {
|
|
3444
|
+
let v;
|
|
3388
3445
|
if (input.tagName === 'INPUT' || input.tagName === 'TEXTAREA') {
|
|
3389
3446
|
isEditable = !input.hasAttribute('readonly') && !input.hasAttribute('disabled');
|
|
3390
|
-
|
|
3447
|
+
v = input.value;
|
|
3391
3448
|
} else if (input.isContentEditable) {
|
|
3392
3449
|
isEditable = true;
|
|
3393
|
-
|
|
3450
|
+
v = input.textContent;
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
let tmp = Mask.extractDateFromString(v, self.format);
|
|
3454
|
+
if (tmp) {
|
|
3455
|
+
value = tmp;
|
|
3394
3456
|
}
|
|
3395
3457
|
}
|
|
3396
3458
|
|
|
@@ -3641,8 +3703,20 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
3641
3703
|
// Update input
|
|
3642
3704
|
let input = getInput();
|
|
3643
3705
|
if (input) {
|
|
3706
|
+
if (self.format && v) {
|
|
3707
|
+
if (self.range) {
|
|
3708
|
+
if (v[0]) {
|
|
3709
|
+
v[0] = Mask.render(v[0], self.format);
|
|
3710
|
+
}
|
|
3711
|
+
if (v[1]) {
|
|
3712
|
+
v[1] = Mask.render(v[1], self.format);
|
|
3713
|
+
}
|
|
3714
|
+
} else {
|
|
3715
|
+
v = Mask.render(v, self.format);
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3644
3718
|
// Update input value
|
|
3645
|
-
input.value =
|
|
3719
|
+
input.value = v;
|
|
3646
3720
|
// Dispatch event
|
|
3647
3721
|
Dispatch.call(input, null, 'change', {
|
|
3648
3722
|
instance: self,
|
package/dist/style.css
CHANGED
package/package.json
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@lemonadejs/calendar",
|
|
3
|
-
"title": "LemonadeJS calendar",
|
|
4
|
-
"description": "LemonadeJS reactive JavaScript calendar plugin",
|
|
5
|
-
"author": {
|
|
6
|
-
"name": "Contact <contact@lemonadejs.net>",
|
|
7
|
-
"url": "https://lemonadejs.net"
|
|
8
|
-
},
|
|
9
|
-
"keywords": [
|
|
10
|
-
"javascript calendar",
|
|
11
|
-
"lemonadejs plugins",
|
|
12
|
-
"js",
|
|
13
|
-
"library",
|
|
14
|
-
"javascript plugins"
|
|
15
|
-
],
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"lemonadejs": "^5.2.0",
|
|
18
|
-
"@lemonadejs/modal": "^5.2.0"
|
|
19
|
-
},
|
|
20
|
-
"main": "dist/index.js",
|
|
21
|
-
"types": "dist/index.d.ts",
|
|
22
|
-
"version": "5.2.
|
|
23
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@lemonadejs/calendar",
|
|
3
|
+
"title": "LemonadeJS calendar",
|
|
4
|
+
"description": "LemonadeJS reactive JavaScript calendar plugin",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Contact <contact@lemonadejs.net>",
|
|
7
|
+
"url": "https://lemonadejs.net"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"javascript calendar",
|
|
11
|
+
"lemonadejs plugins",
|
|
12
|
+
"js",
|
|
13
|
+
"library",
|
|
14
|
+
"javascript plugins"
|
|
15
|
+
],
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"lemonadejs": "^5.2.0",
|
|
18
|
+
"@lemonadejs/modal": "^5.2.0"
|
|
19
|
+
},
|
|
20
|
+
"main": "dist/index.js",
|
|
21
|
+
"types": "dist/index.d.ts",
|
|
22
|
+
"version": "5.2.1"
|
|
23
|
+
}
|