您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
选中内容后添加注释并复制到剪贴板
当前为
// ==UserScript== // @name annotation-board // @name:zh-CN 注释墙 // @description allow you to add annotation after selected content and copy to clipboard // @description:zh-CN 选中内容后添加注释并复制到剪贴板 // @version 0.1.0 // @author jferroal // @license GPL-3.0 // @include http://* // @include https://* // @run-at document-start // @namespace https://gf.qytechs.cn/users/34556 // ==/UserScript== // Features // 1. 选中后弹出输入框添加注释 // 2. 添加的注释中需要有事件信息 // 3. 窗口关闭后/不活跃后将内容复制到剪贴板 // 4. 剪贴板中的内容需要有文章信息 class AnnotationBoardStyle { constructor() { } static containerStyle(containerStyleObj, position) { containerStyleObj.fontFamily = 'Noto'; containerStyleObj.display = 'flex'; containerStyleObj.flexDirection = 'column'; containerStyleObj.border = '4px'; containerStyleObj.boxShadow = '0px 3px 8px 1px rgba(0, 0, 0, 0.26)'; containerStyleObj.position = 'absolute'; containerStyleObj.backgroundColor = 'rgba(0, 0, 0, 0.56)'; containerStyleObj.padding = '16px 4px 8px 4px'; containerStyleObj.we } static textareaStyle(textareaStyleObj) { textareaStyleObj.fontFamily = 'Noto'; textareaStyleObj.width = '240px'; textareaStyleObj.height = '128px'; textareaStyleObj.backgroundColor = 'rgba(255, 255, 255, 0.87)'; textareaStyleObj.marginBottom = '8px'; textareaStyleObj.borderRadius = '4px'; textareaStyleObj.color = 'rgba(0, 0, 0, 0.76)' textareaStyleObj.fontSize = '12px'; } static saveButtonStyle(buttonStyleObj) { buttonStyleObj.fontFamily = 'Noto'; buttonStyleObj.border = 'none'; buttonStyleObj.borderRadius = '4px'; buttonStyleObj.height = '24px'; buttonStyleObj.backgroundColor = 'rgba(255, 255, 255, 0.87)' buttonStyleObj.color = 'rgba(0, 0, 0, 0.76)' buttonStyleObj.fontSize = '14px'; } } const formatDate = (dateObj) => { const year = dateObj.getFullYear(); const month = dateObj.getMonth(); const date = dateObj.getDate(); const hour = dateObj.getHours(); const minute = dateObj.getMinutes(); return `Date: ${year}-${month + 1}-${date}[${hour}:${minute > 9 ? minute : '0' + minute}]`; } const AnnotationBoardId = { CONTAINER: 'annotation-container', TEXTAREA: 'annotation-textarea', BUTTON: 'annotation-button' }; class Selection { constructor() { this.createAtStr = formatDate(new Date()); this.selectionText = document.getSelection().toString(); } concat() { return this.createAtStr + '\n' + `Content: \n${this.selectionText}`; } content(previousContent) { if (previousContent) { return previousContent + '\n' + '========' + '\n' + this.concat() + '\n'; } else { return this.concat() + '\n'; } } isEmpty() { return !this.selectionText; } static copyToClipboard(button, textarea) { document.getSelection().removeAllRanges(); const range = document.createRange(); range.selectNode(textarea); document.getSelection().addRange(range); try { document.execCommand('copy'); } catch (err) { console.log('Oops, unable to copy'); } document.getSelection().removeAllRanges(); } } class Position { constructor(rect, offset) { this._left = (rect.left + (offset || 32)) + 'px'; this._top = (rect.top + (offset || 16)) + 'px'; } top() { return this._top; } left() { return this._left; } } class AnnotationTextArea { constructor() { this.container = document.createElement('div'); this.container.id = AnnotationBoardId.CONTAINER; AnnotationBoardStyle.containerStyle(this.container.style); this.textarea = document.createElement('textarea'); this.textarea.id = AnnotationBoardId.TEXTAREA; AnnotationBoardStyle.textareaStyle(this.textarea.style); this.saveBtn = document.createElement('button'); this.saveBtn.innerHTML = '复制到剪贴板'; this.saveBtn.id = AnnotationBoardId.BUTTON; AnnotationBoardStyle.saveButtonStyle(this.saveBtn.style); this.isShowing = false; } getPosition() { const focusNode = document.getSelection().focusNode; if (!focusNode) throw new Error('no selection, should not create node'); const focusParentElement = focusNode.parentElement; return new Position(focusParentElement.getBoundingClientRect()); } updateContainer() { try { const pos = this.getPosition(); this.container.style.left = pos.left(); this.container.style.top = pos.top(); } catch (err) { console.error(err); } } updateSaveButton() { this.saveBtn.addEventListener('click', (event) => { Selection.copyToClipboard(this.saveBtn, this.textarea); this.hide(); }) } updateTextarea(selection) { this.textarea.value = selection.content(this.textarea.value); } show() { this.updateTextarea(new Selection()); this.updateContainer(); if (!this.isShowed) { this.container.appendChild(this.textarea); this.updateSaveButton(); this.container.appendChild(this.saveBtn); } document.body.appendChild(this.container); this.isShowing = true; this.isShowed = true; } shouldShow() { return !this.isShowing && !(new Selection()).isEmpty(); } hide() { this.isShowing = false; document.body.removeChild(this.container) } shouldHide(event) { const target = event && event.target; if (!target && this.iShowing) { return true; } else { const inContainer = event.target.id === AnnotationBoardId.CONTAINER; const inTextarea = event.target.id === AnnotationBoardId.TEXTAREA; const inButton = event.target.id === AnnotationBoardId.BUTTON; return !inContainer && !inTextarea && !inButton && this.isShowing; } } destory() { this.container.removeChild(this.saveBtn); this.saveBtn = null; this.container.removeChild(this.textarea); this.textarea = null; document.body.removeChild(this.container); this.container = null; } } class AnnotationBoard { constructor() { this.annotationTextArea = new AnnotationTextArea(); } run() { this.eventBinding(); } eventBinding() { window.addEventListener('mouseup', (event) => { this.handleMouseUp(event); }, false); } handleMouseUp(event) { if (this.annotationTextArea.shouldShow()) { this.annotationTextArea.show(); } else if (this.annotationTextArea.shouldHide(event)) { this.annotationTextArea.hide(); } } } const annotationBoard = new AnnotationBoard(); annotationBoard.run();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址