@kizmann/pico-js 1.0.13 → 2.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/README.md +27 -7
- package/dist/pico-js.browser.js +2 -0
- package/dist/pico-js.browser.js.map +1 -0
- package/dist/pico-js.esm.js +2 -0
- package/dist/pico-js.esm.js.map +1 -0
- package/package.json +20 -7
- package/src/dom/DomAttribute.js +374 -0
- package/src/dom/DomBuilder.js +152 -0
- package/src/dom/DomEvent.js +253 -0
- package/src/dom/DomFinder.js +669 -0
- package/src/dom/DomForm.js +57 -0
- package/src/dom/DomGlobal.js +193 -0
- package/src/dom/DomInview.js +332 -0
- package/src/dom/DomMeta.js +66 -0
- package/src/dom/DomObserver.js +57 -0
- package/src/dom/DomRectangle.js +657 -0
- package/src/format/FormatFile.js +54 -0
- package/src/format/FormatOption.js +108 -0
- package/src/format/FormatParam.js +107 -0
- package/src/format/FormatParser.js +156 -0
- package/src/format/FormatUrl.js +75 -0
- package/src/index.browser.js +10 -0
- package/src/index.esm.js +138 -0
- package/src/now/NowDefault.js +533 -0
- package/src/now/NowFormat.js +196 -0
- package/src/now/NowGrid.js +251 -0
- package/src/now/NowHuman.js +118 -0
- package/src/now/NowMatch.js +175 -0
- package/src/now/NowRange.js +70 -0
- package/src/now/NowWalker.js +544 -0
- package/src/tool/scope.js +103 -0
- package/src/utils/Array.js +986 -0
- package/src/utils/Cookie.js +184 -0
- package/src/utils/Data.js +200 -0
- package/src/utils/Dom.js +208 -0
- package/src/utils/Event.js +140 -0
- package/src/utils/Format.js +62 -0
- package/src/utils/Hash.js +164 -0
- package/src/utils/Locale.js +229 -0
- package/src/utils/Mixed.js +887 -0
- package/src/utils/Now.js +234 -0
- package/src/utils/Number.js +238 -0
- package/src/utils/Object.js +655 -0
- package/src/utils/Route.js +67 -0
- package/src/utils/Runner.js +327 -0
- package/src/utils/String.js +618 -0
- package/src/{library/element.js → wip/Element.js} +90 -16
- package/src/{library/map.js → wip/Map.js} +256 -40
- package/types/dom/DomAttribute.d.ts +137 -0
- package/types/dom/DomBuilder.d.ts +67 -0
- package/types/dom/DomEvent.d.ts +103 -0
- package/types/dom/DomFinder.d.ts +321 -0
- package/types/dom/DomForm.d.ts +21 -0
- package/types/dom/DomGlobal.d.ts +79 -0
- package/types/dom/DomInview.d.ts +114 -0
- package/types/dom/DomMeta.d.ts +29 -0
- package/types/dom/DomObserver.d.ts +21 -0
- package/types/dom/DomRectangle.d.ts +270 -0
- package/types/format/FormatFile.d.ts +18 -0
- package/types/format/FormatOption.d.ts +40 -0
- package/types/format/FormatParam.d.ts +39 -0
- package/types/format/FormatParser.d.ts +46 -0
- package/types/format/FormatUrl.d.ts +17 -0
- package/types/index.browser.d.ts +1 -0
- package/types/index.esm.d.ts +52 -0
- package/types/now/NowDefault.d.ts +183 -0
- package/types/now/NowFormat.d.ts +70 -0
- package/types/now/NowGrid.d.ts +107 -0
- package/types/now/NowHuman.d.ts +37 -0
- package/types/now/NowMatch.d.ts +108 -0
- package/types/now/NowRange.d.ts +21 -0
- package/types/now/NowWalker.d.ts +301 -0
- package/types/tool/scope.d.ts +24 -0
- package/types/utils/Array.d.ts +480 -0
- package/types/utils/Cookie.d.ts +60 -0
- package/types/utils/Data.d.ts +91 -0
- package/types/utils/Dom.d.ts +138 -0
- package/types/utils/Event.d.ts +58 -0
- package/types/utils/Format.d.ts +37 -0
- package/types/utils/Hash.d.ts +81 -0
- package/types/utils/Locale.d.ts +115 -0
- package/types/utils/Mixed.d.ts +469 -0
- package/types/utils/Now.d.ts +125 -0
- package/types/utils/Number.d.ts +127 -0
- package/types/utils/Object.d.ts +255 -0
- package/types/utils/Route.d.ts +37 -0
- package/types/utils/Runner.d.ts +139 -0
- package/types/utils/String.d.ts +330 -0
- package/types/wip/Element.d.ts +119 -0
- package/types/wip/Map.d.ts +254 -0
- package/dist/.ignore.js +0 -0
- package/dist/pico-js.js +0 -2
- package/dist/pico-js.js.map +0 -1
- package/src/element/default.js +0 -46
- package/src/element/example.js +0 -58
- package/src/index.js +0 -90
- package/src/library/cookie.js +0 -123
- package/src/library/data.js +0 -111
- package/src/library/event.js +0 -91
- package/src/library/locale.js +0 -84
- package/src/library/queue.js +0 -64
- package/src/library/route.js +0 -28
- package/src/utility/any.js +0 -369
- package/src/utility/array.js +0 -410
- package/src/utility/dom.js +0 -1425
- package/src/utility/now.js +0 -544
- package/src/utility/number.js +0 -128
- package/src/utility/object.js +0 -429
- package/src/utility/string.js +0 -328
- package/types/index.d.ts +0 -77
- package/types/library/cookie.d.ts +0 -10
- package/types/library/data.d.ts +0 -15
- package/types/library/element.d.ts +0 -22
- package/types/library/event.d.ts +0 -13
- package/types/library/locale.d.ts +0 -14
- package/types/library/map.d.ts +0 -43
- package/types/library/queue.d.ts +0 -18
- package/types/library/route.d.ts +0 -11
- package/types/utility/any.d.ts +0 -35
- package/types/utility/array.d.ts +0 -46
- package/types/utility/dom.d.ts +0 -101
- package/types/utility/now.d.ts +0 -79
- package/types/utility/number.d.ts +0 -17
- package/types/utility/object.d.ts +0 -29
- package/types/utility/string.d.ts +0 -26
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Str, Event, For, Mix, Arr } from "#src/index.esm.js";
|
|
2
|
+
export class PicoEvent
|
|
3
|
+
{
|
|
4
|
+
static $events = [];
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Bind callback to event name
|
|
8
|
+
*
|
|
9
|
+
* @example Event.bind("x", cb) // => Event
|
|
10
|
+
* @example Event.bind(["a","b"], cb) // => Event
|
|
11
|
+
*
|
|
12
|
+
* @param {any} event Event name(s)
|
|
13
|
+
* @param {function} cb Event callback
|
|
14
|
+
* @param {any} [options] Listener options
|
|
15
|
+
* @param {boolean} [paused] Start paused
|
|
16
|
+
* @returns {typeof PicoEvent} Event class
|
|
17
|
+
*/
|
|
18
|
+
static bind(event, cb, options = {}, paused = false)
|
|
19
|
+
{
|
|
20
|
+
if ( Mix.isArr(event) ) {
|
|
21
|
+
return Arr.each(event, (e) => this.bind(e, ...arguments), this);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if ( Mix.isPrim(options) ) {
|
|
25
|
+
options = { id: options };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.$events = Arr.append(this.$events, {
|
|
29
|
+
event, cb, options, paused
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Unbind callback(s) from event
|
|
37
|
+
*
|
|
38
|
+
* @example Event.unbind("x") // => Event
|
|
39
|
+
* @example Event.unbind(["a","b"]) // => Event
|
|
40
|
+
*
|
|
41
|
+
* @param {any} event Event name(s)
|
|
42
|
+
* @param {any} [options] Listener options
|
|
43
|
+
* @returns {typeof PicoEvent} Event class
|
|
44
|
+
*/
|
|
45
|
+
static unbind(event, options = {})
|
|
46
|
+
{
|
|
47
|
+
if ( Mix.isArr(event) ) {
|
|
48
|
+
return Arr.each(event, (e) => this.unbind(e, ...arguments), this);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if ( Mix.isPrim(options) ) {
|
|
52
|
+
options = { id: options };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Arr.remove(this.$events, {
|
|
56
|
+
event, options
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Fire event with arguments
|
|
64
|
+
*
|
|
65
|
+
* @example Event.fire("x", 1) // => Event
|
|
66
|
+
*
|
|
67
|
+
* @param {string} event Event name
|
|
68
|
+
* @param {...any} [args] Event args
|
|
69
|
+
* @returns {typeof PicoEvent} Event class
|
|
70
|
+
*/
|
|
71
|
+
static fire(event, ...args)
|
|
72
|
+
{
|
|
73
|
+
let events = this.$events.filter((item) => {
|
|
74
|
+
return item.event === event;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
Arr.each(events, (e) => {
|
|
78
|
+
if ( ! e.paused ) {
|
|
79
|
+
e.cb.call({}, ...args);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Pause listeners for event
|
|
88
|
+
*
|
|
89
|
+
* @example Event.pause("x") // => Event
|
|
90
|
+
*
|
|
91
|
+
* @param {any} event Event name(s)
|
|
92
|
+
* @param {any} [options] Listener options
|
|
93
|
+
* @returns {typeof PicoEvent} Event class
|
|
94
|
+
*/
|
|
95
|
+
static pause(event, options = {})
|
|
96
|
+
{
|
|
97
|
+
if ( Mix.isArr(event) ) {
|
|
98
|
+
return Arr.each(event, (e) => this.pause(e, ...arguments), this);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let value = Arr.find(this.$events, {
|
|
102
|
+
event, options
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if ( value != null ) {
|
|
106
|
+
value.paused = true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return this;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Unpause listeners for event
|
|
114
|
+
*
|
|
115
|
+
* @example Event.unpause("x") // => Event
|
|
116
|
+
*
|
|
117
|
+
* @param {any} event Event name(s)
|
|
118
|
+
* @param {any} [options] Listener options
|
|
119
|
+
* @returns {typeof PicoEvent} Event class
|
|
120
|
+
*/
|
|
121
|
+
static unpause(event, options = {})
|
|
122
|
+
{
|
|
123
|
+
if ( Mix.isArr(event) ) {
|
|
124
|
+
return Arr.each(event, (e) => this.pause(e, ...arguments), this);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let value = Arr.find(this.$events, {
|
|
128
|
+
event, options
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if ( value != null ) {
|
|
132
|
+
value.paused = false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export default PicoEvent;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { PicoFormatParserPlugin } from "#src/format/FormatParser.js";
|
|
2
|
+
import { PicoFormatParamPlugin } from "#src/format/FormatParam.js";
|
|
3
|
+
import { PicoFormatOptionPlugin } from "#src/format/FormatOption.js";
|
|
4
|
+
import { PicoFormatUrlPlugin } from "#src/format/FormatUrl.js";
|
|
5
|
+
import { PicoFormatFilePlugin } from "#src/format/FormatFile.js";
|
|
6
|
+
|
|
7
|
+
export const PicoFormatPlugins = [
|
|
8
|
+
PicoFormatParserPlugin,
|
|
9
|
+
PicoFormatParamPlugin,
|
|
10
|
+
PicoFormatOptionPlugin,
|
|
11
|
+
PicoFormatUrlPlugin,
|
|
12
|
+
PicoFormatFilePlugin,
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @class PicoFormat
|
|
17
|
+
*
|
|
18
|
+
* @typedef {import('#src/format/FormatParser.js').PicoFormatParserStatic} PicoFormatParserStatic
|
|
19
|
+
* @typedef {import('#src/format/FormatParam.js').PicoFormatParamStatic} PicoFormatParamStatic
|
|
20
|
+
* @typedef {import('#src/format/FormatOption.js').PicoFormatOptionStatic} PicoFormatOptionStatic
|
|
21
|
+
* @typedef {import('#src/format/FormatUrl.js').PicoFormatUrlStatic} PicoFormatUrlStatic
|
|
22
|
+
* @typedef {import('#src/format/FormatFile.js').PicoFormatFileStatic} PicoFormatFileStatic
|
|
23
|
+
*
|
|
24
|
+
* @mixes PicoFormatParserStatic
|
|
25
|
+
* @mixes PicoFormatParamStatic
|
|
26
|
+
* @mixes PicoFormatOptionStatic
|
|
27
|
+
* @mixes PicoFormatUrlStatic
|
|
28
|
+
* @mixes PicoFormatFileStatic
|
|
29
|
+
*/
|
|
30
|
+
export class PicoFormat
|
|
31
|
+
{
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Extend format with a plugin
|
|
35
|
+
*
|
|
36
|
+
* @example For.extend(fn)
|
|
37
|
+
*
|
|
38
|
+
* @param {function} plugin Plugin function
|
|
39
|
+
* @returns {void} No return value
|
|
40
|
+
*/
|
|
41
|
+
static extend(plugin)
|
|
42
|
+
{
|
|
43
|
+
plugin.call({}, this);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @returns {typeof PicoFormat}
|
|
50
|
+
*/
|
|
51
|
+
export function PicoFormatBuilder() {
|
|
52
|
+
|
|
53
|
+
let cls = PicoFormat;
|
|
54
|
+
|
|
55
|
+
for ( const plugin of PicoFormatPlugins ) {
|
|
56
|
+
cls = plugin.call(cls, cls);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return cls;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default PicoFormatBuilder;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { Str, Hash } from "#src/index.esm.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @var {Array<string>} RADIX_NUMBER Radix from 0 to 9
|
|
5
|
+
*/
|
|
6
|
+
export const RADIX_NUMBER = [
|
|
7
|
+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @var {Array<string>} RADIX_LETTER_LC Radix from a to z
|
|
12
|
+
*/
|
|
13
|
+
export const RADIX_LETTER_LC = [
|
|
14
|
+
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @var {Array<string>} RADIX_LETTER_UC Radix from A to Z
|
|
19
|
+
*/
|
|
20
|
+
export const RADIX_LETTER_UC = [
|
|
21
|
+
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @var {Array<string>} RADIX_UUID Radix from 0-9, a-f and A-F
|
|
26
|
+
*/
|
|
27
|
+
export const RADIX_UUID = [
|
|
28
|
+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F',
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @var {Array<string>} RADIX_UP19 Radix with 8, 9, a and b
|
|
34
|
+
*/
|
|
35
|
+
export const RADIX_UP19 = [
|
|
36
|
+
'8', '9', 'a', 'b',
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @var {Array<string>} radix_symbol_pass Radix for passwords
|
|
41
|
+
*/
|
|
42
|
+
export const radix_symbol_pass = [
|
|
43
|
+
'@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '-', '=', '[', ']', '{', '}', ';', ':', ',', '.', '/', '<', '>', '?'
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
export class PicoHash
|
|
47
|
+
{
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @var {Array<string>} RADIX
|
|
51
|
+
*/
|
|
52
|
+
static RADIX = [
|
|
53
|
+
...RADIX_NUMBER, ...RADIX_LETTER_LC, ...RADIX_LETTER_UC
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get random char from radix
|
|
58
|
+
*
|
|
59
|
+
* @example Hash.radix(2, ['R', 'f']) // => 'R' or 'f'
|
|
60
|
+
*
|
|
61
|
+
* @param {number} [limit=60] Maximum radix char index
|
|
62
|
+
* @param {Array<string>} [radix=null] A defined radix or null for default
|
|
63
|
+
* @returns {string} Returns random char from radix
|
|
64
|
+
*/
|
|
65
|
+
static radix(limit = 60, radix = null)
|
|
66
|
+
{
|
|
67
|
+
return (radix || this.RADIX)[this.number(limit - 1)];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get random number
|
|
72
|
+
*
|
|
73
|
+
* @example Hash.number(20, 18) // => 18, 19 or 20
|
|
74
|
+
*
|
|
75
|
+
* @param {number} [limit=1024] Maximum value
|
|
76
|
+
* @param {number} [start=0] Minimum value
|
|
77
|
+
* @returns {number} Returns a random number between start and limit
|
|
78
|
+
*/
|
|
79
|
+
static number(limit = 1024, start = 0)
|
|
80
|
+
{
|
|
81
|
+
return Math.floor(Math.random() * (limit - start + 1)) + start;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get a random hash with given options
|
|
86
|
+
*
|
|
87
|
+
* @example Hash.make(4, 32, { 0: '?' }) // => '?8Wj'
|
|
88
|
+
*
|
|
89
|
+
* @param {number} [length] Length of generated hash
|
|
90
|
+
* @param {number} [radix] Maximum radix char index (10 for 0-9, 36 incl. a-z, 62 incl. A-Z)
|
|
91
|
+
* @param {Record<number, string>} [map] Remap for generated string
|
|
92
|
+
* @returns {string} Returns a random hash with fixed length
|
|
93
|
+
*/
|
|
94
|
+
static make(length = 6, radix = 62, map = {})
|
|
95
|
+
{
|
|
96
|
+
let hash = '';
|
|
97
|
+
|
|
98
|
+
for ( let i = 0; i < length; i ++ ) {
|
|
99
|
+
hash += Hash.radix(radix);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for ( const k of Object.keys(map) ) {
|
|
103
|
+
hash = Str.set(hash, k, map[k]);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return hash;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get a valid v4 UUID
|
|
111
|
+
*
|
|
112
|
+
* @example Hash.uuid() // => 'FBbA001F-0a01-4bE8-b29C-A9c47fA090f'
|
|
113
|
+
*
|
|
114
|
+
* @param {string|number} [version] UUID version number
|
|
115
|
+
* @returns {string} Returns a valid UUID
|
|
116
|
+
*/
|
|
117
|
+
static uuid(version = 4)
|
|
118
|
+
{
|
|
119
|
+
let hash = '';
|
|
120
|
+
|
|
121
|
+
// Use only selected chars from the radix store
|
|
122
|
+
for ( let i = 0; i < 31; i ++ ) {
|
|
123
|
+
if ( i === 15 ) {
|
|
124
|
+
hash += Hash.radix(RADIX_UP19.length, RADIX_UP19);
|
|
125
|
+
} else {
|
|
126
|
+
hash += Hash.radix(RADIX_UUID.length, RADIX_UUID);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// For higher performance use substring
|
|
131
|
+
return hash.substring(0, 8)
|
|
132
|
+
+ '-' + hash.substring(8, 12)
|
|
133
|
+
+ '-' + version + hash.substring(12, 15)
|
|
134
|
+
+ '-' + hash.substring(15, 19)
|
|
135
|
+
+ '-' + hash.substring(19, 31);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Generate a password with or without symbols
|
|
140
|
+
*
|
|
141
|
+
* @example Hash.password(12, ['%', '&']) // => '0unJ%VDi2RJX'
|
|
142
|
+
*
|
|
143
|
+
* @param {number} [length=24] Length of password
|
|
144
|
+
* @param {Array<string>} [symbols=null] Defined symbols or null for default
|
|
145
|
+
* @returns {string} A random password with fixed length
|
|
146
|
+
*/
|
|
147
|
+
static password(length = 24, symbols = null)
|
|
148
|
+
{
|
|
149
|
+
let radix = [
|
|
150
|
+
...this.RADIX, ...(symbols || radix_symbol_pass)
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
let hash = '';
|
|
154
|
+
|
|
155
|
+
for ( let i = 0; i < length; i ++ ) {
|
|
156
|
+
hash += Hash.radix(radix.length, radix);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return hash;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export default PicoHash;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { Mix, Obj, Locale } from "#src/index.esm.js";
|
|
2
|
+
|
|
3
|
+
export class PicoLocale
|
|
4
|
+
{
|
|
5
|
+
/**
|
|
6
|
+
* Translation dictionary
|
|
7
|
+
*
|
|
8
|
+
* @type {Record<any, any>}
|
|
9
|
+
*/
|
|
10
|
+
static $text = {};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Cached collator instance
|
|
14
|
+
*
|
|
15
|
+
* @type {Intl.Collator|null}
|
|
16
|
+
*/
|
|
17
|
+
static $sort = null;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Active locale code
|
|
21
|
+
*
|
|
22
|
+
* @type {string}
|
|
23
|
+
*/
|
|
24
|
+
static $code = 'en';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Check if translation key exists
|
|
28
|
+
*
|
|
29
|
+
* @example Locale.has("known.key") // => true
|
|
30
|
+
* @example Locale.has("unknown.key") // => false
|
|
31
|
+
*
|
|
32
|
+
* @param {any} [key] Translation key
|
|
33
|
+
* @returns {boolean} True if exists
|
|
34
|
+
*/
|
|
35
|
+
static has(key = undefined)
|
|
36
|
+
{
|
|
37
|
+
if ( key === undefined ) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return Mix.has(PicoLocale.$text, key);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get translation value or map
|
|
46
|
+
*
|
|
47
|
+
* @example Locale.get("known.key") // => "value"
|
|
48
|
+
* @example Locale.get() // => object
|
|
49
|
+
*
|
|
50
|
+
* @param {any} [key] Translation key
|
|
51
|
+
* @param {any} [fallback] Fallback value
|
|
52
|
+
* @returns {any} Translation value
|
|
53
|
+
*/
|
|
54
|
+
static get(key = undefined, fallback = null)
|
|
55
|
+
{
|
|
56
|
+
if ( key === undefined ) {
|
|
57
|
+
return PicoLocale.$text;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return Obj.get(PicoLocale.$text, key, fallback);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Set translation key or map
|
|
65
|
+
*
|
|
66
|
+
* @example Locale.set({foo:"bar"})
|
|
67
|
+
* @example Locale.set("unknown", "nix")
|
|
68
|
+
*
|
|
69
|
+
* @param {any} [key] Key or map
|
|
70
|
+
* @param {any} [value] Value to set
|
|
71
|
+
* @returns {any} Updated map
|
|
72
|
+
*/
|
|
73
|
+
static set(key = undefined, value = undefined)
|
|
74
|
+
{
|
|
75
|
+
if ( value === undefined ) {
|
|
76
|
+
return PicoLocale.$text = key;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return Obj.set(PicoLocale.$text, key, value);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get or set locale code
|
|
84
|
+
*
|
|
85
|
+
* @example Locale.code() // => "en"
|
|
86
|
+
* @example Locale.code("de") // => "de"
|
|
87
|
+
*
|
|
88
|
+
* @param {string|null} [code] Locale code
|
|
89
|
+
* @returns {string} Active code
|
|
90
|
+
*/
|
|
91
|
+
static code(code = null)
|
|
92
|
+
{
|
|
93
|
+
if ( ! Mix.isNull(code) ) {
|
|
94
|
+
return Locale.$code = code;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if ( ! Mix.isNull(Locale.$code) ) {
|
|
98
|
+
return Locale.$code;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
Locale.$code = (navigator.language || 'en-US')
|
|
102
|
+
.replace(/-[A-Z]+$/, '');
|
|
103
|
+
|
|
104
|
+
return Locale.$code;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get Intl.Collator for sorting
|
|
109
|
+
*
|
|
110
|
+
* @example Locale.collator().compare("a","b")
|
|
111
|
+
*
|
|
112
|
+
* @returns {Intl.Collator} Collator instance
|
|
113
|
+
*/
|
|
114
|
+
static collator()
|
|
115
|
+
{
|
|
116
|
+
if ( ! Mix.isNull(Locale.$sort) ) {
|
|
117
|
+
return Locale.$sort;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Locale.$sort = new Intl.Collator(Locale.code(), {
|
|
121
|
+
numeric: true, sensitivity: 'base'
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return Locale.$sort;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Replace :tokens in text
|
|
129
|
+
*
|
|
130
|
+
* @example Locale.replace("Hi :x", {x:"Bob"}) // => "Hi Bob"
|
|
131
|
+
* @example Locale.replace("Hi", null) // => "Hi"
|
|
132
|
+
*
|
|
133
|
+
* @param {string} text Input text
|
|
134
|
+
* @param {any} [replace] Replace map
|
|
135
|
+
* @returns {string} Replaced text
|
|
136
|
+
*/
|
|
137
|
+
static replace(text, replace = null)
|
|
138
|
+
{
|
|
139
|
+
if ( replace == null ) {
|
|
140
|
+
return text;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
Obj.each(replace, (val, key) => {
|
|
144
|
+
text = text.replace(new RegExp(':' + key, 'g'), val);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
return text;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Translate key with replace map
|
|
152
|
+
*
|
|
153
|
+
* @example Locale.trans("known.key") // => "..."
|
|
154
|
+
* @example Locale.trans("Hi :x", {x:"Bob"}) // => "Hi Bob"
|
|
155
|
+
*
|
|
156
|
+
* @param {string} text Key or text
|
|
157
|
+
* @param {any} [replace] Replace map
|
|
158
|
+
* @returns {string} Translated text
|
|
159
|
+
*/
|
|
160
|
+
static trans(text, replace = null)
|
|
161
|
+
{
|
|
162
|
+
text = Obj.get(PicoLocale.$text, text, text);
|
|
163
|
+
|
|
164
|
+
return Locale.replace(text, replace);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Translate plural choice by count
|
|
169
|
+
*
|
|
170
|
+
* @example Locale.choice("items", 2) // => "..."
|
|
171
|
+
* @example Locale.choice("items", 1, {x:"y"}) // => "..."
|
|
172
|
+
*
|
|
173
|
+
* @param {string} text Key or text
|
|
174
|
+
* @param {number} [count] Choice count
|
|
175
|
+
* @param {any} [replace] Replace map
|
|
176
|
+
* @returns {string} Chosen text
|
|
177
|
+
*/
|
|
178
|
+
static choice(text, count = 0, replace = {})
|
|
179
|
+
{
|
|
180
|
+
text = Obj.get(PicoLocale.$text, text, text);
|
|
181
|
+
|
|
182
|
+
if ( typeof replace.count === 'undefined' ) {
|
|
183
|
+
replace.count = count;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
text = Locale.countpick(text.split('|'), count);
|
|
187
|
+
|
|
188
|
+
return Locale.replace(text, replace);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Pick plural variant from list
|
|
193
|
+
*
|
|
194
|
+
* @example Locale.countpick(["a","b"], 2) // => "b"
|
|
195
|
+
*
|
|
196
|
+
* @param {Array<string>} splits Variant list
|
|
197
|
+
* @param {number} count Choice count
|
|
198
|
+
* @returns {string} Picked text
|
|
199
|
+
*/
|
|
200
|
+
static countpick(splits, count)
|
|
201
|
+
{
|
|
202
|
+
let length = splits.length;
|
|
203
|
+
|
|
204
|
+
if ( length === 3 && count === 0 ) {
|
|
205
|
+
return splits[0];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if ( length === 3 && count === 1 ) {
|
|
209
|
+
return splits[1];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if ( length === 3 && count >= 2 ) {
|
|
213
|
+
return splits[2];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if ( length === 2 && count === 1 ) {
|
|
217
|
+
return splits[0];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if ( length === 2 && count !== 1 ) {
|
|
221
|
+
return splits[1];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return splits[0];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export default PicoLocale
|