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,124 @@
1
+ /*!
2
+ * sculp-js v0.0.1
3
+ * (c) 2023-2023 chandq
4
+ * Released under the MIT License.
5
+ */
6
+
7
+ /**
8
+ * 将字符串转换为驼峰格式
9
+ * @param {string} string
10
+ * @param {boolean} [bigger] 是否大写第一个字母
11
+ * @returns {string}
12
+ */
13
+ const stringCamelCase = (string, bigger) => {
14
+ let string2 = string;
15
+ if (bigger) {
16
+ string2 = string.replace(/^./, origin => origin.toUpperCase());
17
+ }
18
+ const HUMP_RE = /[\s_-](.)/g;
19
+ return string2.replace(HUMP_RE, (orign, char) => char.toUpperCase());
20
+ };
21
+ /**
22
+ * 将字符串转换为连字格式
23
+ * @param {string} string
24
+ * @param {string} [separator] 分隔符,默认是"-"(短横线)
25
+ * @returns {string}
26
+ */
27
+ const stringKebabCase = (string, separator = '-') => {
28
+ const string2 = string.replace(/^./, origin => origin.toLowerCase());
29
+ return string2.replace(/[A-Z]/g, origin => `${separator}${origin.toLowerCase()}`);
30
+ };
31
+ const STRING_ARABIC_NUMERALS = '0123456789';
32
+ const STRING_LOWERCASE_ALPHA = 'abcdefghijklmnopqrstuvwxyz';
33
+ const STRING_UPPERCASE_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
34
+ const placeholderRE = /%[%sdo]/g;
35
+ /**
36
+ * 字符串格式化
37
+ * @example
38
+ * ```js
39
+ * stringFormat("My name is %s.", "zhangsan")
40
+ * // => "My name is zhangsan."
41
+ * ```
42
+ * @param {string} string 字符串模板,使用 %s 表示字符串,%d 表示数值,%o 表示对象,%% 表示百分号,参考 console.log
43
+ * @param args
44
+ * @returns {string}
45
+ */
46
+ const stringFormat = (string, ...args) => {
47
+ let index = 0;
48
+ const result = string.replace(placeholderRE, (origin) => {
49
+ const arg = args[index++];
50
+ switch (origin) {
51
+ case '%%':
52
+ index--;
53
+ return '%';
54
+ default:
55
+ case '%s':
56
+ return String(arg);
57
+ case '%d':
58
+ return String(Number(arg));
59
+ case '%o':
60
+ return JSON.stringify(arg);
61
+ }
62
+ });
63
+ return [result, ...args.splice(index).map(String)].join(' ');
64
+ };
65
+ const ev = (expression, data) => {
66
+ try {
67
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval,@typescript-eslint/no-unsafe-return
68
+ return new Function('with(arguments[0]){' +
69
+ /****/ `if(arguments[0].${expression} === undefined)throw "";` +
70
+ /****/
71
+ /****/ `return String(arguments[0].${expression})` +
72
+ '}')(data);
73
+ }
74
+ catch (err) {
75
+ throw new SyntaxError(`无法执行表达式:${expression}`);
76
+ }
77
+ };
78
+ const templateRE = /\${(.*?)}/g;
79
+ /**
80
+ * 字符串赋值
81
+ * @example
82
+ * ```js
83
+ * stringAssign('My name is ${user}.', { user: 'zhangsan' });
84
+ * // => "My name is zhangsan."
85
+ * ```
86
+ * @param {string} template
87
+ * @param {AnyObject} data
88
+ * @returns {string}
89
+ */
90
+ const stringAssign = (template, data) => {
91
+ return template.replace(templateRE, (origin, expression) => ev(expression, data));
92
+ };
93
+ /**
94
+ * 字符串编码 HTML
95
+ * @example
96
+ * ```js
97
+ * stringEscapeHtml('<b>You & Me speak "xixi"</b>')
98
+ * // => "&lt;b&gt;You &amp; Me speak &quot;xixi&quot;&lt;/b&gt;"
99
+ * ```
100
+ * @param {string} html
101
+ * @returns {string}
102
+ */
103
+ const stringEscapeHtml = (html) => {
104
+ const htmlCharRE = /[&<>"]/g;
105
+ const htmlCharReplacements = {
106
+ '&': '&amp;',
107
+ '<': '&lt;',
108
+ '>': '&gt;',
109
+ '"': '&quot;'
110
+ };
111
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
112
+ // @ts-ignore
113
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
114
+ return html.replace(htmlCharRE, $0 => htmlCharReplacements[$0]);
115
+ };
116
+ /**
117
+ * 字符串填充
118
+ * @param {number} length
119
+ * @param {string} value
120
+ * @returns {string}
121
+ */
122
+ const stringFill = (length, value = ' ') => new Array(length).fill(value).join('');
123
+
124
+ export { STRING_ARABIC_NUMERALS, STRING_LOWERCASE_ALPHA, STRING_UPPERCASE_ALPHA, stringAssign, stringCamelCase, stringEscapeHtml, stringFill, stringFormat, stringKebabCase };
package/lib/es/type.js ADDED
@@ -0,0 +1,28 @@
1
+ /*!
2
+ * sculp-js v0.0.1
3
+ * (c) 2023-2023 chandq
4
+ * Released under the MIT License.
5
+ */
6
+
7
+ const typeIs = (any) => Object.prototype.toString.call(any).slice(8, -1);
8
+ // 基本数据类型判断
9
+ const isString = (any) => typeof any === 'string';
10
+ const isBoolean = (any) => typeof any === 'boolean';
11
+ const isSymbol = (any) => typeof any === 'symbol';
12
+ const isBigInt = (any) => typeof any === 'bigint';
13
+ const isNumber = (any) => typeof any === 'number' && !Number.isNaN(any);
14
+ const isUndefined = (any) => typeof any === 'undefined';
15
+ const isNull = (any) => any === null;
16
+ const isPrimitive = (any) => any === null || typeof any !== 'object';
17
+ // 复合数据类型判断
18
+ const isObject = (any) => typeIs(any) === 'Object';
19
+ const isArray = (any) => Array.isArray(any);
20
+ // eslint-disable-next-line @typescript-eslint/ban-types
21
+ const isFunction = (any) => typeof any === 'function';
22
+ // 对象类型判断
23
+ const isNaN = (any) => Number.isNaN(any);
24
+ const isDate = (any) => typeIs(any) === 'Date';
25
+ const isError = (any) => typeIs(any) === 'Error';
26
+ const isRegExp = (any) => typeIs(any) === 'RegExp';
27
+
28
+ export { typeIs as default, isArray, isBigInt, isBoolean, isDate, isError, isFunction, isNaN, isNull, isNumber, isObject, isPrimitive, isRegExp, isString, isSymbol, isUndefined };
package/lib/es/url.js ADDED
@@ -0,0 +1,79 @@
1
+ /*!
2
+ * sculp-js v0.0.1
3
+ * (c) 2023-2023 chandq
4
+ * Released under the MIT License.
5
+ */
6
+
7
+ import { pathJoin } from './path.js';
8
+ import { qsParse, qsStringify } from './qs.js';
9
+
10
+ const anchorEl = document.createElement('a');
11
+ /**
12
+ * url 解析
13
+ * @param {string} url
14
+ * @returns {Url}
15
+ */
16
+ const urlParse = (url) => {
17
+ anchorEl.href = url;
18
+ const { protocol, username, password, host, port, hostname, hash, search, pathname: _pathname } = anchorEl;
19
+ // fix: ie 浏览器下,解析出来的 pathname 是没有 / 根的
20
+ const pathname = pathJoin('/', _pathname);
21
+ const auth = username && password ? `${username}:${password}` : '';
22
+ const query = search.replace(/^\?/, '');
23
+ const searchParams = qsParse(query);
24
+ const path = `${pathname}${search}`;
25
+ return {
26
+ protocol,
27
+ auth,
28
+ username,
29
+ password,
30
+ host,
31
+ port,
32
+ hostname,
33
+ hash,
34
+ search,
35
+ searchParams,
36
+ query,
37
+ pathname,
38
+ path,
39
+ href: url
40
+ };
41
+ };
42
+ /**
43
+ * url 字符化,url 对象里的 searchParams 会覆盖 url 原有的查询参数
44
+ * @param {Url} url
45
+ * @returns {string}
46
+ */
47
+ const urlStringify = (url) => {
48
+ const { protocol, auth, host, pathname, searchParams, hash } = url;
49
+ const authorize = auth ? `${auth}@` : '';
50
+ const querystring = qsStringify(searchParams);
51
+ const search = querystring ? `?${querystring}` : '';
52
+ let hashstring = hash.replace(/^#/, '');
53
+ hashstring = hashstring ? '#' + hashstring : '';
54
+ return `${protocol}//${authorize}${host}${pathname}${search}${hashstring}`;
55
+ };
56
+ /**
57
+ * 设置 url 查询参数
58
+ * @param {string} url
59
+ * @param {AnyObject} setter
60
+ * @returns {string}
61
+ */
62
+ const urlSetParams = (url, setter) => {
63
+ const p = urlParse(url);
64
+ Object.assign(p.searchParams, setter);
65
+ return urlStringify(p);
66
+ };
67
+ /**
68
+ * 删除 url 查询参数
69
+ * @param {string} url
70
+ * @param {string[]} removeKeys
71
+ * @returns {string}
72
+ */
73
+ const urlDelParams = (url, removeKeys) => {
74
+ const p = urlParse(url);
75
+ removeKeys.forEach(key => delete p.searchParams[key]);
76
+ return urlStringify(p);
77
+ };
78
+
79
+ export { urlDelParams, urlParse, urlSetParams, urlStringify };
@@ -0,0 +1,89 @@
1
+ /*!
2
+ * sculp-js v0.0.1
3
+ * (c) 2023-2023 chandq
4
+ * Released under the MIT License.
5
+ */
6
+
7
+ /*
8
+ * @created: Saturday, 2020-04-18 14:38:23
9
+ * @author: chendq
10
+ * ---------
11
+ * @desc 网页加水印的工具类
12
+ */
13
+ /**
14
+ * canvas 实现 watermark
15
+ * @param {ICanvasWM} canvasWM
16
+ */
17
+ const genCanvasWM = (canvasWM) => {
18
+ const { container = document.body, width = '300px', height = '200px', textAlign = 'center', textBaseline = 'middle', font = '20px PingFangSC-Medium,PingFang SC',
19
+ // fontWeight = 500,
20
+ fillStyle = 'rgba(189, 177, 167, .3)', content = '请勿外传', rotate = 30, zIndex = 2147483647 } = canvasWM;
21
+ // 仅限主页面添加水印
22
+ if (!location.pathname.includes('/home')) {
23
+ return;
24
+ }
25
+ const args = canvasWM;
26
+ const canvas = document.createElement('canvas');
27
+ canvas.setAttribute('width', width);
28
+ canvas.setAttribute('height', height);
29
+ const ctx = canvas.getContext('2d');
30
+ ctx.textAlign = textAlign;
31
+ ctx.textBaseline = textBaseline;
32
+ ctx.font = font;
33
+ // ctx!.fontWeight = fontWeight;
34
+ ctx.fillStyle = fillStyle;
35
+ ctx.rotate((Math.PI / 180) * rotate);
36
+ ctx.fillText(content, parseFloat(width) / 4, parseFloat(height) / 2);
37
+ const base64Url = canvas.toDataURL();
38
+ const __wm = document.querySelector('.__wm');
39
+ const watermarkDiv = __wm || document.createElement('div');
40
+ 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}')`;
41
+ watermarkDiv.setAttribute('style', styleStr);
42
+ watermarkDiv.classList.add('__wm');
43
+ watermarkDiv.classList.add('nav-height');
44
+ if (!__wm) {
45
+ container.style.position = 'relative';
46
+ container.appendChild(watermarkDiv);
47
+ }
48
+ const getMutableStyle = (ele) => {
49
+ const computedStle = getComputedStyle(ele);
50
+ return {
51
+ opacity: computedStle.getPropertyValue('opacity'),
52
+ zIndex: computedStle.getPropertyValue('z-index'),
53
+ display: computedStle.getPropertyValue('display'),
54
+ visibility: computedStle.getPropertyValue('visibility')
55
+ };
56
+ };
57
+ //@ts-ignore
58
+ const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
59
+ if (MutationObserver) {
60
+ let mo = new MutationObserver(function () {
61
+ const __wm = document.querySelector('.__wm'); // 只在__wm元素变动才重新调用 __canvasWM
62
+ if (!__wm) {
63
+ // 避免一直触发
64
+ // console.log('regenerate watermark by delete::')
65
+ mo.disconnect();
66
+ mo = null;
67
+ genCanvasWM(JSON.parse(JSON.stringify(args)));
68
+ }
69
+ else {
70
+ const { opacity, zIndex, display, visibility } = getMutableStyle(__wm);
71
+ if ((__wm && __wm.getAttribute('style') !== styleStr) ||
72
+ !__wm ||
73
+ !(opacity === '1' && zIndex === '2147483647' && display === 'block' && visibility === 'visible')) {
74
+ // 避免一直触发
75
+ // console.log('regenerate watermark by inline style changed ::')
76
+ mo.disconnect();
77
+ mo = null;
78
+ container.removeChild(__wm);
79
+ genCanvasWM(JSON.parse(JSON.stringify(args)));
80
+ }
81
+ }
82
+ });
83
+ mo.observe(container, { attributes: true, subtree: true, childList: true });
84
+ }
85
+ };
86
+ // 调用
87
+ // __canvasWM({ content: 'QQMusicFE' })
88
+
89
+ export { genCanvasWM };