您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
选中内容后添加注释并复制到剪贴板, 同时在本地的服务其中新建一个副本, 参见 https://github.com/ezirmusitua/snippet-board
// ==UserScript== // @name annotation-board // @name:zh-CN 注释墙 // @description allow you to add annotation after selected content and copy to clipboard and save to local server // @description:zh-CN 选中内容后添加注释并复制到剪贴板, 同时在本地的服务其中新建一个副本, 参见 https://github.com/ezirmusitua/snippet-board // @version 0.2.0 // @author jferroal // @license GPL-3.0 // @require https://greasyfork.org/scripts/31793-jmul/code/JMUL.js?version=209567 // @include http://* // @include https://* // @grant GM_xmlhttpRequest // @run-at document-start // @namespace https://greasyfork.org/users/34556 // ==/UserScript== (function e (t, n, r) { function s (o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require === 'function' && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); var f = new Error("Cannot find module '" + o + "'"); throw f.code = 'MODULE_NOT_FOUND', f } var l = n[o] = { exports: {} }; t[o][0].call(l.exports, function (e) { var n = t[o][1][e]; return s(n || e) }, l, l.exports, e, t, n, r) } return n[o].exports } var i = typeof require === 'function' && require; for (var o = 0; o < r.length; o++)s(r[o]); return s })({ 1: [function (require, module, exports) { const elements = require('./element'); const request = require('./snippet.service'); class AnnotationBoard { constructor () { this.request = request; this.container = new elements.Container(); this.textarea = new elements.Textarea(); this.saveBtn = new elements.Button(); this.saveBtn.listenClick(() => { this.textarea.copyToClipboard(); this.request.save({ link: window.location.href, raw_content: this.textarea.value, }); this.hide(); }); this.container.appendChild([this.textarea, this.saveBtn]); this.container.element.appendTo(document.body); this.isShowing = false; } show () { this.textarea.appendSelection(); this.container.show(); this.isShowing = true; } shouldShow () { const isEmptySelection = !!this.textarea.element.getSelection(); return !this.isShowing && isEmptySelection; } hide () { this.isShowing = false; this.container.hide('display', 'none'); } shouldHide (event) { const target = event && event.target; if (!target && this.isShowing) { return true; } else { const inContainer = elements.Container.isContainer(target.id); const inTextarea = elements.Textarea.isTextarea(target.id); const inButton = elements.Button.isButton(target.id); return !inContainer && !inTextarea && !inButton && this.isShowing; } } } module.exports = AnnotationBoard; }, { './element': 2, './snippet.service': 4 }], 2: [function (require, module, exports) { const JMUL = window.JMUL || {}; const AnnotationBoardId = { CONTAINER: 'annotation-container', TEXTAREA: 'annotation-textarea', BUTTON: 'annotation-button', }; class BoardContainer { constructor () { this.element = new JMUL.Element('div'); this.element.setId(AnnotationBoardId.CONTAINER); BoardContainer._initCss(this.element) } appendChild (children) { children.forEach((c) => { try { this.element.appendChild(c.element) } catch (er) { console.log(er); } }); } show () { try { const pos = JMUL.Element.getSelectedPosition(); this.element.setCss({ display: 'flex', flexDirection: 'column', left: pos.x, top: pos.y, }); } catch (err) { console.error(err); } } hide () { this.element.setCss({ display: 'none', }); } static isContainer (id) { return AnnotationBoardId.CONTAINER === id; } static _initCss (elem) { elem.setCss({ display: 'none', fontFamily: 'Noto', border: '4px', boxShadow: '0px 3px 8px 1px rgba(0, 0, 0, 0.26)', position: 'absolute', backgroundColor: 'rgba(0, 0, 0, 0.56)', padding: '16px 4px 8px 4px', }); } } class BoardEdit { constructor () { this.element = JMUL.Decorator.selectable(new JMUL.Element('textarea')); this.element.setId(AnnotationBoardId.TEXTAREA); BoardEdit._initCss(this.element); } appendSelection () { const prevVal = this.element.value(); const selectedText = this.element.getSelection(); const newVal = (!!prevVal && (prevVal + '\n') || '') + '========' + '\n' + selectedText + '\n'; this.element.setValue(newVal) } hide () { this.element.setStyle('display', 'none'); } copyToClipboard () { this.element.copyToClipboard(); } get value () { return this.element.value(); } static isTextarea (id) { return AnnotationBoardId.TEXTAREA === id; } static _initCss (elem) { elem.setCss({ fontFamily: 'Noto', width: '240px', height: '128px', backgroundColor: 'rgba(255, 255, 255, 0.87)', marginBottom: '8px', borderRadius: '4px', color: 'rgba(0, 0, 0, 0.76)', fontSize: '12px', }); } } class BoardButton { constructor () { this.element = new JMUL.Element('button'); this.element.setId(AnnotationBoardId.BUTTON); this.element.setInnerHTML('复制到剪贴板'); BoardButton._initCss(this.element); } listenClick (fn) { this.element.listen('click', (e) => fn()); } static isButton (id) { return AnnotationBoardId.BUTTON === id; } static _initCss (elem) { elem.setCss({ fontFamily: 'Noto', border: 'none', borderRadius: '4px', height: '24px', backgroundColor: 'rgba(255, 255, 255, 0.87)', color: 'rgba(0, 0, 0, 0.76)', fontSize: '14px', }); } } module.exports = { Container: BoardContainer, Textarea: BoardEdit, Button: BoardButton, }; }, {}], 3: [function (require, module, exports) { const AnnotationBoard = require('./annotation-board'); (function () { const annotationBoard = new AnnotationBoard(); bindEvent(); function bindEvent () { window.addEventListener('mouseup', (event) => { handleMouseUp(event); }, false); } function handleMouseUp (event) { if (annotationBoard.shouldShow()) { annotationBoard.show(); } else if (annotationBoard.shouldHide(event)) { annotationBoard.hide(); } } })(); }, { './annotation-board': 1 }], 4: [function (require, module, exports) { const JMUL = window.JMUL || {}; class SnippetService { constructor (host = 'http://127.0.0.1', port = 5000, _options = {}) { if (!SnippetService.instance) { this.host = host; this.port = port; this.options = _options; if (!this.options.headers) { this.options.headers = { 'Content-Type': 'application/json' }; } SnippetService.instance = this; } return SnippetService.instance; } save (data) { const request = new JMUL.Request(this.options); request.setMethod('POST'); request.setUrl(this.host + ':' + this.port.toString() + '/snippet/api/v0.1.0'); request.setData(data); request.send(); } } SnippetService.instance = undefined; module.exports = new SnippetService(); }, {}] }, {}, [3]);