annotation-board

allow you to add annotation after selected content and copy to clipboard and save to local server

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==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]);