@tmagic/utils 1.7.6 → 1.7.8-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,360 @@
1
+ import { addClassName, asyncLoadCss, asyncLoadJs, calcValueByFontsize, createDiv, getDocument, getElById, getIdFromEl, injectStyle, removeClassName, removeClassNameByClassName, setDslDomRelateConfig, setIdToEl } from "./dom.js";
2
+ import { cloneDeep, set } from "lodash-es";
3
+ import { NodeType } from "@tmagic/schema";
4
+ //#region packages/utils/src/index.ts
5
+ var _globalThis;
6
+ var getGlobalThis = () => _globalThis || (_globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {});
7
+ var sleep = (ms) => new Promise((resolve) => {
8
+ const timer = setTimeout(() => {
9
+ clearTimeout(timer);
10
+ resolve();
11
+ }, ms);
12
+ });
13
+ var toLine = (name = "") => name.replace(/\B([A-Z])/g, "-$1").toLowerCase();
14
+ var toHump = (name = "") => name.replace(/-(\w)/g, (_all, letter) => letter.toUpperCase());
15
+ var emptyFn = () => void 0;
16
+ /**
17
+ * 通过id获取组件在应用的子孙路径
18
+ * @param {number | string} id 组件id
19
+ * @param {Array} data 要查找的根容器节点
20
+ * @return {Array} 组件在data中的子孙路径
21
+ */
22
+ var getNodePath = (id, data = []) => {
23
+ const path = [];
24
+ const get = function(id, data) {
25
+ if (!Array.isArray(data)) return null;
26
+ for (let i = 0, l = data.length; i < l; i++) {
27
+ const item = data[i];
28
+ path.push(item);
29
+ if (`${item.id}` === `${id}`) return item;
30
+ if (item.items) {
31
+ const node = get(id, item.items);
32
+ if (node) return node;
33
+ }
34
+ path.pop();
35
+ }
36
+ return null;
37
+ };
38
+ get(id, data);
39
+ return path;
40
+ };
41
+ var getNodeInfo = (id, root) => {
42
+ const info = {
43
+ node: null,
44
+ parent: null,
45
+ page: null
46
+ };
47
+ if (!root) return info;
48
+ if (id === root.id) {
49
+ info.node = root;
50
+ return info;
51
+ }
52
+ const path = getNodePath(id, root.items);
53
+ if (!path.length) return info;
54
+ path.unshift(root);
55
+ info.node = path[path.length - 1];
56
+ info.parent = path[path.length - 2];
57
+ path.forEach((item) => {
58
+ if (isPage(item) || isPageFragment(item)) {
59
+ info.page = item;
60
+ return;
61
+ }
62
+ });
63
+ return info;
64
+ };
65
+ var filterXSS = (str) => str.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
66
+ var getUrlParam = (param, url) => {
67
+ const u = url || location.href;
68
+ const reg = new RegExp(`[?&#]${param}=([^&#]+)`, "gi");
69
+ const matches = u.match(reg);
70
+ let strArr;
71
+ if (matches && matches.length > 0) {
72
+ strArr = matches[matches.length - 1].split("=");
73
+ if (strArr && strArr.length > 1) return filterXSS(strArr[1]);
74
+ return "";
75
+ }
76
+ return "";
77
+ };
78
+ /**
79
+ * 设置url中指定的参数
80
+ *
81
+ * @param {string}
82
+ * name [参数名]
83
+ * @param {string}
84
+ * value [参数值]
85
+ * @param {string}
86
+ * url [发生替换的url地址|默认为location.href]
87
+ * @return {string} [返回处理后的url]
88
+ */
89
+ var setUrlParam = (name, value, url = globalThis.location.href) => {
90
+ const reg = new RegExp(`[?&#]${name}=([^&#]*)`, "gi");
91
+ const matches = url.match(reg);
92
+ const key = `{key${(/* @__PURE__ */ new Date()).getTime()}}`;
93
+ let strArr;
94
+ if (matches && matches.length > 0) strArr = matches[matches.length - 1];
95
+ else strArr = "";
96
+ const extra = `${name}=${value}`;
97
+ if (strArr) {
98
+ const first = strArr.charAt(0);
99
+ url = url.replace(strArr, key);
100
+ url = url.replace(key, value ? first + extra : "");
101
+ } else if (value) if (url.indexOf("?") > -1) url += `&${extra}`;
102
+ else url += `?${extra}`;
103
+ return url;
104
+ };
105
+ var getSearchObj = (search = globalThis.location.search ? globalThis.location.search.substring(1) : "") => {
106
+ return search.split("&").reduce((obj, item) => {
107
+ const [a, b = ""] = item.split("=");
108
+ return {
109
+ ...obj,
110
+ [a]: b
111
+ };
112
+ }, {});
113
+ };
114
+ var delQueStr = (url, ref) => {
115
+ let str = "";
116
+ if (url.indexOf("?") !== -1) str = url.substring(url.indexOf("?") + 1);
117
+ else return url;
118
+ let arr = [];
119
+ let returnurl = "";
120
+ const isHit = Array.isArray(ref) ? function(v) {
121
+ return ~ref.indexOf(v);
122
+ } : function(v) {
123
+ return v === ref;
124
+ };
125
+ if (str.indexOf("&") !== -1) {
126
+ arr = str.split("&");
127
+ for (let i = 0, len = arr.length; i < len; i++) if (!isHit(arr[i].split("=")[0])) returnurl = `${returnurl + arr[i].split("=")[0]}=${arr[i].split("=")[1]}&`;
128
+ return returnurl ? `${url.substr(0, url.indexOf("?"))}?${returnurl.substr(0, returnurl.length - 1)}` : url.substr(0, url.indexOf("?"));
129
+ }
130
+ arr = str.split("=");
131
+ if (isHit(arr[0])) return url.substr(0, url.indexOf("?"));
132
+ return url;
133
+ };
134
+ var isObject = (obj) => Object.prototype.toString.call(obj) === "[object Object]";
135
+ var isPop = (node) => Boolean(node?.type?.toLowerCase().endsWith("pop"));
136
+ var isPage = (node) => {
137
+ if (!node) return false;
138
+ return Boolean(node.type?.toLowerCase() === NodeType.PAGE);
139
+ };
140
+ var isPageFragment = (node) => {
141
+ if (!node) return false;
142
+ return Boolean(node.type?.toLowerCase() === NodeType.PAGE_FRAGMENT);
143
+ };
144
+ var isNumber = (value) => typeof value === "number" && !isNaN(value) || /^(-?\d+)(\.\d+)?$/.test(`${value}`);
145
+ var getHost = (targetUrl) => targetUrl.match(/\/\/([^/]+)/)?.[1];
146
+ var isSameDomain = (targetUrl = "", source = globalThis.location.host) => {
147
+ if (!/^(http[s]?:)?\/\//.test(targetUrl)) return true;
148
+ return getHost(targetUrl) === source;
149
+ };
150
+ /**
151
+ * 生成指定位数的GUID,无【-】格式
152
+ * @param digit 位数,默认值8
153
+ * @returns
154
+ */
155
+ var guid = (digit = 8) => "x".repeat(digit).replace(/[xy]/g, (c) => {
156
+ const r = Math.random() * 16 | 0;
157
+ return (c === "x" ? r : r & 3 | 8).toString(16);
158
+ });
159
+ var getKeysArray = (keys) => `${keys}`.replace(/\[(\d+)\]/g, ".$1").split(".");
160
+ var getValueByKeyPath = (keys = "", data = {}) => {
161
+ return (Array.isArray(keys) ? keys : getKeysArray(keys)).reduce((accumulator, currentValue) => {
162
+ if (isObject(accumulator)) return accumulator[currentValue];
163
+ if (Array.isArray(accumulator) && /^\d*$/.test(`${currentValue}`)) return accumulator[currentValue];
164
+ throw new Error(`${data}中不存在${keys}`);
165
+ }, data);
166
+ };
167
+ var setValueByKeyPath = (keys, value, data = {}) => set(data, keys, value);
168
+ var getNodes = (ids, data = []) => {
169
+ const nodes = [];
170
+ const get = function(ids, data) {
171
+ if (!Array.isArray(data)) return;
172
+ for (const item of data) {
173
+ const index = ids.findIndex((id) => `${id}` === `${item.id}`);
174
+ if (index > -1) {
175
+ ids.splice(index, 1);
176
+ nodes.push(item);
177
+ }
178
+ if (item.items) get(ids, item.items);
179
+ }
180
+ };
181
+ get(ids, data);
182
+ return nodes;
183
+ };
184
+ var getDepKeys = (dataSourceDeps = {}, nodeId) => Array.from(Object.values(dataSourceDeps).reduce((prev, cur) => {
185
+ (cur[nodeId]?.keys || []).forEach((key) => prev.add(key));
186
+ return prev;
187
+ }, /* @__PURE__ */ new Set()));
188
+ var getDepNodeIds = (dataSourceDeps = {}) => Array.from(Object.values(dataSourceDeps).reduce((prev, cur) => {
189
+ Object.keys(cur).forEach((id) => {
190
+ prev.add(id);
191
+ });
192
+ return prev;
193
+ }, /* @__PURE__ */ new Set()));
194
+ /**
195
+ * 将新节点更新到data或者parentId对应的节点的子节点中
196
+ * @param newNode 新节点
197
+ * @param data 需要修改的数据
198
+ * @param parentId 父节点 id
199
+ */
200
+ var replaceChildNode = (newNode, data, parentId) => {
201
+ const path = getNodePath(newNode.id, data);
202
+ const node = path.pop();
203
+ let parent = path.pop();
204
+ if (parentId) parent = getNodePath(parentId, data).pop();
205
+ if (!node) {
206
+ console.warn(`未找到目标节点(${newNode.id})`);
207
+ return;
208
+ }
209
+ if (!parent) {
210
+ console.warn(`未找到父节点(${newNode.id})`);
211
+ return;
212
+ }
213
+ const index = parent.items?.findIndex((child) => child.id === node.id);
214
+ parent.items.splice(index, 1, newNode);
215
+ };
216
+ var DSL_NODE_KEY_COPY_PREFIX = "__tmagic__";
217
+ var IS_DSL_NODE_KEY = "__tmagic__dslNode";
218
+ var PAGE_FRAGMENT_CONTAINER_ID_KEY = "tmagic-page-fragment-container-id";
219
+ var compiledNode = (compile, node, dataSourceDeps = {}, sourceId) => {
220
+ let keys = [];
221
+ if (!sourceId) keys = getDepKeys(dataSourceDeps, node.id);
222
+ else keys = dataSourceDeps[sourceId]?.[node.id].keys || [];
223
+ keys.forEach((key) => {
224
+ const keys = getKeysArray(key);
225
+ const cacheKey = keys.map((key, index) => {
226
+ if (index < keys.length - 1) return key;
227
+ return `${DSL_NODE_KEY_COPY_PREFIX}${key}`;
228
+ });
229
+ let templateValue = getValueByKeyPath(cacheKey, node);
230
+ if (typeof templateValue === "undefined") try {
231
+ const value = getValueByKeyPath(key, node);
232
+ setValueByKeyPath(cacheKey.join("."), value, node);
233
+ templateValue = value;
234
+ } catch (e) {
235
+ console.warn(e);
236
+ return;
237
+ }
238
+ let newValue;
239
+ try {
240
+ newValue = compile(templateValue);
241
+ } catch (e) {
242
+ console.error(e);
243
+ newValue = "";
244
+ }
245
+ setValueByKeyPath(key, newValue, node);
246
+ });
247
+ return node;
248
+ };
249
+ var compiledCond = (op, fieldValue, inputValue, range = []) => {
250
+ if (typeof fieldValue === "string" && typeof inputValue === "undefined") inputValue = "";
251
+ switch (op) {
252
+ case "is": return fieldValue === inputValue;
253
+ case "not": return fieldValue !== inputValue;
254
+ case "=": return fieldValue === inputValue;
255
+ case "!=": return fieldValue !== inputValue;
256
+ case ">": return fieldValue > inputValue;
257
+ case ">=": return fieldValue >= inputValue;
258
+ case "<": return fieldValue < inputValue;
259
+ case "<=": return fieldValue <= inputValue;
260
+ case "between": return range.length > 1 && fieldValue >= range[0] && fieldValue <= range[1];
261
+ case "not_between": return range.length < 2 || fieldValue < range[0] || fieldValue > range[1];
262
+ case "include": return fieldValue?.includes?.(inputValue);
263
+ case "not_include": return typeof fieldValue === "undefined" || !fieldValue.includes?.(inputValue);
264
+ default: break;
265
+ }
266
+ return false;
267
+ };
268
+ var getDefaultValueFromFields = (fields) => {
269
+ const data = {};
270
+ const defaultValue = {
271
+ string: void 0,
272
+ object: {},
273
+ array: [],
274
+ boolean: void 0,
275
+ number: void 0,
276
+ null: null,
277
+ any: void 0
278
+ };
279
+ fields.forEach((field) => {
280
+ if (typeof field.defaultValue !== "undefined") {
281
+ if (field.type === "array" && !Array.isArray(field.defaultValue)) {
282
+ data[field.name] = defaultValue.array;
283
+ return;
284
+ }
285
+ if (field.type === "object" && !isObject(field.defaultValue)) {
286
+ if (typeof field.defaultValue === "string") {
287
+ try {
288
+ data[field.name] = JSON.parse(field.defaultValue);
289
+ } catch (e) {
290
+ data[field.name] = defaultValue.object;
291
+ console.warn("defaultValue 解析失败", field.defaultValue, e);
292
+ }
293
+ return;
294
+ }
295
+ data[field.name] = defaultValue.object;
296
+ return;
297
+ }
298
+ data[field.name] = cloneDeep(field.defaultValue);
299
+ return;
300
+ }
301
+ if (field.type === "object") {
302
+ data[field.name] = field.fields ? getDefaultValueFromFields(field.fields) : defaultValue.object;
303
+ return;
304
+ }
305
+ if (field.type) {
306
+ data[field.name] = defaultValue[field.type];
307
+ return;
308
+ }
309
+ data[field.name] = void 0;
310
+ });
311
+ return data;
312
+ };
313
+ var DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX = "ds-field::";
314
+ var DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX = "ds-field-changed";
315
+ var getKeys = Object.keys;
316
+ var calculatePercentage = (value, percentageStr) => {
317
+ return value * (globalThis.parseFloat(percentageStr) / 100);
318
+ };
319
+ var isPercentage = (value) => /^(\d+)(\.\d+)?%$/.test(`${value}`);
320
+ var convertToNumber = (value, parentValue = 0) => {
321
+ if (typeof value === "number") return value;
322
+ if (typeof value === "string" && isPercentage(value)) return calculatePercentage(parentValue, value);
323
+ return parseFloat(value);
324
+ };
325
+ /**
326
+ * 添加参数到URL
327
+ * @param obj 参数对象
328
+ * @param global window对象
329
+ * @param needReload 是否需要刷新
330
+ */
331
+ var addParamToUrl = (obj, global = globalThis, needReload = true) => {
332
+ const url = new URL(global.location.href);
333
+ const { searchParams } = url;
334
+ for (const [k, v] of Object.entries(obj)) searchParams.set(k, v);
335
+ const newUrl = url.toString();
336
+ if (needReload) global.location.href = newUrl;
337
+ else global.history.pushState({}, "", url);
338
+ };
339
+ var dataSourceTemplateRegExp = /\$\{([\s\S]+?)\}/g;
340
+ var isDslNode = (config) => typeof config["__tmagic__dslNode"] === "undefined" || config["__tmagic__dslNode"] === true;
341
+ var traverseNode = (node, cb, parents = [], evalCbAfter = false) => {
342
+ if (!evalCbAfter) cb(node, parents);
343
+ if (Array.isArray(node.items) && node.items.length) {
344
+ parents.push(node);
345
+ node.items.forEach((item) => {
346
+ traverseNode(item, cb, [...parents], evalCbAfter);
347
+ });
348
+ }
349
+ if (evalCbAfter) cb(node, parents);
350
+ };
351
+ var isValueIncludeDataSource = (value) => {
352
+ if (typeof value === "string" && /\$\{([\s\S]+?)\}/.test(value)) return true;
353
+ if (Array.isArray(value) && `${value[0]}`.startsWith("ds-field::")) return true;
354
+ if (value?.isBindDataSource && value.dataSourceId) return true;
355
+ if (value?.isBindDataSourceField && value.dataSourceId) return true;
356
+ return false;
357
+ };
358
+ var removeDataSourceFieldPrefix = (id) => id?.replace("ds-field::", "") || "";
359
+ //#endregion
360
+ export { DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX, DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, DSL_NODE_KEY_COPY_PREFIX, IS_DSL_NODE_KEY, PAGE_FRAGMENT_CONTAINER_ID_KEY, addClassName, addParamToUrl, asyncLoadCss, asyncLoadJs, calcValueByFontsize, calculatePercentage, compiledCond, compiledNode, convertToNumber, createDiv, dataSourceTemplateRegExp, delQueStr, emptyFn, filterXSS, getDefaultValueFromFields, getDepKeys, getDepNodeIds, getDocument, getElById, getGlobalThis, getHost, getIdFromEl, getKeys, getKeysArray, getNodeInfo, getNodePath, getNodes, getSearchObj, getUrlParam, getValueByKeyPath, guid, injectStyle, isDslNode, isNumber, isObject, isPage, isPageFragment, isPercentage, isPop, isSameDomain, isValueIncludeDataSource, removeClassName, removeClassNameByClassName, removeDataSourceFieldPrefix, replaceChildNode, setDslDomRelateConfig, setIdToEl, setUrlParam, setValueByKeyPath, sleep, toHump, toLine, traverseNode };