// ==UserScript==
// @name 剪贴板 FillText
// @namespace http://tampermonkey.net/
// @version 1.13
// @description 快速填写预设文本到输入框,适用于所有https网站。
// @author Unitiny
// @match https://*/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant unsafeWindow
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addValueChangeListener
// @license MIT
// ==/UserScript==
let Global = {};
let GlobalDoms = {};
const GlobalKey = "fillTextGlobal";
const CSS = {
flex: {
bs: "space-between", start: "flex-start", end: "flex-end", center: "center", column: "column", row: "row"
},
};
(function () {
Global = getGlobal()
Global.renderStatus = 1
loadResource()
initStyle()
setInputDom()
operationBoard()
Global.renderStatus = 0
getGlobalHook()
})();
/**
* 初始化
*/
//设置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 = getSpanText(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().spans.map(v => {
if (editKey === v.key) {
dom.value = getSpanText(v.index) || dom.value
event.preventDefault()
downingKeys = []
editKey = ""
}
})
return;
}
//编辑模式
let str = dom.value + event.key
getCurCateVal().spans.map(v => {
if (str === v.key.split("+").join("")) {
dom.value = getSpanText(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 = ""
}
})
})
GlobalDoms.inputDoms = inputDoms
//有拿到inputDoms
if (inputDoms.length > 0) {
clearInterval(t)
}
}, 1000)
}
/**
* 工具函数
*/
function isOnline() {
return !window.location.host.includes("localhost") && !window.location.host.includes("127.0.0.1")
}
//添加前缀来防止与原页面id重复
function prefixStr(str) {
return `${Global.prefix}-${str}`
}
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 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 domCtl(showDoms, hiddenDoms) {
showDoms?.forEach(v => {
showDom(v)
})
hiddenDoms?.forEach(v => {
hiddenDom(v)
})
}
function emptyFunc() {
}
function getCloseSpan() {
let close = document.createElement("span")
close.style = CSS.iconStyle
close.style.cssText += `
position: absolute;
right: -9px;
top: -14px;`
close.innerText = "×"
return close
}
/**
* 样式区
*/
function initStyle() {
CSS.parentBoardStyle = `
${flexStyle({jc: CSS.flex.start})}
position: absolute;
left: 0px;
top: 0px;
width: auto;
overflow: auto;
z-index:999;`
CSS.boardStyle = `
${flexStyle({jc: CSS.flex.bs, fd: CSS.flex.column})}
position: relative;
left: 0px;
top: 0px;
width: 330px;
height: 400px;
margin: 10px;
background: white;
border: 5px solid ${themeColor()};
border-radius: 5px;
overflow: auto;
z-index:999;`
CSS.rightBoardStyle = `
${flexStyle({jc: CSS.flex.end, fd: CSS.flex.column})}
position: relative;
left: 0px;
top: 0px;
width: 330px;
height: 400px;
margin: 10px;
background: white;
border: 5px solid ${themeColor()};
border-radius: 5px;
overflow: auto;
z-index:999;`
CSS.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;`
CSS.divStyle = `
${flexStyle({fd: CSS.flex.column})}
width: 300px;
height: 400px;
margin: 10px;
border: 1px solid skyblue;
border-radius: 5px;
overflow: auto`
CSS.cateSpanStyle = `
margin: 3px;
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;`
CSS.spanStyle = `
${flexStyle({jc: CSS.flex.center, ai: CSS.flex.start, fd: CSS.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;`
CSS.pStyle = `
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;`
CSS.operationStyle = `
padding: 0 12px 0 12px;
margin: 5px;
width: auto;
height: 35px;
border-radius: 5px;
background: #4bb84b;
color: white;
font-size: 16px;
text-align: center;
line-height: 33px;
margin-right: 10px;`
CSS.textArea = `
border: 1px solid ${themeColor()};
border-radius: 5px;
flex-grow: 0;
flex-shrink: 0;
min-width: 90%;
max-width: 90%;
min-height: 100px;
max-height: 100px;
margin: 10px 5px 10px 5px;`
CSS.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;`
CSS.spanSettingStyle = `
width: 100%;
${flexStyle({jc: CSS.flex.end})}
`
CSS.displayNone = "display: none;"
CSS.displayFlex = "display: flex;"
CSS.borderRed = "border: 1px solid red;"
CSS.borderSkyblue = "border: 1px solid skyblue;"
}
function themeColor() {
return Global.theme ? "skyblue" : "black"
}
function isShow(show) {
return show ? "" : CSS.displayNone
}
function showDom(dom, add = CSS.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 = CSS.flex.center, ai = CSS.flex.center, fd = CSS.flex.row}) {
return `display: flex;
justify-content: ${jc};
align-items: ${ai};
flex-direction: ${fd};`
}
/**
* Global
*/
function defaultGlobal() {
return {
id: 0,
version: Date.now(),
renderStatus: 0, //1渲染中
order: 0,
style: {},
parentShow: 0,
show: 0,
theme: true,
curSpan: 0,
curInputDom: 0,
prefix: "fillText",
attributeName: "data-fillText",
hiddenKey: "Alt+q",
inputDoms: [],
boardChildNodes: 3,
curCate: "default",
category: [
{
name: "default",
setting: {},
spans: randSpans()
},
{
name: "常用",
setting: {},
spans: []
}
]
}
}
function checkGlobal(data) {
return data && JSON.stringify(data) !== "{}" && containKeys(data, defaultGlobal())
}
function saveGlobalInterval() {
setInterval(function () {
saveGlobal()
}, 1000 * 30)
}
function getGlobalHook() {
if (!isOnline()) {
return
}
GM_addValueChangeListener(GlobalKey, function(name, old_value, new_value, remote) {
console.log(name, old_value, new_value, remote)
if(remote) {
Global = getGlobal()
Global.renderStatus = 1
//重新渲染
document.body.removeChild(GlobalDoms.parentBoard)
document.body.removeChild(GlobalDoms.hiddenBoard)
loadResource()
initStyle()
setInputDom()
operationBoard()
Global.renderStatus = 0
}
})
}
function saveGlobal(g = Global) {
if (!isOnline() || Global.renderStatus === 1) {
return false
}
console.log("saveGlobal", g)
let lastG = GM_getValue(GlobalKey)
if (!checkGlobal(lastG)) {
g.version = Date.now()
GM_setValue(GlobalKey, g)
return true
}
if (checkGlobal(g)) {
g.version = Date.now()
GM_setValue(GlobalKey, g)
return true
}
return false
}
function getGlobal() {
if (!isOnline()) {
return defaultGlobal();
}
let data = GM_getValue(GlobalKey)
if (!checkGlobal(data)) {
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() {
let divDom = GlobalDoms.categoryAreaDom.getElementsByTagName("div")[0];
if (divDom.getElementsByClassName("cateInput").length > 0) {
return
}
let el = document.createElement("input");
el.className = "cateInput"
el.placeholder = "请输入内容,按回车添加"
el.style.cssText = CSS.textArea
replaceStyle(el, "border", `1px solid ${themeColor()}`)
el.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
if (addCategory(event.target.value)) {
renderCateSpan()
renderBoard(renderSpan())
// alert("添加分类成功!")
event.stopImmediatePropagation()
}
}
})
divDom.insertBefore(el, divDom.childNodes[0])
}
function addCategory(name) {
if (name.length > 10) {
alert("分类名过长")
return false
}
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: []
})
Global.curCate = name
saveGlobal()
changeCurCateText()
return true
}
function delCategory(name) {
if (Global.category.length <= 1) {
alert("必须有一个分类存在")
return false
}
let index = 0
Global.category.map((v, i) => {
if (v.name === name) {
index = i
}
})
Global.category.splice(index, 1)
if (name === Global.curCate) {
Global.curCate = Global.category[0].name
}
saveGlobal()
changeCurCateText()
return true
}
function categoryList() {
let divDom = GlobalDoms.categoryAreaDom.getElementsByTagName("div")[0];
if (divDom.getElementsByClassName(prefixStr("categoryList")).length > 0) {
return
}
let list = []
for (let i = 0; i < Global.category.length; i++) {
list.push(getCategorySpan(i, Global.category[i]))
}
let div = document.createElement("div")
div.className = prefixStr("categoryList")
div.setAttribute("id", prefixStr("categoryList"))
div.style.cssText = `${flexStyle({jc: CSS.flex.start})}flex-flow:row wrap;width:80%; margin: 0 20px 10px 0px;`
div.append(...list)
divDom.insertBefore(div, divDom.childNodes[0])
toBottom()
}
function getCategorySpan(i, cate) {
let close = getCloseSpan()
close.addEventListener("click", function (event) {
let curCate = Global.curCate
if (delCategory(cate.name)) {
if (cate.name === curCate) {
renderBoard(renderSpan())
}
renderCateSpan()
event.stopImmediatePropagation()
}
})
let span = document.createElement("span")
span.innerText = cate.name
span.style.cssText = CSS.cateSpanStyle
span.style.cssText += `position: relative;`
span.addEventListener("click", function (event) {
Global.curSpan = 0
Global.curCate = cate.name
renderBoard(renderSpan())
changeCurCateText()
})
span.appendChild(close)
return span
}
function changeCurCateText() {
document.getElementById(prefixStr("curCate")).innerText = `当前分类:${Global.curCate}`
}
function renderCateSpan() {
let list = []
for (let i = 0; i < Global.category.length; i++) {
list.push(getCategorySpan(i, Global.category[i]))
}
let div = document.getElementById(prefixStr("categoryList"))
div.innerHTML = ""
div.append(...list)
return div
}
/**
* 文本栏
*/
//输入栏添加span
function showInput() {
// if (GlobalDoms.board.childNodes.length > GlobalDoms.boardChildNodes + 1) {
// return
// }
let el = document.createElement("input");
el.placeholder = "请输入内容,按回车添加"
el.style.cssText = CSS.textArea
replaceStyle(el, "border", `1px solid ${themeColor()}`)
el.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
addSpan(event.target.value, {index: getCurCateVal().spans.length})
renderBoard(renderSpan())
toBottom()
saveGlobal()
}
})
let divDom = GlobalDoms.textAreaDom.getElementsByTagName("div")[0];
divDom.insertBefore(el, divDom.childNodes[0])
toBottom()
}
function addSpan(text, {
cancel = false,
editKey = "",
finish = false,
index = 0,
input = false,
key = "",
set = false,
show = false
}) {
let s = createSpanData(text, getCurCateVal().spans.length)
s.show = show
s.input = input
s.set = set
s.finish = finish
s.cancel = cancel
s.index = index
s.key = key
s.editKey = editKey
getCurCateVal().spans.push(s)
}
function createSpanData(text, i = 0) {
return {
text: text,
cancel: false,
editKey: "",
finish: false,
index: i,
input: false,
key: "",
set: false,
show: false,
}
}
function randSpans() {
if (isOnline()) {
return [
createSpanData("账号: 123456"),
createSpanData("密码: 123456"),
createSpanData("点击输入框,再点击任意文本即可自动填写。也可设置快捷键填写。")
]
}
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(createSpanData(s, i))
}
return list
}
function getSpanText(index) {
return getCurCateVal().spans[index].text
}
function getSpans() {
let list = []
for (let i = 0; i < getCurCateVal().spans.length; i++) {
list.push(getSpan(i, getSpanText(i)))
}
return list
}
function getSpan(i, text) {
let span = document.createElement("span")
span.tabIndex = 0
span.innerHTML = `
<p style="${CSS.pStyle}">${text}</p>
<div style="${CSS.spanSettingStyle}${isShow(getSpanData(i).show)}">
<input id="settingInput${i}" style="width: 80%; height: 30px;${isShow(getSpanData(i).input)}" type="text" placeholder="请按键设置" readonly>
<span style="${CSS.iconStyle}${isShow(getSpanData(i).set)}">settings</span>
<span style="${CSS.iconStyle}${isShow(getSpanData(i).finish)}">done</span>
<span style="${CSS.iconStyle}${isShow(getSpanData(i).cancel)}">close</span>
</div>
`
span.style.cssText = CSS.spanStyle
replaceStyle(span, "border", `1px solid ${themeColor()}`)
span.addEventListener("click", function (event) {
selectSpan(i)
span.removeEventListener("keydown", moveSpan)
span.addEventListener("keydown", moveSpan)
if (Global.order === 0) {
let target = `${Global.attributeName}="${Global.curInputDom}"`
let element = document.querySelector(`input[${target}]`);
element.value = text
}
})
let childSpan = span.getElementsByTagName("span")
childSpan[0].addEventListener("click", function () {
settingCtl({input: true, set: false, finish: true, cancel: true, index: i})
})
childSpan[1].addEventListener("click", function () {
saveKey(i)
})
childSpan[2].addEventListener("click", function () {
cancel(i)
})
return span
}
function selectSpan(i = Global.curSpan) {
let spanList = getCurCateVal().spanList
if (spanList.length === 0 || spanList.childNodes.length === 0) {
return
}
let spanNodes = spanList.childNodes
replaceStyle(spanNodes[Global.curSpan], "border", `1px solid ${themeColor()}`)
Global.curSpan = i
replaceStyle(spanNodes[Global.curSpan], "border", "1px solid red")
}
function moveSpan(event) {
if (event.altKey) {
let arrow = 0
if (event.key === 'ArrowDown') {
if (Global.curSpan >= getCurCateVal().spans.length - 1) {
return
}
arrow = 1
} else if (event.key === 'ArrowUp') {
if (Global.curSpan <= 0) {
return
}
arrow = -1
}
if (arrow !== 0) {
let target = Global.curSpan + arrow
let s = getCurCateVal().spans[Global.curSpan]
getCurCateVal().spans.splice(Global.curSpan, 1)
getCurCateVal().spans.splice(target, 0, s)
exchangeSpanText(Global.curSpan, target)
selectSpan(target)
Global.curSpan = target
// moveSpan无法多次触发问题,好bug,找了好久
// 由于之前selectSpan()写法会先移除moveSpan事件,导致当前执行的moveSpan直接return了,
// 无法触发后面添加moveSpan逻辑。
}
}
}
function exchangeSpanText(i, j) {
let spanNodes = getCurCateVal().spanList.childNodes
let a = spanNodes[i].getElementsByTagName("p")[0]
let b = spanNodes[j].getElementsByTagName("p")[0]
let t = a.innerText
a.innerText = b.innerText
b.innerText = t
}
function delSpan() {
getCurCateVal().spans.splice(Global.curSpan, 1)
Global.curSpan = 0
renderBoard(renderSpan())
saveGlobal()
}
function delAllSpan() {
getCurCateVal().spans = []
renderBoard(renderSpan())
saveGlobal()
}
function renderSpan() {
let div = document.createElement("div");
div.setAttribute("id", "textSpanList")
div.style.cssText = flexStyle({fd: CSS.flex.column})
div.append(...getSpans())
getCurCateVal().spanList = div
return div
}
function getSpanData(index) {
return index >= 0 ? getCurCateVal().spans[index] : getCurCateVal().setting
}
/**
* 快捷键
*/
function changeOrder() {
let d = document.getElementById(prefixStr("orderOperation"))
d.innerText = d.innerText === "先填后选" ? "先选后填" : "先填后选"
Global.order = Global.order ? 0 : 1
saveGlobal()
}
function editKey() {
settingCtl({show: !getCurCateVal().setting.show, set: !getCurCateVal().setting.set})
}
function settingCtl({show = true, input = false, set = true, finish = false, cancel = false, index = -1}) {
if (index !== -1) {
//单span控制
let span = getCurCateVal().spans[index]
getCurCateVal().spans[index].show = show
getCurCateVal().spans[index].input = input
getCurCateVal().spans[index].set = set
getCurCateVal().spans[index].finish = finish
getCurCateVal().spans[index].cancel = cancel
} else {
//全局控制
getCurCateVal().setting.show = show
getCurCateVal().setting.input = input
getCurCateVal().setting.set = set
getCurCateVal().setting.finish = finish
getCurCateVal().setting.cancel = cancel
getCurCateVal().spans.map(v => {
v.show = show
v.input = input
v.set = set
v.finish = finish
v.cancel = cancel
})
}
renderBoard(renderSpan())
if (input) {
listenKey(index)
}
//阻止冒泡
let event = window.event || arguments.callee.caller.arguments[0];
event.stopPropagation()
}
function listenKey(index) {
let ss = getSpanData(index)
let input = document.getElementById("settingInput" + index);
input.focus()
input.value = ss.key
ss.editKey = ss.key
let downingKeys = [] //按下未松开的keys
input.addEventListener("keydown", function (event) {
if (event.key === "Backspace") {
//如果存在,则移除按下中的key
let i = downingKeys.indexOf(event.key)
i !== -1 ? downingKeys.splice(i, 1) : null
let arr = ss.editKey.split("+")
arr.pop()
ss.editKey = arr.join("+")
} else if (!downingKeys.includes(event.key)) {
if (ss.editKey === "") {
ss.editKey += event.key
} else {
ss.editKey += "+" + event.key
}
downingKeys.push(event.key)
}
input.value = ss.editKey
});
input.addEventListener("keyup", function (event) {
if (event.key !== "Backspace") {
let i = downingKeys.indexOf(event.key)
i !== -1 ? downingKeys.splice(i, 1) : null
}
});
let event = window.event || arguments.callee.caller.arguments[0];
event.stopPropagation()
}
function saveKey(index) {
let ss = getSpanData(index)
let has = false
getCurCateVal().spans.map(v => {
if (v.key === ss.editKey && v.index !== ss.index) {
alert(`文本 ${getSpanText(v.index)} 已设置该快捷键`)
has = true
}
})
if (!has) {
ss.key = ss.editKey
ss.editKey = ""
settingCtl({index: index})
}
saveGlobal()
}
function cancel(index) {
let ss = getSpanData(index)
ss.editKey = ""
settingCtl({index: index})
}
/**
* 右侧操作面板
*/
function rightOperateBoard() {
let b = document.createElement("div");
b.style.cssText = CSS.rightBoardStyle
b.setAttribute("id", "fillTextOperateBoard")
GlobalDoms.textAreaDom = textArea()
GlobalDoms.categoryAreaDom = categoryArea()
GlobalDoms.settingAreaDom = settingArea()
domCtl([], [GlobalDoms.textAreaDom, GlobalDoms.categoryAreaDom, GlobalDoms.settingAreaDom])
b.appendChild(GlobalDoms.textAreaDom)
b.appendChild(GlobalDoms.categoryAreaDom)
b.appendChild(GlobalDoms.settingAreaDom)
GlobalDoms.rightBoard = b
return b
}
function textArea() {
let operation = document.createElement("div")
operation.style.width = "100%"
operation.style.cssText += flexStyle({})
operation.innerHTML = `
<div id="${prefixStr("bottomOperation")}">
<div style="${flexStyle({jc: CSS.flex.start})}margin: 0 20px 10px 0px;flex-flow:row wrap;">
<span style="${CSS.operationStyle}" >快捷键</span>
<span style="${CSS.operationStyle}">添加</span>
<span style="${CSS.operationStyle}background: #ea5c5c;">删除</span>
<span style="${CSS.operationStyle}margin-right: 0px;background: #ea5c5c;">清空</span>
</div>
<div style="${flexStyle({jc: CSS.flex.start})}flex-flow:row wrap;">
<span style="${CSS.operationStyle}">隐藏</span>
</div>
</div>`
let list = [editKey, showInput, delSpan, delAllSpan, domCtl]
list.forEach((v, i) => {
if (v.name === "domCtl") {
operation.getElementsByTagName("span")[i].addEventListener("click", function () {
v([], [GlobalDoms.rightBoard])
})
return
}
operation.getElementsByTagName("span")[i].addEventListener("click", v)
})
return operation
}
function categoryArea() {
let operation = document.createElement("div")
operation.style.width = "100%"
operation.style.cssText += flexStyle({})
operation.style.cssText += "flex-flow:row wrap;"
operation.innerHTML = `
<div id="${prefixStr("bottomOperation")}">
<div style="${flexStyle({jc: CSS.flex.start})}margin: 0 20px 10px 0px;flex-flow:row wrap;">
<span style="${CSS.operationStyle}">添加分类</span>
<span style="${CSS.operationStyle}margin-right: 0px;">分类列表</span>
<span id="${prefixStr("curCate")}" style="${CSS.operationStyle}">当前分类:${Global.curCate}</span>
</div>
<div style="${flexStyle({jc: CSS.flex.start})}flex-flow:row wrap;">
<span style="${CSS.operationStyle}">隐藏</span>
</div>
</div>`
let list = [showCateInput, categoryList, emptyFunc, domCtl]
list.forEach((v, i) => {
if (v.name === "domCtl") {
operation.getElementsByTagName("span")[i].addEventListener("click", function () {
v([], [GlobalDoms.rightBoard])
})
return
}
operation.getElementsByTagName("span")[i].addEventListener("click", v)
})
return operation
}
function settingArea() {
let operation = document.createElement("div")
operation.style.width = "100%"
operation.style.cssText += flexStyle({})
operation.style.cssText += "flex-flow:row wrap;"
operation.innerHTML = `
<div id="${prefixStr("bottomOperation")}">
<div style="${flexStyle({jc: CSS.flex.start})}margin: 0 20px 10px 0px;flex-flow:row wrap;">
<span style="${CSS.operationStyle}">⬆</span>
<span style="${CSS.operationStyle}">⬇</span>
<span style="${CSS.operationStyle}">说明</span>
<span id="${prefixStr("orderOperation")}" style="${CSS.operationStyle}">先填后选</span>
<span id="${prefixStr("orderOperation")}" style="${CSS.operationStyle}margin-right: 0px;">编辑隐藏快捷键</span>
</div>
<div style="${flexStyle({jc: CSS.flex.start})}flex-flow:row wrap;">
<span style="${CSS.operationStyle}">隐藏</span>
</div>
</div>`
let list = [changeBoardHeight, changeBoardHeight, doc, changeOrder, showEditKeyInput, domCtl]
list.forEach((v, i) => {
if (v.name === "changeBoardHeight") {
operation.getElementsByTagName("span")[i].addEventListener("click", function () {
i % 2 === 0 ? v(40) : v(-40)
})
} else if (v.name === "domCtl") {
operation.getElementsByTagName("span")[i].addEventListener("click", function () {
v([], [GlobalDoms.rightBoard])
})
} else if (v.name === "showEditKeyInput") {
operation.getElementsByTagName("span")[i].addEventListener("click", v)
} else {
operation.getElementsByTagName("span")[i].addEventListener("click", v)
}
})
return operation
}
function showEditKeyInput() {
let divDom = GlobalDoms.settingAreaDom.getElementsByTagName("div")[0];
if (divDom.getElementsByClassName("editKeyInput").length > 0) {
return
}
let inputDom = document.createElement("div");
inputDom.className = "editKeyInput"
inputDom.innerHTML = `
<input id="editKeyInput" style="width: 80%; height: 30px;" type="text" value="${Global.hiddenKey}"
placeholder="请按键设置" readOnly>
`
divDom.insertBefore(inputDom, divDom.childNodes[0])
listenHiddenKey()
}
function listenHiddenKey() {
let input = GlobalDoms.settingAreaDom.getElementsByTagName("input")[0]
input.focus()
input.value = Global.hiddenKey
let editKey = ""
let downingKeys = [] //按下未松开的keys
input.addEventListener("keydown", function (event) {
if (event.key === "Backspace") {
//如果存在,则移除按下中的key
let i = downingKeys.indexOf(event.key)
i !== -1 ? downingKeys.splice(i, 1) : null
let arr = editKey.split("+")
arr.pop()
editKey = arr.join("+")
} else if(event.key === "Enter") {
let arr = editKey.split("+")
if(arr.length === 2 && arr[0] === "Alt" && arr[1] !== "Alt") {
Global.hiddenKey = editKey
let divDom = GlobalDoms.settingAreaDom.getElementsByTagName("div")[0]
divDom.removeChild(divDom.getElementsByTagName("div")[0])
saveGlobal()
} else {
alert("只能设置为Alt+任意键,长度为2")
}
} else if (!downingKeys.includes(event.key)) {
if (editKey === "") {
editKey += event.key
} else {
editKey += "+" + event.key
}
downingKeys.push(event.key)
}
input.value = editKey
});
input.addEventListener("keyup", function (event) {
if (event.key !== "Backspace") {
let i = downingKeys.indexOf(event.key)
i !== -1 ? downingKeys.splice(i, 1) : null
}
});
let event = window.event || arguments.callee.caller.arguments[0];
event.stopPropagation()
}
/**
* 控制面板
*/
function changeBoardHeight(h) {
GlobalDoms.board.style.height = parseInt(GlobalDoms.board.style.height) + h + "px"
}
function renderBoard(spanListDom) {
GlobalDoms.board.replaceChild(spanListDom, GlobalDoms.board.childNodes[1])
let l = GlobalDoms.board.childNodes.length
if (l > GlobalDoms.boardChildNodes) {
for (let i = GlobalDoms.boardChildNodes; i < l; i++) {
GlobalDoms.board.removeChild(GlobalDoms.board.lastChild)
}
}
selectSpan()
}
function modeCtl() {
if (Global.theme) {
Global.theme = false
replaceStyle(GlobalDoms.board, "border", `5px solid ${themeColor()}`)
getCurCateVal().spanList.childNodes.forEach(v => {
replaceStyle(v, "border", `1px solid ${themeColor()}`)
})
return
}
Global.theme = true
replaceStyle(GlobalDoms.board, "border", `5px solid ${themeColor()}`)
getCurCateVal().spanList.childNodes.forEach(v => {
replaceStyle(v, "border", `1px solid ${themeColor()}`)
})
saveGlobal()
}
function topOperation() {
let operation = document.createElement("div")
operation.style.width = "100%"
operation.innerHTML = `
<div id="${prefixStr("topOperation")}" style="${flexStyle({jc: CSS.flex.end})}margin: 0 20px 10px 0px;">
<span style="${CSS.iconStyle}font-size: 20px;">light_mode</span>
<span style="${CSS.iconStyle}">expand_more</span>
<span style="${CSS.iconStyle}">remove</span>
</div>`
let childSpan = operation.getElementsByTagName("span")
childSpan[0].addEventListener("click", modeCtl)
childSpan[1].addEventListener("click", toBottom)
childSpan[2].addEventListener("click", function () {
parentBoardCtl(1)
})
return operation
}
function bottomOperation() {
let operation = document.createElement("div")
operation.style.width = "100%"
operation.innerHTML = `
<div id="${prefixStr("bottomOperation")}">
<div style="${flexStyle({jc: CSS.flex.end})}margin: 0 20px 10px 0px;">
<span style="${CSS.operationStyle}" >快捷键</span>
<span style="${CSS.operationStyle}">添加</span>
<span style="${CSS.operationStyle}background: #ea5c5c;">删除</span>
<span style="${CSS.operationStyle}margin-right: 0px;background: #ea5c5c;">清空</span>
</div>
<div style="${flexStyle({jc: CSS.flex.end})}margin: 0 20px 10px 0px;">
<span style="${CSS.operationStyle}">说明</span>
<span style="${CSS.operationStyle}">保存配置</span>
<span id="${prefixStr("orderOperation")}" style="${CSS.operationStyle}margin-right: 0px;">先填后选</span>
</div>
<div style="${flexStyle({jc: CSS.flex.end})}margin: 0 20px 10px 0px;">
<span style="${CSS.operationStyle}">⬆</span>
<span style="${CSS.operationStyle}">⬇</span>
<span style="${CSS.operationStyle}">添加分类</span>
<span style="${CSS.operationStyle}margin-right: 0px;">分类列表</span>
</div>
<div style="${flexStyle({jc: CSS.flex.end})}margin: 0 20px 10px 0px;">
<span id="${prefixStr("curCate")}" style="${CSS.operationStyle}margin-right: 0px;">当前分类:${Global.curCate}</span>
</div>
</div>`
let list = [editKey, showInput, delSpan, delAllSpan, doc, saveGlobal, changeOrder, changeBoardHeight, changeBoardHeight, showCateInput, categoryList]
list.forEach((v, i) => {
if (v.name === "changeBoardHeight") {
operation.getElementsByTagName("span")[i].addEventListener("click", function () {
i % 2 === 0 ? v(40) : v(-40)
})
} else if (v.name === "saveGlobal") {
operation.getElementsByTagName("span")[i].addEventListener("click", function () {
if (saveGlobal()) {
alert(`保存成功!`)
} else {
alert(`配置数据太旧,无法保存。请刷新页面后再编辑保存`)
}
})
} else {
operation.getElementsByTagName("span")[i].addEventListener("click", v)
}
})
return operation
}
function bottomOperationV2() {
let operation = document.createElement("div")
operation.style.width = "100%"
operation.innerHTML = `
<div id="${prefixStr("bottomOperationV2")}">
<div style="${flexStyle({jc: CSS.flex.end})}margin: 0 20px 10px 0px;">
<span style="${CSS.operationStyle}" >文本</span>
<span style="${CSS.operationStyle}">分类</span>
<span style="${CSS.operationStyle}margin-right: 0px;">设置</span>
</div>
</div>`
let list = [domCtl, domCtl, domCtl]
list.forEach((v, i) => {
if (i === 0) {
operation.getElementsByTagName("span")[i].addEventListener("click", function () {
v([GlobalDoms.rightBoard], [])
v([GlobalDoms.textAreaDom], [GlobalDoms.categoryAreaDom, GlobalDoms.settingAreaDom])
})
} else if (i === 1) {
operation.getElementsByTagName("span")[i].addEventListener("click", function () {
v([GlobalDoms.rightBoard], [])
v([GlobalDoms.categoryAreaDom], [GlobalDoms.textAreaDom, GlobalDoms.settingAreaDom])
})
} else if (i === 2) {
operation.getElementsByTagName("span")[i].addEventListener("click", function () {
v([GlobalDoms.rightBoard], [])
v([GlobalDoms.settingAreaDom], [GlobalDoms.textAreaDom, GlobalDoms.categoryAreaDom])
})
}
})
return operation
}
function board() {
let b = document.createElement("div");
b.style.cssText = CSS.boardStyle
b.setAttribute("id", "fillTextBoard")
b.appendChild(topOperation())
b.appendChild(renderSpan())
b.appendChild(bottomOperationV2())
GlobalDoms.board = b
return b
}
function hiddenBoard() {
let hb = document.createElement("div")
hb.style.cssText = CSS.hiddenBoardStyle
hb.setAttribute("id", "fillTextHiddenBoard")
hb.innerHTML = `<span style="${CSS.iconStyle}font-size:30px;pointer-events: none;">add</span>`
hb.addEventListener("click", function () {
parentBoardCtl(0)
})
GlobalDoms.hiddenBoard = hb
return hb
}
// 两个boardCtl优化为domCtl方法
function boardCtl(show) {
if (show === 0) {
hiddenDom(GlobalDoms.hiddenBoard)
showDom(GlobalDoms.board)
} else if (show === 1) {
hiddenDom(GlobalDoms.board)
showDom(GlobalDoms.hiddenBoard)
} else if (show === -1) {
hiddenDom(GlobalDoms.board)
hiddenDom(GlobalDoms.hiddenBoard)
}
Global.show = show
saveGlobal()
}
function parentBoardCtl(show) {
if (show === 0) {
hiddenDom(GlobalDoms.hiddenBoard)
showDom(GlobalDoms.parentBoard)
} else if (show === 1) {
hiddenDom(GlobalDoms.parentBoard)
showDom(GlobalDoms.hiddenBoard)
} else if (show === -1) {
hiddenDom(GlobalDoms.parentBoard)
hiddenDom(GlobalDoms.hiddenBoard)
}
Global.parentShow = show
saveGlobal()
}
function parentBoard() {
let b = document.createElement("div");
b.style.cssText = CSS.parentBoardStyle
b.setAttribute("id", "fillTextParentBoard")
b.appendChild(board())
b.appendChild(rightOperateBoard())
GlobalDoms.parentBoard = b
return b
}
//操作面板
function operationBoard() {
document.body.appendChild(parentBoard())
document.body.appendChild(hiddenBoard())
document.body.removeEventListener("keydown", listenBodyKey)
document.body.addEventListener("keydown", listenBodyKey)
parentBoardCtl(Global.parentShow)
moveDom(GlobalDoms.parentBoard)
domCtl([GlobalDoms.board], [GlobalDoms.rightBoard])
}
/**
* 响应事件区
*/
function listenBodyKey (event) {
if (event.altKey) {
if ("Alt+" + event.key === Global.hiddenKey) {
Global.parentShow === -1 ? parentBoardCtl(0) : parentBoardCtl(-1)
}
}
}
function toBottom() {
GlobalDoms.board.scrollTop = GlobalDoms.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+q,可自行更改(只能设置为Alt+任意键,修改后按下Enter保存)\n快捷键建议Alt开头或纯字母数字,如:Alt+1、qq、11\n")
}