// ==UserScript== // @name FillText 剪贴板 // @namespace http://tampermonkey.net/ // @version 1.1 // @description 快速填写预设文本到输入框。 // @author Unitiny // @match https://*/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant unsafeWindow // @grant GM_setValue // @grant GM_getValue // @license MIT // @downloadURL none // ==/UserScript== let online = true let global = {}; const flex = { bs: "space-between", start: "flex-start", end: "flex-end", center: "center", column: "column", row: "row" }; (function () { global = getGlobal() loadResource() initStyle() setInputDom() operationBoard() saveGlobalInterval() })(); function icons () { // delete // colorize // remove } function getLink () { let link = document.createElement("link"); link.rel = "stylesheet"; link.href = "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0"; return link } function loadResource () { document.head.appendChild(getLink()); } function initStyle () { global.style.boardStyle = ` ${flexStyle({ jc: flex.bs, fd: flex.column })} position: absolute; left: 0px; top: 0px; width: 330px; height: 400px; margin: 10px; background: white; border: 5px solid ${themeColor()}; border-radius: 5px; overflow: auto; z-index:999;` global.style.hiddenBoardStyle = ` ${flexStyle({})} position: absolute; left: 0px; top: 0px; width: 40px; height: 40px; margin: 10px; border: 5px solid skyblue; border-radius: 50%; overflow: auto; color: white; background: skyblue; z-index:999; display: none;` global.style.divStyle = ` ${flexStyle({ fd: flex.column })} width: 300px; height: 400px; margin: 10px; border: 1px solid skyblue; border-radius: 5px; overflow: auto` global.style.cateSpanStyle = ` padding: 5px 12px; width: auto; height: 35px; border: 1px solid ${themeColor()}; border-radius: 5px; background: white; font-size: 16px; text-align: center; line-height: 33px; margin-right: 10px;` global.style.spanStyle = ` ${flexStyle({ jc: flex.center, ai: flex.start, fd: flex.column })} flex-grow: 0; flex-shrink: 0; min-width: 250px; max-width: 250px; min-height: 100px; max-height: 100px; margin: 10px 20px; border: 1px solid ${themeColor()}; border-radius: 7px; height: 70px; padding: 0 10px 0 10px;` global.style.pStyle = ` word-break: break-all; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;` global.style.operationStyle = ` padding: 0 12px 0 12px; width: auto; height: 35px; border-radius: 5px; background: #4bb84b; color: white; font-size: 16px; text-align: center; line-height: 33px; margin-right: 10px;` global.style.textArea = ` border: 1px solid ${themeColor()}; border-radius: 5px; flex-grow: 0; flex-shrink: 0; min-width: 250px; max-width: 250px; min-height: 100px; max-height: 100px; margin: 10px 0 10px 0;` global.style.iconStyle = ` font-family: 'Material Symbols Outlined'; font-weight: normal; font-style: normal; font-size: 24px; line-height: 1; letter-spacing: normal; text-transform: none; display: inline-block; white-space: nowrap; word-wrap: normal; direction: ltr; -webkit-font-feature-settings: 'liga'; -webkit-font-smoothing: antialiased;` global.style.spanSettingStyle = ` width: 100%; ${flexStyle({ jc: flex.end })} ` global.style.displayNone = "display: none;" global.style.displayFlex = "display: flex;" global.style.borderRed = "border: 1px solid red;" global.style.borderSkyblue = "border: 1px solid skyblue;" } function themeColor () { return global.theme ? "skyblue" : "black" } //添加前缀来防止与原页面id重复 function prefixStr (str) { return `${global.prefix}-${str}` } function isShow (show) { return show ? "" : global.style.displayNone } function showDom (dom, add = global.style.displayFlex) { dom.style.cssText = dom.style.cssText.replace(isShow(false), "") dom.style.cssText += add } function hiddenDom (dom) { dom.style.cssText += isShow(false) } function replaceStyle (dom, key, value) { let list = dom.style.cssText.split(";"); for (let i = 0; i < list.length; i++) { if (list[i].includes(key + ":")) { list[i] = `${key}:${value}` break } } dom.style.cssText = list.join(";") } function flexStyle ({ jc = flex.center, ai = flex.center, fd = flex.row }) { return `display: flex; justify-content: ${jc}; align-items: ${ai}; flex-direction: ${fd};` } function toBottom () { global.board.scrollTop = global.board.scrollHeight } function moveDom (dom) { let isDragging = false; let x, y; dom.addEventListener("mousedown", function (event) { isDragging = true; x = event.x; y = event.y; }); dom.addEventListener("mousemove", function (event) { if (isDragging) { let offsetX = event.x - x; let offsetY = event.y - y; dom.style.left = parseInt(dom.style.left) + offsetX + "px"; dom.style.top = parseInt(dom.style.top) + offsetY + "px"; x = event.x y = event.y } }); dom.addEventListener("mouseup", function () { isDragging = false; }); } function doc () { alert("快捷键建议Alt开头或纯字母数字,如:Alt+1、qq、11") } function containKeys (a, b) { const aKeys = Object.keys(a); const bKeys = Object.keys(b); return aKeys.length >= bKeys.length && bKeys.every(key => aKeys.includes(key)); } function defaultGlobal () { return { order: 0, style: {}, show: true, theme: true, curSpan: 0, curInputDom: 0, prefix: "fillText", attributeName: "data-fillText", inputDoms: [], boardChildNodes: 3, curCate: "default", category: [ { name: "default", spansText: randText(), setting: { spans: [] } }, { name: "常用", spansText: [], setting: { spans: [] } } ] } } function saveGlobalInterval () { setInterval(function () { saveGlobal() }, 1000 * 30) } function saveGlobal (g = global) { online ? GM_setValue("fillTextGlobal", g) : null; } function getGlobal () { if (!online) { return defaultGlobal(); } let data = GM_getValue("fillTextGlobal") if (!data || JSON.stringify(data) === "{}" || !containKeys(data, defaultGlobal())) { console.log(!data, JSON.stringify(data) === "{}", !containKeys(data, defaultGlobal())); saveGlobal(defaultGlobal()) return defaultGlobal() } return data } function getCurCateVal () { for (const v of global.category) { if (v.name === global.curCate) { return v } } return global.category[0] } function showCateInput () { if (global.board.childNodes.length > global.boardChildNodes + 1) { return } let el = document.createElement("input"); el.placeholder = "请输入内容,按回车添加" el.style.cssText = global.style.textArea replaceStyle(el, "border", `1px solid ${themeColor()}`) el.addEventListener("keydown", function (event) { if (event.key === "Enter") { addCategory(event.target.value) renderBoard(renderSpan()) toBottom() } }) global.board.appendChild(el) toBottom() } function addCategory (name) { if (name.length > 10) { alert("分类名过长") return } let has = false global.category.forEach((v, i) => { if (v.name === name) { alert("已存在该分类") has = true return } }) if (has) return global.category.push({ name: name, spansText: [], setting: { spans: [] } }) saveGlobal() } function delCategory (name) { let index = 0 global.category.map((v, i) => { if (v.name === name) { index = i } }) global.category.splice(index, 1) saveGlobal() } function categoryList () { let list = [] for (let i = 0; i < global.category.length; i++) { list.push(getCategorySpan(i, global.category[i])) } let div = document.createElement("div") div.setAttribute("id", prefixStr("categoryList")) div.style.cssText = `${flexStyle({ jc: flex.start })}width:80%; margin: 0 20px 10px 0px;` div.append(...list) global.board.appendChild(div) toBottom() } function getCategorySpan (i, cate) { let close = document.createElement("span") close.style = global.style.iconStyle close.style.cssText += ` position: absolute; right: -9px; top: -14px;` close.innerText = "×" close.addEventListener("click", function (event) { delCategory(cate.name) let div = document.getElementById(prefixStr("categoryList")) div.removeChild(div.childNodes[i]) event.stopImmediatePropagation() }) let span = document.createElement("span") span.innerText = cate.name span.style.cssText = global.style.cateSpanStyle span.style.cssText += `position: relative;` span.addEventListener("click", function (event) { global.curSpan = 0 global.curCate = cate.name renderBoard(renderSpan()) document.getElementById(prefixStr("curCate")).innerText = `当前分类:${global.curCate}` }) if (i !== 0) span.appendChild(close) return span } //设置input节点 function setInputDom () { let t = setInterval(() => { let downingKeys = []; let editKey = ""; let inputDoms = document.querySelectorAll('input'); inputDoms.forEach(function (dom, i) { dom.setAttribute(global.attributeName, i) dom.addEventListener("click", function (event) { let d = event.target global.curInputDom = d.getAttribute(global.attributeName) if (global.order === 1) { d.value = getCurCateVal().spansText[global.curSpan] } }) dom.addEventListener("keydown", function (event) { //快捷键模式,按下Alt开始 if (event.key === "Alt") { downingKeys = [] downingKeys.push(event.key) editKey = event.key return } if (downingKeys.length > 0) { if (downingKeys.indexOf(event.key) !== -1) return; downingKeys.push(event.key) editKey += "+" + event.key getCurCateVal().setting.spans.map(v => { if (editKey === v.key) { dom.value = getCurCateVal().spansText[v.index] || dom.value event.preventDefault() downingKeys = [] editKey = "" } }) return; } //编辑模式 let str = dom.value + event.key getCurCateVal().setting.spans.map(v => { if (str === v.key.split("+").join("")) { dom.value = getCurCateVal().spansText[v.index] || dom.value event.preventDefault() //阻止写入该字符 } }) }) dom.addEventListener("keyup", function (event) { let i = downingKeys.indexOf(event.key) i !== -1 ? downingKeys.splice(i, 1) : null if (event.key === "Alt") { downingKeys = [] editKey = "" } }) }) global.inputDoms = inputDoms if (inputDoms.length > 0) { clearInterval(t) } }, 1000) } function randText () { if (online) { return ["点击输入框,再点击该文本即可自动填写。也可设置快捷键填写。"] } let list = [] for (let i = 0; i < Math.round(Math.random() * 10 + 3); i++) { let s = "" for (let j = 0; j < Math.round(Math.random() * 50 + 10); j++) { s += Math.round(Math.random() * 10).toString() } list.push(s) } return list } //输入栏添加span function showInput () { if (global.board.childNodes.length > global.boardChildNodes + 1) { return } let el = document.createElement("input"); el.placeholder = "请输入内容,按回车添加" el.style.cssText = global.style.textArea replaceStyle(el, "border", `1px solid ${themeColor()}`) el.addEventListener("keydown", function (event) { if (event.key === "Enter") { getCurCateVal().spansText.push(event.target.value) renderBoard(renderSpan()) toBottom() saveGlobal() } }) global.board.appendChild(el) toBottom() } function getSpanText (index) { return getCurCateVal().spansText[index] } function getSpans () { let list = [] for (let i = 0; i < getCurCateVal().spansText.length; i++) { list.push(getSpan(i, getCurCateVal().spansText[i])) } return list } function getSpan (i, text) { let span = document.createElement("span") span.innerHTML = `
${text}