mirror of
https://github.com/Jonnyan404/memos-bber.git
synced 2026-04-24 19:48:37 +09:00
Firefox: add icons, rewrite viewer, update manifest
Add Firefox icon assets and update manifest to use the new icon files and opt-out data_collection_permissions. Replace minified view-image.js with a modern, readable implementation (style injection, accessible controls, keyboard navigation, and better DOM handling). Simplify background popup logic to call chrome.browserAction.openPopup directly. Remove the packaging section from README to clean up docs.
This commit is contained in:
@@ -6,16 +6,6 @@
|
||||
|
||||
一个通过浏览器插件发布 [Memos](https://usememos.com/) 的插件。基于 iSpeak-bber 修改,原作者为 [DreamyTZK](https://www.antmoe.com/)。
|
||||
|
||||
## 打包
|
||||
|
||||
仓库内置了 GitHub Actions 工作流 [package-extensions.yml](.github/workflows/package-extensions.yml),支持手动触发或在推送 `v*` 标签时自动打包并发布到 GitHub Releases。
|
||||
|
||||
- 推送 `v*` 标签时:自动把 Chrome 的 zip 包和 Firefox 的 xpi 包上传为对应 Release 的 assets。
|
||||
- 手动触发时:需要填写 `release_tag`,工作流会把产物直接上传到这个 tag 对应的 Release。
|
||||
- 下载时拿到的是文件本体,不再通过 Actions artifact 额外包一层 zip。
|
||||
- 打包源码固定来自 `main` 分支;`tag` 只用于决定上传到哪个 Release。
|
||||
|
||||
说明:Chrome 的 zip 包可用于商店上传,Firefox 的 xpi 包可用于 AMO 上传或离线分发。工作流已显式启用 Node 24 运行 JavaScript actions,并使用新的 `actions/checkout@v5`。
|
||||
|
||||
## 更新日志
|
||||
- 20260422 调整发送设置,支持仅发送附件
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 844 B |
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -99,24 +99,17 @@ function getSelectionTextFromTab(tabId, fallbackText) {
|
||||
})
|
||||
}
|
||||
|
||||
function getActionApi() {
|
||||
if (chrome.action && typeof chrome.action.openPopup === 'function') return chrome.action
|
||||
if (chrome.browserAction && typeof chrome.browserAction.openPopup === 'function') return chrome.browserAction
|
||||
return null
|
||||
}
|
||||
|
||||
function tryOpenActionPopup(tab) {
|
||||
try {
|
||||
const actionApi = getActionApi()
|
||||
if (!actionApi) return
|
||||
if (!chrome.browserAction || typeof chrome.browserAction.openPopup !== 'function') return
|
||||
const windowId = tab && typeof tab.windowId === 'number' ? tab.windowId : undefined
|
||||
|
||||
const open = () => {
|
||||
try {
|
||||
if (typeof windowId === 'number') {
|
||||
actionApi.openPopup({ windowId }, () => void chrome.runtime.lastError)
|
||||
chrome.browserAction.openPopup({ windowId }, () => void chrome.runtime.lastError)
|
||||
} else {
|
||||
actionApi.openPopup({}, () => void chrome.runtime.lastError)
|
||||
chrome.browserAction.openPopup({}, () => void chrome.runtime.lastError)
|
||||
}
|
||||
} catch (_) {
|
||||
// best-effort only
|
||||
|
||||
+172
-12
@@ -1,12 +1,172 @@
|
||||
/**
|
||||
* ViewImage.min.js 2.0.2
|
||||
* MIT License - http://www.opensource.org/licenses/mit-license.php
|
||||
* https://tokinx.github.io/ViewImage/
|
||||
*/
|
||||
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.createTemplateTagFirstArg=function(b){return b.raw=b};$jscomp.createTemplateTagFirstArgWithRaw=function(b,a){b.raw=a;return b};$jscomp.arrayIteratorImpl=function(b){var a=0;return function(){return a<b.length?{done:!1,value:b[a++]}:{done:!0}}};$jscomp.arrayIterator=function(b){return{next:$jscomp.arrayIteratorImpl(b)}};$jscomp.makeIterator=function(b){var a="undefined"!=typeof Symbol&&Symbol.iterator&&b[Symbol.iterator];return a?a.call(b):$jscomp.arrayIterator(b)};
|
||||
$jscomp.arrayFromIterator=function(b){for(var a,d=[];!(a=b.next()).done;)d.push(a.value);return d};$jscomp.arrayFromIterable=function(b){return b instanceof Array?b:$jscomp.arrayFromIterator($jscomp.makeIterator(b))};
|
||||
(function(){window.ViewImage=new function(){var b=this;this.target="[view-image] img";this.listener=function(a){if(!(a.ctrlKey||a.metaKey||a.shiftKey||a.altKey)){var d=String(b.target.split(",").map(function(g){return g.trim()+":not([no-view])"})),c=a.target.closest(d);if(c){var e=c.closest("[view-image]")||document.body;d=[].concat($jscomp.arrayFromIterable(e.querySelectorAll(d))).map(function(g){return g.href||g.src});b.display(d,c.href||c.src);a.stopPropagation();a.preventDefault()}}};this.init=
|
||||
function(a){a&&(b.target=a);["removeEventListener","addEventListener"].forEach(function(d){document[d]("click",b.listener,!1)})};this.display=function(a,d){var c=a.indexOf(d),e=(new DOMParser).parseFromString('\n <div class="view-image">\n <style>.view-image{position:fixed;inset:0;z-index:500;padding:1rem;display:flex;flex-direction:column;animation:view-image-in 300ms;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px)}.view-image__out{animation:view-image-out 300ms}@keyframes view-image-in{0%{opacity:0}}@keyframes view-image-out{100%{opacity:0}}.view-image-btn{width:32px;height:32px;display:flex;justify-content:center;align-items:center;cursor:pointer;border-radius:3px;background-color:rgba(255,255,255,0.2)}.view-image-btn:hover{background-color:rgba(255,255,255,0.5)}.view-image-close__full{position:absolute;inset:0;background-color:rgba(48,55,66,0.3);z-index:unset;cursor:zoom-out;margin:0}.view-image-container{height:0;flex:1;display:flex;align-items:center;justify-content:center;}.view-image-lead{display:contents}.view-image-lead img{position:relative;z-index:1;max-width:100%;max-height:100%;object-fit:contain;border-radius:3px}.view-image-lead__in img{animation:view-image-lead-in 300ms}.view-image-lead__out img{animation:view-image-lead-out 300ms forwards}@keyframes view-image-lead-in{0%{opacity:0;transform:translateY(-20px)}}@keyframes view-image-lead-out{100%{opacity:0;transform:translateY(20px)}}[class*=__out] ~ .view-image-loading{display:block}.view-image-loading{position:absolute;inset:50%;width:8rem;height:2rem;color:#aab2bd;overflow:hidden;text-align:center;margin:-1rem -4rem;z-index:1;display:none}.view-image-loading::after{content:"";position:absolute;inset:50% 0;width:100%;height:3px;background:rgba(255,255,255,0.5);transform:translateX(-100%) translateY(-50%);animation:view-image-loading 800ms -100ms ease-in-out infinite}@keyframes view-image-loading{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}.view-image-tools{position:relative;display:flex;justify-content:space-between;align-content:center;color:#fff;max-width:600px;position: absolute; bottom: 5%; left: 1rem; right: 1rem; backdrop-filter: blur(10px);margin:0 auto;padding:10px;border-radius:5px;background:rgba(0,0,0,0.1);margin-bottom:constant(safe-area-inset-bottom);margin-bottom:env(safe-area-inset-bottom);z-index:1}.view-image-tools__count{width:60px;display:flex;align-items:center;justify-content:center}.view-image-tools__flip{display:flex;gap:10px}.view-image-tools [class*=-close]{margin:0 10px}</style>\n <div class="view-image-container">\n <div class="view-image-lead"></div>\n <div class="view-image-loading"></div>\n <div class="view-image-close view-image-close__full"></div>\n </div>\n <div class="view-image-tools">\n <div class="view-image-tools__count">\n <span><b class="view-image-index">'+
|
||||
(c+1)+"</b>/"+a.length+'</span>\n </div>\n <div class="view-image-tools__flip">\n <div class="view-image-btn view-image-tools__flip-prev">\n <svg width="20" height="20" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M31 36L19 24L31 12" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>\n </div>\n <div class="view-image-btn view-image-tools__flip-next">\n <svg width="20" height="20" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M19 12L31 24L19 36" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>\n </div>\n </div>\n <div class="view-image-btn view-image-close">\n <svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M8 8L40 40" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M8 40L40 8" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>\n </div>\n </div>\n </div>\n ',
|
||||
"text/html").body.firstChild,g=function(f){var h={Escape:"close",ArrowLeft:"tools__flip-prev",ArrowRight:"tools__flip-next"};h[f.key]&&e.querySelector(".view-image-"+h[f.key]).click()},l=function(f){var h=new Image,k=e.querySelector(".view-image-lead");k.className="view-image-lead view-image-lead__out";setTimeout(function(){k.innerHTML="";h.onload=function(){setTimeout(function(){k.innerHTML='<img src="'+h.src+'" alt="ViewImage" no-view/>';k.className="view-image-lead view-image-lead__in"},100)};
|
||||
h.src=f},300)};document.body.appendChild(e);l(d);window.addEventListener("keydown",g);e.onclick=function(f){f.target.closest(".view-image-close")?(window.removeEventListener("keydown",g),e.onclick=null,e.classList.add("view-image__out"),setTimeout(function(){return e.remove()},290)):f.target.closest(".view-image-tools__flip")&&(c=f.target.closest(".view-image-tools__flip-prev")?0===c?a.length-1:c-1:c===a.length-1?0:c+1,l(a[c]),e.querySelector(".view-image-index").innerHTML=c+1)}}}})();
|
||||
;(function () {
|
||||
const STYLE_ID = 'view-image-style'
|
||||
const STYLE_TEXT = `
|
||||
.view-image{position:fixed;inset:0;z-index:500;padding:1rem;display:flex;flex-direction:column;animation:view-image-in 300ms;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px)}
|
||||
.view-image__out{animation:view-image-out 300ms}
|
||||
@keyframes view-image-in{0%{opacity:0}}
|
||||
@keyframes view-image-out{100%{opacity:0}}
|
||||
.view-image-btn{width:32px;height:32px;display:flex;justify-content:center;align-items:center;cursor:pointer;border-radius:3px;background-color:rgba(255,255,255,0.2);color:#fff;font-size:20px;line-height:1}
|
||||
.view-image-btn:hover{background-color:rgba(255,255,255,0.5)}
|
||||
.view-image-close__full{position:absolute;inset:0;background-color:rgba(48,55,66,0.3);cursor:zoom-out;margin:0}
|
||||
.view-image-container{height:0;flex:1;display:flex;align-items:center;justify-content:center}
|
||||
.view-image-lead{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;max-width:100%;max-height:100%}
|
||||
.view-image-lead img{max-width:100%;max-height:100%;object-fit:contain;border-radius:3px}
|
||||
.view-image-lead__in img{animation:view-image-lead-in 300ms}
|
||||
.view-image-lead__out img{animation:view-image-lead-out 300ms forwards}
|
||||
@keyframes view-image-lead-in{0%{opacity:0;transform:translateY(-20px)}}
|
||||
@keyframes view-image-lead-out{100%{opacity:0;transform:translateY(20px)}}
|
||||
[class*=__out] ~ .view-image-loading{display:block}
|
||||
.view-image-loading{position:absolute;inset:50%;width:8rem;height:2rem;color:#aab2bd;overflow:hidden;text-align:center;margin:-1rem -4rem;z-index:1;display:none}
|
||||
.view-image-loading::after{content:"";position:absolute;inset:50% 0;width:100%;height:3px;background:rgba(255,255,255,0.5);transform:translateX(-100%) translateY(-50%);animation:view-image-loading 800ms -100ms ease-in-out infinite}
|
||||
@keyframes view-image-loading{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}
|
||||
.view-image-tools{position:absolute;bottom:5%;left:1rem;right:1rem;display:flex;justify-content:space-between;align-content:center;color:#fff;max-width:600px;backdrop-filter:blur(10px);margin:0 auto;padding:10px;border-radius:5px;background:rgba(0,0,0,0.1);margin-bottom:constant(safe-area-inset-bottom);margin-bottom:env(safe-area-inset-bottom);z-index:1}
|
||||
.view-image-tools__count{width:60px;display:flex;align-items:center;justify-content:center}
|
||||
.view-image-tools__flip{display:flex;gap:10px}
|
||||
.view-image-tools [class*=-close]{margin:0 10px}
|
||||
`
|
||||
|
||||
function ensureStyle() {
|
||||
if (document.getElementById(STYLE_ID)) return
|
||||
const style = document.createElement('style')
|
||||
style.id = STYLE_ID
|
||||
style.textContent = STYLE_TEXT
|
||||
document.head.appendChild(style)
|
||||
}
|
||||
|
||||
function createButton(className, label, ariaLabel) {
|
||||
const button = document.createElement('button')
|
||||
button.type = 'button'
|
||||
button.className = className
|
||||
button.setAttribute('aria-label', ariaLabel)
|
||||
button.textContent = label
|
||||
return button
|
||||
}
|
||||
|
||||
window.ViewImage = new (function () {
|
||||
const api = this
|
||||
api.target = '[view-image] img'
|
||||
api.listener = function (event) {
|
||||
if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return
|
||||
const selector = String(
|
||||
api.target
|
||||
.split(',')
|
||||
.map(function (item) {
|
||||
return item.trim() + ':not([no-view])'
|
||||
})
|
||||
.join(',')
|
||||
)
|
||||
const current = event.target.closest(selector)
|
||||
if (!current) return
|
||||
const root = current.closest('[view-image]') || document.body
|
||||
const sources = Array.from(root.querySelectorAll(selector)).map(function (item) {
|
||||
return item.href || item.src
|
||||
})
|
||||
api.display(sources, current.href || current.src)
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
api.init = function (target) {
|
||||
if (target) api.target = target
|
||||
document.removeEventListener('click', api.listener, false)
|
||||
document.addEventListener('click', api.listener, false)
|
||||
}
|
||||
|
||||
api.display = function (sources, currentSrc) {
|
||||
ensureStyle()
|
||||
|
||||
let currentIndex = Math.max(0, sources.indexOf(currentSrc))
|
||||
const overlay = document.createElement('div')
|
||||
overlay.className = 'view-image'
|
||||
|
||||
const container = document.createElement('div')
|
||||
container.className = 'view-image-container'
|
||||
|
||||
const lead = document.createElement('div')
|
||||
lead.className = 'view-image-lead'
|
||||
|
||||
const loading = document.createElement('div')
|
||||
loading.className = 'view-image-loading'
|
||||
|
||||
const backdrop = document.createElement('div')
|
||||
backdrop.className = 'view-image-close view-image-close__full'
|
||||
|
||||
container.appendChild(lead)
|
||||
container.appendChild(loading)
|
||||
container.appendChild(backdrop)
|
||||
|
||||
const tools = document.createElement('div')
|
||||
tools.className = 'view-image-tools'
|
||||
|
||||
const count = document.createElement('div')
|
||||
count.className = 'view-image-tools__count'
|
||||
const countText = document.createElement('span')
|
||||
count.appendChild(countText)
|
||||
|
||||
const flips = document.createElement('div')
|
||||
flips.className = 'view-image-tools__flip'
|
||||
const prev = createButton('view-image-btn view-image-tools__flip-prev', '‹', 'Previous image')
|
||||
const next = createButton('view-image-btn view-image-tools__flip-next', '›', 'Next image')
|
||||
flips.appendChild(prev)
|
||||
flips.appendChild(next)
|
||||
|
||||
const close = createButton('view-image-btn view-image-close', '×', 'Close image viewer')
|
||||
|
||||
tools.appendChild(count)
|
||||
tools.appendChild(flips)
|
||||
tools.appendChild(close)
|
||||
|
||||
overlay.appendChild(container)
|
||||
overlay.appendChild(tools)
|
||||
|
||||
function render() {
|
||||
countText.textContent = `${currentIndex + 1}/${sources.length}`
|
||||
lead.className = 'view-image-lead view-image-lead__out'
|
||||
|
||||
window.setTimeout(function () {
|
||||
const image = document.createElement('img')
|
||||
image.alt = 'ViewImage'
|
||||
image.setAttribute('no-view', '')
|
||||
image.addEventListener('load', function () {
|
||||
window.setTimeout(function () {
|
||||
lead.replaceChildren(image)
|
||||
lead.className = 'view-image-lead view-image-lead__in'
|
||||
}, 100)
|
||||
})
|
||||
image.src = sources[currentIndex]
|
||||
}, 300)
|
||||
}
|
||||
|
||||
function closeViewer() {
|
||||
window.removeEventListener('keydown', onKeyDown)
|
||||
overlay.classList.add('view-image__out')
|
||||
window.setTimeout(function () {
|
||||
overlay.remove()
|
||||
}, 290)
|
||||
}
|
||||
|
||||
function onKeyDown(event) {
|
||||
if (event.key === 'Escape') closeViewer()
|
||||
if (event.key === 'ArrowLeft') prev.click()
|
||||
if (event.key === 'ArrowRight') next.click()
|
||||
}
|
||||
|
||||
prev.addEventListener('click', function () {
|
||||
currentIndex = currentIndex === 0 ? sources.length - 1 : currentIndex - 1
|
||||
render()
|
||||
})
|
||||
|
||||
next.addEventListener('click', function () {
|
||||
currentIndex = currentIndex === sources.length - 1 ? 0 : currentIndex + 1
|
||||
render()
|
||||
})
|
||||
|
||||
backdrop.addEventListener('click', closeViewer)
|
||||
close.addEventListener('click', closeViewer)
|
||||
|
||||
document.body.appendChild(overlay)
|
||||
window.addEventListener('keydown', onKeyDown)
|
||||
render()
|
||||
}
|
||||
})()
|
||||
})()
|
||||
|
||||
@@ -12,13 +12,16 @@
|
||||
"homepage_url": "https://github.com/Jonnyan404/memos-bber",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "memos-bber@jonnyan404.github.io"
|
||||
"id": "memos-bber@jonnyan404.github.io",
|
||||
"data_collection_permissions": {
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"icons": {
|
||||
"128": "assets/logo.png",
|
||||
"16": "assets/logo.png",
|
||||
"48": "assets/logo.png"
|
||||
"128": "assets/logo-128.png",
|
||||
"16": "assets/logo-16.png",
|
||||
"48": "assets/logo-48.png"
|
||||
},
|
||||
"background": {
|
||||
"scripts": ["js/background.js"]
|
||||
|
||||
Reference in New Issue
Block a user