@lowentry/utils 0.2.1 → 0.2.2
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/LeUtils.js +566 -43
- package/package.json +1 -1
package/LeUtils.js
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
import {ISSET, IS_OBJECT, STRING, INT_LAX, FLOAT_LAX, INT_LAX_ANY, FLOAT_LAX_ANY} from './LeTypes.js';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
6
|
+
*/
|
|
7
|
+
const checkTransactionalValue = (transactionalValue) =>
|
|
8
|
+
{
|
|
9
|
+
if(!LeUtils.isTransactionalValueValid(transactionalValue))
|
|
10
|
+
{
|
|
11
|
+
console.error('The given value is not a valid TransactionalValue:');
|
|
12
|
+
console.error(transactionalValue);
|
|
13
|
+
throw new Error('The given value is not a valid TransactionalValue');
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
19
|
+
* @param {string} changeId
|
|
20
|
+
* @returns {{index:number, value:*}|null}
|
|
21
|
+
*/
|
|
22
|
+
const findTransactionalValueChange = (transactionalValue, changeId) =>
|
|
23
|
+
{
|
|
24
|
+
for(let i = 0; i < transactionalValue.changes.length; i++)
|
|
25
|
+
{
|
|
26
|
+
const change = transactionalValue.changes[i];
|
|
27
|
+
if(change.id === changeId)
|
|
28
|
+
{
|
|
29
|
+
return {index:i, value:change.value};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
|
|
4
36
|
export const LeUtils = {
|
|
5
37
|
/**
|
|
6
38
|
* Parses the given version string, and returns an object with the major, minor, and patch numbers, as well as some comparison functions.
|
|
@@ -738,18 +770,7 @@ export const LeUtils = {
|
|
|
738
770
|
* @returns {number}
|
|
739
771
|
*/
|
|
740
772
|
compare:
|
|
741
|
-
(a, b) =>
|
|
742
|
-
{
|
|
743
|
-
if(a < b)
|
|
744
|
-
{
|
|
745
|
-
return -1;
|
|
746
|
-
}
|
|
747
|
-
if(a > b)
|
|
748
|
-
{
|
|
749
|
-
return 1;
|
|
750
|
-
}
|
|
751
|
-
return 0;
|
|
752
|
-
},
|
|
773
|
+
(a, b) => (a < b) ? -1 : ((a > b) ? 1 : 0),
|
|
753
774
|
|
|
754
775
|
/**
|
|
755
776
|
* Compares two numbers. Primarily used for sorting.
|
|
@@ -1377,6 +1398,40 @@ export const LeUtils = {
|
|
|
1377
1398
|
return messageParts[messageParts.length - 1].trim();
|
|
1378
1399
|
},
|
|
1379
1400
|
|
|
1401
|
+
/**
|
|
1402
|
+
* Generates all permutations of the given names.
|
|
1403
|
+
*
|
|
1404
|
+
* For example, if you pass "foo" and "bar", it will return:
|
|
1405
|
+
* - foobar
|
|
1406
|
+
* - fooBar
|
|
1407
|
+
* - FooBar
|
|
1408
|
+
* - foo-bar
|
|
1409
|
+
* - foo_bar
|
|
1410
|
+
*
|
|
1411
|
+
* @param {string} names
|
|
1412
|
+
* @returns {string[]}
|
|
1413
|
+
*/
|
|
1414
|
+
generateNamePermutations:
|
|
1415
|
+
(...names) =>
|
|
1416
|
+
{
|
|
1417
|
+
names = LeUtils.flattenArray(names)
|
|
1418
|
+
.map(name => STRING(name).trim().toLowerCase())
|
|
1419
|
+
.filter(name => (name.length > 0));
|
|
1420
|
+
let results = [];
|
|
1421
|
+
if(names.length > 0)
|
|
1422
|
+
{
|
|
1423
|
+
results.push(names.join('')); //foobar
|
|
1424
|
+
results.push(names.map(LeUtils.capitalize).join('')); //FooBar
|
|
1425
|
+
}
|
|
1426
|
+
if(names.length > 1)
|
|
1427
|
+
{
|
|
1428
|
+
results.push([names[0]].concat(names.slice(1).map(LeUtils.capitalize)).join('')); //fooBar
|
|
1429
|
+
results.push(names.join('-')); //foo-bar
|
|
1430
|
+
results.push(names.join('_')); //foo_bar
|
|
1431
|
+
}
|
|
1432
|
+
return results;
|
|
1433
|
+
},
|
|
1434
|
+
|
|
1380
1435
|
/**
|
|
1381
1436
|
* Increases the given numeric string by 1, this allows you to increase a numeric string without a limit.
|
|
1382
1437
|
*
|
|
@@ -1608,27 +1663,27 @@ export const LeUtils = {
|
|
|
1608
1663
|
},
|
|
1609
1664
|
|
|
1610
1665
|
/**
|
|
1611
|
-
* Returns the
|
|
1666
|
+
* Returns the RGB(A) of the given hex color.
|
|
1612
1667
|
*
|
|
1613
|
-
* @param {
|
|
1668
|
+
* @param {string} hexstring
|
|
1614
1669
|
* @returns {number[]}
|
|
1615
1670
|
*/
|
|
1616
|
-
|
|
1617
|
-
(
|
|
1671
|
+
hexToRgb:
|
|
1672
|
+
(hexstring) =>
|
|
1618
1673
|
{
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1674
|
+
hexstring = hexstring.replace(/[^0-9A-F]/gi, '');
|
|
1675
|
+
const hasAlpha = ((hexstring.length === 4) || (hexstring.length === 8));
|
|
1676
|
+
while(hexstring.length < 6)
|
|
1677
|
+
{
|
|
1678
|
+
hexstring = hexstring.replace(/(.)/g, '$1$1');
|
|
1679
|
+
}
|
|
1680
|
+
const result = hexstring.match(/\w{2}/g).map((a) => parseInt(a, 16));
|
|
1681
|
+
return [
|
|
1682
|
+
result[0],
|
|
1683
|
+
result[1],
|
|
1684
|
+
result[2],
|
|
1685
|
+
...(hasAlpha ? [result[3]] : []),
|
|
1686
|
+
];
|
|
1632
1687
|
},
|
|
1633
1688
|
|
|
1634
1689
|
/**
|
|
@@ -1643,11 +1698,9 @@ export const LeUtils = {
|
|
|
1643
1698
|
const r = rgb[0] / 255;
|
|
1644
1699
|
const g = rgb[1] / 255;
|
|
1645
1700
|
const b = rgb[2] / 255;
|
|
1646
|
-
|
|
1647
1701
|
const max = Math.max(r, g, b);
|
|
1648
1702
|
const min = Math.min(r, g, b);
|
|
1649
1703
|
let h, s, l = (max + min) / 2;
|
|
1650
|
-
|
|
1651
1704
|
if(max === min)
|
|
1652
1705
|
{
|
|
1653
1706
|
h = s = 0;
|
|
@@ -1670,16 +1723,90 @@ export const LeUtils = {
|
|
|
1670
1723
|
}
|
|
1671
1724
|
h /= 6;
|
|
1672
1725
|
}
|
|
1673
|
-
|
|
1674
|
-
|
|
1726
|
+
return [h, s, l, ...((rgb.length >= 4) ? [rgb[3] / 255] : [])];
|
|
1727
|
+
},
|
|
1728
|
+
|
|
1729
|
+
/**
|
|
1730
|
+
* Returns the RGB(A) of the given HSL(A).
|
|
1731
|
+
*
|
|
1732
|
+
* @param {number[]} hsl
|
|
1733
|
+
* @returns {number[]}
|
|
1734
|
+
*/
|
|
1735
|
+
hslToRgb:
|
|
1736
|
+
(() =>
|
|
1737
|
+
{
|
|
1738
|
+
const hue2rgb = (p, q, t) =>
|
|
1675
1739
|
{
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1740
|
+
if(t < 0)
|
|
1741
|
+
{
|
|
1742
|
+
t += 1;
|
|
1743
|
+
}
|
|
1744
|
+
if(t > 1)
|
|
1745
|
+
{
|
|
1746
|
+
t -= 1;
|
|
1747
|
+
}
|
|
1748
|
+
if(t < 1 / 6)
|
|
1749
|
+
{
|
|
1750
|
+
return p + (q - p) * 6 * t;
|
|
1751
|
+
}
|
|
1752
|
+
if(t < 1 / 2)
|
|
1753
|
+
{
|
|
1754
|
+
return q;
|
|
1755
|
+
}
|
|
1756
|
+
if(t < 2 / 3)
|
|
1757
|
+
{
|
|
1758
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
1759
|
+
}
|
|
1760
|
+
return p;
|
|
1761
|
+
};
|
|
1762
|
+
return (hsl) =>
|
|
1763
|
+
{
|
|
1764
|
+
const h = hsl[0];
|
|
1765
|
+
const s = hsl[1];
|
|
1766
|
+
const l = hsl[2];
|
|
1767
|
+
let r, g, b;
|
|
1768
|
+
if(s === 0)
|
|
1769
|
+
{
|
|
1770
|
+
r = g = b = l;
|
|
1771
|
+
}
|
|
1772
|
+
else
|
|
1773
|
+
{
|
|
1774
|
+
const q = (l < 0.5) ? (l * (1 + s)) : (l + s - (l * s));
|
|
1775
|
+
const p = (2 * l) - q;
|
|
1776
|
+
r = hue2rgb(p, q, h + (1 / 3));
|
|
1777
|
+
g = hue2rgb(p, q, h);
|
|
1778
|
+
b = hue2rgb(p, q, h - (1 / 3));
|
|
1779
|
+
}
|
|
1780
|
+
return [r * 255, g * 255, b * 255, ...((hsl.length >= 4) ? [hsl[3] * 255] : [])].map((c) => Math.max(0, Math.min(255, Math.round(c))));
|
|
1781
|
+
};
|
|
1782
|
+
})(),
|
|
1783
|
+
|
|
1784
|
+
/**
|
|
1785
|
+
* Returns the LAB(A) of the given RGB(A).
|
|
1786
|
+
*
|
|
1787
|
+
* @param {number[]} rgb
|
|
1788
|
+
* @returns {number[]}
|
|
1789
|
+
*/
|
|
1790
|
+
rgbToLab:
|
|
1791
|
+
(rgb) =>
|
|
1792
|
+
{
|
|
1793
|
+
let r = rgb[0] / 255;
|
|
1794
|
+
let g = rgb[1] / 255;
|
|
1795
|
+
let b = rgb[2] / 255;
|
|
1796
|
+
r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : (r / 12.92);
|
|
1797
|
+
g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : (g / 12.92);
|
|
1798
|
+
b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : (b / 12.92);
|
|
1799
|
+
let x = ((r * 0.4124) + (g * 0.3576) + (b * 0.1805)) / 0.95047;
|
|
1800
|
+
let y = ((r * 0.2126) + (g * 0.7152) + (b * 0.0722));
|
|
1801
|
+
let z = ((r * 0.0193) + (g * 0.1192) + (b * 0.9505)) / 1.08883;
|
|
1802
|
+
x = (x > 0.008856) ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
|
|
1803
|
+
y = (y > 0.008856) ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
|
|
1804
|
+
z = (z > 0.008856) ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
|
|
1805
|
+
return [(116 * y) - 16, 500 * (x - y), 200 * (y - z), ...((rgb.length >= 4) ? [rgb[3] / 255] : [])];
|
|
1679
1806
|
},
|
|
1680
1807
|
|
|
1681
1808
|
/**
|
|
1682
|
-
* Returns the difference (calculated with DeltaE) of the
|
|
1809
|
+
* Returns the difference (calculated with DeltaE) of the LAB values of the given RGB values.
|
|
1683
1810
|
*
|
|
1684
1811
|
* Returns a number:
|
|
1685
1812
|
*
|
|
@@ -1704,7 +1831,7 @@ export const LeUtils = {
|
|
|
1704
1831
|
},
|
|
1705
1832
|
|
|
1706
1833
|
/**
|
|
1707
|
-
* Returns the difference (calculated with DeltaE) of the given
|
|
1834
|
+
* Returns the difference (calculated with DeltaE) of the given LAB values. Ignores the Alpha channel.
|
|
1708
1835
|
*
|
|
1709
1836
|
* Returns a number:
|
|
1710
1837
|
*
|
|
@@ -1737,7 +1864,7 @@ export const LeUtils = {
|
|
|
1737
1864
|
const deltaCkcsc = deltaC / (sc);
|
|
1738
1865
|
const deltaHkhsh = deltaH / (sh);
|
|
1739
1866
|
const i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;
|
|
1740
|
-
return i < 0 ? 0 : Math.sqrt(i);
|
|
1867
|
+
return (i < 0) ? 0 : Math.sqrt(i);
|
|
1741
1868
|
},
|
|
1742
1869
|
|
|
1743
1870
|
/**
|
|
@@ -1930,7 +2057,7 @@ export const LeUtils = {
|
|
|
1930
2057
|
base64ToUtf8:
|
|
1931
2058
|
(base64string) =>
|
|
1932
2059
|
{
|
|
1933
|
-
return decodeURIComponent(LeUtils.atob(base64string).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join(''));
|
|
2060
|
+
return decodeURIComponent(LeUtils.atob(base64string.trim()).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join(''));
|
|
1934
2061
|
},
|
|
1935
2062
|
|
|
1936
2063
|
/**
|
|
@@ -1942,7 +2069,7 @@ export const LeUtils = {
|
|
|
1942
2069
|
base64ToHex:
|
|
1943
2070
|
(base64string) =>
|
|
1944
2071
|
{
|
|
1945
|
-
return LeUtils.atob(base64string).split('').map((c) => ('0' + c.charCodeAt(0).toString(16)).slice(-2)).join('');
|
|
2072
|
+
return LeUtils.atob(base64string.trim()).split('').map((c) => ('0' + c.charCodeAt(0).toString(16)).slice(-2)).join('');
|
|
1946
2073
|
},
|
|
1947
2074
|
|
|
1948
2075
|
/**
|
|
@@ -1954,7 +2081,7 @@ export const LeUtils = {
|
|
|
1954
2081
|
hexToBase64:
|
|
1955
2082
|
(hexstring) =>
|
|
1956
2083
|
{
|
|
1957
|
-
return LeUtils.btoa(hexstring.match(/\w{2}/g).map((a) => String.fromCharCode(parseInt(a, 16))).join(''));
|
|
2084
|
+
return LeUtils.btoa(hexstring.replace(/[^0-9A-F]/gi, '').match(/\w{2}/g).map((a) => String.fromCharCode(parseInt(a, 16))).join(''));
|
|
1958
2085
|
},
|
|
1959
2086
|
|
|
1960
2087
|
/**
|
|
@@ -1966,7 +2093,7 @@ export const LeUtils = {
|
|
|
1966
2093
|
base64ToBytes:
|
|
1967
2094
|
(base64string) =>
|
|
1968
2095
|
{
|
|
1969
|
-
const binary = LeUtils.atob(base64string);
|
|
2096
|
+
const binary = LeUtils.atob(base64string.trim());
|
|
1970
2097
|
const len = binary.length;
|
|
1971
2098
|
let data = new Uint8Array(len);
|
|
1972
2099
|
for(let i = 0; i < len; i++)
|
|
@@ -1995,6 +2122,23 @@ export const LeUtils = {
|
|
|
1995
2122
|
return LeUtils.btoa(binary);
|
|
1996
2123
|
},
|
|
1997
2124
|
|
|
2125
|
+
/**
|
|
2126
|
+
* Downloads the given base64 string as a file.
|
|
2127
|
+
*
|
|
2128
|
+
* @param {string} base64string
|
|
2129
|
+
* @param {string} [fileName]
|
|
2130
|
+
* @param {string} [mimeType]
|
|
2131
|
+
*/
|
|
2132
|
+
downloadFile:
|
|
2133
|
+
(base64string, fileName, mimeType) =>
|
|
2134
|
+
{
|
|
2135
|
+
const link = document.createElement('a');
|
|
2136
|
+
link.setAttribute('download', (typeof fileName === 'string') ? fileName : 'file');
|
|
2137
|
+
link.href = 'data:' + mimeType + ';base64,' + base64string;
|
|
2138
|
+
link.setAttribute('target', '_blank');
|
|
2139
|
+
link.click();
|
|
2140
|
+
},
|
|
2141
|
+
|
|
1998
2142
|
/**
|
|
1999
2143
|
* Loads the value from the browser, returns undefined if the value doesn't exist.
|
|
2000
2144
|
*
|
|
@@ -2061,4 +2205,383 @@ export const LeUtils = {
|
|
|
2061
2205
|
}
|
|
2062
2206
|
window.localStorage.removeItem('LeUtils_' + id);
|
|
2063
2207
|
},
|
|
2208
|
+
|
|
2209
|
+
/**
|
|
2210
|
+
* Creates and returns a new TreeSet.
|
|
2211
|
+
* A TreeSet is a set of elements, sorted by a comparator.
|
|
2212
|
+
* Binary search is used to find elements, which makes it very fast to find elements.
|
|
2213
|
+
*
|
|
2214
|
+
* The comparator is also used to determine if two values are equal to each other.
|
|
2215
|
+
* This way, you can have values that aren't the same be treated as if they are. This can be used to deal with issues such as floating point errors for example.
|
|
2216
|
+
*
|
|
2217
|
+
* @param {*[]} elements
|
|
2218
|
+
* @param {Function} comparator
|
|
2219
|
+
* @returns {{getElements: (function(): *[]), getComparator: (function(): Function), size: (function(): number), isEmpty: (function(): boolean), contains: (function(*): boolean), first: (function(): *|undefined), last: (function(): *|undefined), pollFirst: (function(): *|undefined), pollLast: (function(): *|undefined), add: function(*), addAll: function(*[]|object), getEqualValue: (function(*): (*)), getEqualValueOrAdd: (function(*): (*))}}
|
|
2220
|
+
*/
|
|
2221
|
+
createTreeSet:
|
|
2222
|
+
(elements, comparator) =>
|
|
2223
|
+
{
|
|
2224
|
+
comparator = comparator || LeUtils.compare;
|
|
2225
|
+
elements = elements || [];
|
|
2226
|
+
elements.sort(comparator);
|
|
2227
|
+
|
|
2228
|
+
/**
|
|
2229
|
+
* Performs a binary search on the elements, and returns the result.
|
|
2230
|
+
*
|
|
2231
|
+
* @param {*} value
|
|
2232
|
+
* @returns {{found: boolean, index: number, value: *|undefined}}
|
|
2233
|
+
*/
|
|
2234
|
+
const binarySearch = (value) =>
|
|
2235
|
+
{
|
|
2236
|
+
let low = 0;
|
|
2237
|
+
let high = elements.length - 1;
|
|
2238
|
+
while(low <= high)
|
|
2239
|
+
{
|
|
2240
|
+
const mid = Math.floor((low + high) / 2);
|
|
2241
|
+
const midValue = elements[mid];
|
|
2242
|
+
const cmp = comparator(midValue, value);
|
|
2243
|
+
if(cmp < 0)
|
|
2244
|
+
{
|
|
2245
|
+
low = mid + 1;
|
|
2246
|
+
}
|
|
2247
|
+
else if(cmp > 0)
|
|
2248
|
+
{
|
|
2249
|
+
high = mid - 1;
|
|
2250
|
+
}
|
|
2251
|
+
else
|
|
2252
|
+
{
|
|
2253
|
+
return {found:true, index:mid, value:midValue};
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
return {found:false, index:low, value:undefined};
|
|
2257
|
+
};
|
|
2258
|
+
|
|
2259
|
+
const treeSet = {
|
|
2260
|
+
/**
|
|
2261
|
+
* Returns the elements of the set.
|
|
2262
|
+
*
|
|
2263
|
+
* @returns {*[]}
|
|
2264
|
+
*/
|
|
2265
|
+
getElements:
|
|
2266
|
+
() => elements,
|
|
2267
|
+
|
|
2268
|
+
/**
|
|
2269
|
+
* Returns the comparator of the set.
|
|
2270
|
+
*
|
|
2271
|
+
* @returns {Function}
|
|
2272
|
+
*/
|
|
2273
|
+
getComparator:
|
|
2274
|
+
() => comparator,
|
|
2275
|
+
|
|
2276
|
+
/**
|
|
2277
|
+
* Returns the size of the set.
|
|
2278
|
+
*
|
|
2279
|
+
* @returns {number}
|
|
2280
|
+
*/
|
|
2281
|
+
size:
|
|
2282
|
+
() => elements.length,
|
|
2283
|
+
|
|
2284
|
+
/**
|
|
2285
|
+
* Returns true if the set is empty, false otherwise.
|
|
2286
|
+
*
|
|
2287
|
+
* @returns {boolean}
|
|
2288
|
+
*/
|
|
2289
|
+
isEmpty:
|
|
2290
|
+
() => (elements.length <= 0),
|
|
2291
|
+
|
|
2292
|
+
/**
|
|
2293
|
+
* Returns true if the set contains a value that is equal to the given value, returns false otherwise.
|
|
2294
|
+
*
|
|
2295
|
+
* @param {*} value
|
|
2296
|
+
* @returns {boolean}
|
|
2297
|
+
*/
|
|
2298
|
+
contains:
|
|
2299
|
+
(value) => binarySearch(value).found,
|
|
2300
|
+
|
|
2301
|
+
/**
|
|
2302
|
+
* Returns the first element of the set, or undefined if it is empty.
|
|
2303
|
+
*
|
|
2304
|
+
* @returns {*|undefined}
|
|
2305
|
+
*/
|
|
2306
|
+
first:
|
|
2307
|
+
() => (elements.length > 0) ? elements[0] : undefined,
|
|
2308
|
+
|
|
2309
|
+
/**
|
|
2310
|
+
* Returns the last element of the set, or undefined if it is empty.
|
|
2311
|
+
*
|
|
2312
|
+
* @returns {*|undefined}
|
|
2313
|
+
*/
|
|
2314
|
+
last:
|
|
2315
|
+
() => (elements.length > 0) ? elements[elements.length - 1] : undefined,
|
|
2316
|
+
|
|
2317
|
+
/**
|
|
2318
|
+
* Removes and returns the first element of the set, or undefined if it is empty.
|
|
2319
|
+
*
|
|
2320
|
+
* @returns {*|undefined}
|
|
2321
|
+
*/
|
|
2322
|
+
pollFirst:
|
|
2323
|
+
() => (elements.length > 0) ? elements.splice(0, 1)[0] : undefined,
|
|
2324
|
+
|
|
2325
|
+
/**
|
|
2326
|
+
* Removes and returns the last element of the set, or undefined if it is empty.
|
|
2327
|
+
*
|
|
2328
|
+
* @returns {*|undefined}
|
|
2329
|
+
*/
|
|
2330
|
+
pollLast:
|
|
2331
|
+
() => (elements.length > 0) ? elements.splice(elements.length - 1, 1)[0] : undefined,
|
|
2332
|
+
|
|
2333
|
+
/**
|
|
2334
|
+
* Adds the given value to the set. Will only do so if no equal value already exists.
|
|
2335
|
+
*
|
|
2336
|
+
* @param {*} value
|
|
2337
|
+
*/
|
|
2338
|
+
add:
|
|
2339
|
+
(value) =>
|
|
2340
|
+
{
|
|
2341
|
+
const result = binarySearch(value);
|
|
2342
|
+
if(result.found)
|
|
2343
|
+
{
|
|
2344
|
+
return;
|
|
2345
|
+
}
|
|
2346
|
+
elements.splice(result.index, 0, value);
|
|
2347
|
+
},
|
|
2348
|
+
|
|
2349
|
+
/**
|
|
2350
|
+
* Adds all the given values to the set. Will only do so if no equal value already exists.
|
|
2351
|
+
*
|
|
2352
|
+
* @param {*[]|object} values
|
|
2353
|
+
*/
|
|
2354
|
+
addAll:
|
|
2355
|
+
(values) =>
|
|
2356
|
+
{
|
|
2357
|
+
LeUtils.each(values, treeSet.add);
|
|
2358
|
+
},
|
|
2359
|
+
|
|
2360
|
+
/**
|
|
2361
|
+
* Returns an equal value that's already in the tree set, or undefined if no equal values in it exist.
|
|
2362
|
+
*
|
|
2363
|
+
* @param {*} value
|
|
2364
|
+
* @returns {*|undefined}
|
|
2365
|
+
*/
|
|
2366
|
+
getEqualValue:
|
|
2367
|
+
(value) =>
|
|
2368
|
+
{
|
|
2369
|
+
const result = binarySearch(value);
|
|
2370
|
+
if(result.found)
|
|
2371
|
+
{
|
|
2372
|
+
return result.value;
|
|
2373
|
+
}
|
|
2374
|
+
return undefined;
|
|
2375
|
+
},
|
|
2376
|
+
|
|
2377
|
+
/**
|
|
2378
|
+
* Returns an equal value that's already in the tree set. If no equal values in it exist, the given value will be added and returned.
|
|
2379
|
+
*
|
|
2380
|
+
* @param {*} value
|
|
2381
|
+
* @returns {*}
|
|
2382
|
+
*/
|
|
2383
|
+
getEqualValueOrAdd:
|
|
2384
|
+
(value) =>
|
|
2385
|
+
{
|
|
2386
|
+
const result = binarySearch(value);
|
|
2387
|
+
if(result.found)
|
|
2388
|
+
{
|
|
2389
|
+
return result.value;
|
|
2390
|
+
}
|
|
2391
|
+
elements.splice(result.index, 0, value);
|
|
2392
|
+
return value;
|
|
2393
|
+
},
|
|
2394
|
+
};
|
|
2395
|
+
return treeSet;
|
|
2396
|
+
},
|
|
2397
|
+
|
|
2398
|
+
/**
|
|
2399
|
+
* @typedef {Object} LeUtils~TransactionalValue
|
|
2400
|
+
* @property {*} value
|
|
2401
|
+
* @property {{id:string, value:*}[]} changes
|
|
2402
|
+
*/
|
|
2403
|
+
/**
|
|
2404
|
+
* Creates and returns a new TransactionalValue object.
|
|
2405
|
+
* With a TransactionalValue, you can keep track of changes to a value, and commit or cancel them.
|
|
2406
|
+
*
|
|
2407
|
+
* Multiple uncommitted changes can be made at the same time, the last change will be the one that overwrites older changes.
|
|
2408
|
+
* If that change is cancelled, the previous change will be the one that overwrites older changes.
|
|
2409
|
+
* This allows you to make multiple unconfirmed changes, and confirm or cancel each of them individually at any time.
|
|
2410
|
+
*
|
|
2411
|
+
* @param {*} [value]
|
|
2412
|
+
* @returns {LeUtils~TransactionalValue}
|
|
2413
|
+
*/
|
|
2414
|
+
createTransactionalValue:
|
|
2415
|
+
(value) =>
|
|
2416
|
+
{
|
|
2417
|
+
if(typeof value === 'undefined')
|
|
2418
|
+
{
|
|
2419
|
+
value = null;
|
|
2420
|
+
}
|
|
2421
|
+
return {value:value, changes:[]};
|
|
2422
|
+
},
|
|
2423
|
+
|
|
2424
|
+
/**
|
|
2425
|
+
* Returns true if the given value is a valid TransactionalValue, returns false if it isn't.
|
|
2426
|
+
*
|
|
2427
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
2428
|
+
* @returns {boolean}
|
|
2429
|
+
*/
|
|
2430
|
+
isTransactionalValueValid:
|
|
2431
|
+
(transactionalValue) =>
|
|
2432
|
+
{
|
|
2433
|
+
return ((typeof transactionalValue === 'object') && ('value' in transactionalValue) && ('changes' in transactionalValue) && Array.isArray(transactionalValue.changes));
|
|
2434
|
+
},
|
|
2435
|
+
|
|
2436
|
+
/**
|
|
2437
|
+
* Returns true if the given value is a TransactionalValue, false otherwise.
|
|
2438
|
+
*
|
|
2439
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
2440
|
+
* @returns {string}
|
|
2441
|
+
*/
|
|
2442
|
+
transactionalValueToString:
|
|
2443
|
+
(transactionalValue) =>
|
|
2444
|
+
{
|
|
2445
|
+
if(!LeUtils.isTransactionalValueValid(transactionalValue))
|
|
2446
|
+
{
|
|
2447
|
+
return transactionalValue + '';
|
|
2448
|
+
}
|
|
2449
|
+
if(transactionalValue.changes.length <= 0)
|
|
2450
|
+
{
|
|
2451
|
+
return '' + transactionalValue.value;
|
|
2452
|
+
}
|
|
2453
|
+
let valuesString = '' + transactionalValue.value;
|
|
2454
|
+
for(let i = 0; i < transactionalValue.changes.length; i++)
|
|
2455
|
+
{
|
|
2456
|
+
valuesString += ' -> ' + transactionalValue.changes[i].value;
|
|
2457
|
+
}
|
|
2458
|
+
return transactionalValue.changes[transactionalValue.changes.length - 1].value + ' (' + valuesString + ')';
|
|
2459
|
+
},
|
|
2460
|
+
|
|
2461
|
+
/**
|
|
2462
|
+
* Sets the committed value of the given TransactionalValue to the given value. Clears out the previously uncommitted changes.
|
|
2463
|
+
*
|
|
2464
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
2465
|
+
* @param {*} value
|
|
2466
|
+
*/
|
|
2467
|
+
transactionSetAndCommit:
|
|
2468
|
+
(transactionalValue, value) =>
|
|
2469
|
+
{
|
|
2470
|
+
checkTransactionalValue(transactionalValue);
|
|
2471
|
+
if(typeof value === 'undefined')
|
|
2472
|
+
{
|
|
2473
|
+
value = null;
|
|
2474
|
+
}
|
|
2475
|
+
transactionalValue.value = value;
|
|
2476
|
+
transactionalValue.changes = [];
|
|
2477
|
+
},
|
|
2478
|
+
|
|
2479
|
+
/**
|
|
2480
|
+
* Sets the value of the given TransactionalValue to the given value, without yet committing it, meaning it can be committed or cancelled later.
|
|
2481
|
+
* It returns the ID of the change, which can be used to commit or cancel the change later.
|
|
2482
|
+
*
|
|
2483
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
2484
|
+
* @param {*} value
|
|
2485
|
+
* @returns {string}
|
|
2486
|
+
*/
|
|
2487
|
+
transactionSetWithoutCommitting:
|
|
2488
|
+
(transactionalValue, value) =>
|
|
2489
|
+
{
|
|
2490
|
+
checkTransactionalValue(transactionalValue);
|
|
2491
|
+
if(typeof value === 'undefined')
|
|
2492
|
+
{
|
|
2493
|
+
value = null;
|
|
2494
|
+
}
|
|
2495
|
+
const id = LeUtils.uniqueId();
|
|
2496
|
+
transactionalValue.changes.push({id:id, value:value});
|
|
2497
|
+
return id;
|
|
2498
|
+
},
|
|
2499
|
+
|
|
2500
|
+
/**
|
|
2501
|
+
* Commits the change with the given ID, making it the new committed value.
|
|
2502
|
+
* Returns true if the change was found and committed, returns false if it was already overwritten by a newer committed change.
|
|
2503
|
+
*
|
|
2504
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
2505
|
+
* @param {string} changeId
|
|
2506
|
+
* @returns {boolean}
|
|
2507
|
+
*/
|
|
2508
|
+
transactionCommitChange:
|
|
2509
|
+
(transactionalValue, changeId) =>
|
|
2510
|
+
{
|
|
2511
|
+
checkTransactionalValue(transactionalValue);
|
|
2512
|
+
const change = findTransactionalValueChange(transactionalValue, changeId);
|
|
2513
|
+
if(change === null)
|
|
2514
|
+
{
|
|
2515
|
+
return false;
|
|
2516
|
+
}
|
|
2517
|
+
transactionalValue.value = change.value;
|
|
2518
|
+
transactionalValue.changes.splice(0, change.index + 1);
|
|
2519
|
+
return true;
|
|
2520
|
+
},
|
|
2521
|
+
|
|
2522
|
+
/**
|
|
2523
|
+
* Cancels the change with the given ID, removing it from the uncommitted changes.
|
|
2524
|
+
* Returns true if the change was found and removed, returns false if it was already overwritten by a newer committed change.
|
|
2525
|
+
*
|
|
2526
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
2527
|
+
* @param {string} changeId
|
|
2528
|
+
* @returns {boolean}
|
|
2529
|
+
*/
|
|
2530
|
+
transactionCancelChange:
|
|
2531
|
+
(transactionalValue, changeId) =>
|
|
2532
|
+
{
|
|
2533
|
+
checkTransactionalValue(transactionalValue);
|
|
2534
|
+
const change = findTransactionalValueChange(transactionalValue, changeId);
|
|
2535
|
+
if(change === null)
|
|
2536
|
+
{
|
|
2537
|
+
return false;
|
|
2538
|
+
}
|
|
2539
|
+
transactionalValue.changes.splice(change.index, 1);
|
|
2540
|
+
return true;
|
|
2541
|
+
},
|
|
2542
|
+
|
|
2543
|
+
/**
|
|
2544
|
+
* Returns true if the change was found, meaning it can still make a difference to the final committed value of this TransactionalValue.
|
|
2545
|
+
* Returns false if it was already overwritten by a newer committed change, meaning that this change can no longer make a difference to the final committed value of this TransactionalValue.
|
|
2546
|
+
*
|
|
2547
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
2548
|
+
* @param {string} changeId
|
|
2549
|
+
* @returns {boolean}
|
|
2550
|
+
*/
|
|
2551
|
+
transactionIsChangeRelevant:
|
|
2552
|
+
(transactionalValue, changeId) =>
|
|
2553
|
+
{
|
|
2554
|
+
checkTransactionalValue(transactionalValue);
|
|
2555
|
+
return (findTransactionalValueChange(transactionalValue, changeId) !== null);
|
|
2556
|
+
},
|
|
2557
|
+
|
|
2558
|
+
/**
|
|
2559
|
+
* Returns the committed value of the given TransactionalValue.
|
|
2560
|
+
*
|
|
2561
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
2562
|
+
* @returns {*}
|
|
2563
|
+
*/
|
|
2564
|
+
transactionGetCommittedValue:
|
|
2565
|
+
(transactionalValue) =>
|
|
2566
|
+
{
|
|
2567
|
+
checkTransactionalValue(transactionalValue);
|
|
2568
|
+
return transactionalValue.value;
|
|
2569
|
+
},
|
|
2570
|
+
|
|
2571
|
+
/**
|
|
2572
|
+
* Returns the value (including any uncommitted changes made to it) of the given TransactionalValue.
|
|
2573
|
+
*
|
|
2574
|
+
* @param {LeUtils~TransactionalValue} transactionalValue
|
|
2575
|
+
* @returns {*}
|
|
2576
|
+
*/
|
|
2577
|
+
transactionGetValue:
|
|
2578
|
+
(transactionalValue) =>
|
|
2579
|
+
{
|
|
2580
|
+
checkTransactionalValue(transactionalValue);
|
|
2581
|
+
if(transactionalValue.changes.length <= 0)
|
|
2582
|
+
{
|
|
2583
|
+
return transactionalValue.value;
|
|
2584
|
+
}
|
|
2585
|
+
return transactionalValue.changes[transactionalValue.changes.length - 1].value;
|
|
2586
|
+
},
|
|
2064
2587
|
};
|