此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/478390/1271751/TetteLib.js
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
(我已经安装了用户样式管理器,让我安装!)
// ==UserScript==
// @name TetteLib
// @namespace http://tampermonkey.net/
// @version 0.4
// @description A library containing several functions I use often in my other scripts
// @author TetteDev
// @match *://*/*
// @grant none
// ==/UserScript==
function simulateNotification(title, message, type = "info", timeout = 2500) {
const toastId = "simpleToast";
var notificationContainer = document.createElement("div");
notificationContainer.id = toastId;
let existingNotification = document.getElementById(toastId);
if (existingNotification) existingNotification.remove();
notificationContainer.title = "Click to dismiss this message";
var innerContainer = document.createElement("div");
const imgSize = 54;
let imgSrc = "";
let backgroundColor = "";
let fontColor = "";
if (type.toLowerCase() === "debug") {
imgSrc = "https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678124-wrench-screwdriver-64.png";
backgroundColor = "#eac100";
fontColor = "#323232";
}
else if (type.toLowerCase() === "error") {
imgSrc = "https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678069-sign-error-64.png";
backgroundColor = "#ff0000";
fontColor = "#ffffff";
}
else {
imgSrc = "https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678110-sign-info-64.png";
backgroundColor = "#0f0f0f";
fontColor = "#ffffff";
}
notificationContainer.style.cssText
= `position: fixed;
bottom: 15px;
right: 15px;
background-color: ${backgroundColor};
color: ${fontColor};
border: 1px solid #ffffff;
max-width: 20%;
padding-left: 50px;
padding-right: 50px;
padding-top:10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
z-index: 9999;
opacity: 1;
transition: opacity 1s, border-radius 0.5s;
border-radius: 5px;
cursor: pointer;
`
innerContainer.innerHTML =
`<img src='${imgSrc}' style='width:${imgSize}px;height:${imgSize}px;padding-bottom:10px;display:block;margin:auto;'></img>
<p id='title' style='text-align:center;font-weight:bold;font-size:20px;'>${title}</p>
<p id='message' style='text-align:center;padding-bottom:15px;font-size:15px;'>${message}</p>`;
notificationContainer.appendChild(innerContainer);
notificationContainer.onclick = function() { document.body.removeChild(notificationContainer); notificationContainer = null; }
document.body.appendChild(notificationContainer);
if (type.toLowerCase() === "debug") {
console.warn(`[DEBUG] ${title}: ${message}`);
}
else if (type.toLowerCase() === "error") {
console.error(`[ERROR] ${title}: ${message}`);
}
// Set a timer to fade out the notification after 'timeout' milliseconds if (if 'timeout' is not -1 or less)
if (timeout > -1) {
setTimeout(function() {
if (notificationContainer == null) return;
notificationContainer.style.opacity = 0;
setTimeout(function() {
if (notificationContainer == null) return;
document.body.removeChild(notificationContainer);
}, 500); // Remove the notification after the fade-out animation (adjust as needed)
}, (timeout < 1 ? 2500 : timeout)); // Start the fade-out animation after 5 seconds (adjust as needed)
}
}
function waitForElement(selector) {
return new Promise((resolve, reject) => {
const el = document.querySelector(selector);
if (el) {resolve(el);}
new MutationObserver((mutationRecords, observer) => {
// Query for elements matching the specified selector
Array.from(document.querySelectorAll(selector)).forEach((element) => {
resolve(element);
//Once we have resolved we don't need the observer anymore.
observer.disconnect();
});
})
.observe(document.documentElement, {
childList: true,
subtree: true
});
});
}
function waitForElementWithTimeout(selector, mustBeVisibleToEye = false, timeout = 3000) {
return new Promise((resolve, reject) => {
if (timeout < 0) timeout = 0;
if (!selector) reject("No selector specified");
const el = document.querySelector(selector);
if (el && (mustBeVisibleToEye ? __visible(el) : true)) {
resolve(el);
}
const timeoutMessage = `Timeout: Element with selector '${selector}' not found within ${timeout} ms`;
const timer = setTimeout(() => {
observer.disconnect();
reject(new Error(timeoutMessage));
}, timeout);
const observer = new MutationObserver((mutationRecords, observer) => {
let elements = Array.from(document.querySelectorAll(selector));
if (elements.length > 0 && mustBeVisibleToEye) elements = elements.filter((el) => __visible(el));
//debugger;
if (elements.length > 0) {
clearTimeout(timer);
observer.disconnect();
resolve(elements[0]);
}
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
});
});
}
function traverseParentsUntil(startElement, predicateUntil) {
if (!startElement) return null;
if (!predicateUntil || typeof predicateUntil !== "function") return null;
if (!startElement.parentElement) return predicateUntil(startElement) ? startElement : null;
while (startElement.parentElement) {
if (predicateUntil(startElement.parentElement)) return startElement.parentElement;
else startElement = startElement.parentElement;
}
return null;
}
function traverseChildrenUntil(startElement, predicateUntil) {
if (!startElement) return null;
if (!predicateUntil || typeof predicateUntil !== "function") return null;
if (!startElement.firstChild) return predicateUntil(startElement) ? startElement : null;
while (startElement.firstChild) {
if (predicateUntil(startElement.firstChild)) return startElement.firstChild;
else startElement = startElement.firstChild;
}
return null;
}
function __visible(el) {
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
}
function removeAllEventListeners(el, preserveChildrenEvents = true) {
if (!preserveChildrenEvents) {
el.parentNode.replaceChild(el.cloneNode(true), el);
}
else {
var newEl = el.cloneNode(false);
while (el.hasChildNodes()) newEl.appendChild(el.firstChild);
el.parentNode.replaceChild(newEl, el);
}
return el;
}
// Expected object layout for options is
/*
{
timeoutMessage: null,
onElementFoundValidatorFunc: null,
returnAllMatches: false
}
*/
function waitForElementWithTimeoutExtended(selector, options = {timeoutMessage: null, onElementFoundValidatorFunc: null, returnAllMatches: false }, timeoutThresholdMs = 3000) {
return new Promise((resolve, reject) => {
if (timeoutThresholdMs < 0) timeoutThresholdMs = 0;
if (!selector) reject("No selector specified");
if (options && typeof options !== 'object') reject("Options parameter must be an object");
if (options.returnAllMatches) {
let els = Array.from(document.querySelectorAll(selector));
if (els.length > 0) {
if (options.onElementFoundValidatorFunc && typeof options.onElementFoundValidatorFunc === 'function') {
els = els.filter((e) => options.onElementFoundValidatorFunc(e));
if (els.length > 0) resolve(els);
}
else resolve(els);
}
}
else {
const el = document.querySelector(selector);
if (el && (options.onElementFoundValidatorFunc && typeof options.onElementFoundValidatorFunc === 'function' ? options.onElementFoundValidatorFunc(el) : true)) {
resolve(el);
}
}
const timeoutMessage = (options.timeoutMessage || `Timeout: Element with selector '${selector}' not found within ${timeoutThresholdMs} ms`);
const timer = setTimeout(() => {
observer.disconnect();
reject(new Error(timeoutMessage));
}, timeoutThresholdMs);
const observer = new MutationObserver((mutationRecords, observer) => {
let elements = Array.from(document.querySelectorAll(selector));
if (elements.length > 0 && (options.onElementFoundValidatorFunc && typeof options.onElementFoundValidatorFunc === 'function')) elements = elements.filter((el) => options.onElementFoundValidatorFunc(el));
if (elements.length > 0) {
clearTimeout(timer);
observer.disconnect();
if (options.returnAllMatches) resolve(elements);
else resolve(elements[0]);
}
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
});
});
}