您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Choose your favorite DOM node and its content will be automatically copied to the clipboard in markdown format
- // ==UserScript==
- // @name ivnote-web-clipper
- // @version 0.8.1
- // @description Choose your favorite DOM node and its content will be automatically copied to the clipboard in markdown format
- // @author Ivan Jiang
- // @match http://*/*
- // @match https://*/*
- // @grant GM_addStyle
- // @require https://cdn.bootcss.com/to-markdown/3.0.3/to-markdown.min.js
- // @namespace http://ivnote.xyz
- // ==/UserScript==
- /* globals GM_addStyle, toMarkdown */
- GM_addStyle(` .ivnote-web-clipper-hover { background: rgba(124, 201, 191, .7); }
- .ivnote-web-clipper-icon {
- position: fixed; bottom: 15px; right: 15px;
- height: 50px; width: 50px; border-radius: 50%;
- background: RGBA(124, 201, 191, .6) url('https://github.com/iplus26/ivnote/raw/master/web-clipper/toggle-icon.png') no-repeat center center / 80%;
- opacity: .7; cursor: pointer;
- transition: all .3s ease-in-out;
- z-index: 9999;
- }
- .ivnote-web-clipper-icon.ivnote-web-clipper-enable {
- opacity: 1; transform: rotate(180deg);
- right: 50px;
- }
- .ivnote-web-clipper-icon:hover {
- opacity: 1;
- transform: rotate(180deg)
- }`);
- (function() {
- 'use strict';
- // Utils =========================================================================
- var classCache = {};
- var _ = {
- hasClass: hasClass,
- addClass: addClass,
- removeClass: removeClass,
- };
- function hasClass(node, name) {
- if (!name) {
- return false;
- }
- return classRE(name).test(className(node));
- }
- function addClass(node, name) {
- if (!name) {
- return node;
- }
- if (!('className' in node)) {
- return;
- }
- var classList = [];
- var cls = className(node); // get node's className
- name.split(/\s+/g).forEach(function(klass) {
- if (!hasClass(node, klass)) {
- classList.push(klass);
- }
- });
- return classList.length && className(node, cls + (cls ? ' ' : '') + classList.join(' '));
- }
- function removeClass(node, name) {
- if (!('className' in node)) {
- return;
- }
- if (name === undefined) {
- return className(node, '');
- }
- let cls = className(node);
- name.split(/\s+/g)
- .forEach((klass) => cls = cls.replace(classRE(klass), ' '));
- className(node, cls.trim());
- }
- function classRE(name) {
- return name in classCache ?
- classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'));
- }
- // access className property while respecting SVGAnimatedString
- function className(el, value) {
- var klass = el.className || '',
- svg = klass && klass.baseVal !== undefined;
- // get className
- if (value === undefined) {
- return svg ? klass.baseVal : klass;
- }
- // set className
- return svg ? (klass.baseVal = value) : (el.className = value);
- }
- // Toggle icon =====================================================================
- var toggle = document.createElement('div');
- toggle.className = "ivnote-web-clipper-icon";
- document.body.appendChild(toggle);
- var enable = false;
- toggle.addEventListener('click', function(e) {
- if (_.hasClass(toggle, 'ivnote-web-clipper-enable')) {
- // turn it off
- _.removeClass(toggle, 'ivnote-web-clipper-enable');
- enable = false;
- } else {
- // turn it on
- _.addClass(toggle, 'ivnote-web-clipper-enable');
- enable = true;
- }
- e.stopPropagation();
- });
- // Manipulate the doms ==============================================================
- document.addEventListener('mouseover', function(e) {
- if (enable) _.addClass(e.target, 'ivnote-web-clipper-hover');
- });
- document.addEventListener('mouseout', function(e) {
- if (enable) {
- _.removeClass(e.target, 'ivnote-web-clipper-hover');
- // To be safe
- var select = document.querySelectorAll('.ivnote-web-clipper-hover');
- Array.prototype.slice.call(select).forEach(function(el) { _.removeClass(el, 'ivnote-web-clipper-hover'); });
- }
- });
- document.addEventListener('click', function(e) {
- if (enable) {
- var el = e.target;
- var fRemoveContent = function() { return '' }
- var fRemoveInlineTag = function(content) { return content }
- var fRemoveBlockTag = function(content) { return '\n\n' + content + '\n\n' }
- var generalConverters = [
- // Originally, toMarkdown keeps the tag name of block level elements.
- {
- filter: ['article', 'div'],
- replacement: fRemoveBlockTag
- },
- {
- filter: ['span'],
- replacement: fRemoveInlineTag
- },
- {
- filter: ['style', 'script'],
- replacement: fRemoveContent
- },
- {
- filter: function(node) {
- return node.nodeName === 'A' && !node.getAttribute('href');
- },
- replacement: fRemoveInlineTag
- },
- // More cases to create the TR spec.
- {
- filter: 'tr',
- replacement: function(content, node) {
- var borderCells = '';
- var alignMap = {
- left: ':--',
- right: '--:',
- center: ':-:'
- };
- var headRow = node.parentNode.nodeName === 'THEAD';
- // Assume ths in first tr in tbody are header cells. (Issue #89)
- headRow = headRow || node.parentNode.nodeName === 'TBODY' && !node.previousSibling && !node.parentNode.previousSibling;
- if (headRow) {
- for (var i = 0; i < node.childNodes.length; i++) {
- var align = node.childNodes[i].attributes.align;
- var border = '---';
- if (align) {
- border = alignMap[align.value] || border;
- }
- borderCells += cell(border, node.childNodes[i]);
- }
- }
- return '\n' + content + (borderCells ? '\n' + borderCells : '');
- }
- }
- ];
- var particularWebsitesConverters = [
- {
- filter: function(node) {
- return node.nodeName === 'BR' && /^(.+\.)?zhihu.com$/gi.test(location.host)
- },
- replacement: function() {
- return '\n\n'
- }
- }
- ];
- var markdown = '*The note is clipped from [here](' + location.href + ').*\n\n' +
- (document.title && !el.querySelector('h1') ? '#' + document.title + '\n\n' : '') +
- toMarkdown(el.outerHTML, {
- gfm: true,
- converters: particularWebsitesConverters.concat(generalConverters)
- });
- copyTextToClipboard(markdown);
- }
- });
- // Internal function of to-markdown
- function cell (content, node) {
- var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node);
- var prefix = ' ';
- if (index === 0) prefix = '| ';
- return prefix + content + ' |';
- }
- // Copy to the clipboard ============================================================
- // Copyright (c) Dean Taylor. Original post: http://stackoverflow.com/a/30810322/4158282
- function copyTextToClipboard(text) {
- var textArea = document.createElement("textarea");
- textArea.style.position = 'fixed';
- textArea.style.top = 0;
- textArea.style.left = 0;
- textArea.style.width = '2em';
- textArea.style.height = '2em';
- textArea.style.padding = 0;
- textArea.style.border = 'none';
- textArea.style.outline = 'none';
- textArea.style.boxShadow = 'none';
- textArea.style.background = 'transparent';
- textArea.value = text;
- document.body.appendChild(textArea);
- textArea.select();
- try {
- var successful = document.execCommand('copy');
- var msg = successful ? 'successful' : 'unsuccessful';
- console.log('Copying text command was ' + msg);
- } catch (err) {
- console.log('Oops, unable to copy');
- }
- document.body.removeChild(textArea);
- }
- })();