@igo2/utils 1.15.4 → 16.0.0-rc.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/{esm2020 → esm2022}/igo2-utils.mjs +4 -4
- package/esm2022/lib/base64.mjs +85 -0
- package/esm2022/lib/cache.utils.mjs +10 -0
- package/esm2022/lib/change.interface.mjs +7 -0
- package/esm2022/lib/change.mjs +87 -0
- package/{esm2020 → esm2022}/lib/clipboard.mjs +52 -52
- package/esm2022/lib/dom.utils.mjs +16 -0
- package/esm2022/lib/file.mjs +28 -0
- package/esm2022/lib/index.mjs +16 -0
- package/esm2022/lib/number-utils.mjs +7 -0
- package/esm2022/lib/object-utils.mjs +248 -0
- package/{esm2020 → esm2022}/lib/strenum.mjs +8 -8
- package/{esm2020 → esm2022}/lib/string-utils.mjs +113 -105
- package/esm2022/lib/theme.utils.mjs +18 -0
- package/{esm2020 → esm2022}/lib/user-agent.mjs +3 -3
- package/{esm2020 → esm2022}/lib/uuid.mjs +9 -9
- package/esm2022/lib/watcher.mjs +40 -0
- package/{esm2020 → esm2022}/public_api.mjs +5 -5
- package/{fesm2020 → fesm2022}/igo2-utils.mjs +706 -656
- package/fesm2022/igo2-utils.mjs.map +1 -0
- package/index.d.ts +5 -5
- package/lib/base64.d.ts +8 -8
- package/lib/cache.utils.d.ts +1 -0
- package/lib/change.d.ts +5 -5
- package/lib/change.interface.d.ts +24 -24
- package/lib/clipboard.d.ts +7 -7
- package/lib/dom.utils.d.ts +4 -0
- package/lib/file.d.ts +16 -16
- package/lib/index.d.ts +15 -12
- package/lib/number-utils.d.ts +3 -3
- package/lib/object-utils.d.ts +27 -26
- package/lib/strenum.d.ts +4 -4
- package/lib/string-utils.d.ts +8 -6
- package/lib/theme.utils.d.ts +1 -0
- package/lib/user-agent.d.ts +5 -5
- package/lib/uuid.d.ts +2 -2
- package/lib/watcher.d.ts +19 -19
- package/package.json +10 -16
- package/public_api.d.ts +1 -1
- package/esm2020/lib/base64.mjs +0 -85
- package/esm2020/lib/change.interface.mjs +0 -7
- package/esm2020/lib/change.mjs +0 -87
- package/esm2020/lib/file.mjs +0 -28
- package/esm2020/lib/index.mjs +0 -13
- package/esm2020/lib/number-utils.mjs +0 -7
- package/esm2020/lib/object-utils.mjs +0 -248
- package/esm2020/lib/watcher.mjs +0 -41
- package/fesm2015/igo2-utils.mjs +0 -688
- package/fesm2015/igo2-utils.mjs.map +0 -1
- package/fesm2020/igo2-utils.mjs.map +0 -1
|
@@ -1,688 +1,738 @@
|
|
|
1
|
+
import { HttpParams } from '@angular/common/http';
|
|
1
2
|
import * as Bowser from 'bowser';
|
|
2
3
|
import { Subject } from 'rxjs';
|
|
3
4
|
import { distinctUntilChanged } from 'rxjs/operators';
|
|
4
5
|
|
|
5
|
-
/* eslint-disable */
|
|
6
|
-
const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
7
|
-
class Base64 {
|
|
8
|
-
static
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.getByte64(s, i +
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
x.push(this.ALPHA.charAt(
|
|
66
|
-
x.push(this.ALPHA.charAt(b10 & 63));
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
6
|
+
/* eslint-disable */
|
|
7
|
+
const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
8
|
+
class Base64 {
|
|
9
|
+
static PADCHAR = '=';
|
|
10
|
+
static ALPHA = ALPHA;
|
|
11
|
+
static getByte(s, i) {
|
|
12
|
+
const x = s.charCodeAt(i);
|
|
13
|
+
return x;
|
|
14
|
+
}
|
|
15
|
+
static getByte64(s, i) {
|
|
16
|
+
const idx = this.ALPHA.indexOf(s.charAt(i));
|
|
17
|
+
return idx;
|
|
18
|
+
}
|
|
19
|
+
static decode(s) {
|
|
20
|
+
let pads = 0, i, b10, imax = s.length, x = [];
|
|
21
|
+
s = String(s);
|
|
22
|
+
if (imax === 0) {
|
|
23
|
+
return s;
|
|
24
|
+
}
|
|
25
|
+
if (s.charAt(imax - 1) === this.PADCHAR) {
|
|
26
|
+
pads = 1;
|
|
27
|
+
if (s.charAt(imax - 2) === this.PADCHAR) {
|
|
28
|
+
pads = 2;
|
|
29
|
+
}
|
|
30
|
+
imax -= 4;
|
|
31
|
+
}
|
|
32
|
+
for (i = 0; i < imax; i += 4) {
|
|
33
|
+
b10 =
|
|
34
|
+
(this.getByte64(s, i) << 18) |
|
|
35
|
+
(this.getByte64(s, i + 1) << 12) |
|
|
36
|
+
(this.getByte64(s, i + 2) << 6) |
|
|
37
|
+
this.getByte64(s, i + 3);
|
|
38
|
+
x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 255, b10 & 255));
|
|
39
|
+
}
|
|
40
|
+
switch (pads) {
|
|
41
|
+
case 1:
|
|
42
|
+
b10 =
|
|
43
|
+
(this.getByte64(s, i) << 18) |
|
|
44
|
+
(this.getByte64(s, i + 1) << 12) |
|
|
45
|
+
(this.getByte64(s, i + 2) << 6);
|
|
46
|
+
x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 255));
|
|
47
|
+
break;
|
|
48
|
+
case 2:
|
|
49
|
+
b10 = (this.getByte64(s, i) << 18) | (this.getByte64(s, i + 1) << 12);
|
|
50
|
+
x.push(String.fromCharCode(b10 >> 16));
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
return x.join('');
|
|
54
|
+
}
|
|
55
|
+
static encode(s) {
|
|
56
|
+
s = String(s);
|
|
57
|
+
let i, b10, x = [], imax = s.length - (s.length % 3);
|
|
58
|
+
if (s.length === 0) {
|
|
59
|
+
return s;
|
|
60
|
+
}
|
|
61
|
+
for (i = 0; i < imax; i += 3) {
|
|
62
|
+
b10 =
|
|
63
|
+
(this.getByte(s, i) << 16) |
|
|
64
|
+
(this.getByte(s, i + 1) << 8) |
|
|
65
|
+
this.getByte(s, i + 2);
|
|
66
|
+
x.push(this.ALPHA.charAt(b10 >> 18));
|
|
67
|
+
x.push(this.ALPHA.charAt((b10 >> 12) & 63));
|
|
68
|
+
x.push(this.ALPHA.charAt((b10 >> 6) & 63));
|
|
69
|
+
x.push(this.ALPHA.charAt(b10 & 63));
|
|
70
|
+
}
|
|
71
|
+
switch (s.length - imax) {
|
|
72
|
+
case 1:
|
|
73
|
+
b10 = this.getByte(s, i) << 16;
|
|
74
|
+
x.push(this.ALPHA.charAt(b10 >> 18) +
|
|
75
|
+
this.ALPHA.charAt((b10 >> 12) & 63) +
|
|
76
|
+
this.PADCHAR +
|
|
77
|
+
this.PADCHAR);
|
|
78
|
+
break;
|
|
79
|
+
case 2:
|
|
80
|
+
b10 = (this.getByte(s, i) << 16) | (this.getByte(s, i + 1) << 8);
|
|
81
|
+
x.push(this.ALPHA.charAt(b10 >> 18) +
|
|
82
|
+
this.ALPHA.charAt((b10 >> 12) & 63) +
|
|
83
|
+
this.ALPHA.charAt((b10 >> 6) & 63) +
|
|
84
|
+
this.PADCHAR);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
return x.join('');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function customCacheHasher(parameters) {
|
|
92
|
+
return parameters.map((param) => {
|
|
93
|
+
if (param instanceof HttpParams) {
|
|
94
|
+
return param.toString();
|
|
95
|
+
}
|
|
96
|
+
return param !== undefined ? JSON.parse(JSON.stringify(param)) : param;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
89
99
|
|
|
90
100
|
const userAgent = Bowser.getParser(window.navigator.userAgent);
|
|
91
101
|
|
|
92
|
-
class Clipboard {
|
|
93
|
-
static copy(element) {
|
|
94
|
-
let successful = false;
|
|
95
|
-
if (typeof element === 'string') {
|
|
96
|
-
const textArea = Clipboard.createTextArea(element);
|
|
97
|
-
Clipboard.selectText(textArea);
|
|
98
|
-
successful = Clipboard.copyTextToClipboard();
|
|
99
|
-
Clipboard.destroyTextArea(textArea);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
Clipboard.selectText(element);
|
|
103
|
-
successful = Clipboard.copyTextToClipboard();
|
|
104
|
-
}
|
|
105
|
-
return successful;
|
|
106
|
-
}
|
|
107
|
-
static createTextArea(text) {
|
|
108
|
-
const textArea = document.createElement('textArea');
|
|
109
|
-
textArea.value = text;
|
|
110
|
-
document.body.appendChild(textArea);
|
|
111
|
-
return textArea;
|
|
112
|
-
}
|
|
113
|
-
static destroyTextArea(textArea) {
|
|
114
|
-
document.body.removeChild(textArea);
|
|
115
|
-
}
|
|
116
|
-
static selectText(textArea) {
|
|
117
|
-
if (userAgent.getOSName() === 'iOS') {
|
|
118
|
-
const oldContentEditable = textArea.contentEditable;
|
|
119
|
-
const oldReadOnly = textArea.readOnly;
|
|
120
|
-
const range = document.createRange();
|
|
121
|
-
const selection = window.getSelection();
|
|
122
|
-
textArea.contenteditable = true;
|
|
123
|
-
textArea.readonly = false;
|
|
124
|
-
range.selectNodeContents(textArea);
|
|
125
|
-
selection.removeAllRanges();
|
|
126
|
-
selection.addRange(range);
|
|
127
|
-
textArea.setSelectionRange(0, 999999);
|
|
128
|
-
textArea.contentEditable = oldContentEditable;
|
|
129
|
-
textArea.readOnly = oldReadOnly;
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
textArea.select();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
static copyTextToClipboard() {
|
|
136
|
-
if (!(userAgent.getOSName() === 'iOS' && userAgent.compareVersion('<10'))) {
|
|
137
|
-
return document.execCommand('copy');
|
|
138
|
-
}
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
102
|
+
class Clipboard {
|
|
103
|
+
static copy(element) {
|
|
104
|
+
let successful = false;
|
|
105
|
+
if (typeof element === 'string') {
|
|
106
|
+
const textArea = Clipboard.createTextArea(element);
|
|
107
|
+
Clipboard.selectText(textArea);
|
|
108
|
+
successful = Clipboard.copyTextToClipboard();
|
|
109
|
+
Clipboard.destroyTextArea(textArea);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
Clipboard.selectText(element);
|
|
113
|
+
successful = Clipboard.copyTextToClipboard();
|
|
114
|
+
}
|
|
115
|
+
return successful;
|
|
116
|
+
}
|
|
117
|
+
static createTextArea(text) {
|
|
118
|
+
const textArea = document.createElement('textArea');
|
|
119
|
+
textArea.value = text;
|
|
120
|
+
document.body.appendChild(textArea);
|
|
121
|
+
return textArea;
|
|
122
|
+
}
|
|
123
|
+
static destroyTextArea(textArea) {
|
|
124
|
+
document.body.removeChild(textArea);
|
|
125
|
+
}
|
|
126
|
+
static selectText(textArea) {
|
|
127
|
+
if (userAgent.getOSName() === 'iOS') {
|
|
128
|
+
const oldContentEditable = textArea.contentEditable;
|
|
129
|
+
const oldReadOnly = textArea.readOnly;
|
|
130
|
+
const range = document.createRange();
|
|
131
|
+
const selection = window.getSelection();
|
|
132
|
+
textArea.contenteditable = true;
|
|
133
|
+
textArea.readonly = false;
|
|
134
|
+
range.selectNodeContents(textArea);
|
|
135
|
+
selection.removeAllRanges();
|
|
136
|
+
selection.addRange(range);
|
|
137
|
+
textArea.setSelectionRange(0, 999999);
|
|
138
|
+
textArea.contentEditable = oldContentEditable;
|
|
139
|
+
textArea.readOnly = oldReadOnly;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
textArea.select();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
static copyTextToClipboard() {
|
|
146
|
+
if (!(userAgent.getOSName() === 'iOS' && userAgent.compareVersion('<10'))) {
|
|
147
|
+
return document.execCommand('copy');
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
141
151
|
}
|
|
142
152
|
|
|
143
|
-
class StringUtils {
|
|
144
|
-
static diff(s1, s2, p = 4) {
|
|
145
|
-
if (!s1 && !s2) {
|
|
146
|
-
return '';
|
|
147
|
-
}
|
|
148
|
-
if (!s1) {
|
|
149
|
-
return '<span class="inserted">' + s2 + '</span>';
|
|
150
|
-
}
|
|
151
|
-
if (!s2) {
|
|
152
|
-
return '<span class="deleted">' + s1 + '</span>';
|
|
153
|
-
}
|
|
154
|
-
s1 = s1.toString();
|
|
155
|
-
s2 = s2.toString();
|
|
156
|
-
const changeData = StringUtils.getChanges(s1, s2, '', p);
|
|
157
|
-
const nextS = s2.slice(changeData.mtc.length + changeData.ins.length + changeData.sbs.length); // remaining part of "s"
|
|
158
|
-
const nextThis = s1.slice(changeData.mtc.length + changeData.del.length + changeData.sbs.length); // remaining part of "this"
|
|
159
|
-
let result = ''; // the glorious result
|
|
160
|
-
if (changeData.del.length > 0) {
|
|
161
|
-
changeData.del = '<span class="deleted">' + changeData.del + '</span>';
|
|
162
|
-
}
|
|
163
|
-
if (changeData.ins.length > 0) {
|
|
164
|
-
changeData.ins = '<span class="inserted">' + changeData.ins + '</span>';
|
|
165
|
-
}
|
|
166
|
-
result = changeData.mtc + changeData.del + changeData.ins + changeData.sbs;
|
|
167
|
-
result +=
|
|
168
|
-
nextThis !== '' || nextS !== ''
|
|
169
|
-
? StringUtils.diff(nextThis, nextS, p)
|
|
170
|
-
: '';
|
|
171
|
-
return result;
|
|
172
|
-
}
|
|
173
|
-
static getMatchingSubstring(s, l, m) {
|
|
174
|
-
// returns the first matching substring in-between the two strings
|
|
175
|
-
let i = 0;
|
|
176
|
-
let match = false;
|
|
177
|
-
const slen = s.length;
|
|
178
|
-
const o = { fis: slen, mtc: m, sbs: '' }; // temporary object used to construct the cd (change data) object
|
|
179
|
-
while (i < slen) {
|
|
180
|
-
l[i] === s[i]
|
|
181
|
-
? match
|
|
182
|
-
? (o.sbs += s[i]) // o.sbs holds the matching substring itsef
|
|
183
|
-
: ((match = true), (o.fis = i), (o.sbs = s[i]))
|
|
184
|
-
: match
|
|
185
|
-
? (i = slen) // stop after the first found substring
|
|
186
|
-
: (i = i);
|
|
187
|
-
++i;
|
|
188
|
-
}
|
|
189
|
-
return o;
|
|
190
|
-
}
|
|
191
|
-
static getChanges(s1, s2, m, p) {
|
|
192
|
-
const isThisLonger = s1.length >= s1.length ? true : false;
|
|
193
|
-
let [longer, shorter] = isThisLonger ? [s1, s2] : [s2, s1]; // assignment of longer and shorter by es6 destructuring
|
|
194
|
-
let bi = 0; // base index designating the index of first mismacthing character in both strings
|
|
195
|
-
while (shorter[bi] === longer[bi] && bi < shorter.length) {
|
|
196
|
-
++bi;
|
|
197
|
-
} // make bi the index of first mismatching character
|
|
198
|
-
longer = longer.split('').slice(bi); // as the longer string will be rotated it is converted into array
|
|
199
|
-
shorter = shorter.slice(bi); // shorter and longer now starts from the first mismatching character
|
|
200
|
-
const len = longer.length; // length of the longer string
|
|
201
|
-
let cd = {
|
|
202
|
-
fis: shorter.length,
|
|
203
|
-
fil: len,
|
|
204
|
-
sbs: '',
|
|
205
|
-
mtc: m + s2.slice(0, bi)
|
|
206
|
-
}; // if exists mtc holds the matching string at the front
|
|
207
|
-
let sub = { sbs: '' }; // returned substring per 1 character rotation of the longer string
|
|
208
|
-
if (shorter !== '') {
|
|
209
|
-
for (let rc = 0; rc < len && sub.sbs.length < p; rc++) {
|
|
210
|
-
// rc -> rotate count, p -> precision factor
|
|
211
|
-
sub = StringUtils.getMatchingSubstring(shorter, StringUtils.rotateArray(longer, rc), cd.mtc); // rotate longer string 1 char and get substring
|
|
212
|
-
sub.fil =
|
|
213
|
-
rc < len - sub.fis
|
|
214
|
-
? sub.fis + rc // mismatch is longer than the mismatch in short
|
|
215
|
-
: sub.fis - len + rc; // mismatch is shorter than the mismatch in short
|
|
216
|
-
if (sub.sbs.length > cd.sbs.length) {
|
|
217
|
-
cd = sub; // only keep the one with the longest substring.
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
// insert the mismatching delete subsrt and insert substr to the cd object and attach the previous substring
|
|
222
|
-
[cd.del, cd.ins] = isThisLonger
|
|
223
|
-
? [longer.slice(0, cd.fil).join(''), shorter.slice(0, cd.fis)]
|
|
224
|
-
: [shorter.slice(0, cd.fis), longer.slice(0, cd.fil).join('')];
|
|
225
|
-
return cd.del.indexOf(' ') === -1 ||
|
|
226
|
-
cd.ins.indexOf(' ') === -1 ||
|
|
227
|
-
cd.del === '' ||
|
|
228
|
-
cd.ins === '' ||
|
|
229
|
-
cd.sbs === ''
|
|
230
|
-
? cd
|
|
231
|
-
: StringUtils.getChanges(cd.del, cd.ins, cd.mtc, p);
|
|
232
|
-
}
|
|
233
|
-
static rotateArray(array, n) {
|
|
234
|
-
const len = array.length;
|
|
235
|
-
const res = new Array(array.length);
|
|
236
|
-
if (n % len === 0) {
|
|
237
|
-
return array.slice();
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
for (let i = 0; i < len; i++) {
|
|
241
|
-
res[i] = array[(i + (len + (n % len))) % len];
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return res;
|
|
245
|
-
}
|
|
153
|
+
class StringUtils {
|
|
154
|
+
static diff(s1, s2, p = 4) {
|
|
155
|
+
if (!s1 && !s2) {
|
|
156
|
+
return '';
|
|
157
|
+
}
|
|
158
|
+
if (!s1) {
|
|
159
|
+
return '<span class="inserted">' + s2 + '</span>';
|
|
160
|
+
}
|
|
161
|
+
if (!s2) {
|
|
162
|
+
return '<span class="deleted">' + s1 + '</span>';
|
|
163
|
+
}
|
|
164
|
+
s1 = s1.toString();
|
|
165
|
+
s2 = s2.toString();
|
|
166
|
+
const changeData = StringUtils.getChanges(s1, s2, '', p);
|
|
167
|
+
const nextS = s2.slice(changeData.mtc.length + changeData.ins.length + changeData.sbs.length); // remaining part of "s"
|
|
168
|
+
const nextThis = s1.slice(changeData.mtc.length + changeData.del.length + changeData.sbs.length); // remaining part of "this"
|
|
169
|
+
let result = ''; // the glorious result
|
|
170
|
+
if (changeData.del.length > 0) {
|
|
171
|
+
changeData.del = '<span class="deleted">' + changeData.del + '</span>';
|
|
172
|
+
}
|
|
173
|
+
if (changeData.ins.length > 0) {
|
|
174
|
+
changeData.ins = '<span class="inserted">' + changeData.ins + '</span>';
|
|
175
|
+
}
|
|
176
|
+
result = changeData.mtc + changeData.del + changeData.ins + changeData.sbs;
|
|
177
|
+
result +=
|
|
178
|
+
nextThis !== '' || nextS !== ''
|
|
179
|
+
? StringUtils.diff(nextThis, nextS, p)
|
|
180
|
+
: '';
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
static getMatchingSubstring(s, l, m) {
|
|
184
|
+
// returns the first matching substring in-between the two strings
|
|
185
|
+
let i = 0;
|
|
186
|
+
let match = false;
|
|
187
|
+
const slen = s.length;
|
|
188
|
+
const o = { fis: slen, mtc: m, sbs: '' }; // temporary object used to construct the cd (change data) object
|
|
189
|
+
while (i < slen) {
|
|
190
|
+
l[i] === s[i]
|
|
191
|
+
? match
|
|
192
|
+
? (o.sbs += s[i]) // o.sbs holds the matching substring itsef
|
|
193
|
+
: ((match = true), (o.fis = i), (o.sbs = s[i]))
|
|
194
|
+
: match
|
|
195
|
+
? (i = slen) // stop after the first found substring
|
|
196
|
+
: (i = i);
|
|
197
|
+
++i;
|
|
198
|
+
}
|
|
199
|
+
return o;
|
|
200
|
+
}
|
|
201
|
+
static getChanges(s1, s2, m, p) {
|
|
202
|
+
const isThisLonger = s1.length >= s1.length ? true : false;
|
|
203
|
+
let [longer, shorter] = isThisLonger ? [s1, s2] : [s2, s1]; // assignment of longer and shorter by es6 destructuring
|
|
204
|
+
let bi = 0; // base index designating the index of first mismacthing character in both strings
|
|
205
|
+
while (shorter[bi] === longer[bi] && bi < shorter.length) {
|
|
206
|
+
++bi;
|
|
207
|
+
} // make bi the index of first mismatching character
|
|
208
|
+
longer = longer.split('').slice(bi); // as the longer string will be rotated it is converted into array
|
|
209
|
+
shorter = shorter.slice(bi); // shorter and longer now starts from the first mismatching character
|
|
210
|
+
const len = longer.length; // length of the longer string
|
|
211
|
+
let cd = {
|
|
212
|
+
fis: shorter.length,
|
|
213
|
+
fil: len,
|
|
214
|
+
sbs: '',
|
|
215
|
+
mtc: m + s2.slice(0, bi)
|
|
216
|
+
}; // if exists mtc holds the matching string at the front
|
|
217
|
+
let sub = { sbs: '' }; // returned substring per 1 character rotation of the longer string
|
|
218
|
+
if (shorter !== '') {
|
|
219
|
+
for (let rc = 0; rc < len && sub.sbs.length < p; rc++) {
|
|
220
|
+
// rc -> rotate count, p -> precision factor
|
|
221
|
+
sub = StringUtils.getMatchingSubstring(shorter, StringUtils.rotateArray(longer, rc), cd.mtc); // rotate longer string 1 char and get substring
|
|
222
|
+
sub.fil =
|
|
223
|
+
rc < len - sub.fis
|
|
224
|
+
? sub.fis + rc // mismatch is longer than the mismatch in short
|
|
225
|
+
: sub.fis - len + rc; // mismatch is shorter than the mismatch in short
|
|
226
|
+
if (sub.sbs.length > cd.sbs.length) {
|
|
227
|
+
cd = sub; // only keep the one with the longest substring.
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// insert the mismatching delete subsrt and insert substr to the cd object and attach the previous substring
|
|
232
|
+
[cd.del, cd.ins] = isThisLonger
|
|
233
|
+
? [longer.slice(0, cd.fil).join(''), shorter.slice(0, cd.fis)]
|
|
234
|
+
: [shorter.slice(0, cd.fis), longer.slice(0, cd.fil).join('')];
|
|
235
|
+
return cd.del.indexOf(' ') === -1 ||
|
|
236
|
+
cd.ins.indexOf(' ') === -1 ||
|
|
237
|
+
cd.del === '' ||
|
|
238
|
+
cd.ins === '' ||
|
|
239
|
+
cd.sbs === ''
|
|
240
|
+
? cd
|
|
241
|
+
: StringUtils.getChanges(cd.del, cd.ins, cd.mtc, p);
|
|
242
|
+
}
|
|
243
|
+
static rotateArray(array, n) {
|
|
244
|
+
const len = array.length;
|
|
245
|
+
const res = new Array(array.length);
|
|
246
|
+
if (n % len === 0) {
|
|
247
|
+
return array.slice();
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
for (let i = 0; i < len; i++) {
|
|
251
|
+
res[i] = array[(i + (len + (n % len))) % len];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return res;
|
|
255
|
+
}
|
|
256
|
+
static isValidNumber(value) {
|
|
257
|
+
return !isNaN(Number(value));
|
|
258
|
+
}
|
|
259
|
+
static isOctalNumber(value) {
|
|
260
|
+
return (StringUtils.isValidNumber(value) &&
|
|
261
|
+
value.startsWith('0') &&
|
|
262
|
+
value.length > 1);
|
|
263
|
+
}
|
|
246
264
|
}
|
|
247
265
|
|
|
248
|
-
var ChangeType;
|
|
249
|
-
(function (ChangeType) {
|
|
250
|
-
ChangeType["ADDED"] = "added";
|
|
251
|
-
ChangeType["DELETED"] = "deleted";
|
|
252
|
-
ChangeType["MODIFIED"] = "modified";
|
|
266
|
+
var ChangeType;
|
|
267
|
+
(function (ChangeType) {
|
|
268
|
+
ChangeType["ADDED"] = "added";
|
|
269
|
+
ChangeType["DELETED"] = "deleted";
|
|
270
|
+
ChangeType["MODIFIED"] = "modified";
|
|
253
271
|
})(ChangeType || (ChangeType = {}));
|
|
254
272
|
|
|
255
|
-
class ChangeUtils {
|
|
256
|
-
static findChanges(obj1, obj2, ignoreKeys = []) {
|
|
257
|
-
const items = {
|
|
258
|
-
added: [],
|
|
259
|
-
deleted: [],
|
|
260
|
-
modified: []
|
|
261
|
-
};
|
|
262
|
-
if (!obj1 || !obj2) {
|
|
263
|
-
return items;
|
|
264
|
-
}
|
|
265
|
-
const obj1Clone = [...obj1];
|
|
266
|
-
const obj2Clone = [...obj2];
|
|
267
|
-
for (const fromItem of obj1Clone) {
|
|
268
|
-
const index = obj2Clone.findIndex(s => s.id === fromItem.id);
|
|
269
|
-
if (index === -1) {
|
|
270
|
-
items.deleted.push({
|
|
271
|
-
change: { type: ChangeType.DELETED },
|
|
272
|
-
value: fromItem
|
|
273
|
-
});
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
const toItem = obj2Clone.splice(index, 1)[0];
|
|
277
|
-
const fromItemClone = JSON.parse(JSON.stringify(fromItem));
|
|
278
|
-
const toItemClone = JSON.parse(JSON.stringify(toItem));
|
|
279
|
-
const keysChanged = ChangeUtils.compareObject(fromItemClone, toItemClone, undefined, ignoreKeys);
|
|
280
|
-
if (keysChanged.length) {
|
|
281
|
-
items.modified.push({
|
|
282
|
-
change: {
|
|
283
|
-
type: ChangeType.MODIFIED,
|
|
284
|
-
keysChanged
|
|
285
|
-
},
|
|
286
|
-
value: fromItemClone,
|
|
287
|
-
oldValue: fromItem,
|
|
288
|
-
newValue: toItem
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
items.added = obj2Clone.map(itemAdded => {
|
|
293
|
-
return {
|
|
294
|
-
change: { type: ChangeType.ADDED },
|
|
295
|
-
value: itemAdded
|
|
296
|
-
};
|
|
297
|
-
});
|
|
298
|
-
return items;
|
|
299
|
-
}
|
|
300
|
-
static compareObject(fromItem, toItem, baseKey, ignoreKeys = []) {
|
|
301
|
-
const fromItemClone = JSON.parse(JSON.stringify(fromItem));
|
|
302
|
-
const toItemClone = JSON.parse(JSON.stringify(toItem));
|
|
303
|
-
const keys = new Set([
|
|
304
|
-
...Object.keys(fromItem),
|
|
305
|
-
...Object.keys(toItem)
|
|
306
|
-
]);
|
|
307
|
-
let keysChanged = [];
|
|
308
|
-
keys.forEach(key => {
|
|
309
|
-
const keyString = baseKey ? `${baseKey}.${key}` : key;
|
|
310
|
-
if (ignoreKeys.indexOf(keyString) !== -1) {
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
if (Array.isArray(fromItem[key])) {
|
|
314
|
-
fromItem[key] = fromItem[key].join(',<br>');
|
|
315
|
-
}
|
|
316
|
-
if (Array.isArray(toItem[key])) {
|
|
317
|
-
toItem[key] = toItem[key].join(',<br>');
|
|
318
|
-
}
|
|
319
|
-
if (typeof fromItem[key] === 'object' &&
|
|
320
|
-
typeof toItem[key] === 'object' &&
|
|
321
|
-
fromItem[key] !== null &&
|
|
322
|
-
toItem[key] !== null) {
|
|
323
|
-
keysChanged = keysChanged.concat(this.compareObject(fromItem[key], toItem[key], keyString));
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
if (fromItem[key] !== toItem[key]) {
|
|
327
|
-
keysChanged.push({
|
|
328
|
-
key: keyString,
|
|
329
|
-
oldValue: fromItemClone[key],
|
|
330
|
-
newValue: toItemClone[key]
|
|
331
|
-
});
|
|
332
|
-
fromItem[key] = StringUtils.diff(fromItem[key], toItem[key]);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
return keysChanged;
|
|
337
|
-
}
|
|
273
|
+
class ChangeUtils {
|
|
274
|
+
static findChanges(obj1, obj2, ignoreKeys = []) {
|
|
275
|
+
const items = {
|
|
276
|
+
added: [],
|
|
277
|
+
deleted: [],
|
|
278
|
+
modified: []
|
|
279
|
+
};
|
|
280
|
+
if (!obj1 || !obj2) {
|
|
281
|
+
return items;
|
|
282
|
+
}
|
|
283
|
+
const obj1Clone = [...obj1];
|
|
284
|
+
const obj2Clone = [...obj2];
|
|
285
|
+
for (const fromItem of obj1Clone) {
|
|
286
|
+
const index = obj2Clone.findIndex((s) => s.id === fromItem.id);
|
|
287
|
+
if (index === -1) {
|
|
288
|
+
items.deleted.push({
|
|
289
|
+
change: { type: ChangeType.DELETED },
|
|
290
|
+
value: fromItem
|
|
291
|
+
});
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
const toItem = obj2Clone.splice(index, 1)[0];
|
|
295
|
+
const fromItemClone = JSON.parse(JSON.stringify(fromItem));
|
|
296
|
+
const toItemClone = JSON.parse(JSON.stringify(toItem));
|
|
297
|
+
const keysChanged = ChangeUtils.compareObject(fromItemClone, toItemClone, undefined, ignoreKeys);
|
|
298
|
+
if (keysChanged.length) {
|
|
299
|
+
items.modified.push({
|
|
300
|
+
change: {
|
|
301
|
+
type: ChangeType.MODIFIED,
|
|
302
|
+
keysChanged
|
|
303
|
+
},
|
|
304
|
+
value: fromItemClone,
|
|
305
|
+
oldValue: fromItem,
|
|
306
|
+
newValue: toItem
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
items.added = obj2Clone.map((itemAdded) => {
|
|
311
|
+
return {
|
|
312
|
+
change: { type: ChangeType.ADDED },
|
|
313
|
+
value: itemAdded
|
|
314
|
+
};
|
|
315
|
+
});
|
|
316
|
+
return items;
|
|
317
|
+
}
|
|
318
|
+
static compareObject(fromItem, toItem, baseKey, ignoreKeys = []) {
|
|
319
|
+
const fromItemClone = JSON.parse(JSON.stringify(fromItem));
|
|
320
|
+
const toItemClone = JSON.parse(JSON.stringify(toItem));
|
|
321
|
+
const keys = new Set([
|
|
322
|
+
...Object.keys(fromItem),
|
|
323
|
+
...Object.keys(toItem)
|
|
324
|
+
]);
|
|
325
|
+
let keysChanged = [];
|
|
326
|
+
keys.forEach((key) => {
|
|
327
|
+
const keyString = baseKey ? `${baseKey}.${key}` : key;
|
|
328
|
+
if (ignoreKeys.indexOf(keyString) !== -1) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (Array.isArray(fromItem[key])) {
|
|
332
|
+
fromItem[key] = fromItem[key].join(',<br>');
|
|
333
|
+
}
|
|
334
|
+
if (Array.isArray(toItem[key])) {
|
|
335
|
+
toItem[key] = toItem[key].join(',<br>');
|
|
336
|
+
}
|
|
337
|
+
if (typeof fromItem[key] === 'object' &&
|
|
338
|
+
typeof toItem[key] === 'object' &&
|
|
339
|
+
fromItem[key] !== null &&
|
|
340
|
+
toItem[key] !== null) {
|
|
341
|
+
keysChanged = keysChanged.concat(this.compareObject(fromItem[key], toItem[key], keyString));
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
if (fromItem[key] !== toItem[key]) {
|
|
345
|
+
keysChanged.push({
|
|
346
|
+
key: keyString,
|
|
347
|
+
oldValue: fromItemClone[key],
|
|
348
|
+
newValue: toItemClone[key]
|
|
349
|
+
});
|
|
350
|
+
fromItem[key] = StringUtils.diff(fromItem[key], toItem[key]);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
return keysChanged;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
class DomUtils {
|
|
359
|
+
static create(doc, tagName, options) {
|
|
360
|
+
const el = doc.createElement(tagName);
|
|
361
|
+
for (const key in options) {
|
|
362
|
+
el[key] = options[key];
|
|
363
|
+
}
|
|
364
|
+
return el;
|
|
365
|
+
}
|
|
366
|
+
static remove(node) {
|
|
367
|
+
if (!node.parentNode) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
node.parentNode.removeChild(node);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Trigger download of a file
|
|
376
|
+
*
|
|
377
|
+
* @param content File content
|
|
378
|
+
* @param mimeType File mime type
|
|
379
|
+
* @param fileName File name
|
|
380
|
+
*/
|
|
381
|
+
function downloadContent(content, mimeType, fileName) {
|
|
382
|
+
const uri = `data:${mimeType},${encodeURIComponent(content)}`;
|
|
383
|
+
downloadFromUri(uri, fileName);
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Trigger download of a file
|
|
387
|
+
*
|
|
388
|
+
* @param content File content
|
|
389
|
+
* @param mimeType File mime type
|
|
390
|
+
* @param fileName File name
|
|
391
|
+
*/
|
|
392
|
+
function downloadFromUri(uri, fileName) {
|
|
393
|
+
const element = document.createElement('a');
|
|
394
|
+
element.setAttribute('href', uri);
|
|
395
|
+
element.setAttribute('download', fileName);
|
|
396
|
+
element.style.display = 'none';
|
|
397
|
+
document.body.appendChild(element);
|
|
398
|
+
element.click();
|
|
399
|
+
document.body.removeChild(element);
|
|
338
400
|
}
|
|
339
401
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
402
|
+
class ObjectUtils {
|
|
403
|
+
static resolve(obj, key) {
|
|
404
|
+
const keysArray = key.replace(/\[/g, '.').replace(/\]/g, '').split('.');
|
|
405
|
+
let current = obj;
|
|
406
|
+
while (keysArray.length) {
|
|
407
|
+
if (typeof current !== 'object') {
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
410
|
+
current = current[keysArray.shift()];
|
|
411
|
+
}
|
|
412
|
+
return current;
|
|
413
|
+
}
|
|
414
|
+
static isObject(item) {
|
|
415
|
+
return (item &&
|
|
416
|
+
typeof item === 'object' &&
|
|
417
|
+
!Array.isArray(item) &&
|
|
418
|
+
item !== null &&
|
|
419
|
+
!(item instanceof Date));
|
|
420
|
+
}
|
|
421
|
+
static mergeDeep(target, source, ignoreUndefined = false) {
|
|
422
|
+
const output = Object.assign({}, target);
|
|
423
|
+
if (ObjectUtils.isObject(target) && ObjectUtils.isObject(source)) {
|
|
424
|
+
Object.keys(source)
|
|
425
|
+
.filter((key) => !ignoreUndefined || source[key] !== undefined)
|
|
426
|
+
.forEach((key) => {
|
|
427
|
+
if (ObjectUtils.isObject(source[key])) {
|
|
428
|
+
if (!(key in target)) {
|
|
429
|
+
Object.assign(output, { [key]: source[key] });
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
output[key] = ObjectUtils.mergeDeep(target[key], source[key], ignoreUndefined);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
Object.assign(output, { [key]: source[key] });
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
return output;
|
|
441
|
+
}
|
|
442
|
+
static copyDeep(src) {
|
|
443
|
+
const target = Array.isArray(src) ? [] : {};
|
|
444
|
+
for (const prop in src) {
|
|
445
|
+
if (src.hasOwnProperty(prop)) {
|
|
446
|
+
const value = src[prop];
|
|
447
|
+
if (value && typeof value === 'object') {
|
|
448
|
+
target[prop] = this.copyDeep(value);
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
target[prop] = value;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return target;
|
|
456
|
+
}
|
|
457
|
+
static removeDuplicateCaseInsensitive(obj) {
|
|
458
|
+
const summaryCapitalizeObject = {};
|
|
459
|
+
const capitalizeObject = {};
|
|
460
|
+
const upperCaseCount = [];
|
|
461
|
+
for (const property in obj) {
|
|
462
|
+
if (obj.hasOwnProperty(property)) {
|
|
463
|
+
const upperCaseProperty = property.toUpperCase();
|
|
464
|
+
if (!summaryCapitalizeObject.hasOwnProperty(upperCaseProperty)) {
|
|
465
|
+
summaryCapitalizeObject[upperCaseProperty] = [
|
|
466
|
+
{ [property]: obj[property] }
|
|
467
|
+
];
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
summaryCapitalizeObject[upperCaseProperty].push({
|
|
471
|
+
[property]: obj[property]
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
// counting the number of uppercase lettersMna
|
|
475
|
+
upperCaseCount.push({
|
|
476
|
+
key: property,
|
|
477
|
+
count: property.replace(/[^A-Z]/g, '').length
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
for (const capitalizedProperty in summaryCapitalizeObject) {
|
|
482
|
+
if (summaryCapitalizeObject.hasOwnProperty(capitalizedProperty)) {
|
|
483
|
+
if (summaryCapitalizeObject.hasOwnProperty(capitalizedProperty)) {
|
|
484
|
+
const capitalizedPropertyObject = summaryCapitalizeObject[capitalizedProperty];
|
|
485
|
+
if (capitalizedPropertyObject.length === 1) {
|
|
486
|
+
// for single params (no duplicates)
|
|
487
|
+
const singlePossibility = capitalizedPropertyObject[0];
|
|
488
|
+
capitalizeObject[capitalizedProperty] =
|
|
489
|
+
singlePossibility[Object.keys(singlePossibility)[0]];
|
|
490
|
+
}
|
|
491
|
+
else if (capitalizedPropertyObject.length > 1) {
|
|
492
|
+
// defining the closest to lowercase property
|
|
493
|
+
const paramClosestToLowercase = upperCaseCount
|
|
494
|
+
.filter((f) => f.key.toLowerCase() === capitalizedProperty.toLowerCase())
|
|
495
|
+
.reduce((prev, current) => {
|
|
496
|
+
return prev.y < current.y ? prev : current;
|
|
497
|
+
});
|
|
498
|
+
capitalizeObject[paramClosestToLowercase.key.toUpperCase()] =
|
|
499
|
+
obj[paramClosestToLowercase.key];
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
for (const property in obj) {
|
|
505
|
+
if (obj.hasOwnProperty(property)) {
|
|
506
|
+
delete obj[property];
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
for (const property in capitalizeObject) {
|
|
510
|
+
if (capitalizeObject.hasOwnProperty(property)) {
|
|
511
|
+
obj[property] = capitalizeObject[property];
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
static removeUndefined(obj) {
|
|
516
|
+
const output = {};
|
|
517
|
+
if (ObjectUtils.isObject(obj)) {
|
|
518
|
+
Object.keys(obj)
|
|
519
|
+
.filter((key) => obj[key] !== undefined)
|
|
520
|
+
.forEach((key) => {
|
|
521
|
+
if (ObjectUtils.isObject(obj[key]) || Array.isArray(obj[key])) {
|
|
522
|
+
output[key] = ObjectUtils.removeUndefined(obj[key]);
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
output[key] = obj[key];
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
return output;
|
|
529
|
+
}
|
|
530
|
+
if (Array.isArray(obj)) {
|
|
531
|
+
return obj.map((o) => ObjectUtils.removeUndefined(o));
|
|
532
|
+
}
|
|
533
|
+
return obj;
|
|
534
|
+
}
|
|
535
|
+
static removeNull(obj) {
|
|
536
|
+
const output = {};
|
|
537
|
+
if (ObjectUtils.isObject(obj)) {
|
|
538
|
+
Object.keys(obj)
|
|
539
|
+
.filter((key) => obj[key] !== null)
|
|
540
|
+
.forEach((key) => {
|
|
541
|
+
if (ObjectUtils.isObject(obj[key]) || Array.isArray(obj[key])) {
|
|
542
|
+
output[key] = ObjectUtils.removeNull(obj[key]);
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
output[key] = obj[key];
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
return output;
|
|
549
|
+
}
|
|
550
|
+
if (Array.isArray(obj)) {
|
|
551
|
+
return obj.map((o) => ObjectUtils.removeNull(o));
|
|
552
|
+
}
|
|
553
|
+
return obj;
|
|
554
|
+
}
|
|
555
|
+
static naturalCompare(a, b, direction = 'asc', nullsFirst) {
|
|
556
|
+
if (direction === 'desc') {
|
|
557
|
+
b = [a, (a = b)][0];
|
|
558
|
+
}
|
|
559
|
+
// nullsFirst = undefined : end if direction = 'asc', first if direction = 'desc'
|
|
560
|
+
// nullsFirst = true : always first
|
|
561
|
+
// nullsFirst = false : always end
|
|
562
|
+
if (a === null ||
|
|
563
|
+
a === '' ||
|
|
564
|
+
a === undefined ||
|
|
565
|
+
b === null ||
|
|
566
|
+
b === '' ||
|
|
567
|
+
b === undefined) {
|
|
568
|
+
const nullScore = a === b
|
|
569
|
+
? 0
|
|
570
|
+
: a === undefined
|
|
571
|
+
? 3
|
|
572
|
+
: b === undefined
|
|
573
|
+
? -3
|
|
574
|
+
: a === null
|
|
575
|
+
? 2
|
|
576
|
+
: b === null
|
|
577
|
+
? -2
|
|
578
|
+
: a === ''
|
|
579
|
+
? 1
|
|
580
|
+
: -1;
|
|
581
|
+
if (direction === 'desc') {
|
|
582
|
+
return nullsFirst !== false ? nullScore : nullScore * -1;
|
|
583
|
+
}
|
|
584
|
+
return nullsFirst === true ? nullScore * -1 : nullScore;
|
|
585
|
+
}
|
|
586
|
+
const ax = [];
|
|
587
|
+
const bx = [];
|
|
588
|
+
a = '' + a;
|
|
589
|
+
b = '' + b;
|
|
590
|
+
a.replace(/(\d+)|(\D+)/g, (_, $1, $2) => {
|
|
591
|
+
ax.push([$1 || Infinity, $2 || '']);
|
|
592
|
+
});
|
|
593
|
+
b.replace(/(\d+)|(\D+)/g, (_, $1, $2) => {
|
|
594
|
+
bx.push([$1 || Infinity, $2 || '']);
|
|
595
|
+
});
|
|
596
|
+
while (ax.length && bx.length) {
|
|
597
|
+
const an = ax.shift();
|
|
598
|
+
const bn = bx.shift();
|
|
599
|
+
const nn = an[0] - bn[0] || an[1].localeCompare(bn[1]);
|
|
600
|
+
if (nn) {
|
|
601
|
+
return nn;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return ax.length - bx.length;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Return true if two object are equivalent.
|
|
608
|
+
* Objects are considered equivalent if they have the same properties and
|
|
609
|
+
* if all of their properties (first-level only) share the same value.
|
|
610
|
+
* @param obj1 First object
|
|
611
|
+
* @param obj2 Second object
|
|
612
|
+
* @returns Whether two objects arer equivalent
|
|
613
|
+
*/
|
|
614
|
+
static objectsAreEquivalent(obj1, obj2) {
|
|
615
|
+
if (obj1 === obj2) {
|
|
616
|
+
return true;
|
|
617
|
+
}
|
|
618
|
+
const obj1Props = Object.getOwnPropertyNames(obj1);
|
|
619
|
+
const obj2Props = Object.getOwnPropertyNames(obj2);
|
|
620
|
+
if (obj1Props.length !== obj2Props.length) {
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
for (const prop of obj1Props) {
|
|
624
|
+
if (obj1[prop] !== obj2[prop]) {
|
|
625
|
+
return false;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Return a new object with an array of keys removed
|
|
632
|
+
* @param obj Source object
|
|
633
|
+
* @param keys Keys to remove
|
|
634
|
+
* @returns A new object
|
|
635
|
+
*/
|
|
636
|
+
static removeKeys(obj, keys) {
|
|
637
|
+
const newObj = Object.keys(obj)
|
|
638
|
+
.filter((key) => keys.indexOf(key) < 0)
|
|
639
|
+
.reduce((_obj, key) => {
|
|
640
|
+
_obj[key] = obj[key];
|
|
641
|
+
return _obj;
|
|
642
|
+
}, {});
|
|
643
|
+
return newObj;
|
|
644
|
+
}
|
|
645
|
+
static isEmpty(obj) {
|
|
646
|
+
return Object.keys(obj).length === 0;
|
|
647
|
+
}
|
|
366
648
|
}
|
|
367
649
|
|
|
368
|
-
class
|
|
369
|
-
static
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
.split('.');
|
|
374
|
-
let current = obj;
|
|
375
|
-
while (keysArray.length) {
|
|
376
|
-
if (typeof current !== 'object') {
|
|
377
|
-
return undefined;
|
|
378
|
-
}
|
|
379
|
-
current = current[keysArray.shift()];
|
|
380
|
-
}
|
|
381
|
-
return current;
|
|
382
|
-
}
|
|
383
|
-
static isObject(item) {
|
|
384
|
-
return (item &&
|
|
385
|
-
typeof item === 'object' &&
|
|
386
|
-
!Array.isArray(item) &&
|
|
387
|
-
item !== null &&
|
|
388
|
-
!(item instanceof Date));
|
|
389
|
-
}
|
|
390
|
-
static mergeDeep(target, source, ignoreUndefined = false) {
|
|
391
|
-
const output = Object.assign({}, target);
|
|
392
|
-
if (ObjectUtils.isObject(target) && ObjectUtils.isObject(source)) {
|
|
393
|
-
Object.keys(source)
|
|
394
|
-
.filter(key => !ignoreUndefined || source[key] !== undefined)
|
|
395
|
-
.forEach(key => {
|
|
396
|
-
if (ObjectUtils.isObject(source[key])) {
|
|
397
|
-
if (!(key in target)) {
|
|
398
|
-
Object.assign(output, { [key]: source[key] });
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
output[key] = ObjectUtils.mergeDeep(target[key], source[key], ignoreUndefined);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
else {
|
|
405
|
-
Object.assign(output, { [key]: source[key] });
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
return output;
|
|
410
|
-
}
|
|
411
|
-
static copyDeep(src) {
|
|
412
|
-
const target = Array.isArray(src) ? [] : {};
|
|
413
|
-
for (const prop in src) {
|
|
414
|
-
if (src.hasOwnProperty(prop)) {
|
|
415
|
-
const value = src[prop];
|
|
416
|
-
if (value && typeof value === 'object') {
|
|
417
|
-
target[prop] = this.copyDeep(value);
|
|
418
|
-
}
|
|
419
|
-
else {
|
|
420
|
-
target[prop] = value;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
return target;
|
|
425
|
-
}
|
|
426
|
-
static removeDuplicateCaseInsensitive(obj) {
|
|
427
|
-
const summaryCapitalizeObject = {};
|
|
428
|
-
const capitalizeObject = {};
|
|
429
|
-
const upperCaseCount = [];
|
|
430
|
-
for (const property in obj) {
|
|
431
|
-
if (obj.hasOwnProperty(property)) {
|
|
432
|
-
const upperCaseProperty = property.toUpperCase();
|
|
433
|
-
if (!summaryCapitalizeObject.hasOwnProperty(upperCaseProperty)) {
|
|
434
|
-
summaryCapitalizeObject[upperCaseProperty] = [
|
|
435
|
-
{ [property]: obj[property] }
|
|
436
|
-
];
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
summaryCapitalizeObject[upperCaseProperty].push({
|
|
440
|
-
[property]: obj[property]
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
// counting the number of uppercase lettersMna
|
|
444
|
-
upperCaseCount.push({
|
|
445
|
-
key: property,
|
|
446
|
-
count: property.replace(/[^A-Z]/g, '').length
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
for (const capitalizedProperty in summaryCapitalizeObject) {
|
|
451
|
-
if (summaryCapitalizeObject.hasOwnProperty(capitalizedProperty)) {
|
|
452
|
-
if (summaryCapitalizeObject.hasOwnProperty(capitalizedProperty)) {
|
|
453
|
-
const capitalizedPropertyObject = summaryCapitalizeObject[capitalizedProperty];
|
|
454
|
-
if (capitalizedPropertyObject.length === 1) {
|
|
455
|
-
// for single params (no duplicates)
|
|
456
|
-
const singlePossibility = capitalizedPropertyObject[0];
|
|
457
|
-
capitalizeObject[capitalizedProperty] =
|
|
458
|
-
singlePossibility[Object.keys(singlePossibility)[0]];
|
|
459
|
-
}
|
|
460
|
-
else if (capitalizedPropertyObject.length > 1) {
|
|
461
|
-
// defining the closest to lowercase property
|
|
462
|
-
const paramClosestToLowercase = upperCaseCount
|
|
463
|
-
.filter(f => f.key.toLowerCase() === capitalizedProperty.toLowerCase())
|
|
464
|
-
.reduce((prev, current) => {
|
|
465
|
-
return prev.y < current.y ? prev : current;
|
|
466
|
-
});
|
|
467
|
-
capitalizeObject[paramClosestToLowercase.key.toUpperCase()] =
|
|
468
|
-
obj[paramClosestToLowercase.key];
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
for (const property in obj) {
|
|
474
|
-
if (obj.hasOwnProperty(property)) {
|
|
475
|
-
delete obj[property];
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
for (const property in capitalizeObject) {
|
|
479
|
-
if (capitalizeObject.hasOwnProperty(property)) {
|
|
480
|
-
obj[property] = capitalizeObject[property];
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
static removeUndefined(obj) {
|
|
485
|
-
const output = {};
|
|
486
|
-
if (ObjectUtils.isObject(obj)) {
|
|
487
|
-
Object.keys(obj)
|
|
488
|
-
.filter(key => obj[key] !== undefined)
|
|
489
|
-
.forEach(key => {
|
|
490
|
-
if (ObjectUtils.isObject(obj[key]) || Array.isArray(obj[key])) {
|
|
491
|
-
output[key] = ObjectUtils.removeUndefined(obj[key]);
|
|
492
|
-
}
|
|
493
|
-
else {
|
|
494
|
-
output[key] = obj[key];
|
|
495
|
-
}
|
|
496
|
-
});
|
|
497
|
-
return output;
|
|
498
|
-
}
|
|
499
|
-
if (Array.isArray(obj)) {
|
|
500
|
-
return obj.map(o => ObjectUtils.removeUndefined(o));
|
|
501
|
-
}
|
|
502
|
-
return obj;
|
|
503
|
-
}
|
|
504
|
-
static removeNull(obj) {
|
|
505
|
-
const output = {};
|
|
506
|
-
if (ObjectUtils.isObject(obj)) {
|
|
507
|
-
Object.keys(obj)
|
|
508
|
-
.filter(key => obj[key] !== null)
|
|
509
|
-
.forEach(key => {
|
|
510
|
-
if (ObjectUtils.isObject(obj[key]) || Array.isArray(obj[key])) {
|
|
511
|
-
output[key] = ObjectUtils.removeNull(obj[key]);
|
|
512
|
-
}
|
|
513
|
-
else {
|
|
514
|
-
output[key] = obj[key];
|
|
515
|
-
}
|
|
516
|
-
});
|
|
517
|
-
return output;
|
|
518
|
-
}
|
|
519
|
-
if (Array.isArray(obj)) {
|
|
520
|
-
return obj.map(o => ObjectUtils.removeNull(o));
|
|
521
|
-
}
|
|
522
|
-
return obj;
|
|
523
|
-
}
|
|
524
|
-
static naturalCompare(a, b, direction = 'asc', nullsFirst) {
|
|
525
|
-
if (direction === 'desc') {
|
|
526
|
-
b = [a, (a = b)][0];
|
|
527
|
-
}
|
|
528
|
-
// nullsFirst = undefined : end if direction = 'asc', first if direction = 'desc'
|
|
529
|
-
// nullsFirst = true : always first
|
|
530
|
-
// nullsFirst = false : always end
|
|
531
|
-
if (a === null ||
|
|
532
|
-
a === '' ||
|
|
533
|
-
a === undefined ||
|
|
534
|
-
b === null ||
|
|
535
|
-
b === '' ||
|
|
536
|
-
b === undefined) {
|
|
537
|
-
const nullScore = a === b
|
|
538
|
-
? 0
|
|
539
|
-
: a === undefined
|
|
540
|
-
? 3
|
|
541
|
-
: b === undefined
|
|
542
|
-
? -3
|
|
543
|
-
: a === null
|
|
544
|
-
? 2
|
|
545
|
-
: b === null
|
|
546
|
-
? -2
|
|
547
|
-
: a === ''
|
|
548
|
-
? 1
|
|
549
|
-
: -1;
|
|
550
|
-
if (direction === 'desc') {
|
|
551
|
-
return nullsFirst !== false ? nullScore : nullScore * -1;
|
|
552
|
-
}
|
|
553
|
-
return nullsFirst === true ? nullScore * -1 : nullScore;
|
|
554
|
-
}
|
|
555
|
-
const ax = [];
|
|
556
|
-
const bx = [];
|
|
557
|
-
a = '' + a;
|
|
558
|
-
b = '' + b;
|
|
559
|
-
a.replace(/(\d+)|(\D+)/g, (_, $1, $2) => {
|
|
560
|
-
ax.push([$1 || Infinity, $2 || '']);
|
|
561
|
-
});
|
|
562
|
-
b.replace(/(\d+)|(\D+)/g, (_, $1, $2) => {
|
|
563
|
-
bx.push([$1 || Infinity, $2 || '']);
|
|
564
|
-
});
|
|
565
|
-
while (ax.length && bx.length) {
|
|
566
|
-
const an = ax.shift();
|
|
567
|
-
const bn = bx.shift();
|
|
568
|
-
const nn = an[0] - bn[0] || an[1].localeCompare(bn[1]);
|
|
569
|
-
if (nn) {
|
|
570
|
-
return nn;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
return ax.length - bx.length;
|
|
574
|
-
}
|
|
575
|
-
/**
|
|
576
|
-
* Return true if two object are equivalent.
|
|
577
|
-
* Objects are considered equivalent if they have the same properties and
|
|
578
|
-
* if all of their properties (first-level only) share the same value.
|
|
579
|
-
* @param obj1 First object
|
|
580
|
-
* @param obj2 Second object
|
|
581
|
-
* @returns Whether two objects arer equivalent
|
|
582
|
-
*/
|
|
583
|
-
static objectsAreEquivalent(obj1, obj2) {
|
|
584
|
-
if (obj1 === obj2) {
|
|
585
|
-
return true;
|
|
586
|
-
}
|
|
587
|
-
const obj1Props = Object.getOwnPropertyNames(obj1);
|
|
588
|
-
const obj2Props = Object.getOwnPropertyNames(obj2);
|
|
589
|
-
if (obj1Props.length !== obj2Props.length) {
|
|
590
|
-
return false;
|
|
591
|
-
}
|
|
592
|
-
for (const prop of obj1Props) {
|
|
593
|
-
if (obj1[prop] !== obj2[prop]) {
|
|
594
|
-
return false;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
return true;
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Return a new object with an array of keys removed
|
|
601
|
-
* @param obj Source object
|
|
602
|
-
* @param keys Keys to remove
|
|
603
|
-
* @returns A new object
|
|
604
|
-
*/
|
|
605
|
-
static removeKeys(obj, keys) {
|
|
606
|
-
const newObj = Object.keys(obj)
|
|
607
|
-
.filter(key => keys.indexOf(key) < 0)
|
|
608
|
-
.reduce((_obj, key) => {
|
|
609
|
-
_obj[key] = obj[key];
|
|
610
|
-
return _obj;
|
|
611
|
-
}, {});
|
|
612
|
-
return newObj;
|
|
613
|
-
}
|
|
650
|
+
class NumberUtils {
|
|
651
|
+
static roundToNDecimal(num, decimal = 3) {
|
|
652
|
+
const roundFactor = Math.pow(10, decimal);
|
|
653
|
+
return Math.round(num * roundFactor) / roundFactor;
|
|
654
|
+
}
|
|
614
655
|
}
|
|
615
656
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
657
|
+
/** Utility function to create a K:V from a list of strings */
|
|
658
|
+
function strEnum(o) {
|
|
659
|
+
return o.reduce((res, key) => {
|
|
660
|
+
res[key] = key;
|
|
661
|
+
return res;
|
|
662
|
+
}, Object.create(null));
|
|
621
663
|
}
|
|
622
664
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
665
|
+
const PATH_PREBUILT_THEMES = 'assets/igo2/core/theming/prebuilt-themes';
|
|
666
|
+
const LINK_ID = 'theme-styles';
|
|
667
|
+
function loadTheme(doc, themeName, path = PATH_PREBUILT_THEMES) {
|
|
668
|
+
const src = `${path}/${themeName}.css`;
|
|
669
|
+
const head = doc.getElementsByTagName('head')[0];
|
|
670
|
+
let themeLink = doc.getElementById(LINK_ID);
|
|
671
|
+
themeLink ? (themeLink.href = src) : createHtmlLink(doc, src, head);
|
|
672
|
+
}
|
|
673
|
+
function createHtmlLink(doc, src, parent) {
|
|
674
|
+
const element = DomUtils.create(doc, 'link', {
|
|
675
|
+
id: LINK_ID,
|
|
676
|
+
rel: 'stylesheet',
|
|
677
|
+
href: src
|
|
678
|
+
});
|
|
679
|
+
parent.appendChild(element);
|
|
629
680
|
}
|
|
630
681
|
|
|
631
|
-
function S4() {
|
|
632
|
-
// eslint-disable-next-line no-bitwise
|
|
633
|
-
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
|
634
|
-
}
|
|
635
|
-
function uuid() {
|
|
636
|
-
const id = `${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`;
|
|
637
|
-
return id.toLowerCase();
|
|
682
|
+
function S4() {
|
|
683
|
+
// eslint-disable-next-line no-bitwise
|
|
684
|
+
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
|
685
|
+
}
|
|
686
|
+
function uuid() {
|
|
687
|
+
const id = `${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`;
|
|
688
|
+
return id.toLowerCase();
|
|
638
689
|
}
|
|
639
690
|
|
|
640
|
-
var SubjectStatus;
|
|
641
|
-
(function (SubjectStatus) {
|
|
642
|
-
SubjectStatus[SubjectStatus["Error"] = 0] = "Error";
|
|
643
|
-
SubjectStatus[SubjectStatus["Done"] = 1] = "Done";
|
|
644
|
-
SubjectStatus[SubjectStatus["Working"] = 2] = "Working";
|
|
645
|
-
SubjectStatus[SubjectStatus["Waiting"] = 3] = "Waiting";
|
|
646
|
-
})(SubjectStatus || (SubjectStatus = {}));
|
|
647
|
-
class Watcher {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
this.
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
this.
|
|
661
|
-
|
|
662
|
-
.
|
|
663
|
-
.
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
this.
|
|
670
|
-
|
|
671
|
-
this.status
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
}
|
|
676
|
-
handleStatusChange(status) { }
|
|
691
|
+
var SubjectStatus;
|
|
692
|
+
(function (SubjectStatus) {
|
|
693
|
+
SubjectStatus[SubjectStatus["Error"] = 0] = "Error";
|
|
694
|
+
SubjectStatus[SubjectStatus["Done"] = 1] = "Done";
|
|
695
|
+
SubjectStatus[SubjectStatus["Working"] = 2] = "Working";
|
|
696
|
+
SubjectStatus[SubjectStatus["Waiting"] = 3] = "Waiting";
|
|
697
|
+
})(SubjectStatus || (SubjectStatus = {}));
|
|
698
|
+
class Watcher {
|
|
699
|
+
status$ = new Subject();
|
|
700
|
+
status$$;
|
|
701
|
+
get status() {
|
|
702
|
+
return this._status;
|
|
703
|
+
}
|
|
704
|
+
set status(value) {
|
|
705
|
+
this._status = value;
|
|
706
|
+
this.status$.next(value);
|
|
707
|
+
}
|
|
708
|
+
_status;
|
|
709
|
+
subscribe(callback, scope) {
|
|
710
|
+
this.watch();
|
|
711
|
+
this.status$$ = this.status$
|
|
712
|
+
.pipe(distinctUntilChanged())
|
|
713
|
+
.subscribe((status) => {
|
|
714
|
+
this.handleStatusChange(status);
|
|
715
|
+
callback.call(scope, this);
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
unsubscribe() {
|
|
719
|
+
this.unwatch();
|
|
720
|
+
if (this.status$$ !== undefined) {
|
|
721
|
+
this.status$$.unsubscribe();
|
|
722
|
+
this.status$$ = undefined;
|
|
723
|
+
}
|
|
724
|
+
this.status = SubjectStatus.Waiting;
|
|
725
|
+
}
|
|
726
|
+
handleStatusChange(status) { }
|
|
677
727
|
}
|
|
678
728
|
|
|
679
|
-
/*
|
|
680
|
-
* Public API Surface of utils
|
|
729
|
+
/*
|
|
730
|
+
* Public API Surface of utils
|
|
681
731
|
*/
|
|
682
732
|
|
|
683
|
-
/**
|
|
684
|
-
* Generated bundle index. Do not edit.
|
|
733
|
+
/**
|
|
734
|
+
* Generated bundle index. Do not edit.
|
|
685
735
|
*/
|
|
686
736
|
|
|
687
|
-
export { Base64, ChangeType, ChangeUtils, Clipboard, NumberUtils, ObjectUtils, S4, StringUtils, SubjectStatus, Watcher, downloadContent, downloadFromUri, strEnum, userAgent, uuid };
|
|
737
|
+
export { Base64, ChangeType, ChangeUtils, Clipboard, DomUtils, NumberUtils, ObjectUtils, S4, StringUtils, SubjectStatus, Watcher, customCacheHasher, downloadContent, downloadFromUri, loadTheme, strEnum, userAgent, uuid };
|
|
688
738
|
//# sourceMappingURL=igo2-utils.mjs.map
|