From 508f4081aa6c38895c1d7c6a1d3598aa43dc194e Mon Sep 17 00:00:00 2001 From: MuiseDestiny <2274466799@qq.com> Date: Sat, 26 Nov 2022 13:00:43 +0800 Subject: [PATCH] setting UI --- README.md | 12 ++- src/events.ts | 94 ++++++++++++---- src/module.ts | 29 +++++ src/setting.html | 127 ++++++++++++++++++++++ src/setting.ts | 274 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 515 insertions(+), 21 deletions(-) create mode 100644 src/setting.html create mode 100644 src/setting.ts diff --git a/README.md b/README.md index 9381ba7..d30c14a 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,21 @@ Zotero标签可以显示在标题左侧,有时候条目有不同数量标签 ![](https://spr1ng.live/file/87ac5698538744a03d424.png) +设置界面 +> 鼠标中键,Mac用户没有鼠标右键,可以设置Zotero.ZoteroStyle.progressOpacity=0隐藏进度条 + +1. Zotero.ZoteroStyle.progressColor=#F06292 - 设置进度条颜色 +2. Zotero.ZoteroStyle.progressOpacity=.5 - 设置进度条透明度 +3. Zotero.ZoteroStyle.tagSize=8 - 设置标签宽度 +4. 展开标题后保留的列(即将支持) +![](https://spr1ng.live/file/1f8ea01f480f45a0149ca.png) + ## 主要功能 -1. 标签右对齐,标签由`圆角正方形`->`圆形`🔴🟤🔵 +1. 标签右对齐,标签由`圆角正方形`->`圆形` 2. 增加`只显示标题`按钮🌸 3. 显示阅读进度,是否划水,一看便知👋 +4. 本插件可与`Chartero`共存,若安装`Chartero`不插件将不再渲染进度条,因为这一功能我已合并到`Chartero`,而且`Chartero`支持同步数据 🙌建议配合Zotero Tag使用,本插件无个性化设置界面(其实是我还不会写,用的bootstrap模板`支持以后的Zotero`,现有的大多是overlay`后面升级的Zotero可能不支持这种模式的插件`的) diff --git a/src/events.ts b/src/events.ts index 7292460..0b0f586 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,12 +1,17 @@ import { Addon, addonName } from "./addon"; import AddonModule from "./module"; +import Setting from "./setting"; class AddonEvents extends AddonModule { public Zotero: any; public window: any; public document: any; public notifierCallback : any; + public setting: any; public intervalID: number; + public tagSize = 5; // em + public progressOpacity = .7; // s + public progressColor = "#5AC1BD"; // public recordInterval = 5; // s public maxHangTime = 60; // s public mode = "normal"; // default @@ -60,6 +65,10 @@ class AddonEvents extends AddonModule { this.modifyRenderCell ) + // setting + this.setting = new Setting(AddonModule) + this.setting.init(this.Zotero) + this.setting.settingNode.style.display = "none" // event let notifierID = this.Zotero.Notifier.registerObserver( this.notifierCallback, @@ -75,19 +84,21 @@ class AddonEvents extends AddonModule { ); // listen to Zotero's state - this.window.addEventListener('activate', () => { - console.log('activate') - this.state.activate = true - // once Zotero is activated again, it will continue to record read time - this.intervalID = this.window.setInterval(this.recordReadTime.bind(this), this.recordInterval * 1e3) - }, true); - this.window.addEventListener('deactivate', () => { - console.log('deactivate') - this.state.activate = false - this.state.hangCount = 0; - // once Zotero is deactivate again, it will stop to record read time - this.window.clearInterval(this.intervalID) - }, true); + if (!this.Zotero.Chartero) { + this.window.addEventListener('activate', () => { + console.log('activate') + this.state.activate = true + // once Zotero is activated again, it will continue to record read time + this.intervalID = this.window.setInterval(this.recordReadTime.bind(this), this.recordInterval * 1e3) + }, true); + this.window.addEventListener('deactivate', () => { + console.log('deactivate') + this.state.activate = false + this.state.hangCount = 0; + // once Zotero is deactivate again, it will stop to record read time + this.window.clearInterval(this.intervalID) + }, true); + } } private addSwitchButton(): void { @@ -131,6 +142,15 @@ class AddonEvents extends AddonModule { switchDisplay(_Zotero) this.innerHTML = maxSvg } + } else if (event.button == 1) { + // setting ui + console.log("init Setting") + let settingNode = _Zotero.getMainWindow().document.querySelector("#Zotero-Style-Setting") + if (settingNode.style.display = "none") { + settingNode.style.display = "" + } else { + settingNode.style.display = "none" + } } else if (event.button == 2) { console.log("right click") _Zotero.ZoteroStyle.events.progress = !_Zotero.ZoteroStyle.events.progress @@ -142,7 +162,7 @@ class AddonEvents extends AddonModule { let toolbar = this.document.querySelector("#zotero-items-toolbar") let toolbarbutton = toolbar.querySelector("toolbarbutton").cloneNode() toolbarbutton.setAttribute("id", "zotero-tb-switch-itemtree") - toolbarbutton.setAttribute("tooltiptext", "switch itemtree") + toolbarbutton.setAttribute("tooltiptext", "Zotero Style For You") toolbarbutton.setAttribute("type", "") toolbarbutton.setAttribute("class", "") toolbarbutton.setAttribute("onmousedown", "") @@ -158,9 +178,14 @@ class AddonEvents extends AddonModule { private addStyle(): void { console.log("Start style") let mainWindow = this.document.querySelector('#main-window') + let oldStyle = mainWindow.querySelector("#pageStyle") + if (oldStyle) oldStyle.remove() let style = this.createElement("style") style.setAttribute('type', 'text/css') style.setAttribute('id', 'pageStyle') + // some setting value + let tagSize = this.getValue("Zotero.ZoteroStyle.tagSize", this.tagSize) + let progressOpacity = this.getValue("Zotero.ZoteroStyle.progressOpacity", this.progressOpacity) style.textContent = ` .primary { display: flex; @@ -169,9 +194,10 @@ class AddonEvents extends AddonModule { } .tag-box { position: relative; - width: 5em; + width: ${tagSize}em; height: 1em; line-height: 1em; + margin-left: auto; } #zotero-items-tree .cell.primary .zotero-tag { height: .9em; @@ -190,9 +216,9 @@ class AddonEvents extends AddonModule { position: absolute; left: 3.25em; top: 0; - width: calc(100% - 9em); + width: calc(100% - 3.5em - ${tagSize}em) !important; height: 100%; - opacity: .7; + opacity: ${progressOpacity}; } ` mainWindow.appendChild(style) @@ -229,6 +255,7 @@ class AddonEvents extends AddonModule { // 2693 _renderPrimaryCell(index, data, column) let document = Zotero.getMainWindow().document let createElement = (name) => document.createElementNS("http://www.w3.org/1999/xhtml", name) + // render the tag let tagBoxNode = createElement("span") tagBoxNode.setAttribute("class", "tag-box") @@ -243,6 +270,9 @@ class AddonEvents extends AddonModule { tagNode.style.left = `${i*1.25+delta}em` tagBoxNode.appendChild(tagNode) }) + if (Zotero.Chartero) { + return primaryCell + } // render the read progress let progressNode = createElement("span") progressNode.setAttribute("class", "zotero-style-progress") @@ -252,7 +282,6 @@ class AddonEvents extends AddonModule { // create sub span in this progress node const recordKey = `Zotero.ZoteroStyle.record`; let record = JSON.parse(Zotero.Prefs.get(recordKey) || "{}"); - console.log(record) // i.e. const testTitle = "Satellite remote sensing of aerosol optical depth: advances, challenges, and perspectives" record[testTitle] = { @@ -265,7 +294,6 @@ class AddonEvents extends AddonModule { "total": 12 } const title = args[1] - console.log(title) if (record && record[title]) { let recordTimeObj = record[title] const total = recordTimeObj["total"] @@ -284,6 +312,9 @@ class AddonEvents extends AddonModule { maxSec = meanSec + (maxSec - meanSec) * .5 const minSec = 60 const pct = 1 / total * 100 + let obj = Zotero.ZoteroStyle.events + let progressColor = obj.getValue("Zotero.ZoteroStyle.progressColor", obj.progressColor) + let [r, g, b] = progressColor.colorRgb() for (let i=0; i + + + + + + Document + + +
+ +
+ > + +
+
+ + + + \ No newline at end of file diff --git a/src/setting.ts b/src/setting.ts new file mode 100644 index 0000000..16aabe5 --- /dev/null +++ b/src/setting.ts @@ -0,0 +1,274 @@ +import AddonModule from "./module"; + +class Setting extends AddonModule { + public Zotero: any + public window: any + public document: any + public settingNode: any + public inputNode: any + public historyNode: any + public setValue: any + public getValue: any + public tip = "Enter your command here..." + public _settingHistory = [ + "Zotero.ZoteroStyle.progressOpacity=.7", + "Zotero.ZoteroStyle.tagSize=5", + "" + ] + constructor(parent) { + super(parent) + } + + public init(Zotero) { + this.Zotero = Zotero; + this.window = this.Zotero.getMainWindow(); + this.document = this.window.document; + this.createStyle() + this.createHTML() + this.setEvent() + } + + public execLine(text: string) { + if (text.includes("=")) { + // 赋值 + let [key, value] = text.split("=") + this.setValue(key.trim(), value.trim()) + console.log(`setValue(${key}, ${value})`) + return true + } else if (this.getValue(text, undefined)) { + return this.getValue(text) + } else { + this.inputMessage("Not Support") + return false + } + } + + public appendLine(text: string, selected: boolean = false) { + // 页面变化 + let li = this.createElement("li") + li.setAttribute("class", "line") + li.innerText = text + // let inHistory = false + if (selected) { + this.settingNode.querySelectorAll(".line").forEach(line=>{ + line.removeAttribute("selected") + if (line.innerText==text) { + // inHistory = true + line.remove() + } + }) + li.setAttribute("selected", "") + } + // if (!inHistory && this.execLine(text)) { + if (this.execLine(text)) { + this.historyNode.appendChild(li) + // push to settingHistory + const k = "Zotero.ZoteroStyle.settingHistory" + let settingHistory = this.getValue(k, this._settingHistory) + if (text.includes("=")) { + let varname = text.split("=")[0].trim() + settingHistory = settingHistory.filter(line=>!line.includes(varname)) + } + settingHistory.push(text) + console.log(settingHistory) + this.setValue(k, settingHistory) + this.Zotero.ZoteroStyle.events.addStyle() + return true + } + return false + } + + public createHTML() { + console.log("create HTML") + let settingNode = this.createElement("div") + settingNode.style.zIndex = 999 + settingNode.setAttribute("id", "Zotero-Style-Setting") + + let historyNode = this.createElement("ul") + historyNode.setAttribute("class", "history") + historyNode.style.display = "none" + settingNode.appendChild(historyNode) + + let inputbox = this.createElement("div") + inputbox.setAttribute("class", "input-box") + let span = this.createElement("span") + span.innerText = ">" + inputbox.appendChild(span) + let inputNode = this.createElement("input") + inputNode.setAttribute("placeholder", this.tip) + inputbox.appendChild(inputNode) + settingNode.appendChild(inputbox) + this.document.querySelector('#main-window').appendChild(settingNode) + this.settingNode = settingNode + this.inputNode = inputNode + this.historyNode = historyNode + const k = "Zotero.ZoteroStyle.settingHistory" + console.log(this.getValue(k, [])) + this.getValue(k, []).forEach(text=>this.appendLine(text)) + console.log(settingNode) + } + + public createStyle() { + console.log("add Style") + let styleText = ` + #Zotero-Style-Setting { + ---radius---: 10px; + position: fixed; + left: 30%; + bottom: 10%; + width: 40%; + border-radius: var(---radius---); + border: 1px solid black; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + background-color: white; + font-size: 18px; + box-shadow: 0.3em 0.3em 1em rgba(0, 0, 0, 0.3); + } + #Zotero-Style-Setting .input-box { + width: 100%; + padding-left: 20px; + } + #Zotero-Style-Setting input { + width: 90%; + height: 45px; + border: 1px solid red; + border: none; + outline: none; + border-radius: 5px; + font-size: 20px; + margin-left: .3em; + } + #Zotero-Style-Setting .history { + width: 100%; + margin-top: 0; + padding: 0; + background-color: rgba(248, 240, 240, .4); + } + #Zotero-Style-Setting .history .line { + list-style-type: none; + width: calc(100% - 40px); + line-height: 2.5em; + padding: auto 10px; + display: inline-block; + padding-left: 20px; + padding-right: 20px; + + } + #Zotero-Style-Setting .history .line:active { + background-color: rgba(220, 240, 240, 1);; + } + #Zotero-Style-Setting .history .line[selected] { + background-color: rgba(220, 240, 240, 1); + } + #Zotero-Style-Setting .history .line:first-child { + border-radius: var(---radius---) var(---radius---) 0 0; + } + ` + let style = this.createElement("style") + style.setAttribute('type', 'text/css') + style.setAttribute('id', 'settingStyle') + style.innerHTML = styleText + this.document.querySelector('#main-window').appendChild(style) + } + + public setEvent() { + // let settingNode = this.document.querySelector("#Zotero-Style-Setting") + // let inputNode = this.document.querySelector("input") + // let historyNode = settingNode.querySelector(".history") + this.settingNode.addEventListener("keyup", (event)=>{ + let isInit = false + if (event.key=="ArrowUp") { + // 如果没显示history + if (this.historyNode.style.display=="none") { + let lastLine = this.historyNode.querySelector(".line:last-child") + if (lastLine) { + // 让他显示,并默认选择第一个 + this.historyNode.style.display = "" + this.historyNode.querySelectorAll(".line").forEach(line=>line.removeAttribute("selected")) + lastLine.setAttribute("selected", "") + isInit = true + } else { + this.inputMessage("settingHistory is empty") + } + } + } else if (event.key=="Enter") { + // 回车则获取当前selected,填入input + if (this.historyNode.style.display != "none" && this.inputNode.value.trim() == "") { + this.inputNode.value = this.historyNode.querySelector(".line[selected]").innerText + // 并且收起historyNode + this.historyNode.style.display = "none" + } else { + if (this.appendLine(this.inputNode.value, true)) { + this.historyNode.style.display = "" + } + this.inputNode.value = "" + } + } else if (event.key=="Escape") { + if (this.historyNode.style.display != "none") { + this.historyNode.style.display = "none" + } else { + this.settingNode.style.display = "none" + } + } else if (event.key=="Delete") { + if (this.historyNode.style.display != "none") { + // 删除选中 + let lines = this.historyNode.querySelectorAll(".line") + for (let i=0;itext!=lines[i].innerText) + this.setValue(k, settingHistory) + lines[i+1{ + this.inputNode.setAttribute("placeholder", this.tip) + }, t * 1e3) + } + + public createElement(name) { + return this.document.createElementNS("http://www.w3.org/1999/xhtml", name) + } +} + +export default Setting; \ No newline at end of file