@openremote/core 1.8.0-snapshot.20250725120002 → 1.8.0-snapshot.20250728102340
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 +105 -105
- package/dist/umd/index.bundle.js.map +1 -1
- package/dist/umd/index.js.map +1 -1
- package/dist/umd/index.orbundle.js +49 -49
- package/dist/umd/index.orbundle.js.map +1 -1
- package/lib/asset-mixin.js +1 -161
- package/lib/console.js +1 -541
- package/lib/defaults.js +1 -16
- package/lib/event.js +1 -588
- package/lib/index.js +1 -1003
- package/lib/util.js +1 -1000
- package/package.json +4 -4
package/lib/util.js
CHANGED
|
@@ -1,1000 +1 @@
|
|
|
1
|
-
import i18next from "i18next";
|
|
2
|
-
import Qs from "qs";
|
|
3
|
-
import { AssetModelUtil } from "@openremote/model";
|
|
4
|
-
import moment from "moment";
|
|
5
|
-
import { transform } from "lodash";
|
|
6
|
-
export class Deferred {
|
|
7
|
-
get resolve() {
|
|
8
|
-
return this._resolve;
|
|
9
|
-
}
|
|
10
|
-
get reject() {
|
|
11
|
-
return this._reject;
|
|
12
|
-
}
|
|
13
|
-
get promise() {
|
|
14
|
-
return this._promise;
|
|
15
|
-
}
|
|
16
|
-
constructor() {
|
|
17
|
-
this._promise = new Promise((resolve1, reject1) => {
|
|
18
|
-
this._resolve = resolve1;
|
|
19
|
-
this._reject = reject1;
|
|
20
|
-
});
|
|
21
|
-
Object.freeze(this);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
export function getBrowserLanguage() {
|
|
25
|
-
return navigator.language.split("-")[0] || "en";
|
|
26
|
-
}
|
|
27
|
-
export function getQueryParameters(queryStr) {
|
|
28
|
-
return Qs.parse(queryStr, { ignoreQueryPrefix: true });
|
|
29
|
-
}
|
|
30
|
-
export function getQueryParameter(parameter) {
|
|
31
|
-
let parsed;
|
|
32
|
-
if (location.search && location.search !== "") {
|
|
33
|
-
parsed = getQueryParameters(location.search);
|
|
34
|
-
}
|
|
35
|
-
if (location.hash) {
|
|
36
|
-
const index = location.hash.indexOf("?");
|
|
37
|
-
if (index > -1) {
|
|
38
|
-
parsed = getQueryParameters(location.hash.substring(index + 1));
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return parsed ? parsed[parameter] : undefined;
|
|
42
|
-
}
|
|
43
|
-
export function getGeoNotificationsFromRulesSet(rulesetDefinition) {
|
|
44
|
-
const geoNotifications = [];
|
|
45
|
-
rulesetDefinition.rules.forEach((rule) => {
|
|
46
|
-
if (rule.when && rule.then && rule.then.length > 0) {
|
|
47
|
-
const geoNotificationMap = new Map();
|
|
48
|
-
addGeofencePredicatesFromRuleCondition(rule.when, 0, geoNotificationMap);
|
|
49
|
-
if (geoNotificationMap.size > 0) {
|
|
50
|
-
rule.then.forEach((ruleAction) => addPushNotificationsFromRuleAction(ruleAction, geoNotificationMap));
|
|
51
|
-
}
|
|
52
|
-
for (const geoNotificationsArr of geoNotificationMap.values()) {
|
|
53
|
-
geoNotificationsArr.forEach((geoNotification) => {
|
|
54
|
-
if (geoNotification.notification) {
|
|
55
|
-
geoNotifications.push(geoNotification);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
return geoNotifications;
|
|
62
|
-
}
|
|
63
|
-
function addGeofencePredicatesFromRuleCondition(ruleCondition, index, geoNotificationMap) {
|
|
64
|
-
if (!ruleCondition) {
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
const items = [];
|
|
68
|
-
if (ruleCondition.groups) {
|
|
69
|
-
ruleCondition.groups.forEach((ruleGroup) => {
|
|
70
|
-
if (ruleGroup.items) {
|
|
71
|
-
ruleGroup.items.forEach((ruleTrigger) => {
|
|
72
|
-
items.push(ruleTrigger);
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
if (ruleCondition.items) {
|
|
78
|
-
ruleCondition.items.forEach((ruleTrigger) => {
|
|
79
|
-
items.push(ruleTrigger);
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
if (items) {
|
|
83
|
-
items.forEach((ruleTrigger) => {
|
|
84
|
-
if (ruleTrigger.assets && ruleTrigger.assets.attributes) {
|
|
85
|
-
const geoNotifications = [];
|
|
86
|
-
addGeoNotificationsFromAttributePredicateCondition(ruleTrigger.assets.attributes, geoNotifications);
|
|
87
|
-
if (geoNotifications.length > 0) {
|
|
88
|
-
const tagName = ruleTrigger.tag || index.toString();
|
|
89
|
-
geoNotificationMap.set(tagName, geoNotifications);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function addGeoNotificationsFromAttributePredicateCondition(attributeCondition, geoNotifications) {
|
|
96
|
-
if (!attributeCondition) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
attributeCondition.items.forEach((predicate) => {
|
|
100
|
-
if (predicate.value && (predicate.value.predicateType === "radial" || predicate.value.predicateType === "rect")) {
|
|
101
|
-
geoNotifications.push({
|
|
102
|
-
predicate: predicate.value
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
if (attributeCondition.groups) {
|
|
107
|
-
attributeCondition.groups.forEach((condition) => addGeoNotificationsFromAttributePredicateCondition(condition, geoNotifications));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
function addPushNotificationsFromRuleAction(ruleAction, geoPredicateMap) {
|
|
111
|
-
if (ruleAction && ruleAction.action === "notification") {
|
|
112
|
-
if (ruleAction.notification && ruleAction.notification.message && ruleAction.notification.message.type === "push") {
|
|
113
|
-
// Find applicable targets
|
|
114
|
-
const target = ruleAction.target;
|
|
115
|
-
if (target && target.conditionAssets) {
|
|
116
|
-
const geoNotifications = geoPredicateMap.get(target.conditionAssets);
|
|
117
|
-
if (geoNotifications) {
|
|
118
|
-
geoNotifications.forEach((geoNotification) => {
|
|
119
|
-
geoNotification.notification = ruleAction.notification.message;
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
// Applies to all LHS rule triggers
|
|
125
|
-
for (const geoNotifications of geoPredicateMap.values()) {
|
|
126
|
-
geoNotifications.forEach((geoNotification) => {
|
|
127
|
-
geoNotification.notification = ruleAction.notification.message;
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
const TIME_DURATION_REGEXP = /([+-])?((\d+)[Dd])?\s*((\d+)[Hh])?\s*((\d+)[Mm]$)?\s*((\d+)[Ss])?\s*((\d+)([Mm][Ss]$))?\s*((\d+)[Ww])?\s*((\d+)[Mm][Nn])?\s*((\d+)[Yy])?/;
|
|
135
|
-
export function isTimeDuration(time) {
|
|
136
|
-
if (!time) {
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
time = time.trim();
|
|
140
|
-
return time.length > 0
|
|
141
|
-
&& (TIME_DURATION_REGEXP.test(time)
|
|
142
|
-
|| isTimeDurationPositiveInfinity(time)
|
|
143
|
-
|| isTimeDurationNegativeInfinity(time));
|
|
144
|
-
}
|
|
145
|
-
export function isTimeDurationPositiveInfinity(time) {
|
|
146
|
-
time = time != null ? time.trim() : undefined;
|
|
147
|
-
return "*" === time || "+*" === time;
|
|
148
|
-
}
|
|
149
|
-
export function isTimeDurationNegativeInfinity(time) {
|
|
150
|
-
time = time != null ? time.trim() : undefined;
|
|
151
|
-
return "-*" === time;
|
|
152
|
-
}
|
|
153
|
-
export function isObject(object) {
|
|
154
|
-
if (!!object) {
|
|
155
|
-
return typeof object === "object";
|
|
156
|
-
}
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
export function isFunction(object) {
|
|
160
|
-
return !!(object && object.constructor && object.call && object.apply);
|
|
161
|
-
}
|
|
162
|
-
export function objectsEqual(obj1, obj2, deep = true) {
|
|
163
|
-
if (obj1 === null || obj1 === undefined || obj2 === null || obj2 === undefined) {
|
|
164
|
-
return obj1 === obj2;
|
|
165
|
-
}
|
|
166
|
-
// after this just checking type of one would be enough
|
|
167
|
-
if (obj1.constructor !== obj2.constructor) {
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
// if they are functions, they should exactly refer to same one (because of closures)
|
|
171
|
-
if (obj1 instanceof Function) {
|
|
172
|
-
return obj1 === obj2;
|
|
173
|
-
}
|
|
174
|
-
// if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES)
|
|
175
|
-
if (obj1 instanceof RegExp) {
|
|
176
|
-
return obj1 === obj2;
|
|
177
|
-
}
|
|
178
|
-
if (obj1 === obj2 || obj1.valueOf() === obj2.valueOf()) {
|
|
179
|
-
return true;
|
|
180
|
-
}
|
|
181
|
-
if (Array.isArray(obj1) && obj1.length !== obj2.length) {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
// if they are dates, they must had equal valueOf
|
|
185
|
-
if (obj1 instanceof Date) {
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
// if they are strictly equal, they both need to be object at least
|
|
189
|
-
if (!(obj1 instanceof Object)) {
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
if (!(obj2 instanceof Object)) {
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
if (deep) {
|
|
196
|
-
// recursive object equality check
|
|
197
|
-
const p = Object.keys(obj1);
|
|
198
|
-
return Object.keys(obj2).every((i) => {
|
|
199
|
-
return p.indexOf(i) !== -1;
|
|
200
|
-
}) &&
|
|
201
|
-
p.every((i) => {
|
|
202
|
-
return objectsEqual(obj1[i], obj2[i]);
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Deep diff between two object, using lodash
|
|
209
|
-
* @param {Object} object Object compared
|
|
210
|
-
* @param {Object} base Object to compare with
|
|
211
|
-
* @return {Object} Return a new object who represent the diff
|
|
212
|
-
*/
|
|
213
|
-
export function difference(object, base) {
|
|
214
|
-
const changes = (object, base) => transform(object, function (result, value, key) {
|
|
215
|
-
if (!objectsEqual(value, base === null || base === void 0 ? void 0 : base[key])) {
|
|
216
|
-
result[key] = (isObject(value) && isObject(base === null || base === void 0 ? void 0 : base[key])) ? changes(value, base === null || base === void 0 ? void 0 : base[key]) : value;
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
return changes(object, base);
|
|
220
|
-
}
|
|
221
|
-
export function arrayRemove(arr, item) {
|
|
222
|
-
if (arr.length === 0) {
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const index = arr.indexOf(item);
|
|
226
|
-
if (index >= 0) {
|
|
227
|
-
arr.splice(index, 1);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
export function sentenceCaseToCamelCase(str) {
|
|
231
|
-
if (str === undefined || str === null) {
|
|
232
|
-
return "";
|
|
233
|
-
}
|
|
234
|
-
return str.split(' ').map((value, index) => {
|
|
235
|
-
if (index === 0) {
|
|
236
|
-
return value[0].toLowerCase() + value.substring(1);
|
|
237
|
-
}
|
|
238
|
-
return value[0].toUpperCase() + value.substring(1);
|
|
239
|
-
}).join('');
|
|
240
|
-
}
|
|
241
|
-
export function camelCaseToSentenceCase(str) {
|
|
242
|
-
if (str === undefined || str === null) {
|
|
243
|
-
return "";
|
|
244
|
-
}
|
|
245
|
-
let startDone = false;
|
|
246
|
-
return str.split(/([A-Z]|\d)/).map((v, i, arr) => {
|
|
247
|
-
// Skip empty blocks
|
|
248
|
-
if (!v)
|
|
249
|
-
return v;
|
|
250
|
-
// If first block then capitalise 1st letter regardless
|
|
251
|
-
if (!startDone) {
|
|
252
|
-
startDone = true;
|
|
253
|
-
return v.charAt(0).toUpperCase() + v.slice(1);
|
|
254
|
-
}
|
|
255
|
-
// Underscore substitution
|
|
256
|
-
if (v === '_')
|
|
257
|
-
return " ";
|
|
258
|
-
// We have a capital or number
|
|
259
|
-
if (v.length === 1 && v === v.toUpperCase()) {
|
|
260
|
-
const previousCapital = !arr[i - 1] || arr[i - 1] === '_';
|
|
261
|
-
const nextWord = i + 1 < arr.length && arr[i + 1] && arr[i + 1] !== '_';
|
|
262
|
-
const nextTwoCapitalsOrEndOfString = i + 3 > arr.length || !arr[i + 1] && !arr[i + 3];
|
|
263
|
-
// Insert space
|
|
264
|
-
if (!previousCapital || nextWord)
|
|
265
|
-
v = " " + v;
|
|
266
|
-
// Start of word or single letter word
|
|
267
|
-
if (nextWord || (!previousCapital && !nextTwoCapitalsOrEndOfString))
|
|
268
|
-
v = v.toLowerCase();
|
|
269
|
-
}
|
|
270
|
-
return v;
|
|
271
|
-
}).join("").trim();
|
|
272
|
-
}
|
|
273
|
-
export function stringMatch(needle, haystack) {
|
|
274
|
-
if (haystack === needle) {
|
|
275
|
-
return true;
|
|
276
|
-
}
|
|
277
|
-
const startsWith = needle.endsWith("*");
|
|
278
|
-
const endsWith = !startsWith && needle.startsWith("*");
|
|
279
|
-
const regExp = !startsWith && !endsWith && needle.startsWith("^") && needle.endsWith("$");
|
|
280
|
-
if (startsWith && haystack.startsWith(needle.substr(0, needle.length - 1))) {
|
|
281
|
-
return true;
|
|
282
|
-
}
|
|
283
|
-
if (endsWith && haystack.endsWith(needle.substr(1))) {
|
|
284
|
-
return true;
|
|
285
|
-
}
|
|
286
|
-
if (regExp) {
|
|
287
|
-
try {
|
|
288
|
-
const regexp = new RegExp(needle);
|
|
289
|
-
return regexp.test(haystack);
|
|
290
|
-
}
|
|
291
|
-
catch (e) {
|
|
292
|
-
console.error("Failed to compile needle as a RegExp: " + e);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
297
|
-
export function capitaliseFirstLetter(str) {
|
|
298
|
-
if (!str) {
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
if (str.length === 1) {
|
|
302
|
-
return str.toUpperCase();
|
|
303
|
-
}
|
|
304
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
305
|
-
}
|
|
306
|
-
export function enumContains(enm, val) {
|
|
307
|
-
return enm && Object.values(enm).includes(val);
|
|
308
|
-
}
|
|
309
|
-
export function getEnumKeyAsString(enm, val) {
|
|
310
|
-
// @ts-ignore
|
|
311
|
-
const key = Object.keys(enm).find((k) => enm[k] === val);
|
|
312
|
-
return key;
|
|
313
|
-
}
|
|
314
|
-
/* For a given date, get the ISO week number
|
|
315
|
-
*
|
|
316
|
-
* Based on information at:
|
|
317
|
-
*
|
|
318
|
-
* http://www.merlyn.demon.co.uk/weekcalc.htm#WNR
|
|
319
|
-
*
|
|
320
|
-
* Algorithm is to find nearest thursday, it's year
|
|
321
|
-
* is the year of the week number. Then get weeks
|
|
322
|
-
* between that date and the first day of that year.
|
|
323
|
-
*
|
|
324
|
-
* Note that dates in one year can be weeks of previous
|
|
325
|
-
* or next year, overlap is up to 3 days.
|
|
326
|
-
*
|
|
327
|
-
* e.g. 2014/12/29 is Monday in week 1 of 2015
|
|
328
|
-
* 2012/1/1 is Sunday in week 52 of 2011
|
|
329
|
-
*/
|
|
330
|
-
export function getWeekNumber(date) {
|
|
331
|
-
// Copy date so don't modify original
|
|
332
|
-
date = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
|
333
|
-
// Set to nearest Thursday: current date + 4 - current day number
|
|
334
|
-
// Make Sunday's day number 7
|
|
335
|
-
date.setUTCDate(date.getUTCDate() + 4 - (date.getUTCDay() || 7));
|
|
336
|
-
// Get first day of year
|
|
337
|
-
const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
|
|
338
|
-
// Calculate full weeks to nearest Thursday
|
|
339
|
-
const weekNo = Math.ceil(((((date.getTime() - yearStart.getTime()) / 86400000) + 1) / 7));
|
|
340
|
-
// Return array of year and week number
|
|
341
|
-
return weekNo;
|
|
342
|
-
}
|
|
343
|
-
const monthNames = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'];
|
|
344
|
-
/* Creates a cron string based on the input parameters.
|
|
345
|
-
* You can for example trigger an expression once a month on friday, or on a specific date ass March 1st.
|
|
346
|
-
*
|
|
347
|
-
* Useful URLs for understanding cron:
|
|
348
|
-
* - https://en.wikipedia.org/wiki/Cron
|
|
349
|
-
* - https://www.freeformatter.com/cron-expression-generator-quartz.html
|
|
350
|
-
*
|
|
351
|
-
* @param years What years it should trigger. For example ['2022','2023'] or a string to inject.
|
|
352
|
-
* @param months What months of the year it should trigger. For example ['JAN','FEB'] or [0,1,2,3,4,5] or a string to inject.
|
|
353
|
-
* @param days What days of the month it should trigger. For example [7,14,21,28] or a string to inject.
|
|
354
|
-
* @param hours What hours of the day it should trigger. For example [3,6,9,12,15,18,21] or a string to inject.
|
|
355
|
-
* @param minutes What minutes of the hour it should trigger. For example [0,15,30,45] or a string to inject.
|
|
356
|
-
* @param seconds What seconds of the minute it should trigger. For example [0,15,30,45] or a string to inject.
|
|
357
|
-
* @param daysOfTheWeek String to inject for specifying specific days such as '1st monday of the month'.
|
|
358
|
-
* */
|
|
359
|
-
export function formatCronString(years, months, days, hours, minutes, seconds, daysOfTheWeek) {
|
|
360
|
-
let cron = "";
|
|
361
|
-
if (seconds) {
|
|
362
|
-
if (Array.isArray(seconds)) {
|
|
363
|
-
cron += (seconds.toString().replace(" ", ""));
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
cron += seconds.toString();
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
cron += "0";
|
|
371
|
-
}
|
|
372
|
-
cron += " ";
|
|
373
|
-
if (minutes) {
|
|
374
|
-
if (Array.isArray(minutes)) {
|
|
375
|
-
cron += (minutes.toString().replace(" ", ""));
|
|
376
|
-
}
|
|
377
|
-
else {
|
|
378
|
-
cron += minutes.toString();
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
cron += "0";
|
|
383
|
-
}
|
|
384
|
-
cron += " ";
|
|
385
|
-
if (hours) {
|
|
386
|
-
if (Array.isArray(hours)) {
|
|
387
|
-
cron += (hours.toString().replace(" ", ""));
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
cron += hours.toString();
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
cron += "0";
|
|
395
|
-
}
|
|
396
|
-
cron += " ";
|
|
397
|
-
if (days) {
|
|
398
|
-
if (Array.isArray(days)) {
|
|
399
|
-
cron += (days.toString().replace(" ", ""));
|
|
400
|
-
}
|
|
401
|
-
else {
|
|
402
|
-
cron += days.toString();
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
else {
|
|
406
|
-
cron += "*";
|
|
407
|
-
}
|
|
408
|
-
cron += " ";
|
|
409
|
-
if (months) {
|
|
410
|
-
if (Array.isArray(months)) {
|
|
411
|
-
if (typeof months[0] == 'number') {
|
|
412
|
-
const monthStrings = [];
|
|
413
|
-
months.forEach(month => { monthStrings.push(monthNames[month].toString()); });
|
|
414
|
-
cron += (monthStrings.toString().replace(" ", ""));
|
|
415
|
-
}
|
|
416
|
-
else {
|
|
417
|
-
cron += (months.toString().replace(" ", ""));
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
else {
|
|
421
|
-
cron += months.toString();
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
else {
|
|
425
|
-
cron += "*";
|
|
426
|
-
}
|
|
427
|
-
cron += " ";
|
|
428
|
-
if (daysOfTheWeek) {
|
|
429
|
-
cron += daysOfTheWeek.toString();
|
|
430
|
-
}
|
|
431
|
-
else {
|
|
432
|
-
cron += "?";
|
|
433
|
-
}
|
|
434
|
-
cron += " ";
|
|
435
|
-
if (years) {
|
|
436
|
-
if (Array.isArray(years)) {
|
|
437
|
-
cron += (years.toString().replace(" ", ""));
|
|
438
|
-
}
|
|
439
|
-
else {
|
|
440
|
-
cron += years;
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
else {
|
|
444
|
-
cron += "*";
|
|
445
|
-
}
|
|
446
|
-
return cron;
|
|
447
|
-
}
|
|
448
|
-
/* Transforms an JS date to a cron string, to trigger ONCE A YEAR on that specific date */
|
|
449
|
-
export function dateToCronString(date) {
|
|
450
|
-
return formatCronString(date.getFullYear(), monthNames[date.getMonth()], [date.getDate()], [date.getHours()], [date.getMinutes()]);
|
|
451
|
-
}
|
|
452
|
-
/*
|
|
453
|
-
* Transforms a cron expression string into an ISO String.
|
|
454
|
-
* Input for example would be `0 00 11 * * ? *` for every day at 11am.
|
|
455
|
-
* If the input is '*', it will be replaced by 1. (month parameter of '*' becomes January)
|
|
456
|
-
*/
|
|
457
|
-
export function cronStringToISOString(cronString, isUTC) {
|
|
458
|
-
const splStr = cronString.split(" ");
|
|
459
|
-
if (!Number.isNaN(Number(splStr[0])) && !Number.isNaN(Number(splStr[1])) && !Number.isNaN(Number(splStr[2])) && (!Number.isNaN(Number(splStr[3])) || splStr[3] == '*')) {
|
|
460
|
-
const year = (!Number.isNaN(Number(splStr[6])) ? splStr[6] : new Date().getFullYear()).toString();
|
|
461
|
-
let month = "";
|
|
462
|
-
if (splStr[4] != '*') {
|
|
463
|
-
month = monthNames.indexOf(splStr[4]).toString();
|
|
464
|
-
}
|
|
465
|
-
else {
|
|
466
|
-
month = new Date().getMonth().toString();
|
|
467
|
-
}
|
|
468
|
-
month = (month.length == 1 ? ("0" + month) : month);
|
|
469
|
-
const date = ((splStr[3].length == 1 && splStr[3] != '*') ? ("0" + splStr[3]) : splStr[3].replace('*', '01'));
|
|
470
|
-
const hour = ((splStr[2].length == 1 && splStr[2] != '*') ? ("0" + splStr[2]) : splStr[2].replace('*', '00'));
|
|
471
|
-
const minute = ((splStr[1].length == 1 && splStr[1] != '*') ? ("0" + splStr[1]) : splStr[1].replace('*', '00'));
|
|
472
|
-
const second = ((splStr[0].length == 1 && splStr[0] != '*') ? ("0" + splStr[0]) : splStr[0].replace('*', '00'));
|
|
473
|
-
if (year.length > 0 && month.length > 0) {
|
|
474
|
-
if (isUTC) {
|
|
475
|
-
return moment.utc({ year: Number(year), month: Number(month), date: Number(date), hour: Number(hour), minute: Number(minute), second: Number(second) }).toISOString();
|
|
476
|
-
}
|
|
477
|
-
else {
|
|
478
|
-
return moment({ year: Number(year), month: Number(month), date: Number(date), hour: Number(hour), minute: Number(minute), second: Number(second) }).toISOString();
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
return undefined;
|
|
483
|
-
}
|
|
484
|
-
export function getMetaValue(name, attribute, descriptor) {
|
|
485
|
-
const metaName = typeof name === "string" ? name : name.name;
|
|
486
|
-
if (attribute && attribute.meta && attribute.meta.hasOwnProperty(metaName)) {
|
|
487
|
-
return attribute.meta[metaName];
|
|
488
|
-
}
|
|
489
|
-
if (descriptor && descriptor.meta) {
|
|
490
|
-
return descriptor.meta[metaName];
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
export function hasMetaItem(name, attribute, descriptor) {
|
|
494
|
-
const metaName = typeof name === "string" ? name : name.name;
|
|
495
|
-
if (attribute && attribute.meta && attribute.meta.hasOwnProperty(metaName)) {
|
|
496
|
-
return true;
|
|
497
|
-
}
|
|
498
|
-
if (descriptor && descriptor.meta && descriptor.meta.hasOwnProperty(metaName)) {
|
|
499
|
-
return true;
|
|
500
|
-
}
|
|
501
|
-
return false;
|
|
502
|
-
}
|
|
503
|
-
export function getAssetTypeLabel(type) {
|
|
504
|
-
if (typeof type === "string") {
|
|
505
|
-
type = AssetModelUtil.getAssetDescriptor(type);
|
|
506
|
-
}
|
|
507
|
-
if (!type) {
|
|
508
|
-
return "";
|
|
509
|
-
}
|
|
510
|
-
return i18next.t("label.asset." + type.name, { defaultValue: camelCaseToSentenceCase(type.name) });
|
|
511
|
-
}
|
|
512
|
-
export function getValueDescriptorLabel(descriptor) {
|
|
513
|
-
if (!descriptor) {
|
|
514
|
-
return i18next.t("label.value.unknown", { defaultValue: "Unknown" });
|
|
515
|
-
}
|
|
516
|
-
const name = (typeof (descriptor) === "string" ? descriptor : descriptor.name);
|
|
517
|
-
return i18next.t("label.value." + name, { defaultValue: camelCaseToSentenceCase(name || "") });
|
|
518
|
-
}
|
|
519
|
-
export function getAllowedValueLabel(allowedValue, fallback) {
|
|
520
|
-
if (!allowedValue) {
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
return i18next.t("label.allowedValue." + allowedValue, { defaultValue: fallback || camelCaseToSentenceCase(allowedValue || ""), nsSeparator: false });
|
|
524
|
-
}
|
|
525
|
-
export function getMetaItemNameValueHolder(metaNameOrDescriptor, value) {
|
|
526
|
-
const descriptor = typeof metaNameOrDescriptor === "string" ? AssetModelUtil.getMetaItemDescriptor(metaNameOrDescriptor) : metaNameOrDescriptor;
|
|
527
|
-
if (descriptor) {
|
|
528
|
-
return {
|
|
529
|
-
name: descriptor.name,
|
|
530
|
-
type: descriptor.type,
|
|
531
|
-
value: value
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
return {
|
|
535
|
-
name: typeof metaNameOrDescriptor,
|
|
536
|
-
type: AssetModelUtil.resolveValueTypeFromValue(value),
|
|
537
|
-
value: value
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
export function getAttributeLabel(attribute, descriptor, assetType, showUnits, fallback) {
|
|
541
|
-
return getValueHolderLabel(attribute, descriptor, assetType, showUnits, true, fallback);
|
|
542
|
-
}
|
|
543
|
-
export function getMetaLabel(metaItem, descriptor, assetType, showUnits, fallback) {
|
|
544
|
-
const metaValueHolder = metaItem || getMetaItemNameValueHolder(descriptor, null);
|
|
545
|
-
return getValueHolderLabel(metaValueHolder, descriptor, assetType, showUnits, false, fallback);
|
|
546
|
-
}
|
|
547
|
-
function getValueHolderLabel(nameValueHolder, descriptor, assetType, showUnits, isAttribute, fallback) {
|
|
548
|
-
let label = doStandardTranslationLookup("label" /* WellknownMetaItems.LABEL */, nameValueHolder, descriptor, assetType, isAttribute);
|
|
549
|
-
let unitsStr = "";
|
|
550
|
-
if (!label) {
|
|
551
|
-
// Look in meta if it exists
|
|
552
|
-
label = getMetaValue("label" /* WellknownMetaItems.LABEL */, nameValueHolder, descriptor && descriptor.meta ? descriptor : undefined);
|
|
553
|
-
}
|
|
554
|
-
if (showUnits) {
|
|
555
|
-
const units = getValueFormatConstraintOrUnits("units" /* WellknownMetaItems.UNITS */, nameValueHolder, descriptor, assetType, isAttribute);
|
|
556
|
-
unitsStr = resolveUnits(units);
|
|
557
|
-
}
|
|
558
|
-
if (!label) {
|
|
559
|
-
const name = nameValueHolder ? nameValueHolder.name : descriptor ? typeof descriptor === "string" ? descriptor : descriptor.name : undefined;
|
|
560
|
-
label = fallback || (name ? camelCaseToSentenceCase(name) : undefined);
|
|
561
|
-
}
|
|
562
|
-
return label ? label + (unitsStr ? " (" + unitsStr + ")" : "") : unitsStr;
|
|
563
|
-
}
|
|
564
|
-
export function getAttributeValueAsString(attribute, descriptor, assetType, showUnits, fallback) {
|
|
565
|
-
return getValueHolderValueAsString(attribute, descriptor, assetType, showUnits, true, fallback);
|
|
566
|
-
}
|
|
567
|
-
export function getMetaValueAsString(metaItem, descriptor, assetType, showUnits, fallback) {
|
|
568
|
-
const metaValueHolder = metaItem || getMetaItemNameValueHolder(descriptor, null);
|
|
569
|
-
return getValueHolderValueAsString(metaValueHolder, descriptor, assetType, showUnits, false, fallback);
|
|
570
|
-
}
|
|
571
|
-
function getValueHolderValueAsString(nameValueHolder, descriptor, assetType, showUnits, isAttribute, fallback) {
|
|
572
|
-
let valueStr = getValueAsString(nameValueHolder ? nameValueHolder.value : undefined, () => getValueFormatConstraintOrUnits("format" /* WellknownMetaItems.FORMAT */, nameValueHolder, descriptor, assetType, isAttribute), undefined, fallback);
|
|
573
|
-
const attrUnits = getAttributeUnits(nameValueHolder, descriptor, assetType);
|
|
574
|
-
if (showUnits && attrUnits && !!attrUnits.length) {
|
|
575
|
-
const units = getValueFormatConstraintOrUnits("units" /* WellknownMetaItems.UNITS */, nameValueHolder, descriptor, assetType, isAttribute);
|
|
576
|
-
valueStr = resolveUnits(units, valueStr);
|
|
577
|
-
}
|
|
578
|
-
return valueStr;
|
|
579
|
-
}
|
|
580
|
-
export function getValueAsString(value, formatProvider, language, fallback) {
|
|
581
|
-
let valueStr = "";
|
|
582
|
-
if (value === null || typeof (value) === "undefined") {
|
|
583
|
-
valueStr = fallback || "";
|
|
584
|
-
}
|
|
585
|
-
else {
|
|
586
|
-
if (typeof (value) === "string") {
|
|
587
|
-
valueStr = value;
|
|
588
|
-
}
|
|
589
|
-
else if (typeof (value) === "number" || typeof (value) === "boolean" || value instanceof Date) {
|
|
590
|
-
const format = formatProvider && formatProvider();
|
|
591
|
-
if (format && Object.keys(format).length !== 0) {
|
|
592
|
-
if (typeof (value) === "number") {
|
|
593
|
-
if (format.asBoolean) {
|
|
594
|
-
value = !!value;
|
|
595
|
-
}
|
|
596
|
-
else if (format.asDate) {
|
|
597
|
-
// Assume UNIX timestamp in ms
|
|
598
|
-
value = new Date(value);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
else if (typeof (value) === "boolean" && format.asNumber) {
|
|
602
|
-
value = value ? 1 : 0;
|
|
603
|
-
}
|
|
604
|
-
switch (typeof (value)) {
|
|
605
|
-
case "number":
|
|
606
|
-
valueStr = new Intl.NumberFormat(language || i18next.language, format).format(value);
|
|
607
|
-
break;
|
|
608
|
-
case "boolean":
|
|
609
|
-
if (format.asOnOff) {
|
|
610
|
-
valueStr = value ? i18next.t("on") : i18next.t("off");
|
|
611
|
-
}
|
|
612
|
-
if (format.asOpenClosed) {
|
|
613
|
-
valueStr = value ? i18next.t("open") : i18next.t("closed");
|
|
614
|
-
}
|
|
615
|
-
if (format.asPressedReleased) {
|
|
616
|
-
valueStr = value ? i18next.t("pressed") : i18next.t("released");
|
|
617
|
-
}
|
|
618
|
-
break;
|
|
619
|
-
case "object": // Date instance
|
|
620
|
-
// Special handling for some format options
|
|
621
|
-
if (format.momentJsFormat) {
|
|
622
|
-
valueStr = moment(value).format(format.momentJsFormat);
|
|
623
|
-
}
|
|
624
|
-
else if (format.iso8601) {
|
|
625
|
-
valueStr = value.toISOString();
|
|
626
|
-
}
|
|
627
|
-
else if (format.week) {
|
|
628
|
-
const weekNo = getWeekNumber(value);
|
|
629
|
-
valueStr = format.week === "2-digit" /* ValueFormatStyleRepresentation.DIGIT_2 */ ? String(weekNo).padStart(2, "0") : Number(weekNo).toString(10);
|
|
630
|
-
}
|
|
631
|
-
else {
|
|
632
|
-
valueStr = new Intl.DateTimeFormat(language || i18next.language, format).format(value);
|
|
633
|
-
}
|
|
634
|
-
break;
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
else {
|
|
638
|
-
valueStr = Object(value).toString();
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
return valueStr;
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* Resolve supplied units using current translation locale; and optionally apply the units to the supplied value (this
|
|
646
|
-
* is useful for units containing currency which in some locales is prefixed to the value e.g. £0.00 kW/hr rather than
|
|
647
|
-
* 0.00 £kW/hr)
|
|
648
|
-
*/
|
|
649
|
-
export function resolveUnits(units, valueStr) {
|
|
650
|
-
if (!units) {
|
|
651
|
-
return "";
|
|
652
|
-
}
|
|
653
|
-
if (!valueStr) {
|
|
654
|
-
valueStr = "";
|
|
655
|
-
}
|
|
656
|
-
const unitsStr = units.map((unit, index) => {
|
|
657
|
-
if (unit.length === 3 && unit.toUpperCase() === unit) {
|
|
658
|
-
// This is a currency code - use Intl API to find the symbol
|
|
659
|
-
const parts = new Intl.NumberFormat(i18next.language, { currency: unit, style: "currency" }).formatToParts();
|
|
660
|
-
// Check whether it goes before or after the value
|
|
661
|
-
if (index === 0 && parts[0].type === "currency") {
|
|
662
|
-
if (valueStr) {
|
|
663
|
-
valueStr = parts[0].value + valueStr;
|
|
664
|
-
}
|
|
665
|
-
else {
|
|
666
|
-
return parts[0].value;
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
else {
|
|
670
|
-
return (parts[0].type === "currency" ? parts[0].value : parts[parts.length - 1].value);
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
else {
|
|
674
|
-
return i18next.t(["units." + unit, "or:units." + unit]);
|
|
675
|
-
}
|
|
676
|
-
}).join("");
|
|
677
|
-
return valueStr.length > 0 ? (valueStr + " " + unitsStr) : unitsStr;
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* Looks for {@link ValueConstraint[]} for the specified {@link Attribute} (see {@link getValueFormatConstraintOrUnits})
|
|
681
|
-
*/
|
|
682
|
-
export function getAttributeValueConstraints(attribute, descriptor, assetType) {
|
|
683
|
-
return getValueFormatConstraintOrUnits("constraints" /* WellknownMetaItems.CONSTRAINTS */, attribute, descriptor, assetType, true);
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* Looks for {@link ValueConstraint[]} for the specified {@link NameValueHolder} (see {@link getValueFormatConstraintOrUnits})
|
|
687
|
-
*/
|
|
688
|
-
export function getMetaValueConstraints(metaItem, descriptor, assetType) {
|
|
689
|
-
const metaValueHolder = metaItem || getMetaItemNameValueHolder(descriptor, null);
|
|
690
|
-
return getValueFormatConstraintOrUnits("constraints" /* WellknownMetaItems.CONSTRAINTS */, metaValueHolder, descriptor, assetType, false);
|
|
691
|
-
}
|
|
692
|
-
/**
|
|
693
|
-
* Looks for units string[] for the specified {@link Attribute} (see {@link getValueFormatConstraintOrUnits})
|
|
694
|
-
*/
|
|
695
|
-
export function getAttributeUnits(attribute, descriptor, assetType) {
|
|
696
|
-
return getValueFormatConstraintOrUnits("units" /* WellknownMetaItems.UNITS */, attribute, descriptor, assetType, true);
|
|
697
|
-
}
|
|
698
|
-
/**
|
|
699
|
-
* Looks for units string[] for the specified {@link MetaItem} (see {@link getValueFormatConstraintOrUnits})
|
|
700
|
-
*/
|
|
701
|
-
export function getMetaUnits(metaItem, descriptor, assetType) {
|
|
702
|
-
const metaValueHolder = metaItem || getMetaItemNameValueHolder(descriptor, null);
|
|
703
|
-
return getValueFormatConstraintOrUnits("units" /* WellknownMetaItems.UNITS */, metaValueHolder, descriptor, assetType, false);
|
|
704
|
-
}
|
|
705
|
-
/**
|
|
706
|
-
* Looks for a {@link ValueFormat} for the specified {@link Attribute} (see {@link getValueFormatConstraintOrUnits})
|
|
707
|
-
*/
|
|
708
|
-
export function getAttributeValueFormat(attribute, descriptor, assetType) {
|
|
709
|
-
return getValueFormatConstraintOrUnits("format" /* WellknownMetaItems.FORMAT */, attribute, descriptor, assetType, true);
|
|
710
|
-
}
|
|
711
|
-
/**
|
|
712
|
-
* Looks for a {@see ValueFormat} for the specified {@link MetaItem} (see {@link getValueFormatConstraintOrUnits})
|
|
713
|
-
*/
|
|
714
|
-
export function getMetaValueFormat(metaItem, descriptor, assetType) {
|
|
715
|
-
const metaValueHolder = metaItem || getMetaItemNameValueHolder(descriptor, null);
|
|
716
|
-
return getValueFormatConstraintOrUnits("format" /* WellknownMetaItems.FORMAT */, metaValueHolder, descriptor, assetType, false);
|
|
717
|
-
}
|
|
718
|
-
export function mergeObjects(a, b, mergeArrays) {
|
|
719
|
-
if (a && !b) {
|
|
720
|
-
return Object.assign({}, a);
|
|
721
|
-
}
|
|
722
|
-
if (b && !a) {
|
|
723
|
-
return Object.assign({}, b);
|
|
724
|
-
}
|
|
725
|
-
const merged = Object.assign({}, a);
|
|
726
|
-
const path = [];
|
|
727
|
-
Object.entries(b).forEach(([k, v]) => {
|
|
728
|
-
mergeObjectKey(merged, path, k, v, mergeArrays);
|
|
729
|
-
});
|
|
730
|
-
return merged;
|
|
731
|
-
}
|
|
732
|
-
function mergeObjectKey(destination, path, key, value, mergeArrays) {
|
|
733
|
-
let dest = destination;
|
|
734
|
-
path.forEach((p) => {
|
|
735
|
-
if (!dest.hasOwnProperty(p)) {
|
|
736
|
-
dest[p] = {};
|
|
737
|
-
}
|
|
738
|
-
dest = dest[p];
|
|
739
|
-
});
|
|
740
|
-
if (!dest) {
|
|
741
|
-
return;
|
|
742
|
-
}
|
|
743
|
-
if (!dest.hasOwnProperty(key)) {
|
|
744
|
-
if (value === null || value === undefined) {
|
|
745
|
-
delete dest[key];
|
|
746
|
-
}
|
|
747
|
-
else if (Array.isArray(value)) {
|
|
748
|
-
dest[key] = [...value];
|
|
749
|
-
}
|
|
750
|
-
else if (typeof (value) === "object") {
|
|
751
|
-
dest[key] = Object.assign({}, value);
|
|
752
|
-
}
|
|
753
|
-
else {
|
|
754
|
-
dest[key] = value;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
else {
|
|
758
|
-
if (value === undefined || value === null) {
|
|
759
|
-
delete dest[key];
|
|
760
|
-
}
|
|
761
|
-
else if (Array.isArray(dest[key])) {
|
|
762
|
-
if (mergeArrays) {
|
|
763
|
-
dest[key] = [...dest[key], ...value];
|
|
764
|
-
}
|
|
765
|
-
else {
|
|
766
|
-
dest[key] = [...value];
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
else if (typeof (value) === "object") {
|
|
770
|
-
dest[key] = mergeObjects(Object.assign({}, dest[key]), value, mergeArrays);
|
|
771
|
-
}
|
|
772
|
-
else {
|
|
773
|
-
dest[key] = value;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
/**
|
|
778
|
-
* Looks for the requested {@link ValueFormat}, {@link ValueConstraint[]} or units string[] defined in the translation
|
|
779
|
-
* file in several locations (see {@link doStandardTranslationLookup}).
|
|
780
|
-
* <p>
|
|
781
|
-
* If no value is found in translation files then the standard resolution is used by looking at the nameValueHolder and/or
|
|
782
|
-
* the provided descriptor(s); the resolution order is:
|
|
783
|
-
* {@link NameValueHolder}, {@link ValueDescriptorHolder}, {@link ValueDescriptor}, the first value encountered will be
|
|
784
|
-
* returned; with the exception of {@link ValueFormat} which are merged in reverse priority order.
|
|
785
|
-
*/
|
|
786
|
-
function getValueFormatConstraintOrUnits(lookup, nameValueHolder, descriptor, assetType, isAttribute) {
|
|
787
|
-
let matched;
|
|
788
|
-
const formats = [];
|
|
789
|
-
const name = nameValueHolder && typeof nameValueHolder === "string" ? nameValueHolder : nameValueHolder ? nameValueHolder.name : descriptor ? typeof (descriptor) === "string" ? descriptor : descriptor.name : undefined;
|
|
790
|
-
const str = doStandardTranslationLookup(lookup, name, descriptor, assetType, isAttribute);
|
|
791
|
-
if (str) {
|
|
792
|
-
matched = JSON.parse(str);
|
|
793
|
-
if (matched) {
|
|
794
|
-
if (lookup === "format" /* WellknownMetaItems.FORMAT */) {
|
|
795
|
-
formats.push(matched);
|
|
796
|
-
}
|
|
797
|
-
else {
|
|
798
|
-
return matched;
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
// Look in meta
|
|
803
|
-
if (nameValueHolder && nameValueHolder.meta) {
|
|
804
|
-
matched = getMetaValue(lookup, nameValueHolder, descriptor);
|
|
805
|
-
if (matched) {
|
|
806
|
-
if (lookup === "format" /* WellknownMetaItems.FORMAT */) {
|
|
807
|
-
formats.push(matched);
|
|
808
|
-
}
|
|
809
|
-
else {
|
|
810
|
-
return matched;
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
if (descriptor && typeof (descriptor) !== "string" && descriptor.hasOwnProperty(lookup)) {
|
|
815
|
-
matched = descriptor[lookup];
|
|
816
|
-
if (lookup === "format" /* WellknownMetaItems.FORMAT */) {
|
|
817
|
-
formats.push(matched);
|
|
818
|
-
}
|
|
819
|
-
else {
|
|
820
|
-
return matched;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
if (descriptor && descriptor.type) {
|
|
824
|
-
const valueDescriptor = AssetModelUtil.getValueDescriptor(descriptor.type);
|
|
825
|
-
matched = valueDescriptor[lookup];
|
|
826
|
-
if (lookup === "format" /* WellknownMetaItems.FORMAT */) {
|
|
827
|
-
formats.push(matched);
|
|
828
|
-
}
|
|
829
|
-
else {
|
|
830
|
-
return matched;
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
if (lookup !== "format" /* WellknownMetaItems.FORMAT */ || formats.length === 0) {
|
|
834
|
-
return matched;
|
|
835
|
-
}
|
|
836
|
-
let mergedFormat = {};
|
|
837
|
-
formats.reverse().forEach((format) => {
|
|
838
|
-
mergedFormat = Object.assign(Object.assign({}, mergedFormat), format);
|
|
839
|
-
});
|
|
840
|
-
return mergedFormat;
|
|
841
|
-
}
|
|
842
|
-
/**
|
|
843
|
-
* Looks up the requested lookup in several keys, for example lookup=label, name=custom, isAttribute=true, assetType=ThingAsset,
|
|
844
|
-
* descriptorType=number:
|
|
845
|
-
* <ol>
|
|
846
|
-
* <li>label.attribute.ThingAsset.custom</li>
|
|
847
|
-
* <li>label.attribute.number.custom</li>
|
|
848
|
-
* <li>label.attribute.number</li>
|
|
849
|
-
*/
|
|
850
|
-
function doStandardTranslationLookup(lookup, nameValueHolder, valueHolderDescriptor, assetType, isAttribute, fallback) {
|
|
851
|
-
// Look in translation files for an override in multiple keys e.g.
|
|
852
|
-
// format.ThingAsset.[attribute|meta].custom (look for valueFormat where custom is meta item or attribute name)
|
|
853
|
-
// format.Duration (where Duration is the ValueDescriptor type)
|
|
854
|
-
// units.BuildingAsset.attribute.temperature
|
|
855
|
-
let name;
|
|
856
|
-
if (nameValueHolder) {
|
|
857
|
-
name = typeof nameValueHolder === "string" ? nameValueHolder : nameValueHolder.name;
|
|
858
|
-
}
|
|
859
|
-
else if (valueHolderDescriptor) {
|
|
860
|
-
name = typeof (valueHolderDescriptor) === "string" ? valueHolderDescriptor : valueHolderDescriptor.name;
|
|
861
|
-
}
|
|
862
|
-
if (!name) {
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
const lookups = [];
|
|
866
|
-
const prefix = lookup + "." + (isAttribute ? "attribute" : "meta") + ".";
|
|
867
|
-
if (assetType) {
|
|
868
|
-
lookups.push(prefix + assetType + "." + name);
|
|
869
|
-
}
|
|
870
|
-
if (valueHolderDescriptor && typeof (valueHolderDescriptor) !== "string") {
|
|
871
|
-
lookups.push(prefix + valueHolderDescriptor.type + "." + name);
|
|
872
|
-
lookups.push(prefix + valueHolderDescriptor.type);
|
|
873
|
-
}
|
|
874
|
-
lookups.push(prefix + name);
|
|
875
|
-
if (lookups.length > 0) {
|
|
876
|
-
return i18next.t(lookups, { defaultValue: fallback || "" });
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
/**
|
|
880
|
-
* Immutable update of an asset using the supplied attribute event
|
|
881
|
-
*/
|
|
882
|
-
export function updateAsset(asset, event) {
|
|
883
|
-
const attributeName = event.ref.name;
|
|
884
|
-
if (asset.attributes) {
|
|
885
|
-
if (event.deleted) {
|
|
886
|
-
delete asset.attributes[attributeName];
|
|
887
|
-
}
|
|
888
|
-
else {
|
|
889
|
-
const attribute = asset.attributes[attributeName];
|
|
890
|
-
if (attribute) {
|
|
891
|
-
attribute.value = event.value;
|
|
892
|
-
attribute.timestamp = event.timestamp;
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
return Object.assign({}, asset);
|
|
897
|
-
}
|
|
898
|
-
export function loadJs(url) {
|
|
899
|
-
return new Promise((resolve, reject) => {
|
|
900
|
-
const script = document.createElement('script');
|
|
901
|
-
script.type = 'text/javascript';
|
|
902
|
-
script.src = url;
|
|
903
|
-
script.addEventListener('load', (e) => resolve(e), false);
|
|
904
|
-
script.addEventListener('error', (e) => reject(e), false);
|
|
905
|
-
document.body.appendChild(script);
|
|
906
|
-
});
|
|
907
|
-
}
|
|
908
|
-
;
|
|
909
|
-
export function sortByNumber(valueExtractor) {
|
|
910
|
-
return (a, b) => {
|
|
911
|
-
const v1 = valueExtractor(a);
|
|
912
|
-
const v2 = valueExtractor(b);
|
|
913
|
-
if (!v1 && !v2) {
|
|
914
|
-
return 0;
|
|
915
|
-
}
|
|
916
|
-
if (v1 && !v2) {
|
|
917
|
-
return 1;
|
|
918
|
-
}
|
|
919
|
-
if (!v1 && v2) {
|
|
920
|
-
return -1;
|
|
921
|
-
}
|
|
922
|
-
return v1 - v2;
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
export function sortByString(valueExtractor) {
|
|
926
|
-
return (a, b) => {
|
|
927
|
-
const v1 = valueExtractor(a);
|
|
928
|
-
const v2 = valueExtractor(b);
|
|
929
|
-
if (!v1 && !v2) {
|
|
930
|
-
return 0;
|
|
931
|
-
}
|
|
932
|
-
if (v1 && !v2) {
|
|
933
|
-
return 1;
|
|
934
|
-
}
|
|
935
|
-
if (!v1 && v2) {
|
|
936
|
-
return -1;
|
|
937
|
-
}
|
|
938
|
-
return v1.localeCompare(v2);
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
export function dispatchCancellableEvent(target, event) {
|
|
942
|
-
const deferred = new Deferred();
|
|
943
|
-
target.dispatchEvent(event);
|
|
944
|
-
window.setTimeout(() => {
|
|
945
|
-
deferred.resolve(event.detail);
|
|
946
|
-
});
|
|
947
|
-
return deferred.promise;
|
|
948
|
-
}
|
|
949
|
-
// left: 37, up: 38, right: 39, down: 40,
|
|
950
|
-
// spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36
|
|
951
|
-
const keys = { 37: 1, 38: 1, 39: 1, 40: 1 };
|
|
952
|
-
function preventDefault(e) {
|
|
953
|
-
e.preventDefault();
|
|
954
|
-
}
|
|
955
|
-
function preventDefaultForScrollKeys(e) {
|
|
956
|
-
if (keys[e.keyCode]) {
|
|
957
|
-
preventDefault(e);
|
|
958
|
-
return false;
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
// modern Chrome requires { passive: false } when adding event
|
|
962
|
-
let supportsPassive = false;
|
|
963
|
-
try {
|
|
964
|
-
// @ts-ignore
|
|
965
|
-
window.addEventListener("test", null, Object.defineProperty({}, 'passive', {
|
|
966
|
-
get: () => { supportsPassive = true; }
|
|
967
|
-
}));
|
|
968
|
-
}
|
|
969
|
-
catch (e) { }
|
|
970
|
-
const wheelOpt = supportsPassive ? { passive: false } : false;
|
|
971
|
-
const wheelEvent = "onwheel" in document.createElement("div") ? "wheel" : "mousewheel";
|
|
972
|
-
// call this to Disable
|
|
973
|
-
export function disableScroll() {
|
|
974
|
-
window.addEventListener('DOMMouseScroll', preventDefault, false); // older FF
|
|
975
|
-
window.addEventListener(wheelEvent, preventDefault, wheelOpt); // modern desktop
|
|
976
|
-
window.addEventListener('touchmove', preventDefault, wheelOpt); // mobile
|
|
977
|
-
window.addEventListener('keydown', preventDefaultForScrollKeys, false);
|
|
978
|
-
}
|
|
979
|
-
// call this to Enable
|
|
980
|
-
export function enableScroll() {
|
|
981
|
-
window.removeEventListener('DOMMouseScroll', preventDefault, false);
|
|
982
|
-
// @ts-ignore
|
|
983
|
-
window.removeEventListener(wheelEvent, preventDefault, wheelOpt);
|
|
984
|
-
// @ts-ignore
|
|
985
|
-
window.removeEventListener('touchmove', preventDefault, wheelOpt);
|
|
986
|
-
window.removeEventListener('keydown', preventDefaultForScrollKeys, false);
|
|
987
|
-
}
|
|
988
|
-
export function blobToBase64(blob) {
|
|
989
|
-
return new Promise((resolve, reject) => {
|
|
990
|
-
const fileReader = new FileReader();
|
|
991
|
-
fileReader.readAsDataURL(blob);
|
|
992
|
-
fileReader.onload = () => {
|
|
993
|
-
resolve(fileReader.result);
|
|
994
|
-
};
|
|
995
|
-
fileReader.onerror = (error) => {
|
|
996
|
-
reject(error);
|
|
997
|
-
};
|
|
998
|
-
});
|
|
999
|
-
}
|
|
1000
|
-
//# sourceMappingURL=util.js.map
|
|
1
|
+
import e from"i18next";import t from"qs";import{AssetModelUtil as r}from"@openremote/model";import n from"moment";import{transform as o}from"lodash";export class Deferred{get resolve(){return this._resolve}get reject(){return this._reject}get promise(){return this._promise}constructor(){this._promise=new Promise((e,t)=>{this._resolve=e,this._reject=t}),Object.freeze(this)}}export function getBrowserLanguage(){return navigator.language.split("-")[0]||"en"}export function getQueryParameters(e){return t.parse(e,{ignoreQueryPrefix:!0})}export function getQueryParameter(e){let t;if(location.search&&""!==location.search&&(t=getQueryParameters(location.search)),location.hash){let e=location.hash.indexOf("?");e>-1&&(t=getQueryParameters(location.hash.substring(e+1)))}return t?t[e]:void 0}export function getGeoNotificationsFromRulesSet(e){let t=[];return e.rules.forEach(e=>{if(e.when&&e.then&&e.then.length>0){let r=new Map;for(let n of(addGeofencePredicatesFromRuleCondition(e.when,0,r),r.size>0&&e.then.forEach(e=>addPushNotificationsFromRuleAction(e,r)),r.values()))n.forEach(e=>{e.notification&&t.push(e)})}}),t}function addGeofencePredicatesFromRuleCondition(e,t,r){if(!e)return;let n=[];e.groups&&e.groups.forEach(e=>{e.items&&e.items.forEach(e=>{n.push(e)})}),e.items&&e.items.forEach(e=>{n.push(e)}),n&&n.forEach(e=>{if(e.assets&&e.assets.attributes){let n=[];if(addGeoNotificationsFromAttributePredicateCondition(e.assets.attributes,n),n.length>0){let o=e.tag||t.toString();r.set(o,n)}}})}function addGeoNotificationsFromAttributePredicateCondition(e,t){e&&(e.items.forEach(e=>{e.value&&("radial"===e.value.predicateType||"rect"===e.value.predicateType)&&t.push({predicate:e.value})}),e.groups&&e.groups.forEach(e=>addGeoNotificationsFromAttributePredicateCondition(e,t)))}function addPushNotificationsFromRuleAction(e,t){if(e&&"notification"===e.action&&e.notification&&e.notification.message&&"push"===e.notification.message.type){let r=e.target;if(r&&r.conditionAssets){let n=t.get(r.conditionAssets);n&&n.forEach(t=>{t.notification=e.notification.message})}else for(let r of t.values())r.forEach(t=>{t.notification=e.notification.message})}}let TIME_DURATION_REGEXP=/([+-])?((\d+)[Dd])?\s*((\d+)[Hh])?\s*((\d+)[Mm]$)?\s*((\d+)[Ss])?\s*((\d+)([Mm][Ss]$))?\s*((\d+)[Ww])?\s*((\d+)[Mm][Nn])?\s*((\d+)[Yy])?/;export function isTimeDuration(e){return!!e&&(e=e.trim()).length>0&&(TIME_DURATION_REGEXP.test(e)||isTimeDurationPositiveInfinity(e)||isTimeDurationNegativeInfinity(e))}export function isTimeDurationPositiveInfinity(e){return"*"===(e=null!=e?e.trim():void 0)||"+*"===e}export function isTimeDurationNegativeInfinity(e){return"-*"===(e=null!=e?e.trim():void 0)}export function isObject(e){return!!e&&"object"==typeof e}export function isFunction(e){return!!(e&&e.constructor&&e.call&&e.apply)}export function objectsEqual(e,t,r=!0){if(null==e||null==t)return e===t;if(e.constructor!==t.constructor)return!1;if(e instanceof Function||e instanceof RegExp)return e===t;if(e===t||e.valueOf()===t.valueOf())return!0;if(Array.isArray(e)&&e.length!==t.length||e instanceof Date||!(e instanceof Object)||!(t instanceof Object))return!1;if(r){let r=Object.keys(e);return Object.keys(t).every(e=>-1!==r.indexOf(e))&&r.every(r=>objectsEqual(e[r],t[r]))}return!1}export function difference(e,t){let r=(e,t)=>o(e,function(e,n,o){objectsEqual(n,null==t?void 0:t[o])||(e[o]=isObject(n)&&isObject(null==t?void 0:t[o])?r(n,null==t?void 0:t[o]):n)});return r(e,t)}export function arrayRemove(e,t){if(0===e.length)return;let r=e.indexOf(t);r>=0&&e.splice(r,1)}export function sentenceCaseToCamelCase(e){return null==e?"":e.split(" ").map((e,t)=>0===t?e[0].toLowerCase()+e.substring(1):e[0].toUpperCase()+e.substring(1)).join("")}export function camelCaseToSentenceCase(e){if(null==e)return"";let t=!1;return e.split(/([A-Z]|\d)/).map((e,r,n)=>{if(!e)return e;if(!t)return t=!0,e.charAt(0).toUpperCase()+e.slice(1);if("_"===e)return" ";if(1===e.length&&e===e.toUpperCase()){let t=!n[r-1]||"_"===n[r-1],o=r+1<n.length&&n[r+1]&&"_"!==n[r+1],a=r+3>n.length||!n[r+1]&&!n[r+3];(!t||o)&&(e=" "+e),!o&&(t||a)||(e=e.toLowerCase())}return e}).join("").trim()}export function stringMatch(e,t){if(t===e)return!0;let r=e.endsWith("*"),n=!r&&e.startsWith("*"),o=!r&&!n&&e.startsWith("^")&&e.endsWith("$");if(r&&t.startsWith(e.substr(0,e.length-1))||n&&t.endsWith(e.substr(1)))return!0;if(o)try{return new RegExp(e).test(t)}catch(e){console.error("Failed to compile needle as a RegExp: "+e)}return!1}export function capitaliseFirstLetter(e){if(e)return 1===e.length?e.toUpperCase():e.charAt(0).toUpperCase()+e.slice(1)}export function enumContains(e,t){return e&&Object.values(e).includes(t)}export function getEnumKeyAsString(e,t){return Object.keys(e).find(r=>e[r]===t)}export function getWeekNumber(e){(e=new Date(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate()))).setUTCDate(e.getUTCDate()+4-(e.getUTCDay()||7));let t=new Date(Date.UTC(e.getUTCFullYear(),0,1));return Math.ceil(((e.getTime()-t.getTime())/864e5+1)/7)}let monthNames=["JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"];export function formatCronString(e,t,r,n,o,a,i){let s="";if(a?Array.isArray(a)?s+=a.toString().replace(" ",""):s+=a.toString():s+="0",s+=" ",o?Array.isArray(o)?s+=o.toString().replace(" ",""):s+=o.toString():s+="0",s+=" ",n?Array.isArray(n)?s+=n.toString().replace(" ",""):s+=n.toString():s+="0",s+=" ",r?Array.isArray(r)?s+=r.toString().replace(" ",""):s+=r.toString():s+="*",s+=" ",t)if(Array.isArray(t))if("number"==typeof t[0]){let e=[];t.forEach(t=>{e.push(monthNames[t].toString())}),s+=e.toString().replace(" ","")}else s+=t.toString().replace(" ","");else s+=t.toString();else s+="*";return s+=" ",i?s+=i.toString():s+="?",s+=" ",e?Array.isArray(e)?s+=e.toString().replace(" ",""):s+=e:s+="*",s}export function dateToCronString(e){return formatCronString(e.getFullYear(),monthNames[e.getMonth()],[e.getDate()],[e.getHours()],[e.getMinutes()])}export function cronStringToISOString(e,t){let r=e.split(" ");if(!Number.isNaN(Number(r[0]))&&!Number.isNaN(Number(r[1]))&&!Number.isNaN(Number(r[2]))&&(!Number.isNaN(Number(r[3]))||"*"==r[3])){let e=(!Number.isNaN(Number(r[6]))?r[6]:new Date().getFullYear()).toString(),o="";o=1==(o="*"!=r[4]?monthNames.indexOf(r[4]).toString():new Date().getMonth().toString()).length?"0"+o:o;let a=1==r[3].length&&"*"!=r[3]?"0"+r[3]:r[3].replace("*","01"),i=1==r[2].length&&"*"!=r[2]?"0"+r[2]:r[2].replace("*","00"),s=1==r[1].length&&"*"!=r[1]?"0"+r[1]:r[1].replace("*","00"),u=1==r[0].length&&"*"!=r[0]?"0"+r[0]:r[0].replace("*","00");if(e.length>0&&o.length>0)if(t)return n.utc({year:Number(e),month:Number(o),date:Number(a),hour:Number(i),minute:Number(s),second:Number(u)}).toISOString();else return n({year:Number(e),month:Number(o),date:Number(a),hour:Number(i),minute:Number(s),second:Number(u)}).toISOString()}}export function getMetaValue(e,t,r){let n="string"==typeof e?e:e.name;return t&&t.meta&&t.meta.hasOwnProperty(n)?t.meta[n]:r&&r.meta?r.meta[n]:void 0}export function hasMetaItem(e,t,r){let n="string"==typeof e?e:e.name;return!!(t&&t.meta&&t.meta.hasOwnProperty(n)||r&&r.meta&&r.meta.hasOwnProperty(n))}export function getAssetTypeLabel(t){return("string"==typeof t&&(t=r.getAssetDescriptor(t)),t)?e.t("label.asset."+t.name,{defaultValue:camelCaseToSentenceCase(t.name)}):""}export function getValueDescriptorLabel(t){if(!t)return e.t("label.value.unknown",{defaultValue:"Unknown"});let r="string"==typeof t?t:t.name;return e.t("label.value."+r,{defaultValue:camelCaseToSentenceCase(r||"")})}export function getAllowedValueLabel(t,r){if(t)return e.t("label.allowedValue."+t,{defaultValue:r||camelCaseToSentenceCase(t||""),nsSeparator:!1})}export function getMetaItemNameValueHolder(e,t){let n="string"==typeof e?r.getMetaItemDescriptor(e):e;return n?{name:n.name,type:n.type,value:t}:{name:typeof e,type:r.resolveValueTypeFromValue(t),value:t}}export function getAttributeLabel(e,t,r,n,o){return getValueHolderLabel(e,t,r,n,!0,o)}export function getMetaLabel(e,t,r,n,o){return getValueHolderLabel(e||getMetaItemNameValueHolder(t,null),t,r,n,!1,o)}function getValueHolderLabel(e,t,r,n,o,a){let i=doStandardTranslationLookup("label",e,t,r,o),s="";if(i||(i=getMetaValue("label",e,t&&t.meta?t:void 0)),n&&(s=resolveUnits(getValueFormatConstraintOrUnits("units",e,t,r,o))),!i){let r=e?e.name:t?"string"==typeof t?t:t.name:void 0;i=a||(r?camelCaseToSentenceCase(r):void 0)}return i?i+(s?" ("+s+")":""):s}export function getAttributeValueAsString(e,t,r,n,o){return getValueHolderValueAsString(e,t,r,n,!0,o)}export function getMetaValueAsString(e,t,r,n,o){return getValueHolderValueAsString(e||getMetaItemNameValueHolder(t,null),t,r,n,!1,o)}function getValueHolderValueAsString(e,t,r,n,o,a){let i=getValueAsString(e?e.value:void 0,()=>getValueFormatConstraintOrUnits("format",e,t,r,o),void 0,a),s=getAttributeUnits(e,t,r);return n&&s&&s.length&&(i=resolveUnits(getValueFormatConstraintOrUnits("units",e,t,r,o),i)),i}export function getValueAsString(t,r,o,a){let i="";if(null==t)i=a||"";else if("string"==typeof t)i=t;else if("number"==typeof t||"boolean"==typeof t||t instanceof Date){let a=r&&r();if(a&&0!==Object.keys(a).length)switch("number"==typeof t?a.asBoolean?t=!!t:a.asDate&&(t=new Date(t)):"boolean"==typeof t&&a.asNumber&&(t=+!!t),typeof t){case"number":i=new Intl.NumberFormat(o||e.language,a).format(t);break;case"boolean":a.asOnOff&&(i=t?e.t("on"):e.t("off")),a.asOpenClosed&&(i=t?e.t("open"):e.t("closed")),a.asPressedReleased&&(i=t?e.t("pressed"):e.t("released"));break;case"object":if(a.momentJsFormat)i=n(t).format(a.momentJsFormat);else if(a.iso8601)i=t.toISOString();else if(a.week){let e=getWeekNumber(t);i="2-digit"===a.week?String(e).padStart(2,"0"):Number(e).toString(10)}else i=new Intl.DateTimeFormat(o||e.language,a).format(t)}else i=Object(t).toString()}return i}export function resolveUnits(t,r){if(!t)return"";r||(r="");let n=t.map((t,n)=>{if(3!==t.length||t.toUpperCase()!==t)return e.t(["units."+t,"or:units."+t]);{let o=new Intl.NumberFormat(e.language,{currency:t,style:"currency"}).formatToParts();if(0!==n||"currency"!==o[0].type)return"currency"===o[0].type?o[0].value:o[o.length-1].value;if(!r)return o[0].value;r=o[0].value+r}}).join("");return r.length>0?r+" "+n:n}export function getAttributeValueConstraints(e,t,r){return getValueFormatConstraintOrUnits("constraints",e,t,r,!0)}export function getMetaValueConstraints(e,t,r){return getValueFormatConstraintOrUnits("constraints",e||getMetaItemNameValueHolder(t,null),t,r,!1)}export function getAttributeUnits(e,t,r){return getValueFormatConstraintOrUnits("units",e,t,r,!0)}export function getMetaUnits(e,t,r){return getValueFormatConstraintOrUnits("units",e||getMetaItemNameValueHolder(t,null),t,r,!1)}export function getAttributeValueFormat(e,t,r){return getValueFormatConstraintOrUnits("format",e,t,r,!0)}export function getMetaValueFormat(e,t,r){return getValueFormatConstraintOrUnits("format",e||getMetaItemNameValueHolder(t,null),t,r,!1)}export function mergeObjects(e,t,r){if(e&&!t)return Object.assign({},e);if(t&&!e)return Object.assign({},t);let n=Object.assign({},e),o=[];return Object.entries(t).forEach(([e,t])=>{mergeObjectKey(n,o,e,t,r)}),n}function mergeObjectKey(e,t,r,n,o){let a=e;t.forEach(e=>{a.hasOwnProperty(e)||(a[e]={}),a=a[e]}),a&&(a.hasOwnProperty(r)?null==n?delete a[r]:Array.isArray(a[r])?o?a[r]=[...a[r],...n]:a[r]=[...n]:"object"==typeof n?a[r]=mergeObjects(Object.assign({},a[r]),n,o):a[r]=n:null==n?delete a[r]:Array.isArray(n)?a[r]=[...n]:"object"==typeof n?a[r]=Object.assign({},n):a[r]=n)}function getValueFormatConstraintOrUnits(e,t,n,o,a){let i,s=[],u=doStandardTranslationLookup(e,t&&"string"==typeof t?t:t?t.name:n?"string"==typeof n?n:n.name:void 0,n,o,a);if(u&&(i=JSON.parse(u)))if("format"!==e)return i;else s.push(i);if(t&&t.meta&&(i=getMetaValue(e,t,n)))if("format"!==e)return i;else s.push(i);if(n&&"string"!=typeof n&&n.hasOwnProperty(e)){if(i=n[e],"format"!==e)return i;s.push(i)}if(n&&n.type){if(i=r.getValueDescriptor(n.type)[e],"format"!==e)return i;s.push(i)}if("format"!==e||0===s.length)return i;let l={};return s.reverse().forEach(e=>{l=Object.assign(Object.assign({},l),e)}),l}function doStandardTranslationLookup(t,r,n,o,a,i){let s;if(r?s="string"==typeof r?r:r.name:n&&(s="string"==typeof n?n:n.name),!s)return;let u=[],l=t+"."+(a?"attribute":"meta")+".";if(o&&u.push(l+o+"."+s),n&&"string"!=typeof n&&(u.push(l+n.type+"."+s),u.push(l+n.type)),u.push(l+s),u.length>0)return e.t(u,{defaultValue:i||""})}export function updateAsset(e,t){let r=t.ref.name;if(e.attributes)if(t.deleted)delete e.attributes[r];else{let n=e.attributes[r];n&&(n.value=t.value,n.timestamp=t.timestamp)}return Object.assign({},e)}export function loadJs(e){return new Promise((t,r)=>{let n=document.createElement("script");n.type="text/javascript",n.src=e,n.addEventListener("load",e=>t(e),!1),n.addEventListener("error",e=>r(e),!1),document.body.appendChild(n)})}export function sortByNumber(e){return(t,r)=>{let n=e(t),o=e(r);return n||o?n&&!o?1:!n&&o?-1:n-o:0}}export function sortByString(e){return(t,r)=>{let n=e(t),o=e(r);return n||o?n&&!o?1:!n&&o?-1:n.localeCompare(o):0}}export function dispatchCancellableEvent(e,t){let r=new Deferred;return e.dispatchEvent(t),window.setTimeout(()=>{r.resolve(t.detail)}),r.promise}let keys={37:1,38:1,39:1,40:1};function preventDefault(e){e.preventDefault()}function preventDefaultForScrollKeys(e){if(keys[e.keyCode])return preventDefault(e),!1}let supportsPassive=!1;try{window.addEventListener("test",null,Object.defineProperty({},"passive",{get:()=>{supportsPassive=!0}}))}catch(e){}let wheelOpt=!!supportsPassive&&{passive:!1},wheelEvent="onwheel"in document.createElement("div")?"wheel":"mousewheel";export function disableScroll(){window.addEventListener("DOMMouseScroll",preventDefault,!1),window.addEventListener(wheelEvent,preventDefault,wheelOpt),window.addEventListener("touchmove",preventDefault,wheelOpt),window.addEventListener("keydown",preventDefaultForScrollKeys,!1)}export function enableScroll(){window.removeEventListener("DOMMouseScroll",preventDefault,!1),window.removeEventListener(wheelEvent,preventDefault,wheelOpt),window.removeEventListener("touchmove",preventDefault,wheelOpt),window.removeEventListener("keydown",preventDefaultForScrollKeys,!1)}export function blobToBase64(e){return new Promise((t,r)=>{let n=new FileReader;n.readAsDataURL(e),n.onload=()=>{t(n.result)},n.onerror=e=>{r(e)}})}
|