8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ChatGPTのコピペってイラッとするよね

Posted at

ChatGPTあるある

みなさんもこんな感じでChatGPTを活用していることかと思います。

image.png

さっすがChatGPTちゃん!優秀ー!!
教えてもらった内容をコピーしてメモしとこう。

想像だとこんな感じになるはず ↓

必要なもの
・卵
・フライパン
・油(サラダ油、バター、オリーブオイルなどお好みで)
・フライ返し
・塩やこしょう(お好みで)


突きつけられる非情な現実 (スタイルが全て消えている)↓

必要なもの

フライパン
油(サラダ油、バター、オリーブオイルなどお好みで)
フライ返し
塩やこしょう(お好みで)

えっ、、、体裁が崩れてるというか消えている、、あの優秀なChatGPTちゃんがまさかそんな訳、、
うっ、うそだーー!!

タイトル部分の装飾がコピーできないことは薄々分かってた。
だけど、リストの点(・)くらいはコピーできてたっていいじゃないか!!

このぐらいなら手動で治すけど、分量が多かったりすると修正するのは無理!
ChatGPTへの返信も、こちらで体裁を修正しないといけないとか面倒すぎヽ(`Д´)ノ

(ちなみに、これはテキストエディタの話であり、Wordなどのビジュアルエディタなら体裁もコピーしてくれます。) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233276/3b82ffe8-dc41-35f6-a4f5-48de2d61d20b.png)

というわけで。

ChatGPTで選択した範囲をMarkdown形式でコピーするブックマークレットを作りました。

ソースコード

CopyAsMd.js
javascript:!function(){var e=function(){"use strict";function e(e,n){return Array(n+1).join(e)}var n=["ADDRESS","ARTICLE","ASIDE","AUDIO","BLOCKQUOTE","BODY","CANVAS","CENTER","DD","DIR","DIV","DL","DT","FIELDSET","FIGCAPTION","FIGURE","FOOTER","FORM","FRAMESET","H1","H2","H3","H4","H5","H6","HEADER","HGROUP","HR","HTML","ISINDEX","LI","MAIN","MENU","NAV","NOFRAMES","NOSCRIPT","OL","OUTPUT","P","PRE","SECTION","TABLE","TBODY","TD","TFOOT","TH","THEAD","TR","UL"];function t(e){return a(e,n)}var r=["AREA","BASE","BR","COL","COMMAND","EMBED","HR","IMG","INPUT","KEYGEN","LINK","META","PARAM","SOURCE","TRACK","WBR"];function i(e){return a(e,r)}var o=["A","TABLE","THEAD","TBODY","TFOOT","TH","TD","IFRAME","SCRIPT","AUDIO","VIDEO"];function a(e,n){return 0<=n.indexOf(e.nodeName)}function l(e,n){return e.getElementsByTagName&&n.some(function(n){return e.getElementsByTagName(n).length})}var u={};function c(e){return e?e.replace(/(\n+\s*)+/g,"\n"):""}function s(e){for(var n in this.options=e,this._keep=[],this._remove=[],this.blankRule={replacement:e.blankReplacement},this.keepReplacement=e.keepReplacement,this.defaultRule={replacement:e.defaultReplacement},this.array=[],e.rules)this.array.push(e.rules[n])}function f(e,n,t){for(var r=0;r<e.length;r++){var i=e[r];if(function(e,n,t){var r=e.filter;if("string"==typeof r){if(r===n.nodeName.toLowerCase())return!0}else if(Array.isArray(r)){if(-1<r.indexOf(n.nodeName.toLowerCase()))return!0}else{if("function"!=typeof r)throw TypeError("`filter` needs to be a string, array, or function");if(r.call(e,n,t))return!0}}(i,n,t))return i}}function d(e){var n=e.nextSibling||e.parentNode;return e.parentNode.removeChild(e),n}function p(e,n,t){return e&&e.parentNode===n||t(n)?n.nextSibling||n.parentNode:n.firstChild||n.nextSibling||n.parentNode}u.paragraph={filter:"p",replacement:function(e){return"\n\n"+e+"\n\n"}},u.lineBreak={filter:"br",replacement:function(e,n,t){return t.br+"\n"}},u.heading={filter:["h1","h2","h3","h4","h5","h6"],replacement:function(n,t,r){return t=Number(t.nodeName.charAt(1)),"setext"===r.headingStyle&&t<3?"\n\n"+n+"\n"+e(1===t?"=":"-",n.length)+"\n\n":"\n\n"+e("#",t)+" "+n+"\n\n"}},u.blockquote={filter:"blockquote",replacement:function(e){return"\n\n"+(e=(e=e.replace(/^\n+|\n+$/g,"")).replace(/^/gm,"> "))+"\n\n"}},u.list={filter:["ul","ol"],replacement:function(e,n){var t=n.parentNode;return"LI"===t.nodeName&&t.lastElementChild===n?"\n"+e:"\n\n"+e+"\n\n"}},u.listItem={filter:"li",replacement:function(e,n,t){e=e.replace(/^\n+/,"").replace(/\n+$/,"\n").replace(/\n/gm,"\n    ");var r=t.bulletListMarker+"   ",i=n.parentNode;return"OL"===i.nodeName&&(t=i.getAttribute("start"),i=Array.prototype.indexOf.call(i.children,n),r=(t?Number(t)+i:i+1)+".  "),r+e+(n.nextSibling&&!/\n$/.test(e)?"\n":"")}},u.indentedCodeBlock={filter:function(e,n){return"indented"===n.codeBlockStyle&&"PRE"===e.nodeName&&e.firstChild&&"CODE"===e.firstChild.nodeName},replacement:function(e,n,t){return"\n\n    "+n.firstChild.textContent.replace(/\n/g,"\n    ")+"\n\n"}},u.fencedCodeBlock={filter:function(e,n){return"fenced"===n.codeBlockStyle&&"PRE"===e.nodeName&&e.firstChild&&"CODE"===e.firstChild.nodeName},replacement:function(n,t,r){for(var i,o=((t.firstChild.getAttribute("class")||"").match(/language-(\S+)/)||[null,""])[1],a=t.firstChild.textContent,r=r.fence.charAt(0),l=3,u=RegExp("^"+r+"{3,}","gm");i=u.exec(a);)i[0].length>=l&&(l=i[0].length+1);return"\n\n"+(r=e(r,l))+o+"\n"+a.replace(/\n$/,"")+"\n"+r+"\n\n"}},u.horizontalRule={filter:"hr",replacement:function(e,n,t){return"\n\n"+t.hr+"\n\n"}},u.inlineLink={filter:function(e,n){return"inlined"===n.linkStyle&&"A"===e.nodeName&&e.getAttribute("href")},replacement:function(e,n){var t=n.getAttribute("href"),n=c(n.getAttribute("title"));return"["+e+"]("+t+(n=n&&' "'+n+'"')+")"}},u.referenceLink={filter:function(e,n){return"referenced"===n.linkStyle&&"A"===e.nodeName&&e.getAttribute("href")},replacement:function(e,n,t){var r=n.getAttribute("href"),i=(i=c(n.getAttribute("title")))&&' "'+i+'"';switch(t.linkReferenceStyle){case"collapsed":a="["+e+"][]",l="["+e+"]: "+r+i;break;case"shortcut":a="["+e+"]",l="["+e+"]: "+r+i;break;default:var o=this.references.length+1,a="["+e+"]["+o+"]",l="["+o+"]: "+r+i}return this.references.push(l),a},references:[],append:function(e){var n="";return this.references.length&&(n="\n\n"+this.references.join("\n")+"\n\n",this.references=[]),n}},u.emphasis={filter:["em","i"],replacement:function(e,n,t){return e.trim()?t.emDelimiter+e+t.emDelimiter:""}},u.strong={filter:["strong","b"],replacement:function(e,n,t){return e.trim()?t.strongDelimiter+e+t.strongDelimiter:""}},u.code={filter:function(e){var n=e.previousSibling||e.nextSibling,n="PRE"===e.parentNode.nodeName&&!n;return"CODE"===e.nodeName&&!n},replacement:function(e){if(!e)return"";e=e.replace(/\r?\n|\r/g," ");for(var n=/^`|^ .*?[^ ].* $|`$/.test(e)?" ":"",t="`",r=e.match(/`+/gm)||[];-1!==r.indexOf(t);)t+="`";return t+n+e+n+t}},u.image={filter:"img",replacement:function(e,n){var t=c(n.getAttribute("alt")),r=n.getAttribute("src")||"",n=c(n.getAttribute("title"));return r?"!["+t+"]("+r+(n?' "'+n+'"':"")+")":""}},s.prototype={add:function(e,n){this.array.unshift(n)},keep:function(e){this._keep.unshift({filter:e,replacement:this.keepReplacement})},remove:function(e){this._remove.unshift({filter:e,replacement:function(){return""}})},forNode:function(e){var n;return e.isBlank?this.blankRule:(n=f(this.array,e,this.options))||(n=f(this._keep,e,this.options))||(n=f(this._remove,e,this.options))?n:this.defaultRule},forEach:function(e){for(var n=0;n<this.array.length;n++)e(this.array[n],n)}};var h,g="undefined"!=typeof window?window:{},m=!function(){var e=g.DOMParser,n=!1;try{(new e).parseFromString("","text/html")&&(n=!0)}catch(t){}return n}()?(!function(){var e=!1;try{document.implementation.createHTMLDocument("").open()}catch(n){window.ActiveXObject&&(e=!0)}return e}()?v.prototype.parseFromString=function(e){var n=document.implementation.createHTMLDocument("");return n.open(),n.write(e),n.close(),n}:v.prototype.parseFromString=function(e){var n=new window.ActiveXObject("htmlfile");return n.designMode="on",n.open(),n.write(e),n.close(),n},v):g.DOMParser;function v(){}function A(e,n){return function(e){var n=e.element,t=e.isBlock,r=e.isVoid,i=e.isPre||function(e){return"PRE"===e.nodeName};if(n.firstChild&&!i(n)){for(var o=null,a=!1,l=p(c=null,n,i);l!==n;){if(3===l.nodeType||4===l.nodeType){var u=l.data.replace(/[ \r\n\t]+/g," ");if(!(u=o&&!/ $/.test(o.data)||a||" "!==u[0]?u:u.substr(1))){l=d(l);continue}l.data=u,o=l}else{if(1!==l.nodeType){l=d(l);continue}t(l)||"BR"===l.nodeName?(o&&(o.data=o.data.replace(/ $/,"")),o=null,a=!1):r(l)||i(l)?a=(o=null,!0):o&&(a=!1)}var u=p(c,l,i),c=l,l=u}o&&(o.data=o.data.replace(/ $/,""),o.data||d(o))}}({element:e="string"==typeof e?(h=h||new m).parseFromString('<x-turndown id="turndown-root">'+e+"</x-turndown>","text/html").getElementById("turndown-root"):e.cloneNode(!0),isBlock:t,isVoid:i,isPre:n.preformattedCode?y:null}),e}function y(e){return"PRE"===e.nodeName||"CODE"===e.nodeName}function N(e,n){var u,c,s,f;return e.isBlock=t(e),e.isCode="CODE"===e.nodeName||e.parentNode.isCode,e.isBlank=!i(u=e)&&!a(c=u,o)&&/^\s*$/i.test(u.textContent)&&!l(s=u,r)&&!l(f=u,o),e.flankingWhitespace=function(e,n){if(e.isBlock||n.preformattedCode&&e.isCode)return{leading:"",trailing:""};var t,r={leading:(t=(t=e.textContent).match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/))[1],leadingAscii:t[2],leadingNonAscii:t[3],trailing:t[4],trailingNonAscii:t[5],trailingAscii:t[6]};return r.leadingAscii&&C("left",e,n)&&(r.leading=r.leadingNonAscii),r.trailingAscii&&C("right",e,n)&&(r.trailing=r.trailingNonAscii),{leading:r.leading,trailing:r.trailing}}(e,n),e}function C(e,n,r){var i,o,n="left"===e?(i=n.previousSibling,/ $/):(i=n.nextSibling,/^ /);return i&&(3===i.nodeType?o=n.test(i.nodeValue):r.preformattedCode&&"CODE"===i.nodeName?o=!1:1!==i.nodeType||t(i)||(o=n.test(i.textContent))),o}var E=Array.prototype.reduce,T=[[/\\/g,"\\\\"],[/\*/g,"\\*"],[/^-/g,"\\-"],[/^\+ /g,"\\+ "],[/^(=+)/g,"\\$1"],[/^(#{1,6}) /g,"\\$1 "],[/`/g,"\\`"],[/^~~~/g,"\\~~~"],[/\[/g,"\\["],[/\]/g,"\\]"],[/^>/g,"\\>"],[/_/g,"\\_"],[/^(\d+)\. /g,"$1\\. "]];function R(e){if(!(this instanceof R))return new R(e);this.options=function(e){for(var n=1;n<arguments.length;n++){var t,r=arguments[n];for(t in r)r.hasOwnProperty(t)&&(e[t]=r[t])}return e}({},{rules:u,headingStyle:"setext",hr:"* * *",bulletListMarker:"*",codeBlockStyle:"indented",fence:"```",emDelimiter:"_",strongDelimiter:"**",linkStyle:"inlined",linkReferenceStyle:"full",br:"  ",preformattedCode:!1,blankReplacement:function(e,n){return n.isBlock?"\n\n":""},keepReplacement:function(e,n){return n.isBlock?"\n\n"+n.outerHTML+"\n\n":n.outerHTML},defaultReplacement:function(e,n){return n.isBlock?"\n\n"+e+"\n\n":e}},e),this.rules=new s(this.options)}function k(e){var n=this;return E.call(e.childNodes,function(e,t){var r="";return 3===(t=new N(t,n.options)).nodeType?r=t.isCode?t.nodeValue:n.escape(t.nodeValue):1===t.nodeType&&(r=(function(e){var n=this.rules.forNode(e),t=k.call(this,e),r=e.flankingWhitespace;return(r.leading||r.trailing)&&(t=t.trim()),r.leading+n.replacement(t,e,this.options)+r.trailing}).call(n,t)),b(e,r)},"")}function b(e,n){var t=function(e){for(var n=e.length;0<n&&"\n"===e[n-1];)n--;return e.substring(0,n)}(e),r=n.replace(/^\n*/,""),n=Math.max(e.length-t.length,n.length-r.length);return t+"\n\n".substring(0,n)+r}return R.prototype={turndown:function(e){var n;if(null==(n=e)||"string"!=typeof n&&(!n.nodeType||1!==n.nodeType&&9!==n.nodeType&&11!==n.nodeType))throw TypeError(e+" is not a string, or an element/document/fragment node.");return""===e?"":(function(e){var n=this;return this.rules.forEach(function(t){"function"==typeof t.append&&(e=b(e,t.append(n.options)))}),e.replace(/^[\t\r\n]+/,"").replace(/[\t\r\n\s]+$/,"")}).call(this,e=k.call(this,new A(e,this.options)))},use:function(e){if(Array.isArray(e))for(var n=0;n<e.length;n++)this.use(e[n]);else{if("function"!=typeof e)throw TypeError("plugin must be a Function or an Array of Functions");e(this)}return this},addRule:function(e,n){return this.rules.add(e,n),this},keep:function(e){return this.rules.keep(e),this},remove:function(e){return this.rules.remove(e),this},escape:function(e){return T.reduce(function(e,n){return e.replace(n[0],n[1])},e)}},R}();let n=window.getSelection();if(n.rangeCount>0){let t=n.getRangeAt(0),r=document.createElement("div");r.appendChild(t.cloneContents());let i=r.innerHTML,o=function n(t){let r=new e;return r.turndown(t)}(i);!function e(n){let t=document.createElement("textarea");t.value=n,document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t)}(o),alert("Markdown形式でクリップボードにコピーされました!")}else alert("テキストを選択してください。")}();

ブックマークレットの登録方法

登録は他のブックマークレット同じで、ざっくりこんな感じ。

  • ブラウザのブックマークバーに右クリックして「ブックマークを追加」を選択。
  • 名前を付ける。なんでもOK(例:「HTML to Markdown」)。
  • URLフィールドに上記のコードを貼り付ける。

ブックマークレットの使用方法

使い方は簡単。

  • 変換したいテキストを選択。
  • ブックマークバーの登録したブックマークレット(HTML to Markdown)をクリック。
  • 選択した範囲のHTMLがMarkdown形式でクリップボードにコピーされる。
  • 少しだけ幸せになれる!!

image.png

実行結果

こんな感じになる。

材料

  • 卵: 1個(またはお好みの数)
  • サラダ油またはバター: 適量
  • 塩: 少々
  • コショウ: 少々(お好みで)

Markdown形式でコピーするので、ブラウザの表示とは異なり、タイトルはシャープ(#)、点はアスタリスク(*)で表現される。
だけど、Markdownの方が構造化されていて、ChatGPTにコピペで渡すときとかも解釈してもらいやすいし、エンジニアにとってはこっちの方が使い勝手良いはず。

ちなみに

ChatGPTの前提でここまで書いてきたけど、HTMLの他のサイトでも動く。
もちろんQiitaでも動く。
あら便利。

ソースコードについて解説。

処理はシンプルで、

  1. HTMLを取得し、
  2. HTMLからMarkdownに変換して、
  3. Markdownのクリップボードに入れる

という流れ。

HTMLにからMarkdwonに変換するために外部のライブラリとしてTurndown (https://cdnjs.cloudflare.com/ajax/libs/turndown/7.1.1/turndown.min.js) を参照させたらうまく動かなかった。
調べたところセキュリティポリシーによるものだったので、参照せずにソースコードに直接埋め込んでいる。
→「Turndownライブラリのコードを直接埋め込む」という部分

minifyする前のソースコードはこれ。

CopyAsMd.js
javascript: (function () {
    function htmlToMarkdown(html) {
        const turndownService = new TurndownService();
        return turndownService.turndown(html);
    }

    function copyToClipboard(text) {
        const textarea = document.createElement("textarea");
        textarea.value = text;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand("copy");
        document.body.removeChild(textarea);
    }

    /* Turndownライブラリのコードを直接埋め込む(ここから) */
    var TurndownService = function () { "use strict"; function u(e, n) { return Array(n + 1).join(e) } var n = ["ADDRESS", "ARTICLE", "ASIDE", "AUDIO", "BLOCKQUOTE", "BODY", "CANVAS", "CENTER", "DD", "DIR", "DIV", "DL", "DT", "FIELDSET", "FIGCAPTION", "FIGURE", "FOOTER", "FORM", "FRAMESET", "H1", "H2", "H3", "H4", "H5", "H6", "HEADER", "HGROUP", "HR", "HTML", "ISINDEX", "LI", "MAIN", "MENU", "NAV", "NOFRAMES", "NOSCRIPT", "OL", "OUTPUT", "P", "PRE", "SECTION", "TABLE", "TBODY", "TD", "TFOOT", "TH", "THEAD", "TR", "UL"]; function o(e) { return l(e, n) } var r = ["AREA", "BASE", "BR", "COL", "COMMAND", "EMBED", "HR", "IMG", "INPUT", "KEYGEN", "LINK", "META", "PARAM", "SOURCE", "TRACK", "WBR"]; function i(e) { return l(e, r) } var a = ["A", "TABLE", "THEAD", "TBODY", "TFOOT", "TH", "TD", "IFRAME", "SCRIPT", "AUDIO", "VIDEO"]; function l(e, n) { return 0 <= n.indexOf(e.nodeName) } function c(n, e) { return n.getElementsByTagName && e.some(function (e) { return n.getElementsByTagName(e).length }) } var t = {}; function s(e) { return e ? e.replace(/(\n+\s*)+/g, "\n") : "" } function f(e) { for (var n in this.options = e, this._keep = [], this._remove = [], this.blankRule = { replacement: e.blankReplacement }, this.keepReplacement = e.keepReplacement, this.defaultRule = { replacement: e.defaultReplacement }, this.array = [], e.rules) this.array.push(e.rules[n]) } function d(e, n, t) { for (var r = 0; r < e.length; r++) { var i = e[r]; if (function (e, n, t) { var r = e.filter; if ("string" == typeof r) { if (r === n.nodeName.toLowerCase()) return !0 } else if (Array.isArray(r)) { if (-1 < r.indexOf(n.nodeName.toLowerCase())) return !0 } else { if ("function" != typeof r) throw new TypeError("`filter` needs to be a string, array, or function"); if (r.call(e, n, t)) return !0 } }(i, n, t)) return i } } function p(e) { var n = e.nextSibling || e.parentNode; return e.parentNode.removeChild(e), n } function h(e, n, t) { return e && e.parentNode === n || t(n) ? n.nextSibling || n.parentNode : n.firstChild || n.nextSibling || n.parentNode } t.paragraph = { filter: "p", replacement: function (e) { return "\n\n" + e + "\n\n" } }, t.lineBreak = { filter: "br", replacement: function (e, n, t) { return t.br + "\n" } }, t.heading = { filter: ["h1", "h2", "h3", "h4", "h5", "h6"], replacement: function (e, n, t) { n = Number(n.nodeName.charAt(1)); return "setext" === t.headingStyle && n < 3 ? "\n\n" + e + "\n" + u(1 === n ? "=" : "-", e.length) + "\n\n" : "\n\n" + u("#", n) + " " + e + "\n\n" } }, t.blockquote = { filter: "blockquote", replacement: function (e) { return "\n\n" + (e = (e = e.replace(/^\n+|\n+$/g, "")).replace(/^/gm, "> ")) + "\n\n" } }, t.list = { filter: ["ul", "ol"], replacement: function (e, n) { var t = n.parentNode; return "LI" === t.nodeName && t.lastElementChild === n ? "\n" + e : "\n\n" + e + "\n\n" } }, t.listItem = { filter: "li", replacement: function (e, n, t) { e = e.replace(/^\n+/, "").replace(/\n+$/, "\n").replace(/\n/gm, "\n    "); var r = t.bulletListMarker + "   ", i = n.parentNode; return "OL" === i.nodeName && (t = i.getAttribute("start"), i = Array.prototype.indexOf.call(i.children, n), r = (t ? Number(t) + i : i + 1) + ".  "), r + e + (n.nextSibling && !/\n$/.test(e) ? "\n" : "") } }, t.indentedCodeBlock = { filter: function (e, n) { return "indented" === n.codeBlockStyle && "PRE" === e.nodeName && e.firstChild && "CODE" === e.firstChild.nodeName }, replacement: function (e, n, t) { return "\n\n    " + n.firstChild.textContent.replace(/\n/g, "\n    ") + "\n\n" } }, t.fencedCodeBlock = { filter: function (e, n) { return "fenced" === n.codeBlockStyle && "PRE" === e.nodeName && e.firstChild && "CODE" === e.firstChild.nodeName }, replacement: function (e, n, t) { for (var r, i = ((n.firstChild.getAttribute("class") || "").match(/language-(\S+)/) || [null, ""])[1], o = n.firstChild.textContent, t = t.fence.charAt(0), a = 3, l = new RegExp("^" + t + "{3,}", "gm"); r = l.exec(o);)r[0].length >= a && (a = r[0].length + 1); t = u(t, a); return "\n\n" + t + i + "\n" + o.replace(/\n$/, "") + "\n" + t + "\n\n" } }, t.horizontalRule = { filter: "hr", replacement: function (e, n, t) { return "\n\n" + t.hr + "\n\n" } }, t.inlineLink = { filter: function (e, n) { return "inlined" === n.linkStyle && "A" === e.nodeName && e.getAttribute("href") }, replacement: function (e, n) { var t = n.getAttribute("href"), n = s(n.getAttribute("title")); return "[" + e + "](" + t + (n = n && ' "' + n + '"') + ")" } }, t.referenceLink = { filter: function (e, n) { return "referenced" === n.linkStyle && "A" === e.nodeName && e.getAttribute("href") }, replacement: function (e, n, t) { var r = n.getAttribute("href"), i = (i = s(n.getAttribute("title"))) && ' "' + i + '"'; switch (t.linkReferenceStyle) { case "collapsed": a = "[" + e + "][]", l = "[" + e + "]: " + r + i; break; case "shortcut": a = "[" + e + "]", l = "[" + e + "]: " + r + i; break; default: var o = this.references.length + 1, a = "[" + e + "][" + o + "]", l = "[" + o + "]: " + r + i }return this.references.push(l), a }, references: [], append: function (e) { var n = ""; return this.references.length && (n = "\n\n" + this.references.join("\n") + "\n\n", this.references = []), n } }, t.emphasis = { filter: ["em", "i"], replacement: function (e, n, t) { return e.trim() ? t.emDelimiter + e + t.emDelimiter : "" } }, t.strong = { filter: ["strong", "b"], replacement: function (e, n, t) { return e.trim() ? t.strongDelimiter + e + t.strongDelimiter : "" } }, t.code = { filter: function (e) { var n = e.previousSibling || e.nextSibling, n = "PRE" === e.parentNode.nodeName && !n; return "CODE" === e.nodeName && !n }, replacement: function (e) { if (!e) return ""; e = e.replace(/\r?\n|\r/g, " "); for (var n = /^`|^ .*?[^ ].* $|`$/.test(e) ? " " : "", t = "`", r = e.match(/`+/gm) || []; -1 !== r.indexOf(t);)t += "`"; return t + n + e + n + t } }, t.image = { filter: "img", replacement: function (e, n) { var t = s(n.getAttribute("alt")), r = n.getAttribute("src") || "", n = s(n.getAttribute("title")); return r ? "![" + t + "](" + r + (n ? ' "' + n + '"' : "") + ")" : "" } }, f.prototype = { add: function (e, n) { this.array.unshift(n) }, keep: function (e) { this._keep.unshift({ filter: e, replacement: this.keepReplacement }) }, remove: function (e) { this._remove.unshift({ filter: e, replacement: function () { return "" } }) }, forNode: function (e) { return e.isBlank ? this.blankRule : (n = d(this.array, e, this.options)) || (n = d(this._keep, e, this.options)) || (n = d(this._remove, e, this.options)) ? n : this.defaultRule; var n }, forEach: function (e) { for (var n = 0; n < this.array.length; n++)e(this.array[n], n) } }; var g = "undefined" != typeof window ? window : {}; var m, A = function () { var e = g.DOMParser, n = !1; try { (new e).parseFromString("", "text/html") && (n = !0) } catch (e) { } return n }() ? g.DOMParser : (!function () { var n = !1; try { document.implementation.createHTMLDocument("").open() } catch (e) { window.ActiveXObject && (n = !0) } return n }() ? e.prototype.parseFromString = function (e) { var n = document.implementation.createHTMLDocument(""); return n.open(), n.write(e), n.close(), n } : e.prototype.parseFromString = function (e) { var n = new window.ActiveXObject("htmlfile"); return n.designMode = "on", n.open(), n.write(e), n.close(), n }, e); function e() { } function v(e, n) { return function (e) { var n = e.element, t = e.isBlock, r = e.isVoid, i = e.isPre || function (e) { return "PRE" === e.nodeName }; if (n.firstChild && !i(n)) { for (var o = null, a = !1, l = h(c = null, n, i); l !== n;) { if (3 === l.nodeType || 4 === l.nodeType) { var u = l.data.replace(/[ \r\n\t]+/g, " "); if (!(u = !(o && !/ $/.test(o.data) || a || " " !== u[0]) ? u.substr(1) : u)) { l = p(l); continue } l.data = u, o = l } else { if (1 !== l.nodeType) { l = p(l); continue } t(l) || "BR" === l.nodeName ? (o && (o.data = o.data.replace(/ $/, "")), o = null, a = !1) : r(l) || i(l) ? a = !(o = null) : o && (a = !1) } var u = h(c, l, i), c = l, l = u } o && (o.data = o.data.replace(/ $/, ""), o.data || p(o)) } }({ element: e = "string" == typeof e ? (m = m || new A).parseFromString('<x-turndown id="turndown-root">' + e + "</x-turndown>", "text/html").getElementById("turndown-root") : e.cloneNode(!0), isBlock: o, isVoid: i, isPre: n.preformattedCode ? y : null }), e } function y(e) { return "PRE" === e.nodeName || "CODE" === e.nodeName } function N(e, n) { var t; return e.isBlock = o(e), e.isCode = "CODE" === e.nodeName || e.parentNode.isCode, e.isBlank = !i(t = e) && !function (e) { return l(e, a) }(t) && /^\s*$/i.test(t.textContent) && !function (e) { return c(e, r) }(t) && !function (e) { return c(e, a) }(t), e.flankingWhitespace = function (e, n) { if (e.isBlock || n.preformattedCode && e.isCode) return { leading: "", trailing: "" }; var t = function (e) { e = e.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); return { leading: e[1], leadingAscii: e[2], leadingNonAscii: e[3], trailing: e[4], trailingNonAscii: e[5], trailingAscii: e[6] } }(e.textContent); t.leadingAscii && E("left", e, n) && (t.leading = t.leadingNonAscii); t.trailingAscii && E("right", e, n) && (t.trailing = t.trailingNonAscii); return { leading: t.leading, trailing: t.trailing } }(e, n), e } function E(e, n, t) { var r, i, n = "left" === e ? (r = n.previousSibling, / $/) : (r = n.nextSibling, /^ /); return r && (3 === r.nodeType ? i = n.test(r.nodeValue) : t.preformattedCode && "CODE" === r.nodeName ? i = !1 : 1 !== r.nodeType || o(r) || (i = n.test(r.textContent))), i } var T = Array.prototype.reduce, R = [[/\\/g, "\\\\"], [/\*/g, "\\*"], [/^-/g, "\\-"], [/^\+ /g, "\\+ "], [/^(=+)/g, "\\$1"], [/^(#{1,6}) /g, "\\$1 "], [/`/g, "\\`"], [/^~~~/g, "\\~~~"], [/\[/g, "\\["], [/\]/g, "\\]"], [/^>/g, "\\>"], [/_/g, "\\_"], [/^(\d+)\. /g, "$1\\. "]]; function C(e) { if (!(this instanceof C)) return new C(e); this.options = function (e) { for (var n = 1; n < arguments.length; n++) { var t, r = arguments[n]; for (t in r) r.hasOwnProperty(t) && (e[t] = r[t]) } return e }({}, { rules: t, headingStyle: "setext", hr: "* * *", bulletListMarker: "*", codeBlockStyle: "indented", fence: "```", emDelimiter: "_", strongDelimiter: "**", linkStyle: "inlined", linkReferenceStyle: "full", br: "  ", preformattedCode: !1, blankReplacement: function (e, n) { return n.isBlock ? "\n\n" : "" }, keepReplacement: function (e, n) { return n.isBlock ? "\n\n" + n.outerHTML + "\n\n" : n.outerHTML }, defaultReplacement: function (e, n) { return n.isBlock ? "\n\n" + e + "\n\n" : e } }, e), this.rules = new f(this.options) } function k(e) { var r = this; return T.call(e.childNodes, function (e, n) { var t = ""; return 3 === (n = new N(n, r.options)).nodeType ? t = n.isCode ? n.nodeValue : r.escape(n.nodeValue) : 1 === n.nodeType && (t = function (e) { var n = this.rules.forNode(e), t = k.call(this, e), r = e.flankingWhitespace; (r.leading || r.trailing) && (t = t.trim()); return r.leading + n.replacement(t, e, this.options) + r.trailing }.call(r, n)), b(e, t) }, "") } function b(e, n) { var t = function (e) { for (var n = e.length; 0 < n && "\n" === e[n - 1];)n--; return e.substring(0, n) }(e), r = n.replace(/^\n*/, ""), n = Math.max(e.length - t.length, n.length - r.length); return t + "\n\n".substring(0, n) + r } return C.prototype = { turndown: function (e) { if (null == (n = e) || "string" != typeof n && (!n.nodeType || 1 !== n.nodeType && 9 !== n.nodeType && 11 !== n.nodeType)) throw new TypeError(e + " is not a string, or an element/document/fragment node."); var n; if ("" === e) return ""; e = k.call(this, new v(e, this.options)); return function (n) { var t = this; return this.rules.forEach(function (e) { "function" == typeof e.append && (n = b(n, e.append(t.options))) }), n.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "") }.call(this, e) }, use: function (e) { if (Array.isArray(e)) for (var n = 0; n < e.length; n++)this.use(e[n]); else { if ("function" != typeof e) throw new TypeError("plugin must be a Function or an Array of Functions"); e(this) } return this }, addRule: function (e, n) { return this.rules.add(e, n), this }, keep: function (e) { return this.rules.keep(e), this }, remove: function (e) { return this.rules.remove(e), this }, escape: function (e) { return R.reduce(function (e, n) { return e.replace(n[0], n[1]) }, e) } }, C }();
    /* Turndownライブラリのコードを直接埋め込む(ここまで) */

    const selection = window.getSelection();
    if (selection.rangeCount > 0) {
        const range = selection.getRangeAt(0);
        const div = document.createElement("div");
        div.appendChild(range.cloneContents());
        const html = div.innerHTML;
        const markdown = htmlToMarkdown(html);
        copyToClipboard(markdown);
        alert("Markdown形式でクリップボードにコピーされました!");
    } else {
        alert("テキストを選択してください。");
    }
})();

おわりに

他のサービスも追い上げているけど、大衆的にはまだChatGPTの1強かなというイメージ。
(正直、個人的には最近ChatGPTが無くてはならないものになりつつあって少し怖い気もする)
みんなも良きChatGPTライフを!!

8
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?