diff --git a/src/resources/common.css b/src/resources/common.css
index 9551995b..6518f21d 100644
--- a/src/resources/common.css
+++ b/src/resources/common.css
@@ -208,3 +208,40 @@ span.modal-close:focus {
content: attr(data-anchor-icon);
}
/* Anchor */
+
+/* Button */
+.vnote-btn {
+ position: relative;
+ display: inline-block;
+ padding: 6px 12px;
+ font-size: 13px;
+ font-weight: 700;
+ line-height: 20px;
+ white-space: nowrap;
+ vertical-align: middle;
+ cursor: pointer;
+ border: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-appearance: none;
+}
+
+.vnote-copy-clipboard-btn {
+ transition: opacity .3s ease-in-out;
+ opacity: 0;
+ padding: 2px 6px;
+ position: absolute;
+ top: 5px;
+ right: 5px;
+}
+
+pre:hover .vnote-copy-clipboard-btn {
+ opacity: 1;
+}
+
+pre.vnote-snippet {
+ position: relative;
+}
+/* Button */
diff --git a/src/resources/hoedown.js b/src/resources/hoedown.js
index 1ac593f7..308e8612 100644
--- a/src/resources/hoedown.js
+++ b/src/resources/hoedown.js
@@ -91,6 +91,7 @@ var updateHtml = function(html) {
}
addClassToCodeBlock();
+ addCopyButtonToCodeBlock();
renderCodeBlockLineNumber();
// If you add new logics after handling MathJax, please pay attention to
diff --git a/src/resources/markdown-it.js b/src/resources/markdown-it.js
index 58eff9da..0435c361 100644
--- a/src/resources/markdown-it.js
+++ b/src/resources/markdown-it.js
@@ -175,6 +175,7 @@ var updateText = function(text) {
renderPlantUML('lang-puml');
renderGraphviz('lang-dot');
addClassToCodeBlock();
+ addCopyButtonToCodeBlock();
renderCodeBlockLineNumber();
// If you add new logics after handling MathJax, please pay attention to
diff --git a/src/resources/markdown_template.html b/src/resources/markdown_template.html
index 4e2f36b2..0850bb3d 100644
--- a/src/resources/markdown_template.html
+++ b/src/resources/markdown_template.html
@@ -27,6 +27,7 @@
+
diff --git a/src/resources/markdown_template.js b/src/resources/markdown_template.js
index ea1cde5b..15355043 100644
--- a/src/resources/markdown_template.js
+++ b/src/resources/markdown_template.js
@@ -23,6 +23,8 @@ var VPlantUMLDivClass = 'plantuml-diagram';
var VMetaDataCodeClass = 'markdown-metadata';
var VMarkRectDivClass = 'mark-rect';
+var hljsClass = 'hljs';
+
var VPreviewMode = false;
if (typeof VEnableMermaid == 'undefined') {
@@ -272,6 +274,10 @@ window.onwheel = function(e) {
var skipScrollCheckRange = null;
+window.addEventListener('load', function() {
+ new ClipboardJS('.vnote-copy-clipboard-btn');
+});
+
window.onscroll = function() {
if (g_muteScroll) {
return;
@@ -1247,7 +1253,6 @@ var renderCodeBlockLineNumber = function() {
};
var addClassToCodeBlock = function() {
- var hljsClass = 'hljs';
var codes = document.getElementsByTagName('code');
for (var i = 0; i < codes.length; ++i) {
var code = codes[i];
@@ -1267,6 +1272,23 @@ var addClassToCodeBlock = function() {
}
};
+var addCopyButtonToCodeBlock = function() {
+ var codes = document.getElementsByClassName(hljsClass);
+ for (var i = 0; i < codes.length; ++i) {
+ var code = codes[i];
+ var pare = code.parentElement;
+ pare.classList.add('vnote-snippet');
+
+ var btn = document.createElement('button');
+ btn.innerHTML = '📋';
+ btn.classList.add('vnote-btn');
+ btn.classList.add('vnote-copy-clipboard-btn');
+ btn.setAttribute('type', 'button');
+ btn.setAttribute('data-clipboard-text', code.textContent);
+ code.insertAdjacentElement('beforebegin', btn);
+ }
+};
+
var listContainsRegex = function(strs, exp) {
for (var i = 0, len = strs.length; i < len; ++i) {
if (exp.test(strs[i])) {
diff --git a/src/resources/marked.js b/src/resources/marked.js
index 206cef9c..78688edf 100644
--- a/src/resources/marked.js
+++ b/src/resources/marked.js
@@ -71,6 +71,7 @@ var updateText = function(text) {
renderPlantUML('language-puml');
renderGraphviz('language-dot');
addClassToCodeBlock();
+ addCopyButtonToCodeBlock();
renderCodeBlockLineNumber();
// If you add new logics after handling MathJax, please pay attention to
diff --git a/src/resources/showdown.js b/src/resources/showdown.js
index 6e37b5ee..ea04e2a6 100644
--- a/src/resources/showdown.js
+++ b/src/resources/showdown.js
@@ -126,6 +126,7 @@ var updateText = function(text) {
renderPlantUML('language-puml');
renderGraphviz('language-dot');
addClassToCodeBlock();
+ addCopyButtonToCodeBlock();
renderCodeBlockLineNumber();
// If you add new logics after handling MathJax, please pay attention to
diff --git a/src/utils/clipboard.js/README.md b/src/utils/clipboard.js/README.md
new file mode 100644
index 00000000..61bfead3
--- /dev/null
+++ b/src/utils/clipboard.js/README.md
@@ -0,0 +1,2 @@
+# [clipboard.js](https://github.com/zenorocha/clipboard.js)
+v2.0.4
diff --git a/src/utils/clipboard.js/clipboard.min.js b/src/utils/clipboard.js/clipboard.min.js
new file mode 100644
index 00000000..02c549e3
--- /dev/null
+++ b/src/utils/clipboard.js/clipboard.min.js
@@ -0,0 +1,7 @@
+/*!
+ * clipboard.js v2.0.4
+ * https://zenorocha.github.io/clipboard.js
+ *
+ * Licensed MIT © Zeno Rocha
+ */
+!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(n){var o={};function r(t){if(o[t])return o[t].exports;var e=o[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}return r.m=n,r.c=o,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=0)}([function(t,e,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n\n%1\n\n").arg(js);
}
+ // Clipboard.js.
+ {
+ const QString clipboardjs(":/utils/clipboard.js/clipboard.min.js");
+ QString js = VUtils::readFileFromDisk(clipboardjs);
+ extra += QString("\n").arg(js);
+ extra += "\n";
+ }
+
if (!extra.isEmpty()) {
templ.replace(HtmlHolder::c_extraHolder, extra);
}
diff --git a/src/vnote.qrc b/src/vnote.qrc
index e4cc7774..d7f492af 100644
--- a/src/vnote.qrc
+++ b/src/vnote.qrc
@@ -287,5 +287,6 @@
resources/icons/table.svg
utils/wavedrom/wavedrom.min.js
utils/wavedrom/wavedrom-theme.js
+ utils/clipboard.js/clipboard.min.js