This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greasyfork.org/scripts/442002/1153835/coofoUtils.js
// ==UserScript==
// @name coofoUtils
// @namespace https://github.com/coofo/someScript
// @version 0.3.3
// @license MIT License
// @description 一些工具
// @author coofo
// @downloadURL https://github.com/coofo/someScript/raw/main/tampermonkey/coofoUtils.user.js
// @supportURL https://github.com/coofo/someScript/issues
// @grant GM_download
// @grant GM_xmlhttpRequest
// ==/UserScript==
(function () {
'use strict';
window.coofoUtils = {
commonUtils: {
format: {
num: {
fullNum: function (num, length) {
return (Array(length).join('0') + num).slice(-length);
},
toThousands: function (value, seperator, digitNum) {
if ((value = ((value = value + "").replace(/^\s*|\s*$|,*/g, ''))).match(/^\d*\.?\d*$/) == null)
return value;
value = digitNum >= 0 ? (Number(value).toFixed(digitNum) + "") : value;
let r = [],
tl = value.split(".")[0],
tr = value.split(".")[1];
tr = typeof tr !== "undefined" ? tr : "";
if (seperator != null && seperator !== "") {
while (tl.length >= 3) {
r.push(tl.substring(tl.length - 3));
tl = tl.substring(0, tl.length - 3);
}
if (tl.length > 0)
r.push(tl);
r.reverse();
r = r.join(seperator);
return tr === "" ? r : r + "." + tr;
}
return value;
},
percentAutoDigitNum: function (num, total, maxDigitNum) {
let standard = 100;
let digitNum = 0;
while (standard > total && maxDigitNum < digitNum) {
standard *= 10;
digitNum++;
}
return this.toThousands(num / total * 100, null, digitNum) + "%";
}
},
file: {
getSuffix: function (name) {
let index = name.lastIndexOf('.');
if (index < 0) {
return "";
} else {
return name.substring(index + 1);
}
}
},
string: {
byMap: function (str, map, preprocessing) {
let reg = new RegExp('\\${([a-z][a-zA-Z0-9_.]+)}', 'g');
return str.replace(reg, function (match, pos, originalText) {
let key = match.replace(reg, '$1');
let value = map[key];
if (value === null || value === undefined) {
value = match;
}
if (typeof preprocessing === "function") {
value = preprocessing(value, key, map);
}
return value;
});
},
filePathByMap: function (str, map) {
let preprocessing = function (value, key, map) {
let match = key.match(/^(.*)_([a-zA-Z0-9]+)$/);
let ext = null;
if (match != null) {
let rKey = match[1];
ext = match[2];
let rValue = map[rKey];
if (rValue !== null && rValue !== undefined) {
value = rValue;
} else {
value = "";
}
}
if (typeof value === "string") {
value = value.replace(/[\/:?"<>*|~]/g, function (match, pos, originalText) {
switch (match) {
case "\\":
return "\";
case "/":
return "/";
case ":":
return ":";
case "?":
return "?";
case '"':
return '"';
case '<':
return '<';
case '>':
return '>';
case '*':
return '*';
case '|':
return '|';
case '~':
return '~';
}
});
}
if (ext !== null && value !== "") {
switch (ext) {
case "empty":
break;
case "path":
value += '/';
break;
case "parenthesis":
value = "(" + value + ")";
break;
case "squareBracket":
value = "[" + value + "]";
break;
case "curlyBracket":
value = "{" + value + "}";
break;
default:
let indexMatch = ext.match(/index([0-9]+)/);
if (indexMatch !== null && (typeof value === "number" || ('' + value).match(/^\d+$/))) {
value = coofoUtils.commonUtils.format.num.fullNum(value, Number(indexMatch[1]));
}
break;
}
}
return value;
};
return coofoUtils.commonUtils.format.string.byMap(str, map, preprocessing);
}
},
url: {
fullUrl: function (url) {
if (url.match(/^[a-zA-Z0-9]+:\/\//) !== null) {
return url;
} else if (url.match(/^\/\/[a-zA-Z0-9]+/) !== null) {
return window.location.protocol + url;
} else if (url.match(/^\/[a-zA-Z0-9]+/) !== null) {
return window.location.origin + url;
} else {
return url;
}
}
}
},
assert: {
isTrue: function (value, message) {
if (true !== value) {
console.error(message);
console.error(value);
throw message;
}
},
isNull: function (value, message) {
if (value !== null) {
console.error(message);
console.error(value);
throw message;
}
},
notNull: function (value, message) {
if (value === null) {
console.error(message);
console.error(value);
throw message;
}
},
hasLength: function (value, message) {
if (!(value !== null && value.length > 0)) {
console.error(message);
console.error(value);
throw message;
}
},
},
downloadHelp: {
toBlob: {},
toUser: {
asTagA4Url: function (url, fileName) {
let aLink = document.createElement('a');
if (fileName) {
aLink.download = fileName;
} else {
aLink.download = url.substring(url.lastIndexOf('/') + 1);
}
aLink.className = 'download-temp-node';
aLink.target = "_blank";
aLink.style = "display:none;";
aLink.href = url;
document.body.appendChild(aLink);
if (document.all) {
aLink.click(); //IE
} else {
let evt = document.createEvent("MouseEvents");
evt.initEvent("click", true, true);
aLink.dispatchEvent(evt); // 其它浏览器
}
document.body.removeChild(aLink);
},
asTagA4Blob: function (content, fileName) {
if ('msSaveOrOpenBlob' in navigator) {
navigator.msSaveOrOpenBlob(content, fileName);
} else {
let aLink = document.createElement('a');
aLink.className = 'download-temp-node';
aLink.download = fileName;
aLink.style = "display:none;";
let blob = new Blob([content], {type: content.type});
aLink.href = window.URL.createObjectURL(blob);
document.body.appendChild(aLink);
if (document.all) {
aLink.click(); //IE
} else {
let evt = document.createEvent("MouseEvents");
evt.initEvent("click", true, true);
aLink.dispatchEvent(evt); // 其它浏览器
}
window.URL.revokeObjectURL(aLink.href);
document.body.removeChild(aLink);
}
},
asHref4Blob: function (content, fileName) {
let blob = new Blob([content], {type: content.type});
let file = new File([blob], fileName, {type: blob.type});
let url = window.URL.createObjectURL(file);
window.open(url, "_self")
},
asForm: function (url, method, data = null) {
//新建form表单
let form = document.createElement("form");
form.id = "eform";
form.name = "eform";
form.target = "_blank";
document.body.appendChild(form);
//添加参数
if (data != null) {
Object.keys(data).forEach(function (key) {
let sdate_input = document.createElement("input");
sdate_input.type = "text";
sdate_input.name = key;
sdate_input.value = data[key];
form.appendChild(sdate_input);
});
}
form.method = method;
form.action = url;
form.submit();
document.body.removeChild(form);
}
},
},
xss: {
htmlEscape: function (text) {
if (!text) {
return text;
}
text = text + "";
return text.replace(/[<>"&']/g, function (match, pos, originalText) {
switch (match) {
case "<":
return "<";
case ">":
return ">";
case "&":
return "&";
case "\"":
return """;
case "'":
return "'";
}
})
}
},
url: {
//获取url中的参数
getQueryVariable: function (variableKey, defaultValue = null) {
let query = window.location.search.substring(1);
let vars = query.split("&");
for (let i = 0; i < vars.length; i++) {
let pair = vars[i].split("=");
if (pair[0] === variableKey) {
return decodeURIComponent(pair[1]);
}
}
return defaultValue;
},
//在url中添加参数keyValue格式[{key: xx, value: xx}]
addVariable: function (url, keyValues) {
if (!keyValues || keyValues.length === 0) return url;
let add = (u) => {
if (u.lastIndexOf("?") !== -1) {
u += "&";
} else {
u += "?";
}
for (let i = 0; i < keyValues.length; i++) {
if (!(keyValues[i].key || keyValues[i].value)) continue;
u += keyValues[i].key + "=" + encodeURIComponent(keyValues[i].value);
if (i !== keyValues.length - 1) {
u += "&"
}
}
return u;
};
//处理有url有hash的情况
let index = url.indexOf("#");
if (index !== -1) {
let realUrl = url.substr(0, index);
let hash = url.substr(index);
url = add(realUrl) + hash;
} else {
url = add(url);
}
return url;
},
addVariableByData: function (url, data) {
let keyValues = [];
let i = 0;
Object.keys(data).forEach(function (key) {
keyValues[i] = {
key: key,
value: data[key]
};
i++;
});
return coofoUtils.commonUtils.url.addVariable(url, keyValues);
},
getBaseUrl: function () {
return window.location.protocol + '//' + window.location.host;
}
},
browser: {
type: function () {
let u = navigator.userAgent;
let app = navigator.appVersion;
let name = {};
name.isAndroid = /Android/i.test(u);
name.isiPhone = /iPhone/i.test(u);
name.isiPad = /iPad/i.test(u);
name.isWindowsPc = /Windows/i.test(u);
name.isWindowsPhone = /Windows Phone/i.test(u);
return name;
}(),
},
},
service: {
retryablePromise: {
create: function (exec, retryTimes) {
let taskInfo = {
resolve: null,
reject: null,
retryTimes: retryTimes + 1
};
let p = new Promise((res, rej) => {
taskInfo.resolve = res;
taskInfo.reject = rej;
});
let doTask = function () {
new Promise((res, rej) => {
exec(res, rej);
}).then(
r => taskInfo.resolve(r),
r => {
taskInfo.retryTimes--;
if (taskInfo.retryTimes > 0) {
doTask();
} else {
taskInfo.reject(r);
}
}
);
};
doTask();
return p;
}
},
task: {
create: function () {
let task = {
runtime: {taskList: [], executing: [], nowExec: false},
api: {
addTask: function (exec, lastRetryTimes) {
if (task.runtime.nowExec) {
return;
}
let taskItem = {
complete: false,
lastFinishTime: 0,
lastRetryTimes: lastRetryTimes + 1,
exec: exec,
success: null,
failed: null
};
task.runtime.taskList.push(taskItem);
},
exec: async function (poolLimit) {
if (task.runtime.nowExec) {
return;
}
const executing = task.runtime.executing;
for (const taskItem of task.runtime.taskList) {
let createPromise = function (taskItem) {
let p = new Promise((resolve, reject) => {
taskItem.success = resolve;
taskItem.failed = reject;
taskItem.exec(taskItem)
}).then(() => {
taskItem.complete = true;
executing.splice(executing.indexOf(p), 1)
},
() => {
taskItem.lastFinishTime = Date.now();
taskItem.lastRetryTimes--;
if (taskItem.lastRetryTimes > 0) {
executing.splice(executing.indexOf(p), 1, createPromise(taskItem));
} else {
executing.splice(executing.indexOf(p), 1)
}
}
);
return p;
};
executing.push(createPromise(taskItem));
while (executing.length >= poolLimit) {
await Promise.race(executing);
}
}
while (executing.length > 0) {
await Promise.race(executing);
}
let completeNum = 0;
let retryTimesOutNum = 0;
for (const taskItem of task.runtime.taskList) {
if (taskItem.complete) {
completeNum++;
} else {
retryTimesOutNum++;
}
}
return {completeNum: completeNum, retryTimesOutNum: retryTimesOutNum};
}
}
};
return task;
}
},
threadPoolTaskExecutor: {
create: function (size) {
let executing = [];
let pending = [];
let execOne = function () {
if (executing.length < size && pending.length > 0) {
let pendingItem = pending.shift();
let e = new Promise((r, s) => {
pendingItem.runnable(r, s);
}).then(r => {
executing.splice(executing.indexOf(e), 1);
execOne();
pendingItem.resolve(r);
}, r => {
executing.splice(executing.indexOf(e), 1);
execOne();
pendingItem.reject(r);
});
executing.push(e);
}
};
return {
execute: function (runnable) {
let thisPendingItem = {runnable: runnable};
let p = new Promise((resolve, reject) => {
thisPendingItem.resolve = resolve;
thisPendingItem.reject = reject;
});
pending.push(thisPendingItem);
execOne();
return p;
},
cancelAll: function () {
pending.splice(0);
}
};
}
}
}
};
})();