sculp-js 0.0.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,1458 @@
1
+ /*!
2
+ * sculp-js v0.0.1
3
+ * (c) 2023-2023 chandq
4
+ * Released under the MIT License.
5
+ */
6
+
7
+ (function (global, factory) {
8
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('bezier-easing')) :
9
+ typeof define === 'function' && define.amd ? define(['exports', 'bezier-easing'], factory) :
10
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.sculpJs = {}, global.bezier));
11
+ })(this, (function (exports, bezier) { 'use strict';
12
+
13
+ const typeIs = (any) => Object.prototype.toString.call(any).slice(8, -1);
14
+ // 基本数据类型判断
15
+ const isString = (any) => typeof any === 'string';
16
+ const isBoolean = (any) => typeof any === 'boolean';
17
+ const isSymbol = (any) => typeof any === 'symbol';
18
+ const isBigInt = (any) => typeof any === 'bigint';
19
+ const isNumber = (any) => typeof any === 'number' && !Number.isNaN(any);
20
+ const isUndefined = (any) => typeof any === 'undefined';
21
+ const isNull = (any) => any === null;
22
+ const isPrimitive = (any) => any === null || typeof any !== 'object';
23
+ // 复合数据类型判断
24
+ const isObject = (any) => typeIs(any) === 'Object';
25
+ const isArray = (any) => Array.isArray(any);
26
+ // eslint-disable-next-line @typescript-eslint/ban-types
27
+ const isFunction = (any) => typeof any === 'function';
28
+ // 对象类型判断
29
+ const isNaN = (any) => Number.isNaN(any);
30
+ const isDate = (any) => typeIs(any) === 'Date';
31
+ const isError = (any) => typeIs(any) === 'Error';
32
+ const isRegExp = (any) => typeIs(any) === 'RegExp';
33
+
34
+ var type = /*#__PURE__*/Object.freeze({
35
+ __proto__: null,
36
+ default: typeIs,
37
+ isArray: isArray,
38
+ isBigInt: isBigInt,
39
+ isBoolean: isBoolean,
40
+ isDate: isDate,
41
+ isError: isError,
42
+ isFunction: isFunction,
43
+ isNaN: isNaN,
44
+ isNull: isNull,
45
+ isNumber: isNumber,
46
+ isObject: isObject,
47
+ isPrimitive: isPrimitive,
48
+ isRegExp: isRegExp,
49
+ isString: isString,
50
+ isSymbol: isSymbol,
51
+ isUndefined: isUndefined
52
+ });
53
+
54
+ /**
55
+ * 判断对象是否为纯对象
56
+ * @param {object} obj
57
+ * @returns {boolean}
58
+ */
59
+ const isPlainObject = (obj) => {
60
+ if (!isObject(obj))
61
+ return false;
62
+ const proto = Object.getPrototypeOf(obj);
63
+ // 对象无原型
64
+ if (!proto)
65
+ return true;
66
+ // 是否对象直接实例
67
+ return proto === Object.prototype;
68
+ };
69
+ /**
70
+ * 判断对象内是否有该静态属性
71
+ * @param {object} obj
72
+ * @param {string} key
73
+ * @returns {boolean}
74
+ */
75
+ const objectHas = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
76
+ /**
77
+ * 遍历对象,返回 false 中断遍历
78
+ * @param {O} obj
79
+ * @param {(val: O[keyof O], key: keyof O) => (boolean | void)} iterator
80
+ */
81
+ const objectEach = (obj, iterator) => {
82
+ for (const key in obj) {
83
+ if (!objectHas(obj, key))
84
+ continue;
85
+ if (iterator(obj[key], key) === false)
86
+ break;
87
+ }
88
+ };
89
+ /**
90
+ * 异步遍历对象,返回 false 中断遍历
91
+ * @param {O} obj
92
+ * @param {(val: O[keyof O], key: keyof O) => (boolean | void)} iterator
93
+ */
94
+ async function objectEachAsync(obj, iterator) {
95
+ for (const key in obj) {
96
+ if (!objectHas(obj, key))
97
+ continue;
98
+ if ((await iterator(obj[key], key)) === false)
99
+ break;
100
+ }
101
+ }
102
+ /**
103
+ * 对象映射
104
+ * @param {O} obj
105
+ * @param {(val: O[keyof O], key: Extract<keyof O, string>) => any} iterator
106
+ * @returns {Record<Extract<keyof O, string>, T>}
107
+ */
108
+ function objectMap(obj, iterator) {
109
+ const obj2 = {};
110
+ for (const key in obj) {
111
+ if (!objectHas(obj, key))
112
+ continue;
113
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
114
+ obj2[key] = iterator(obj[key], key);
115
+ }
116
+ return obj2;
117
+ }
118
+ /**
119
+ * 对象提取
120
+ * @param {O} obj
121
+ * @param {K} keys
122
+ * @returns {Pick<O, ArrayElements<K>>}
123
+ */
124
+ function objectPick(obj, keys) {
125
+ const obj2 = {};
126
+ objectEach(obj, (v, k) => {
127
+ if (keys.includes(k)) {
128
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
129
+ // @ts-ignore
130
+ obj2[k] = v;
131
+ }
132
+ });
133
+ return obj2;
134
+ }
135
+ /**
136
+ * 对象祛除
137
+ * @param {O} obj
138
+ * @param {K} keys
139
+ * @returns {Pick<O, ArrayElements<K>>}
140
+ */
141
+ function objectOmit(obj, keys) {
142
+ const obj2 = {};
143
+ objectEach(obj, (v, k) => {
144
+ if (!keys.includes(k)) {
145
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
146
+ // @ts-ignore
147
+ obj2[k] = v;
148
+ }
149
+ });
150
+ return obj2;
151
+ }
152
+ const merge = (map, source, target) => {
153
+ if (isUndefined(target))
154
+ return source;
155
+ const sourceType = typeIs(source);
156
+ const targetType = typeIs(target);
157
+ if (sourceType !== targetType) {
158
+ if (isArray(target))
159
+ return merge(map, [], target);
160
+ if (isObject(target))
161
+ return merge(map, {}, target);
162
+ return target;
163
+ }
164
+ // 朴素对象
165
+ if (isPlainObject(target)) {
166
+ const exist = map.get(target);
167
+ if (exist)
168
+ return exist;
169
+ map.set(target, source);
170
+ objectEach(target, (val, key) => {
171
+ source[key] = merge(map, source[key], val);
172
+ });
173
+ return source;
174
+ }
175
+ // 数组
176
+ else if (isArray(target)) {
177
+ const exist = map.get(target);
178
+ if (exist)
179
+ return exist;
180
+ map.set(target, source);
181
+ target.forEach((val, index) => {
182
+ source[index] = merge(map, source[index], val);
183
+ });
184
+ return source;
185
+ }
186
+ return target;
187
+ };
188
+ /**
189
+ * 对象合并,返回原始对象
190
+ * @param {ObjectAssignItem} source
191
+ * @param {ObjectAssignItem | undefined} targets
192
+ * @returns {R}
193
+ */
194
+ const objectAssign = (source, ...targets) => {
195
+ const map = new Map();
196
+ for (let i = 0; i < targets.length; i++) {
197
+ const target = targets[i];
198
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
199
+ // @ts-ignore
200
+ source = merge(map, source, target);
201
+ }
202
+ map.clear();
203
+ return source;
204
+ };
205
+ /**
206
+ * 对象填充
207
+ * @param {Partial<R>} source
208
+ * @param {Partial<R>} target
209
+ * @param {(s: Partial<R>, t: Partial<R>, key: keyof R) => boolean} fillable
210
+ * @returns {R}
211
+ */
212
+ const objectFill = (source, target, fillable) => {
213
+ const _fillable = fillable || ((source, target, key) => source[key] === undefined);
214
+ objectEach(target, (val, key) => {
215
+ if (_fillable(source, target, key)) {
216
+ source[key] = val;
217
+ }
218
+ });
219
+ return source;
220
+ };
221
+ function objectGet(obj, path, strict = false) {
222
+ path = path.replace(/\[(\w+)\]/g, '.$1');
223
+ path = path.replace(/^\./, '');
224
+ const keyArr = path.split('.');
225
+ let tempObj = obj;
226
+ let i = 0;
227
+ for (let len = keyArr.length; i < len - 1; ++i) {
228
+ const key = keyArr[i];
229
+ if (key in tempObj) {
230
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
231
+ tempObj = tempObj[key];
232
+ }
233
+ else {
234
+ tempObj = undefined;
235
+ if (strict) {
236
+ throw new Error('[berry/js-utils/object] objectGet path 路径不正确');
237
+ }
238
+ break;
239
+ }
240
+ }
241
+ return {
242
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
243
+ p: tempObj,
244
+ k: tempObj ? keyArr[i] : undefined,
245
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
246
+ v: tempObj ? tempObj[keyArr[i]] : undefined
247
+ };
248
+ }
249
+ /**
250
+ * 深拷贝堪称完全体 即:任何类型的数据都会被深拷贝
251
+ * @param {AnyObject | AnyArray} obj
252
+ * @param {WeakMap} map
253
+ * @return {AnyObject | AnyArray}
254
+ */
255
+ function cloneDeep(obj, map = new WeakMap()) {
256
+ if (obj instanceof Date)
257
+ return new Date(obj);
258
+ if (obj instanceof RegExp)
259
+ return new RegExp(obj);
260
+ if (map.has(obj)) {
261
+ return map.get(obj);
262
+ }
263
+ const allDesc = Object.getOwnPropertyDescriptors(obj);
264
+ const cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc);
265
+ map.set(obj, cloneObj);
266
+ for (const key of Reflect.ownKeys(obj)) {
267
+ const value = obj[key];
268
+ cloneObj[key] = value instanceof Object && typeof value !== 'function' ? cloneDeep(value, map) : value;
269
+ }
270
+ return cloneObj;
271
+ }
272
+
273
+ var object = /*#__PURE__*/Object.freeze({
274
+ __proto__: null,
275
+ cloneDeep: cloneDeep,
276
+ isPlainObject: isPlainObject,
277
+ objectAssign: objectAssign,
278
+ objectEach: objectEach,
279
+ objectEachAsync: objectEachAsync,
280
+ objectFill: objectFill,
281
+ objectGet: objectGet,
282
+ objectHas: objectHas,
283
+ objectMap: objectMap,
284
+ objectMerge: objectAssign,
285
+ objectOmit: objectOmit,
286
+ objectPick: objectPick
287
+ });
288
+
289
+ /**
290
+ * 判断一个对象是否为类数组
291
+ * @param any
292
+ * @returns {boolean}
293
+ */
294
+ const arrayLike = (any) => {
295
+ if (isArray(any))
296
+ return true;
297
+ if (isString(any))
298
+ return true;
299
+ if (!isObject(any))
300
+ return false;
301
+ return objectHas(any, 'length');
302
+ };
303
+ /**
304
+ * 遍历数组,返回 false 中断遍历
305
+ * @param {ArrayLike<V>} array
306
+ * @param {(val: V, idx: number) => any} iterator
307
+ * @param reverse {boolean} 是否倒序
308
+ */
309
+ const arrayEach = (array, iterator, reverse = false) => {
310
+ if (reverse) {
311
+ for (let idx = array.length - 1; idx >= 0; idx--) {
312
+ const val = array[idx];
313
+ if (iterator(val, idx) === false)
314
+ break;
315
+ }
316
+ }
317
+ else {
318
+ for (let idx = 0; idx < array.length; idx++) {
319
+ const val = array[idx];
320
+ if (iterator(val, idx) === false)
321
+ break;
322
+ }
323
+ }
324
+ };
325
+ /**
326
+ * 异步遍历数组,返回 false 中断遍历
327
+ * @param {ArrayLike<V>} array
328
+ * @param {(val: V, idx: number) => Promise<any>} iterator
329
+ * @param {boolean} reverse
330
+ */
331
+ async function arrayEachAsync(array, iterator, reverse = false) {
332
+ if (reverse) {
333
+ for (let idx = array.length - 1; idx >= 0; idx--) {
334
+ const val = array[idx];
335
+ if ((await iterator(val, idx)) === false)
336
+ break;
337
+ }
338
+ }
339
+ else {
340
+ for (let idx = 0; idx < array.length; idx++) {
341
+ const val = array[idx];
342
+ if ((await iterator(val, idx)) === false)
343
+ break;
344
+ }
345
+ }
346
+ }
347
+ /**
348
+ * 插入到目标位置之前
349
+ * @param {AnyArray} array
350
+ * @param {number} start
351
+ * @param {number} to
352
+ */
353
+ const arrayInsertBefore = (array, start, to) => {
354
+ if (start === to || start + 1 === to)
355
+ return;
356
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
357
+ const [source] = array.splice(start, 1);
358
+ const insertIndex = to < start ? to : to - 1;
359
+ array.splice(insertIndex, 0, source);
360
+ };
361
+ /**
362
+ * 数组删除指定项目
363
+ * @param {V[]} array
364
+ * @param {(val: V, idx: number) => boolean} expect
365
+ * @returns {V[]}
366
+ */
367
+ function arrayRemove(array, expect) {
368
+ const indexes = [];
369
+ // 这里重命名一下:是为了杜绝 jest 里的 expect 与之产生检查错误
370
+ // eslint 的 jest 语法检查是遇到 expect 函数就以为是单元测试
371
+ const _expect = expect;
372
+ arrayEach(array, (val, idx) => {
373
+ if (_expect(val, idx))
374
+ indexes.push(idx);
375
+ });
376
+ indexes.forEach((val, idx) => array.splice(val - idx, 1));
377
+ return array;
378
+ }
379
+ /**
380
+ * 自定义深度优先遍历函数(支持continue和break操作)
381
+ * @param {array} deepList
382
+ * @param {function} iterator
383
+ * @param {array} children
384
+ * @param {boolean} isReverse 是否反向遍历
385
+ */
386
+ const deepTraversal = (deepList, iterator, children = 'children', isReverse = false) => {
387
+ let level = 0;
388
+ const walk = (arr, parent) => {
389
+ if (isReverse) {
390
+ for (let i = arr.length - 1; i >= 0; i--) {
391
+ const re = iterator(arr[i], i, deepList, parent, level);
392
+ if (re === 'break') {
393
+ break;
394
+ }
395
+ else if (re === 'continue') {
396
+ continue;
397
+ }
398
+ // @ts-ignore
399
+ if (Array.isArray(arr[i][children])) {
400
+ ++level;
401
+ // @ts-ignore
402
+ walk(arr[i][children], arr[i]);
403
+ }
404
+ }
405
+ }
406
+ else {
407
+ for (let i = 0; i < arr.length; i++) {
408
+ const re = iterator(arr[i], i, deepList, parent, level);
409
+ if (re === 'break') {
410
+ break;
411
+ }
412
+ else if (re === 'continue') {
413
+ continue;
414
+ }
415
+ // @ts-ignore
416
+ if (Array.isArray(arr[i][children])) {
417
+ ++level;
418
+ // @ts-ignore
419
+ walk(arr[i][children], arr[i]);
420
+ }
421
+ }
422
+ }
423
+ };
424
+ walk(deepList, null);
425
+ };
426
+ /**
427
+ * 在树中找到 id 为某个值的节点,并返回上游的所有父级节点
428
+ * @param {ArrayLike<T>} tree
429
+ * @param {IdLike} nodeId
430
+ * @param {ITreeConf} config
431
+ * @return {[IdLike[], ITreeItem<V>[]]}
432
+ */
433
+ function getTreeIds(tree, nodeId, config) {
434
+ const { children = 'children', id = 'id' } = config || {};
435
+ const toFlatArray = (tree, parentId, parent) => {
436
+ return tree.reduce((t, _) => {
437
+ const child = _[children];
438
+ return [
439
+ ...t,
440
+ parentId ? { ..._, parentId, parent } : _,
441
+ ...(child && child.length ? toFlatArray(child, _[id], _) : [])
442
+ ];
443
+ }, []);
444
+ };
445
+ const getIds = (flatArray) => {
446
+ let child = flatArray.find(_ => _[id] === nodeId);
447
+ const { parent, parentId, ...other } = child;
448
+ let ids = [nodeId], nodes = [other];
449
+ while (child && child.parentId) {
450
+ ids = [child.parentId, ...ids];
451
+ nodes = [child.parent, ...nodes];
452
+ child = flatArray.find(_ => _[id] === child.parentId);
453
+ }
454
+ return [ids, nodes];
455
+ };
456
+ return getIds(toFlatArray(tree));
457
+ }
458
+ /**
459
+ * 异步ForEach函数
460
+ * @param {array} array
461
+ * @param {asyncFuntion} callback
462
+ * // asyncForEach 使用范例如下
463
+ // const start = async () => {
464
+ // await asyncForEach(result, async (item) => {
465
+ // await request(item);
466
+ // count++;
467
+ // });
468
+
469
+ // console.log('发送次数', count);
470
+ // }
471
+
472
+ // for await...of 使用范例如下
473
+ // const loadImages = async (images) => {
474
+ // for await (const item of images) {
475
+ // await request(item);
476
+ // count++;
477
+ // }
478
+ // }
479
+ * @return {*}
480
+ */
481
+ async function asyncForEach(array, callback) {
482
+ for (let index = 0, len = array.length; index < len; index++) {
483
+ await callback(array[index], index, array);
484
+ }
485
+ }
486
+
487
+ var array = /*#__PURE__*/Object.freeze({
488
+ __proto__: null,
489
+ arrayEach: arrayEach,
490
+ arrayEachAsync: arrayEachAsync,
491
+ arrayInsertBefore: arrayInsertBefore,
492
+ arrayLike: arrayLike,
493
+ arrayRemove: arrayRemove,
494
+ asyncForEach: asyncForEach,
495
+ deepTraversal: deepTraversal,
496
+ getTreeIds: getTreeIds
497
+ });
498
+
499
+ // @ref https://cubic-bezier.com/
500
+ const easingDefines = {
501
+ linear: [0, 0, 1, 1],
502
+ ease: [0.25, 0.1, 0.25, 1],
503
+ 'ease-in': [0.42, 0, 1, 1],
504
+ 'ease-out': [0, 0, 0.58, 1],
505
+ 'ease-in-out': [0.42, 0, 0.58, 1]
506
+ };
507
+ /**
508
+ * 缓冲函数化,用于 js 计算缓冲进度
509
+ * @param {EasingNameOrDefine} [name=linear]
510
+ * @returns {EasingFunction}
511
+ */
512
+ function easingFunctional(name) {
513
+ let fn;
514
+ if (isArray(name)) {
515
+ fn = bezier(...name);
516
+ }
517
+ else {
518
+ const define = easingDefines[name];
519
+ if (!define) {
520
+ throw new Error(`${name} 缓冲函数未定义`);
521
+ }
522
+ fn = bezier(...define);
523
+ }
524
+ return (input) => fn(Math.max(0, Math.min(input, 1)));
525
+ }
526
+
527
+ /**
528
+ * 将字符串转换为驼峰格式
529
+ * @param {string} string
530
+ * @param {boolean} [bigger] 是否大写第一个字母
531
+ * @returns {string}
532
+ */
533
+ const stringCamelCase = (string, bigger) => {
534
+ let string2 = string;
535
+ if (bigger) {
536
+ string2 = string.replace(/^./, origin => origin.toUpperCase());
537
+ }
538
+ const HUMP_RE = /[\s_-](.)/g;
539
+ return string2.replace(HUMP_RE, (orign, char) => char.toUpperCase());
540
+ };
541
+ /**
542
+ * 将字符串转换为连字格式
543
+ * @param {string} string
544
+ * @param {string} [separator] 分隔符,默认是"-"(短横线)
545
+ * @returns {string}
546
+ */
547
+ const stringKebabCase = (string, separator = '-') => {
548
+ const string2 = string.replace(/^./, origin => origin.toLowerCase());
549
+ return string2.replace(/[A-Z]/g, origin => `${separator}${origin.toLowerCase()}`);
550
+ };
551
+ const STRING_ARABIC_NUMERALS = '0123456789';
552
+ const STRING_LOWERCASE_ALPHA = 'abcdefghijklmnopqrstuvwxyz';
553
+ const STRING_UPPERCASE_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
554
+ const placeholderRE = /%[%sdo]/g;
555
+ /**
556
+ * 字符串格式化
557
+ * @example
558
+ * ```js
559
+ * stringFormat("My name is %s.", "zhangsan")
560
+ * // => "My name is zhangsan."
561
+ * ```
562
+ * @param {string} string 字符串模板,使用 %s 表示字符串,%d 表示数值,%o 表示对象,%% 表示百分号,参考 console.log
563
+ * @param args
564
+ * @returns {string}
565
+ */
566
+ const stringFormat = (string, ...args) => {
567
+ let index = 0;
568
+ const result = string.replace(placeholderRE, (origin) => {
569
+ const arg = args[index++];
570
+ switch (origin) {
571
+ case '%%':
572
+ index--;
573
+ return '%';
574
+ default:
575
+ case '%s':
576
+ return String(arg);
577
+ case '%d':
578
+ return String(Number(arg));
579
+ case '%o':
580
+ return JSON.stringify(arg);
581
+ }
582
+ });
583
+ return [result, ...args.splice(index).map(String)].join(' ');
584
+ };
585
+ const ev = (expression, data) => {
586
+ try {
587
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval,@typescript-eslint/no-unsafe-return
588
+ return new Function('with(arguments[0]){' +
589
+ /****/ `if(arguments[0].${expression} === undefined)throw "";` +
590
+ /****/
591
+ /****/ `return String(arguments[0].${expression})` +
592
+ '}')(data);
593
+ }
594
+ catch (err) {
595
+ throw new SyntaxError(`无法执行表达式:${expression}`);
596
+ }
597
+ };
598
+ const templateRE = /\${(.*?)}/g;
599
+ /**
600
+ * 字符串赋值
601
+ * @example
602
+ * ```js
603
+ * stringAssign('My name is ${user}.', { user: 'zhangsan' });
604
+ * // => "My name is zhangsan."
605
+ * ```
606
+ * @param {string} template
607
+ * @param {AnyObject} data
608
+ * @returns {string}
609
+ */
610
+ const stringAssign = (template, data) => {
611
+ return template.replace(templateRE, (origin, expression) => ev(expression, data));
612
+ };
613
+ /**
614
+ * 字符串编码 HTML
615
+ * @example
616
+ * ```js
617
+ * stringEscapeHtml('<b>You & Me speak "xixi"</b>')
618
+ * // => "&lt;b&gt;You &amp; Me speak &quot;xixi&quot;&lt;/b&gt;"
619
+ * ```
620
+ * @param {string} html
621
+ * @returns {string}
622
+ */
623
+ const stringEscapeHtml = (html) => {
624
+ const htmlCharRE = /[&<>"]/g;
625
+ const htmlCharReplacements = {
626
+ '&': '&amp;',
627
+ '<': '&lt;',
628
+ '>': '&gt;',
629
+ '"': '&quot;'
630
+ };
631
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
632
+ // @ts-ignore
633
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
634
+ return html.replace(htmlCharRE, $0 => htmlCharReplacements[$0]);
635
+ };
636
+ /**
637
+ * 字符串填充
638
+ * @param {number} length
639
+ * @param {string} value
640
+ * @returns {string}
641
+ */
642
+ const stringFill = (length, value = ' ') => new Array(length).fill(value).join('');
643
+
644
+ var string = /*#__PURE__*/Object.freeze({
645
+ __proto__: null,
646
+ STRING_ARABIC_NUMERALS: STRING_ARABIC_NUMERALS,
647
+ STRING_LOWERCASE_ALPHA: STRING_LOWERCASE_ALPHA,
648
+ STRING_UPPERCASE_ALPHA: STRING_UPPERCASE_ALPHA,
649
+ stringAssign: stringAssign,
650
+ stringCamelCase: stringCamelCase,
651
+ stringEscapeHtml: stringEscapeHtml,
652
+ stringFill: stringFill,
653
+ stringFormat: stringFormat,
654
+ stringKebabCase: stringKebabCase
655
+ });
656
+
657
+ /**
658
+ * 判断元素是否包含某个样式名
659
+ * @param {HTMLElement} el
660
+ * @param {string} className
661
+ * @returns {boolean}
662
+ */
663
+ const hasClass = (el, className) => {
664
+ if (className.indexOf(' ') !== -1)
665
+ throw new Error('className should not contain space.');
666
+ return el.classList.contains(className);
667
+ };
668
+ const eachClassName = (classNames, func) => {
669
+ const classNameList = classNames.split(/\s+/g);
670
+ classNameList.forEach(func);
671
+ };
672
+ /**
673
+ * 给元素增加样式名
674
+ * @param {HTMLElement} el
675
+ * @param {string} classNames
676
+ */
677
+ const addClass = (el, classNames) => {
678
+ eachClassName(classNames, className => el.classList.add(className));
679
+ };
680
+ /**
681
+ * 给元素移除样式名
682
+ * @param {HTMLElement} el
683
+ * @param {string} classNames
684
+ */
685
+ const removeClass = (el, classNames) => {
686
+ eachClassName(classNames, className => el.classList.remove(className));
687
+ };
688
+ /**
689
+ * 设置元素样式
690
+ * @param {HTMLElement} el
691
+ * @param {string | Style} key
692
+ * @param {string} val
693
+ */
694
+ const setStyle = (el, key, val) => {
695
+ if (isObject(key)) {
696
+ objectEach(key, (val1, key1) => {
697
+ setStyle(el, key1, val1);
698
+ });
699
+ }
700
+ else {
701
+ el.style.setProperty(stringKebabCase(key), val);
702
+ }
703
+ };
704
+ /**
705
+ * 获取元素样式
706
+ * @param {HTMLElement} el
707
+ * @param {string} key
708
+ * @returns {string}
709
+ */
710
+ const getStyle = (el, key) => getComputedStyle(el).getPropertyValue(key);
711
+ async function smoothScroll(options) {
712
+ return new Promise(resolve => {
713
+ const defaults = {
714
+ el: document,
715
+ to: 0,
716
+ duration: 567,
717
+ easing: 'ease'
718
+ };
719
+ const { el, to, duration, easing } = objectAssign(defaults, options);
720
+ const htmlEl = document.documentElement;
721
+ const bodyEl = document.body;
722
+ const globalMode = el === window || el === document || el === htmlEl || el === bodyEl;
723
+ const els = globalMode ? [htmlEl, bodyEl] : [el];
724
+ const query = () => {
725
+ let value = 0;
726
+ arrayEach(els, el => {
727
+ if ('scrollTop' in el) {
728
+ value = el.scrollTop;
729
+ return false;
730
+ }
731
+ });
732
+ return value;
733
+ };
734
+ const update = (val) => {
735
+ els.forEach(el => {
736
+ if ('scrollTop' in el) {
737
+ el.scrollTop = val;
738
+ }
739
+ });
740
+ };
741
+ let startTime;
742
+ const startValue = query();
743
+ const length = to - startValue;
744
+ const easingFn = easingFunctional(easing);
745
+ const render = () => {
746
+ const now = performance.now();
747
+ const passingTime = startTime ? now - startTime : 0;
748
+ const t = passingTime / duration;
749
+ const p = easingFn(t);
750
+ if (!startTime)
751
+ startTime = now;
752
+ update(startValue + length * p);
753
+ if (t >= 1)
754
+ resolve();
755
+ else
756
+ requestAnimationFrame(render);
757
+ };
758
+ render();
759
+ });
760
+ }
761
+ const domReadyCallbacks = [];
762
+ const eventType = 'DOMContentLoaded';
763
+ const listener = () => {
764
+ domReadyCallbacks.forEach(callback => callback());
765
+ domReadyCallbacks.length = 0;
766
+ document.removeEventListener(eventType, listener);
767
+ };
768
+ document.addEventListener(eventType, listener);
769
+ let readied = false;
770
+ function isDomReady() {
771
+ if (readied)
772
+ return true;
773
+ readied = ['complete', 'loaded', 'interactive'].indexOf(document.readyState) !== -1;
774
+ return readied;
775
+ }
776
+ function onDomReady(callback) {
777
+ // document readied
778
+ if (isDomReady()) {
779
+ setTimeout(callback, 0);
780
+ }
781
+ // listen document to ready
782
+ else {
783
+ domReadyCallbacks.push(callback);
784
+ }
785
+ }
786
+
787
+ var dom = /*#__PURE__*/Object.freeze({
788
+ __proto__: null,
789
+ addClass: addClass,
790
+ getStyle: getStyle,
791
+ hasClass: hasClass,
792
+ isDomReady: isDomReady,
793
+ onDomReady: onDomReady,
794
+ removeClass: removeClass,
795
+ setStyle: setStyle,
796
+ smoothScroll: smoothScroll
797
+ });
798
+
799
+ const textEl = document.createElement('textarea');
800
+ setStyle(textEl, {
801
+ position: 'absolute',
802
+ top: '-9999px',
803
+ left: '-9999px',
804
+ opacity: 0
805
+ });
806
+ document.body.appendChild(textEl);
807
+ /**
808
+ * 复制文本
809
+ * @param {string} text
810
+ */
811
+ const copyText = (text) => {
812
+ textEl.value = text;
813
+ textEl.focus({ preventScroll: true });
814
+ textEl.select();
815
+ try {
816
+ document.execCommand('copy');
817
+ textEl.blur();
818
+ }
819
+ catch (err) {
820
+ // ignore
821
+ }
822
+ };
823
+
824
+ var clipboard = /*#__PURE__*/Object.freeze({
825
+ __proto__: null,
826
+ copyText: copyText
827
+ });
828
+
829
+ /**
830
+ * 获取cookie
831
+ * @param {string} name
832
+ * @returns {string}
833
+ */
834
+ const cookieGet = (name) => {
835
+ const { cookie } = document;
836
+ if (!cookie)
837
+ return '';
838
+ const result = cookie.split(';');
839
+ for (let i = 0; i < result.length; i++) {
840
+ const item = result[i];
841
+ const [key, val = ''] = item.split('=');
842
+ if (key === name)
843
+ return decodeURIComponent(val);
844
+ }
845
+ return '';
846
+ };
847
+ /**
848
+ * 设置 cookie
849
+ * @param {string} name
850
+ * @param {string} value
851
+ * @param {number | Date} [maxAge]
852
+ */
853
+ const cookieSet = (name, value, maxAge) => {
854
+ const metas = [];
855
+ const EXPIRES = 'expires';
856
+ metas.push([name, encodeURIComponent(value)]);
857
+ if (isNumber(maxAge)) {
858
+ const d = new Date();
859
+ d.setTime(d.getTime() + maxAge);
860
+ metas.push([EXPIRES, d.toUTCString()]);
861
+ }
862
+ else if (isDate(maxAge)) {
863
+ metas.push([EXPIRES, maxAge.toUTCString()]);
864
+ }
865
+ metas.push(['path', '/']);
866
+ document.cookie = metas
867
+ .map(item => {
868
+ const [key, val] = item;
869
+ return `${key}=${val}`;
870
+ })
871
+ .join(';');
872
+ };
873
+ /**
874
+ * 删除单个 cookie
875
+ * @param name cookie 名称
876
+ */
877
+ const cookieDel = (name) => cookieSet(name, '', -1);
878
+
879
+ var cookie = /*#__PURE__*/Object.freeze({
880
+ __proto__: null,
881
+ cookieDel: cookieDel,
882
+ cookieGet: cookieGet,
883
+ cookieSet: cookieSet
884
+ });
885
+
886
+ /**
887
+ * 格式化为日期对象(带自定义格式化模板)
888
+ * @param {DateValue} value 可以是数值、字符串或 Date 对象
889
+ * @param {string} [format] 模板,默认是 YYYY-MM-DD HH:mm:ss,模板字符:
890
+ * - YYYY:年
891
+ * - yyyy: 年
892
+ * - MM:月
893
+ * - DD:日
894
+ * - dd: 日
895
+ * - HH:时(24 小时制)
896
+ * - hh:时(12 小时制)
897
+ * - mm:分
898
+ * - ss:秒
899
+ * - SSS:毫秒
900
+ * - ww: 周
901
+ * @returns {string}
902
+ */
903
+ const formatDate = (date = new Date(), format = 'YYYY-MM-DD HH:mm:ss') => {
904
+ let fmt = format;
905
+ let ret;
906
+ const opt = {
907
+ 'Y+': `${date.getFullYear()}`,
908
+ 'y+': `${date.getFullYear()}`,
909
+ 'M+': `${date.getMonth() + 1}`,
910
+ 'D+': `${date.getDate()}`,
911
+ 'd+': `${date.getDate()}`,
912
+ 'H+': `${date.getHours()}`,
913
+ 'm+': `${date.getMinutes()}`,
914
+ 's+': `${date.getSeconds()}`,
915
+ 'S+': `${date.getMilliseconds()}`,
916
+ 'w+': ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][date.getDay()] // 周
917
+ // 有其他格式化字符需求可以继续添加,必须转化成字符串
918
+ };
919
+ for (const k in opt) {
920
+ ret = new RegExp('(' + k + ')').exec(fmt);
921
+ if (ret) {
922
+ fmt = fmt.replace(ret[1], ret[1].length === 1 ? opt[k] : opt[k].padStart(ret[1].length, '0'));
923
+ }
924
+ }
925
+ return fmt;
926
+ };
927
+ /**
928
+ * 计算向前或向后N天的具体日期
929
+ * @param {string} strDate 参考日期
930
+ * @param {number} n 正数:向后推算;负数:向前推算
931
+ * @param {string} sep 日期格式的分隔符
932
+ * @return {*} 目标日期
933
+ */
934
+ function calculateDate(strDate, n, sep = '-') {
935
+ //strDate 为字符串日期 如:'2019-01-01' n为你要传入的参数,当前为0,前一天为-1,后一天为1
936
+ let dateArr = strDate.split(sep); //这边给定一个特定时间
937
+ let newDate = new Date(+dateArr[0], +dateArr[1] - 1, +dateArr[2]);
938
+ let befminuts = newDate.getTime() + 1000 * 60 * 60 * 24 * parseInt(String(n)); //计算前几天用减,计算后几天用加,最后一个就是多少天的数量
939
+ let beforeDat = new Date();
940
+ beforeDat.setTime(befminuts);
941
+ let befMonth = beforeDat.getMonth() + 1;
942
+ let mon = befMonth >= 10 ? befMonth : '0' + befMonth;
943
+ let befDate = beforeDat.getDate();
944
+ let da = befDate >= 10 ? befDate : '0' + befDate;
945
+ let finalNewDate = beforeDat.getFullYear() + '-' + mon + '-' + da;
946
+ return finalNewDate;
947
+ }
948
+ /**
949
+ * 计算向前或向后N天的具体时间日期
950
+ * @param {number} n 正数:向后推算;负数:向前推算
951
+ * @param {string} dateSep 日期分隔符
952
+ * @param {string} timeSep 时间分隔符
953
+ * @return {*}
954
+ */
955
+ function calculateDateTime(n, dateSep = '-', timeSep = ':') {
956
+ let date = new Date();
957
+ let separator1 = '-';
958
+ let separator2 = ':';
959
+ let year = date.getFullYear();
960
+ let month = date.getMonth() + 1;
961
+ let strDate = date.getDate() + n;
962
+ if (strDate > new Date(year, month, 0).getDate()) {
963
+ month += 1;
964
+ strDate -= new Date(year, month, 0).getDate();
965
+ if (month > 12) {
966
+ year += 1;
967
+ month = 1;
968
+ }
969
+ }
970
+ if (month >= 1 && month <= 9) {
971
+ month = '0' + month;
972
+ }
973
+ if (strDate >= 0 && strDate <= 9) {
974
+ strDate = '0' + strDate;
975
+ }
976
+ return (year +
977
+ separator1 +
978
+ month +
979
+ separator1 +
980
+ strDate +
981
+ ' ' +
982
+ date.getHours() +
983
+ separator2 +
984
+ date.getMinutes() +
985
+ separator2 +
986
+ date.getSeconds());
987
+ }
988
+
989
+ var date = /*#__PURE__*/Object.freeze({
990
+ __proto__: null,
991
+ calculateDate: calculateDate,
992
+ calculateDateTime: calculateDateTime,
993
+ formatDate: formatDate
994
+ });
995
+
996
+ /**
997
+ * 标准化路径
998
+ * @param {string} path
999
+ * @returns {string}
1000
+ */
1001
+ const pathNormalize = (path) => {
1002
+ const slicees = path
1003
+ .replace(/\\/g, '/')
1004
+ .replace(/\/{2,}/g, '/')
1005
+ .replace(/\.{3,}/g, '..')
1006
+ .replace(/\/\.\//g, '/')
1007
+ .split('/')
1008
+ .map(point => point.trim());
1009
+ const isCurrentSlice = (slice) => slice === '.';
1010
+ const isParentSlice = (slice) => slice === '..';
1011
+ const points = [];
1012
+ let inPoints = false;
1013
+ const push = (point) => {
1014
+ points.push(point);
1015
+ };
1016
+ const back = () => {
1017
+ if (points.length === 0)
1018
+ return;
1019
+ const lastSlice = points[points.length - 1];
1020
+ if (isParentSlice(lastSlice)) {
1021
+ points.push('..');
1022
+ }
1023
+ else {
1024
+ points.pop();
1025
+ }
1026
+ };
1027
+ slicees.forEach(slice => {
1028
+ const isCurrent = isCurrentSlice(slice);
1029
+ const isParent = isParentSlice(slice);
1030
+ // 未进入实际路径
1031
+ if (!inPoints) {
1032
+ push(slice);
1033
+ inPoints = !isCurrent && !isParent;
1034
+ return;
1035
+ }
1036
+ if (isCurrent)
1037
+ return;
1038
+ if (isParent)
1039
+ return back();
1040
+ push(slice);
1041
+ });
1042
+ return points.join('/');
1043
+ };
1044
+ /**
1045
+ * 路径合并
1046
+ * @param {string} from
1047
+ * @param {string} to
1048
+ * @returns {string}
1049
+ */
1050
+ const pathJoin = (from, ...to) => pathNormalize([from, ...to].join('/'));
1051
+
1052
+ var path = /*#__PURE__*/Object.freeze({
1053
+ __proto__: null,
1054
+ pathJoin: pathJoin,
1055
+ pathNormalize: pathNormalize
1056
+ });
1057
+
1058
+ /**
1059
+ * 解析查询参数,内部使用的是浏览器内置的 URLSearchParams 进行处理
1060
+ * @param {string} queryString
1061
+ * @returns {Params}
1062
+ */
1063
+ const qsParse = (queryString) => {
1064
+ const params = new URLSearchParams(queryString);
1065
+ const result = {};
1066
+ for (const [key, val] of params.entries()) {
1067
+ if (isUndefined(result[key])) {
1068
+ result[key] = val;
1069
+ continue;
1070
+ }
1071
+ if (isArray(result[key])) {
1072
+ continue;
1073
+ }
1074
+ result[key] = params.getAll(key);
1075
+ }
1076
+ return result;
1077
+ };
1078
+ const defaultReplacer = (val) => {
1079
+ if (isString(val))
1080
+ return val;
1081
+ if (isNumber(val))
1082
+ return String(val);
1083
+ if (isBoolean(val))
1084
+ return val ? 'true' : 'false';
1085
+ if (isDate(val))
1086
+ return val.toISOString();
1087
+ return null;
1088
+ };
1089
+ /**
1090
+ * 字符化查询对象,内部使用的是浏览器内置的 URLSearchParams 进行处理
1091
+ * @param {LooseParams} query
1092
+ * @param {Replacer} replacer
1093
+ * @returns {string}
1094
+ */
1095
+ const qsStringify = (query, replacer = defaultReplacer) => {
1096
+ const params = new URLSearchParams();
1097
+ objectEach(query, (val, key) => {
1098
+ if (isArray(val)) {
1099
+ val.forEach(i => {
1100
+ const replaced = replacer(i);
1101
+ if (replaced === null)
1102
+ return;
1103
+ params.append(key.toString(), replaced);
1104
+ });
1105
+ }
1106
+ else {
1107
+ const replaced = replacer(val);
1108
+ if (replaced === null)
1109
+ return;
1110
+ params.set(key.toString(), replaced);
1111
+ }
1112
+ });
1113
+ return params.toString();
1114
+ };
1115
+
1116
+ var qs = /*#__PURE__*/Object.freeze({
1117
+ __proto__: null,
1118
+ qsParse: qsParse,
1119
+ qsStringify: qsStringify
1120
+ });
1121
+
1122
+ const anchorEl = document.createElement('a');
1123
+ /**
1124
+ * url 解析
1125
+ * @param {string} url
1126
+ * @returns {Url}
1127
+ */
1128
+ const urlParse = (url) => {
1129
+ anchorEl.href = url;
1130
+ const { protocol, username, password, host, port, hostname, hash, search, pathname: _pathname } = anchorEl;
1131
+ // fix: ie 浏览器下,解析出来的 pathname 是没有 / 根的
1132
+ const pathname = pathJoin('/', _pathname);
1133
+ const auth = username && password ? `${username}:${password}` : '';
1134
+ const query = search.replace(/^\?/, '');
1135
+ const searchParams = qsParse(query);
1136
+ const path = `${pathname}${search}`;
1137
+ return {
1138
+ protocol,
1139
+ auth,
1140
+ username,
1141
+ password,
1142
+ host,
1143
+ port,
1144
+ hostname,
1145
+ hash,
1146
+ search,
1147
+ searchParams,
1148
+ query,
1149
+ pathname,
1150
+ path,
1151
+ href: url
1152
+ };
1153
+ };
1154
+ /**
1155
+ * url 字符化,url 对象里的 searchParams 会覆盖 url 原有的查询参数
1156
+ * @param {Url} url
1157
+ * @returns {string}
1158
+ */
1159
+ const urlStringify = (url) => {
1160
+ const { protocol, auth, host, pathname, searchParams, hash } = url;
1161
+ const authorize = auth ? `${auth}@` : '';
1162
+ const querystring = qsStringify(searchParams);
1163
+ const search = querystring ? `?${querystring}` : '';
1164
+ let hashstring = hash.replace(/^#/, '');
1165
+ hashstring = hashstring ? '#' + hashstring : '';
1166
+ return `${protocol}//${authorize}${host}${pathname}${search}${hashstring}`;
1167
+ };
1168
+ /**
1169
+ * 设置 url 查询参数
1170
+ * @param {string} url
1171
+ * @param {AnyObject} setter
1172
+ * @returns {string}
1173
+ */
1174
+ const urlSetParams = (url, setter) => {
1175
+ const p = urlParse(url);
1176
+ Object.assign(p.searchParams, setter);
1177
+ return urlStringify(p);
1178
+ };
1179
+ /**
1180
+ * 删除 url 查询参数
1181
+ * @param {string} url
1182
+ * @param {string[]} removeKeys
1183
+ * @returns {string}
1184
+ */
1185
+ const urlDelParams = (url, removeKeys) => {
1186
+ const p = urlParse(url);
1187
+ removeKeys.forEach(key => delete p.searchParams[key]);
1188
+ return urlStringify(p);
1189
+ };
1190
+
1191
+ var url = /*#__PURE__*/Object.freeze({
1192
+ __proto__: null,
1193
+ urlDelParams: urlDelParams,
1194
+ urlParse: urlParse,
1195
+ urlSetParams: urlSetParams,
1196
+ urlStringify: urlStringify
1197
+ });
1198
+
1199
+ /**
1200
+ * 通过打开新窗口的方式下载
1201
+ * @param {string} url
1202
+ * @param {LooseParams} params
1203
+ */
1204
+ const downloadURL = (url, params) => {
1205
+ window.open(params ? urlSetParams(url, params) : url);
1206
+ };
1207
+ /**
1208
+ * 通过 A 链接的方式下载
1209
+ * @param {string} href
1210
+ * @param {string} filename
1211
+ */
1212
+ const downloadHref = (href, filename) => {
1213
+ const eleLink = document.createElement('a');
1214
+ eleLink.download = filename;
1215
+ eleLink.style.display = 'none';
1216
+ eleLink.href = href;
1217
+ document.body.appendChild(eleLink);
1218
+ eleLink.click();
1219
+ setTimeout(() => document.body.removeChild(eleLink));
1220
+ };
1221
+ /**
1222
+ * 将大文件对象通过 A 链接的方式下载
1223
+ * @param {Blob} blob
1224
+ * @param {string} filename
1225
+ */
1226
+ const downloadBlob = (blob, filename) => {
1227
+ const objURL = URL.createObjectURL(blob);
1228
+ downloadHref(objURL, filename);
1229
+ setTimeout(() => URL.revokeObjectURL(objURL));
1230
+ };
1231
+ /**
1232
+ * 将指定数据格式通过 A 链接的方式下载
1233
+ * @param {AnyObject | AnyObject[]} data
1234
+ * @param {FileType} fileType 支持 json/csv/xls/xlsx 四种格式
1235
+ * @param {string} filename
1236
+ * @param {string[]} [headers]
1237
+ */
1238
+ const downloadData = (data, fileType, filename, headers) => {
1239
+ filename = filename.replace(`.${fileType}`, '') + `.${fileType}`;
1240
+ if (fileType === 'json') {
1241
+ const blob = new Blob([JSON.stringify(data, null, 4)]);
1242
+ downloadBlob(blob, filename);
1243
+ }
1244
+ else {
1245
+ // xlsx实际生成的也为csv,仅后缀名名不同
1246
+ if (!headers || !headers.length)
1247
+ throw new Error('未传入表头数据');
1248
+ if (!Array.isArray(data))
1249
+ throw new Error('data error! expected array!');
1250
+ const headerStr = headers.join(',') + '\n';
1251
+ let bodyStr = '';
1252
+ data.forEach(row => {
1253
+ // \t防止数字被科学计数法显示
1254
+ bodyStr += Object.values(row).join(',\t') + ',\n';
1255
+ });
1256
+ const MIMETypes = {
1257
+ csv: 'text/csv',
1258
+ xls: 'application/vnd.ms-excel',
1259
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
1260
+ };
1261
+ // encodeURIComponent解决中文乱码
1262
+ const href = 'data:' + MIMETypes[fileType] + ';charset=utf-8,\ufeff' + encodeURIComponent(headerStr + bodyStr);
1263
+ downloadHref(href, filename);
1264
+ }
1265
+ };
1266
+
1267
+ var download = /*#__PURE__*/Object.freeze({
1268
+ __proto__: null,
1269
+ downloadBlob: downloadBlob,
1270
+ downloadData: downloadData,
1271
+ downloadHref: downloadHref,
1272
+ downloadURL: downloadURL
1273
+ });
1274
+
1275
+ /**
1276
+ * 等待一段时间
1277
+ * @param {number} timeout 等待时间,单位毫秒
1278
+ * @returns {Promise<void>}
1279
+ */
1280
+ async function wait(timeout = 1) {
1281
+ return new Promise(resolve => setTimeout(resolve, timeout));
1282
+ }
1283
+ /**
1284
+ * 异步遍历
1285
+ * @ref https://github.com/Kevnz/async-tools/blob/master/src/mapper.js
1286
+ * @ref https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/@@iterator
1287
+ * @param {Array<T>} list
1288
+ * @param {(val: T, idx: number, list: ArrayLike<T>) => Promise<R>} mapper
1289
+ * @param {number} concurrency 并发数量,默认无限
1290
+ * @returns {Promise<R[]>}
1291
+ */
1292
+ async function asyncMap(list, mapper, concurrency = Infinity) {
1293
+ return new Promise((resolve, reject) => {
1294
+ const iterator = list[Symbol.iterator]();
1295
+ const limit = Math.min(list.length, concurrency);
1296
+ const resolves = [];
1297
+ let resolvedLength = 0;
1298
+ let rejected;
1299
+ let index = 0;
1300
+ const next = () => {
1301
+ if (rejected)
1302
+ return reject(rejected);
1303
+ const it = iterator.next();
1304
+ if (it.done) {
1305
+ if (resolvedLength === list.length)
1306
+ resolve(resolves);
1307
+ return;
1308
+ }
1309
+ const current = index++;
1310
+ mapper(it.value, current, list)
1311
+ .then(value => {
1312
+ resolvedLength++;
1313
+ resolves[current] = value;
1314
+ next();
1315
+ })
1316
+ .catch(err => {
1317
+ rejected = err;
1318
+ next();
1319
+ });
1320
+ };
1321
+ // 开始
1322
+ for (let i = 0; i < limit; i++) {
1323
+ next();
1324
+ }
1325
+ });
1326
+ }
1327
+
1328
+ var async = /*#__PURE__*/Object.freeze({
1329
+ __proto__: null,
1330
+ asyncMap: asyncMap,
1331
+ wait: wait
1332
+ });
1333
+
1334
+ /**
1335
+ * 选择本地文件
1336
+ * @param {function} changeCb 选择文件回调
1337
+ * @return {*}
1338
+ */
1339
+ function chooseLocalFile({ accept }, changeCb) {
1340
+ const inputObj = document.createElement('input');
1341
+ inputObj.setAttribute('id', String(Date.now()));
1342
+ inputObj.setAttribute('type', 'file');
1343
+ inputObj.setAttribute('style', 'visibility:hidden');
1344
+ inputObj.setAttribute('accept', accept);
1345
+ document.body.appendChild(inputObj);
1346
+ inputObj.click();
1347
+ // @ts-ignore
1348
+ inputObj.onchange = (e) => {
1349
+ changeCb(e.target.files);
1350
+ setTimeout(() => document.body.removeChild(inputObj));
1351
+ };
1352
+ return inputObj;
1353
+ }
1354
+
1355
+ var file = /*#__PURE__*/Object.freeze({
1356
+ __proto__: null,
1357
+ chooseLocalFile: chooseLocalFile
1358
+ });
1359
+
1360
+ /*
1361
+ * @created: Saturday, 2020-04-18 14:38:23
1362
+ * @author: chendq
1363
+ * ---------
1364
+ * @desc 网页加水印的工具类
1365
+ */
1366
+ /**
1367
+ * canvas 实现 watermark
1368
+ * @param {ICanvasWM} canvasWM
1369
+ */
1370
+ const genCanvasWM = (canvasWM) => {
1371
+ const { container = document.body, width = '300px', height = '200px', textAlign = 'center', textBaseline = 'middle', font = '20px PingFangSC-Medium,PingFang SC',
1372
+ // fontWeight = 500,
1373
+ fillStyle = 'rgba(189, 177, 167, .3)', content = '请勿外传', rotate = 30, zIndex = 2147483647 } = canvasWM;
1374
+ // 仅限主页面添加水印
1375
+ if (!location.pathname.includes('/home')) {
1376
+ return;
1377
+ }
1378
+ const args = canvasWM;
1379
+ const canvas = document.createElement('canvas');
1380
+ canvas.setAttribute('width', width);
1381
+ canvas.setAttribute('height', height);
1382
+ const ctx = canvas.getContext('2d');
1383
+ ctx.textAlign = textAlign;
1384
+ ctx.textBaseline = textBaseline;
1385
+ ctx.font = font;
1386
+ // ctx!.fontWeight = fontWeight;
1387
+ ctx.fillStyle = fillStyle;
1388
+ ctx.rotate((Math.PI / 180) * rotate);
1389
+ ctx.fillText(content, parseFloat(width) / 4, parseFloat(height) / 2);
1390
+ const base64Url = canvas.toDataURL();
1391
+ const __wm = document.querySelector('.__wm');
1392
+ const watermarkDiv = __wm || document.createElement('div');
1393
+ const styleStr = `opacity: 1 !important; display: block !important; visibility: visible !important; position:absolute; left:0; top:0; width:100%; height:100%; z-index:${zIndex}; pointer-events:none; background-repeat:repeat; background-image:url('${base64Url}')`;
1394
+ watermarkDiv.setAttribute('style', styleStr);
1395
+ watermarkDiv.classList.add('__wm');
1396
+ watermarkDiv.classList.add('nav-height');
1397
+ if (!__wm) {
1398
+ container.style.position = 'relative';
1399
+ container.appendChild(watermarkDiv);
1400
+ }
1401
+ const getMutableStyle = (ele) => {
1402
+ const computedStle = getComputedStyle(ele);
1403
+ return {
1404
+ opacity: computedStle.getPropertyValue('opacity'),
1405
+ zIndex: computedStle.getPropertyValue('z-index'),
1406
+ display: computedStle.getPropertyValue('display'),
1407
+ visibility: computedStle.getPropertyValue('visibility')
1408
+ };
1409
+ };
1410
+ //@ts-ignore
1411
+ const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
1412
+ if (MutationObserver) {
1413
+ let mo = new MutationObserver(function () {
1414
+ const __wm = document.querySelector('.__wm'); // 只在__wm元素变动才重新调用 __canvasWM
1415
+ if (!__wm) {
1416
+ // 避免一直触发
1417
+ // console.log('regenerate watermark by delete::')
1418
+ mo.disconnect();
1419
+ mo = null;
1420
+ genCanvasWM(JSON.parse(JSON.stringify(args)));
1421
+ }
1422
+ else {
1423
+ const { opacity, zIndex, display, visibility } = getMutableStyle(__wm);
1424
+ if ((__wm && __wm.getAttribute('style') !== styleStr) ||
1425
+ !__wm ||
1426
+ !(opacity === '1' && zIndex === '2147483647' && display === 'block' && visibility === 'visible')) {
1427
+ // 避免一直触发
1428
+ // console.log('regenerate watermark by inline style changed ::')
1429
+ mo.disconnect();
1430
+ mo = null;
1431
+ container.removeChild(__wm);
1432
+ genCanvasWM(JSON.parse(JSON.stringify(args)));
1433
+ }
1434
+ }
1435
+ });
1436
+ mo.observe(container, { attributes: true, subtree: true, childList: true });
1437
+ }
1438
+ };
1439
+ // 调用
1440
+ // __canvasWM({ content: 'QQMusicFE' })
1441
+
1442
+ exports.array = array;
1443
+ exports.async = async;
1444
+ exports.clipboard = clipboard;
1445
+ exports.cookie = cookie;
1446
+ exports.date = date;
1447
+ exports.dom = dom;
1448
+ exports.download = download;
1449
+ exports.file = file;
1450
+ exports.genCanvasWM = genCanvasWM;
1451
+ exports.object = object;
1452
+ exports.path = path;
1453
+ exports.qs = qs;
1454
+ exports.string = string;
1455
+ exports.type = type;
1456
+ exports.url = url;
1457
+
1458
+ }));