Greasy Fork 还支持 简体中文。

annotation-board

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

目前為 2017-08-03 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // ==UserScript==
  3. // @name annotation-board
  4. // @name:zh-CN 注释墙
  5. // @description allow you to add annotation after selected content and copy to clipboard and save to local server
  6. // @description:zh-CN 选中内容后添加注释并复制到剪贴板, 同时在本地的服务其中新建一个副本, 参见 https://github.com/ezirmusitua/snippet-board
  7. // @version 0.2.0
  8. // @author jferroal
  9. // @license GPL-3.0
  10. // @require https://greasyfork.org/scripts/31793-jmul/code/JMUL.js?version=209567
  11. // @include http://*
  12. // @include https://*
  13. // @grant GM_xmlhttpRequest
  14. // @run-at document-start
  15. // @namespace https://greasyfork.org/users/34556
  16. // ==/UserScript==
  17.  
  18. (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?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){
  19. const elements = require('./element');
  20. const request = require('./snippet.service');
  21.  
  22. class AnnotationBoard {
  23. constructor() {
  24. this.request = request;
  25. this.container = new elements.Container();
  26. this.textarea = new elements.Textarea();
  27. this.saveBtn = new elements.Button();
  28. this.saveBtn.listenClick(() => {
  29. this.textarea.copyToClipboard();
  30. this.request.save({
  31. link: window.location.href,
  32. raw_content: this.textarea.value,
  33. });
  34. this.hide();
  35. });
  36. this.container.appendChild([this.textarea, this.saveBtn]);
  37. this.container.element.appendTo(document.body);
  38. this.isShowing = false;
  39. }
  40.  
  41. show() {
  42. this.textarea.appendSelection();
  43. this.container.show();
  44. this.isShowing = true;
  45. }
  46.  
  47. shouldShow() {
  48. const isEmptySelection = !!this.textarea.element.getSelection();
  49. return !this.isShowing && isEmptySelection;
  50. }
  51.  
  52. hide() {
  53. this.isShowing = false;
  54. this.container.hide('display', 'none');
  55. }
  56.  
  57. shouldHide(event) {
  58. const target = event && event.target;
  59. if (!target && this.isShowing) {
  60. return true;
  61. } else {
  62. const inContainer = elements.Container.isContainer(target.id);
  63. const inTextarea = elements.Textarea.isTextarea(target.id);
  64. const inButton = elements.Button.isButton(target.id);
  65. return !inContainer && !inTextarea && !inButton && this.isShowing;
  66. }
  67. }
  68. }
  69.  
  70. module.exports = AnnotationBoard;
  71. },{"./element":2,"./snippet.service":4}],2:[function(require,module,exports){
  72. const JMUL = window.JMUL || {};
  73.  
  74. const AnnotationBoardId = {
  75. CONTAINER: 'annotation-container',
  76. TEXTAREA: 'annotation-textarea',
  77. BUTTON: 'annotation-button',
  78. };
  79.  
  80. class BoardContainer {
  81. constructor() {
  82. this.element = new JMUL.Element('div');
  83. this.element.setId(AnnotationBoardId.CONTAINER);
  84. BoardContainer._initCss(this.element)
  85. }
  86.  
  87. appendChild(children) {
  88. children.forEach((c) => {
  89. try {
  90. this.element.appendChild(c.element)
  91. } catch(er) {
  92. console.log(er);
  93. }
  94. });
  95. }
  96.  
  97. show() {
  98. try {
  99. const pos = JMUL.Element.getSelectedPosition();
  100. this.element.setCss({
  101. display: 'flex',
  102. flexDirection: 'column',
  103. left: pos.x,
  104. top: pos.y,
  105. });
  106. } catch (err) {
  107. console.error(err);
  108. }
  109. }
  110.  
  111. hide() {
  112. this.element.setCss({
  113. display: 'none',
  114. });
  115. }
  116.  
  117. static isContainer(id) {
  118. return AnnotationBoardId.CONTAINER === id;
  119. }
  120.  
  121. static _initCss(elem) {
  122. elem.setCss({
  123. display: 'none',
  124. fontFamily: 'Noto',
  125. border: '4px',
  126. boxShadow: '0px 3px 8px 1px rgba(0, 0, 0, 0.26)',
  127. position: 'absolute',
  128. backgroundColor: 'rgba(0, 0, 0, 0.56)',
  129. padding: '16px 4px 8px 4px',
  130. });
  131. }
  132. }
  133.  
  134. class BoardEdit {
  135. constructor() {
  136. this.element = JMUL.Decorator.selectable(new JMUL.Element('textarea'));
  137. this.element.setId(AnnotationBoardId.TEXTAREA);
  138. BoardEdit._initCss(this.element);
  139. }
  140.  
  141. appendSelection() {
  142. const prevVal = this.element.value();
  143. const selectedText = this.element.getSelection();
  144. const newVal = (!!prevVal && (prevVal + '\n') || '') + '========' + '\n' + selectedText + '\n';
  145. this.element.setValue(newVal)
  146. }
  147.  
  148. hide() {
  149. this.element.setStyle('display', 'none');
  150. }
  151.  
  152. copyToClipboard() {
  153. this.element.copyToClipboard();
  154. }
  155.  
  156. get value() {
  157. return this.element.value();
  158. }
  159.  
  160. static isTextarea(id) {
  161. return AnnotationBoardId.TEXTAREA === id;
  162. }
  163.  
  164. static _initCss(elem) {
  165. elem.setCss({
  166. fontFamily: 'Noto',
  167. width: '240px',
  168. height: '128px',
  169. backgroundColor: 'rgba(255, 255, 255, 0.87)',
  170. marginBottom: '8px',
  171. borderRadius: '4px',
  172. color: 'rgba(0, 0, 0, 0.76)',
  173. fontSize: '12px',
  174. });
  175. }
  176. }
  177.  
  178. class BoardButton {
  179. constructor() {
  180. this.element = new JMUL.Element('button');
  181. this.element.setId(AnnotationBoardId.BUTTON);
  182. this.element.setInnerHTML('复制到剪贴板');
  183. BoardButton._initCss(this.element);
  184. }
  185.  
  186. listenClick(fn) {
  187. this.element.listen('click', (e) => fn());
  188. }
  189.  
  190. static isButton(id) {
  191. return AnnotationBoardId.BUTTON === id;
  192. }
  193.  
  194. static _initCss(elem) {
  195. elem.setCss({
  196. fontFamily: 'Noto',
  197. border: 'none',
  198. borderRadius: '4px',
  199. height: '24px',
  200. backgroundColor: 'rgba(255, 255, 255, 0.87)',
  201. color: 'rgba(0, 0, 0, 0.76)',
  202. fontSize: '14px',
  203. });
  204. }
  205. }
  206.  
  207. module.exports = {
  208. Container: BoardContainer,
  209. Textarea: BoardEdit,
  210. Button: BoardButton,
  211. };
  212. },{}],3:[function(require,module,exports){
  213. const AnnotationBoard = require('./annotation-board');
  214.  
  215. (function () {
  216. const annotationBoard = new AnnotationBoard();
  217. bindEvent();
  218. function bindEvent() {
  219. window.addEventListener('mouseup', (event) => {
  220. handleMouseUp(event);
  221. }, false);
  222. }
  223.  
  224. function handleMouseUp(event) {
  225. if (annotationBoard.shouldShow()) {
  226. annotationBoard.show();
  227. } else if (annotationBoard.shouldHide(event)) {
  228. annotationBoard.hide();
  229. }
  230. }
  231. })();
  232.  
  233. },{"./annotation-board":1}],4:[function(require,module,exports){
  234. const JMUL = window.JMUL || {};
  235.  
  236. class SnippetService {
  237. constructor(host = 'http://127.0.0.1', port = 5000, _options = {}) {
  238. if (!SnippetService.instance) {
  239. this.host = host;
  240. this.port = port;
  241. this.options = _options;
  242. if (!this.options.headers) {
  243. this.options.headers = {'Content-Type': 'application/json'};
  244. }
  245. SnippetService.instance = this;
  246. }
  247. return SnippetService.instance;
  248. }
  249.  
  250. save(data) {
  251. const request = new JMUL.Request(this.options);
  252. request.setMethod('POST');
  253. request.setUrl(this.host + ':' + this.port.toString() + '/snippet/api/v0.1.0');
  254. request.setData(data);
  255. request.send();
  256. }
  257. }
  258.  
  259. SnippetService.instance = undefined;
  260.  
  261. module.exports = new SnippetService();
  262. },{}]},{},[3]);