すたすた式
Blogger QooQ
pre要素をターゲットにしてコピーボタンを作成してみました。
コピーボタンが常時表示するタイプとホバーしたときに表示するタイプを作成しました。
基本のコードはソースコードをワンクリックで選択 - 7cc@はてなブログさん。
マウスオーバー(ホバー)したときにボタンが表示されるタイプのJavaScriptはコード用コピーボタンをカスタマイズ(Clipboard API対応) | IB-Noteさん、CSSはweb.devをそれぞれ参考にさせていただきました。ありがとうございます。
また、Tabler Icons - 800+ Highly customizable free SVG iconsのSVGアイコン(copyとcheckbox)をCSSの擬似要素として使用しました。
Document.execCommand()は廃止ということなので、かわりにnavigator.clipboard.writeText()を使いました。
コードを一部変更しました。
preタグの検索範囲の変更
const preTag = document.querySelectorAll("pre");
↓↓↓
const preTag = Blog1.querySelectorAll(".post-body pre");
JavaScript
<script> // コピーボタン /*! https://sutasutashiki.blogspot.com/2021/07/create-highlight-js-copy-button.html */ // Reference /*! https://7cc.hatenadiary.jp/entry/2013/07/04/023751 */ //<![CDATA[ "use strict"; (() => { const preTag = Blog1.querySelectorAll(".post-body pre"); for (let i = 0; i < preTag.length; i++) { const btn = document.createElement("button"); btn.className = "copy-button"; btn.textContent = "COPY"; //btn.textContent = "COPY 📋"; preTag[i].appendChild(btn); btn.addEventListener( "click", () => { const Selection = window.getSelection(); const codeTag = btn.parentNode; Selection.selectAllChildren(codeTag); Selection.extend(codeTag, codeTag.childNodes.length - 1); navigator.clipboard.writeText(Selection); Selection.removeAllRanges(); btn.textContent = "COPIED!"; //btn.textContent = "COPIED! ✅"; btn.classList.add("copy-button--after"); setTimeout(() => { btn.textContent = "COPY"; btn.classList.remove("copy-button--after"); }, 1200); }, false ); } })(); //]]> </script>
<script> // コピーボタン // Reference /*! https://7cc.hatenadiary.jp/entry/2013/07/04/023751 */ //<![CDATA[ document.addEventListener("DOMContentLoaded", () => { const preTag = document.querySelectorAll("pre"); for (let i = 0; i < preTag.length; i++) { let btn = document.createElement("button"); btn.className = "copy-button"; btn.textContent = "COPY"; //btn.textContent = "COPY 📋"; preTag[i].appendChild(btn); btn.addEventListener( "click", () => { const Selection = window.getSelection(); const codeTag = btn.parentNode; Selection.selectAllChildren(codeTag); Selection.extend(codeTag, codeTag.childNodes.length - 1); navigator.clipboard.writeText(Selection); Selection.removeAllRanges(); btn.textContent = "COPIED!"; //btn.textContent = "COPIED! ✅"; btn.classList.add("copy-button--after"); setTimeout(() => { btn.textContent = "COPY"; btn.classList.remove("copy-button--after"); }, 1200); }, false ); } }); //]]> </script>
CSS
2021年8月12日:Firefoxで表示したときに文字とアイコンがズレていたのでCSSを修正しました。
具体的には.copy-button::afterと.copy-button--after::afterのvertical-alignの値をtext-bottomに変更しました。
.copy-button::after
.copy-button--after::after
vertical-align
text-bottom
/***************************************** コピーボタン *****************************************/ .hljs { padding: 1.1em 0.5em; } pre { position: relative; } .copy-button { position: absolute; top: 0.1em; right: 0.1em; cursor: pointer; background-color: #363948; color: #fff; padding: 0.1em; border: none; } .copy-button:hover { background-color: #3b1691; transition: 1s; } .copy-button--after { background-color: #3b1691; } /* @tablericons - https://tablericons.com/ Copyright (c) 2020 Paweł Kuna Released under the MIT license Licence - https://github.com/tabler/tabler-icons/blob/master/LICENSE (MIT License) */ .copy-button::after { content: ""; -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-copy' viewBox='0 0 24 24' stroke-width='2' stroke='%23ffffff' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Crect x='8' y='8' width='12' height='12' rx='2' /%3E%3Cpath d='M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2' /%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-copy' viewBox='0 0 24 24' stroke-width='2' stroke='%23ffffff' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Crect x='8' y='8' width='12' height='12' rx='2' /%3E%3Cpath d='M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2' /%3E%3C/svg%3E"); display: inline-block; height: 1.5em; width: 1.5em; vertical-align: text-bottom; margin-left: 0.5em; background-color: #fff; } .copy-button--after::after { content: ""; -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-checkbox' width='20' height='20' viewBox='0 0 24 24' stroke-width='2' stroke='%23ffffff' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpolyline points='9 11 12 14 20 6' /%3E%3Cpath d='M20 12v6a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h9' /%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-checkbox' width='20' height='20' viewBox='0 0 24 24' stroke-width='2' stroke='%23ffffff' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpolyline points='9 11 12 14 20 6' /%3E%3Cpath d='M20 12v6a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h9' /%3E%3C/svg%3E"); display: inline-block; height: 1.5em; width: 1.5em; vertical-align:text-bottom; margin-left: 0.5em; background-color: #7fff00; }
SVGアイコンを利用できない場合は簡易的ですが絵文字が利用出来ます。
//btn.textContent = "COPY"; btn.textContent = "COPY 📋";
btn.textContent = "COPIED! ✅"; //btn.classList.add("copy-button--after"); setTimeout(() => { //btn.textContent = "COPY"; btn.textContent = "COPY 📋"; //btn.classList.remove("copy-button--after"); }, 1200);
<script> // コピーボタン /*! https://sutasutashiki.blogspot.com/2021/07/create-highlight-js-copy-button.html */ // Reference /*! https://7cc.hatenadiary.jp/entry/2013/07/04/023751 */ /*! https://itblogger-note.blogspot.com/2021/03/copy-button-customize.html */ //<![CDATA[ "use strict"; (() => { const btn = document.createElement("button"); btn.id = "copy-button"; btn.className = "copy-button"; btn.setAttribute("aria-label", "Copy code"); const toolTip = document.createElement("span"); toolTip.id = "tooltip"; toolTip.className = "tooltip"; toolTip.textContent = "コピーボタン"; toolTip.setAttribute("role", "tooltip"); btn.addEventListener("click", () => { const selection = window.getSelection(); const codeTag = btn.parentNode; selection.selectAllChildren(codeTag); selection.extend(codeTag, codeTag.childNodes.length - 1); navigator.clipboard.writeText(selection); selection.removeAllRanges(); toolTip.textContent = "コピーしました!"; btn.classList.remove("copy-button--after"); setTimeout(() => { btn.classList.add("copy-button--after"); }, 1200); }); const preTag = Blog1.querySelectorAll(".post-body pre"); for (let i = 0; i < preTag.length; i++) { preTag[i].addEventListener("mouseenter", () => { btn.appendChild(toolTip); preTag[i].appendChild(btn); }); btn.addEventListener("mouseover", () => { toolTip.textContent = "コピーボタン"; }); preTag[i].addEventListener("mouseleave", () => { btn.remove(); }); } })(); //]]> </script>
2021年8月12日:Firefoxで上のGIF画像のような動きが出来ていないことを確認したのでJavaScriptを修正しました。
具体的にはaddEventListenerのmouseoverをmouseenterに変更しました。
addEventListener
mouseover
mouseenter
<script> // コピーボタン // Reference /*! https://7cc.hatenadiary.jp/entry/2013/07/04/023751 */ /*! https://itblogger-note.blogspot.com/2021/03/copy-button-customize.html */ //<![CDATA[ document.addEventListener("DOMContentLoaded", () => { const btn = document.createElement("button"); btn.id = "copy-button"; btn.className = "copy-button"; btn.setAttribute("aria-label", "Copy code"); const toolTip = document.createElement("span"); toolTip.id = "tooltip"; toolTip.className = "tooltip"; toolTip.textContent = "コピーボタン"; toolTip.setAttribute("role", "tooltip"); btn.addEventListener("click", () => { const selection = window.getSelection(); const codeTag = btn.parentNode; selection.selectAllChildren(codeTag); selection.extend(codeTag, codeTag.childNodes.length - 1); navigator.clipboard.writeText(selection); selection.removeAllRanges(); toolTip.textContent = "コピーしました!"; btn.classList.remove("copy-button--after"); setTimeout(() => { toolTip.textContent = "コピーボタン"; btn.classList.add("copy-button--after"); }, 1200); }); const preTag = document.querySelectorAll("pre"); for (let i = 0; i < preTag.length; i++) { preTag[i].addEventListener("mouseenter", () => { preTag[i].appendChild(btn); btn.appendChild(toolTip); }); preTag[i].addEventListener("mouseleave", () => { btn.remove(); }); } }); //]]> </script>
/***************************************** コピーボタン *****************************************/ .hljs { padding: 1.3em 0.5em; } pre { position: relative; } .copy-button { position: absolute; top: 0.2em; right: 0.2em; cursor: pointer; background: 0 0; border-color: transparent; border-radius: 50%; padding: 0.4em; box-sizing: border-box; display: inline-flex; justify-content: center; align-items: center; } .copy-button:hover { background-color: rgb(122 255 148 / 20%); opacity: 1; } .copy-button:hover:focus { box-shadow: 0 0 0 1px #3744ff; outline: 0; } .copy-button:hover:active { background-color: rgb(122 255 148 / 40%); opacity: 1; } .copy-button--after:hover:focus { box-shadow: none; } #tooltip { background: #fff; border-radius: 3px; color: #000; font-weight: bold; font-size: 13px; font-family: Segoe UI, system-ui, -apple-system, sans-serif; left: 100%; letter-spacing: 0.3px; opacity: 0; padding: 6px 8px; pointer-events: none; position: absolute; text-transform: none; top: calc(100% + 6px); transform: translateX(-100%) scale(0.85); transform-origin: top right; transition: opacity 75ms, transform 0s 75ms, visibility 0s 75ms; visibility: hidden; white-space: nowrap; z-index: 1; } :hover > #tooltip { opacity: 0.77; transform: translateX(-100%) scale(1); transition: opacity 0.15s 0.3s, transform 0.15s 0.3s, visibility 0s; visibility: visible; } /* @tablericons - https://tablericons.com/ Copyright (c) 2020 Paweł Kuna Released under the MIT license Licence - https://github.com/tabler/tabler-icons/blob/master/LICENSE (MIT License) */ .copy-button::before { content: ""; -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-copy' viewBox='0 0 24 24' stroke-width='2' stroke='%23ffffff' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Crect x='8' y='8' width='12' height='12' rx='2' /%3E%3Cpath d='M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2' /%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-copy' viewBox='0 0 24 24' stroke-width='2' stroke='%23ffffff' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Crect x='8' y='8' width='12' height='12' rx='2' /%3E%3Cpath d='M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2' /%3E%3C/svg%3E"); display: block; height: 2em; width: 2em; background-color: #fff; }
JavaScriptの設置場所はとくに問題がなければ</body>の上あたりでいいと思います。
</body>
サイト内検索に使ってください 🐤
© 2015 すたすた式
Enjoy!👍
QooQ
コメントなし:
コメントを投稿