Kibelaで書いたPlantUMLをChrome拡張で展開する

您所在的位置:网站首页 华山医院张文宏现任职务 Kibelaで書いたPlantUMLをChrome拡張で展開する

Kibelaで書いたPlantUMLをChrome拡張で展開する

2022-12-30 10:37| 来源: 网络整理| 查看: 265

はじめに

Kibelarのみなさんも、そうでないみなさんも、こんにちは! Kibelarの皆さんはご存知かと思いますが、情報共有ツールKibelaでは、PlantUMLを記事に記述するとUML図が表示されるというとても便利な機能があります。 そんなKibelaでPlantUMLをより快適に閲覧する用のChrome拡張をつくったお話のはじまりはじまり〜。

経緯

Kibelaを使い込んでいると、たくさんの記事で溢れかえって探すのが大変になると思います。 その対策として、フローチャートを辿ることで目当ての記事のリンクにたどれるようなUML図をKibelaで書くことになりました。 しかし、このUMLが大きくなってくるとKibela中の画像では見づらくなります。 また、URLを記していても本文中の画像ではアドレスバーにコピペできません。 右クリック>新しいタブで画像を開く で画像を開くと文字がコピペできますが、これよりももっと扱いやすくしようと考え今回の拡張をつくることになりました。

KibelaでのPlantUMLの書き方 ## フローチャート ```plantuml @startuml (*) --> "Let's search!" if "Would you like google?" then -->[true] "Access https://www.google.co.jp/" --> (*) else ->[false] "Access https://www.yahoo.co.jp/" --> (*) endif

という感じで書くと

image.png

こんな感じで表示されます。 QiitaでもPlantUMLを書くことができますが、それと同じ書き方ですね。

記事中のUML図はどうなっている?

さきほどの記事のHTMLを見てみると、UML図は次のようになっていました。

見やすく要約すると、

という中身になっていました。

srcがdata:image/svg+xml;base64,*のデータをデコードしよう

HTMLを確認した通り、imgタグのsrcとして、Data URIが指定されていたことがわかりました。

RFC2397によると、Data URIスキームは以下の構成になっているようです。

data:[][;base64],

今回はmediatypeがimage/svg+xml(また、文字コードがutf-8)なので、

data:image/svg+xml;charset=utf-8;base64,

となりますね。 これを踏まえると、先述のHTML中のimgのsrcから、UML図のは次のような処理(js)で取り出せることがわかります。

/** * パラメータのdataURIからbase64のdata部分を取り出し返す。 * パラメータがdataURL(svg+xml)以外のときはnullを返す。 * @param {String} src 調べたい画像ソース * @returns {String|Null} */ function getBase64DataFromSvgXmlImgDataUri(src) { const dataUriMatchResult = src.match(/data\:image\/svg\+xml(.*)\;base64,(.*)/); if(!dataUriMatchResult) return null; return dataUriMatchResult[2]; }

この関数で先ほどのHTML中のimgのsrcからを抜き出すと、以下のようになります。

PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBjb250ZW50U3R5bGVUeXBlPSJ0ZXh0L2NzcyIgaGVpZ2h0PSIzNDFweCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSIgc3R5bGU9IndpZHRoOjM3NXB4O2hlaWdodDozNDFweDtiYWNrZ3JvdW5kOiNGRkZGRkY7IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAzNzUgMzQxIiB3aWR0aD0iMzc1cHgiIHpvb21BbmRQYW49Im1hZ25pZnkiPjxkZWZzLz48Zz48ZWxsaXBzZSBjeD0iMTg0IiBjeT0iMTYiIGZpbGw9IiMyMjIyMjIiIHJ4PSIxMCIgcnk9IjEwIiBzdHlsZT0ic3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjEuMDsiLz48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9IjMzLjk2ODgiIHJ4PSIxMi41IiByeT0iMTIuNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB3aWR0aD0iMTAxIiB4PSIxMzMuNSIgeT0iNjciLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI4MSIgeD0iMTQzLjUiIHk9Ijg4LjEzODciPkxldCdzIHNlYXJjaCE8L3RleHQ+PGcgaWQ9ImVsZW1fIzUiPjxwb2x5Z29uIGZpbGw9IiNGMUYxRjEiIHBvaW50cz0iMTg0LDE0MiwxOTYsMTU0LDE4NCwxNjYsMTcyLDE1NCwxODQsMTQyIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiLz48L2c+PHJlY3QgZmlsbD0iI0YxRjFGMSIgaGVpZ2h0PSIzMy45Njg4IiByeD0iMTIuNSIgcnk9IjEyLjUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjIyNSIgeD0iMTQ0LjUiIHk9IjI0MCIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjIwNSIgeD0iMTU0LjUiIHk9IjI2MS4xMzg3Ij5BY2Nlc3MgaHR0cHM6Ly93d3cuZ29vZ2xlLmNvLmpwLzwvdGV4dD48ZWxsaXBzZSBjeD0iMTI2IiBjeT0iMzI1IiBmaWxsPSJub25lIiByeD0iMTAiIHJ5PSIxMCIgc3R5bGU9InN0cm9rZTojMjIyMjIyO3N0cm9rZS13aWR0aDoxLjA7Ii8+PGVsbGlwc2UgY3g9IjEyNi41IiBjeT0iMzI1LjUiIGZpbGw9IiMyMjIyMjIiIHJ4PSI2IiByeT0iNiIgc3R5bGU9InN0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjA7Ii8+PHJlY3QgZmlsbD0iI0YxRjFGMSIgaGVpZ2h0PSIzMy45Njg4IiByeD0iMTIuNSIgcnk9IjEyLjUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjIyMCIgeD0iNyIgeT0iMTg2Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMjAwIiB4PSIxNyIgeT0iMjA3LjEzODciPkFjY2VzcyBodHRwczovL3d3dy55YWhvby5jby5qcC88L3RleHQ+PCEtLU1ENT1bOThmOGM5ODE5ZTdlNjZjMzk0NjBlMjA5ZjM0YjIyNzddCmxpbmsgc3RhcnQgdG8gTGV0J3Mgc2VhcmNoIS0tPjxnIGlkPSJsaW5rX3N0YXJ0X0xldCdzIHNlYXJjaCEiPjxwYXRoIGQ9Ik0xODQsMjYuMTggQzE4NCwzNS4yNyAxODQsNDkuNTMgMTg0LDYxLjQ5ICIgZmlsbD0ibm9uZSIgaWQ9InN0YXJ0LXRvLUxldCdzIHNlYXJjaCEiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMTg0LDY2Ljc5LDE4OCw1Ny43OSwxODQsNjEuNzksMTgwLDU3Ljc5LDE4NCw2Ni43OSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PC9nPjwhLS1NRDU9W2IwYjgwNDE5ZTdlOWE0OGE4MDlmODdlYTA5YWU5ZGFhXQpsaW5rIExldCdzIHNlYXJjaCEgdG8gIzUtLT48ZyBpZD0ibGlua19MZXQncyBzZWFyY2ghXyM1Ij48cGF0aCBkPSJNMTg0LDEwMS4xMiBDMTg0LDExMS45MiAxODQsMTI2LjA4IDE4NCwxMzYuODggIiBmaWxsPSJub25lIiBpZD0iTGV0J3Mgc2VhcmNoIS10by0jNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIxODQsMTQxLjg5LDE4OCwxMzIuODksMTg0LDEzNi44OSwxODAsMTMyLjg5LDE4NCwxNDEuODkiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjEyOCIgeD0iMzYuNCIgeT0iMTM0LjY3NzUiPldvdWxkIHlvdSBsaWtlIGdvb2dsZT88L3RleHQ+PC9nPjwhLS1NRDU9W2QwYmRmOTExNTE0YTg4YzViYjExNDMzZmU4NzI1N2E4XQpsaW5rICM1IHRvIEFjY2VzcyBodHRwczovL3d3dy5nb29nbGUuY28uanAvLS0+PGcgaWQ9ImxpbmtfIzVfQWNjZXNzIGh0dHBzOi8vd3d3Lmdvb2dsZS5jby5qcC8iPjxwYXRoIGQ9Ik0xOTEuOTIsMTU4LjQ3IEMyMDIuMDYsMTYzLjI4IDIxOS41NiwxNzIuOSAyMzAsMTg2IEMyNDEuMzUsMjAwLjI0IDI0OC4zNiwyMTkuODEgMjUyLjM4LDIzNC42NCAiIGZpbGw9Im5vbmUiIGlkPSIjNS10by1BY2Nlc3MgaHR0cHM6Ly93d3cuZ29vZ2xlLmNvLmpwLyIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIyNTMuNzMsMjM5Ljg3LDI1NS4zNjcyLDIzMC4xNTgyLDI1Mi40ODcxLDIzNS4wMjY5LDI0Ny42MTgzLDIzMi4xNDY4LDI1My43MywyMzkuODciIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjIzIiB4PSIyNDkiIHk9IjIwNy4yMTA0Ij50cnVlPC90ZXh0PjwvZz48IS0tTUQ1PVtjNWJkNDg2NDFlMTRlYzkwY2U1YzJiZDgzMjEzN2I1Ml0KbGluayBBY2Nlc3MgaHR0cHM6Ly93d3cuZ29vZ2xlLmNvLmpwLyB0byBlbmQtLT48ZyBpZD0ibGlua19BY2Nlc3MgaHR0cHM6Ly93d3cuZ29vZ2xlLmNvLmpwL19lbmQiPjxwYXRoIGQ9Ik0yMjQuOTUsMjc0LjE1IEMxOTcuNDQsMjg4LjAxIDE1OS4xNiwzMDcuMjkgMTM5LjI0LDMxNy4zMyAiIGZpbGw9Im5vbmUiIGlkPSJBY2Nlc3MgaHR0cHM6Ly93d3cuZ29vZ2xlLmNvLmpwLy10by1lbmQiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMTM0LjU5LDMxOS42NywxNDQuNDI4MSwzMTkuMjEwMiwxMzkuMDU5MywzMTcuNDI4MiwxNDAuODQxMywzMTIuMDU5NCwxMzQuNTksMzE5LjY3IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48L2c+PCEtLU1ENT1bNTZmZTUxMjJkMjBmODk4OTEzZDg3NDkyOTViYTEzMzldCmxpbmsgIzUgdG8gQWNjZXNzIGh0dHBzOi8vd3d3LnlhaG9vLmNvLmpwLy0tPjxnIGlkPSJsaW5rXyM1X0FjY2VzcyBodHRwczovL3d3dy55YWhvby5jby5qcC8iPjxwYXRoIGQ9Ik0xNzcuMzMsMTU5LjY4IEMxNjkuNjEsMTY1LjEgMTU2LjM5LDE3NC4zNyAxNDQuMywxODIuODUgIiBmaWxsPSJub25lIiBpZD0iIzUtdG8tQWNjZXNzIGh0dHBzOi8vd3d3LnlhaG9vLmNvLmpwLyIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIxMzkuOSwxODUuOTMsMTQ5LjU2NjUsMTg0LjA0MzUsMTQzLjk5NTUsMTgzLjA2MTcsMTQ0Ljk3NzMsMTc3LjQ5MDcsMTM5LjksMTg1LjkzIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIyOCIgeD0iMTI5LjU5IiB5PSIxNzAuMDQwNCI+ZmFsc2U8L3RleHQ+PC9nPjwhLS1NRDU9W2QwNjZlYjY0YTM1ZTUzNTZjNGE3OWNlYTdiMDNiNDBlXQpsaW5rIEFjY2VzcyBodHRwczovL3d3dy55YWhvby5jby5qcC8gdG8gZW5kLS0+PGcgaWQ9ImxpbmtfQWNjZXNzIGh0dHBzOi8vd3d3LnlhaG9vLmNvLmpwL19lbmQiPjxwYXRoIGQ9Ik0xMTguMjEsMjIwLjE4IEMxMTkuOTgsMjQzLjc3IDEyMy4yNCwyODcuMjMgMTI0LjkzLDMwOS43MSAiIGZpbGw9Im5vbmUiIGlkPSJBY2Nlc3MgaHR0cHM6Ly93d3cueWFob28uY28uanAvLXRvLWVuZCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIxMjUuMzIsMzE0Ljk0LDEyOC42NDAzLDMwNS42Njc3LDEyNC45NDg1LDMwOS45NTM4LDEyMC42NjI0LDMwNi4yNjIsMTI1LjMyLDMxNC45NCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PC9nPjwhLS1NRDU9WzI1NzdmZGYxZDk2OWU3OTljZDczYzJlNzQwNTI0Nzk2XQpAc3RhcnR1bWwNCigqKSAtIC0+ICJMZXQncyBzZWFyY2ghIg0KDQppZiAiV291bGQgeW91IGxpa2UgZ29vZ2xlPyIgdGhlbg0KICAtIC0+W3RydWVdICJBY2Nlc3MgaHR0cHM6Ly93d3cuZ29vZ2xlLmNvLmpwLyINCi0gLT4gKCopDQplbHNlDQogIC0+W2ZhbHNlXSAiQWNjZXNzIGh0dHBzOi8vd3d3LnlhaG9vLmNvLmpwLyINCi0gLT4gKCopDQplbmRpZg0KQGVuZHVtbA0KClBsYW50VU1MIHZlcnNpb24gMS4yMDIyLjEyKFN1biBPY3QgMjMgMTg6MTI6MjYgVVRDIDIwMjIpCihHUEwgc291cmNlIGRpc3RyaWJ1dGlvbikKSmF2YSBSdW50aW1lOiBPcGVuSkRLIFJ1bnRpbWUgRW52aXJvbm1lbnQKSlZNOiBPcGVuSkRLIDY0LUJpdCBTZXJ2ZXIgVk0KRGVmYXVsdCBFbmNvZGluZzogVVRGLTgKTGFuZ3VhZ2U6IGVuCkNvdW50cnk6IFVTCi0tPjwvZz48L3N2Zz4=

これをデコードしていきます。

こちらの記事を参考にさせていただきました。 ありがとうございます!

をbase64dataに格納した状態で、以下の処理を実行するとdecodedDataにデコードされたが格納されます。

const decodedUtf8str = atob(base64data); const decodedArray = new Uint8Array(Array.prototype.map.call(decodedUtf8str, c => c.charCodeAt())); const decodedData = new TextDecoder().decode(decodedArray);

先ほどのでこの処理を行うと、デコードされたsvg+xmlが現れました。先ほどのをデコードしたものを整形したものは次のとおりです。

Let's search! Access https://www.google.co.jp/ Access https://www.yahoo.co.jp/ \x3C!--MD5=[98f8c9819e7e66c39460e209f34b2277]\nlink start to Let's search!--> \x3C!--MD5=[b0b80419e7e9a48a809f87ea09ae9daa]\nlink Let's search! to #5--> Would you like google? \x3C!--MD5=[d0bdf911514a88c5bb11433fe87257a8]\nlink #5 to Access https://www.google.co.jp/--> true \x3C!--MD5=[c5bd48641e14ec90ce5c2bd832137b52]\nlink Access https://www.google.co.jp/ to end--> \x3C!--MD5=[56fe5122d20f898913d8749295ba1339]\nlink #5 to Access https://www.yahoo.co.jp/--> false \x3C!--MD5=[d066eb64a35e5356c4a79cea7b03b40e]\nlink Access https://www.yahoo.co.jp/ to end--> \x3C!--MD5=[2577fdf1d969e799cd73c2e740524796]\n@startuml\r\n(*) - -> "Let's search!"\r\n\r\nif "Would you like google?" then\r\n - ->[true] "Access https://www.google.co.jp/"\r\n- -> (*)\r\nelse\r\n ->[false] "Access https://www.yahoo.co.jp/"\r\n- -> (*)\r\nendif\r\n@enduml\r\n\nPlantUML version 1.2022.12(Sun Oct 23 18:12:26 UTC 2022)\n(GPL source distribution)\nJava Runtime: OpenJDK Runtime Environment\nJVM: OpenJDK 64-Bit Server VM\nDefault Encoding: UTF-8\nLanguage: en\nCountry: US\n-->

これでの中身がわかりましたね。 この中身をブラウザで直接見てやれば、UML図の画像の内容と同じものでテキスト選択ができるものを表示することができます。

また、中身が解析できたので、置換などを行って任意の文字列を書き換えたりすることもできます。 今回つくるChrome拡張では、URLを見つけるとaタグに置換する処理を埋め込みました。

これが作成したChrome拡張だ!

先述した過程をたどり、そのあと色々あってこんな感じのものに落ち着きました。 機能としては次のようなところです。

plantUML図の右上に展開ボタンを表示し、クリックすると別タブで展開される。 展開されたものはテキスト選択、コピペが可能 展開されたものの文中のURLをクリックするとリンク先に飛べる ?openUml=0などとKibela記事のURLにパラメータを付与することで、記事を開いた時に指定のUML図を自動展開できる

この拡張をChromeに導入すると、

image.png

こんな感じで右上に展開ボタンが表示され、押下すると別タブで展開される仕様です。

自分の欲しかった機能は一通り実装でき、Kibe lifeをより一層充実させてくれるものが完成しました。

おわりに

今回つくったChrome拡張で、「リンク集フローチャートUML図」をKibelaで圧倒的に使いやすくすることができました。 Data URI のbase64でエンコードされたデータ部分はjsで簡単にデコードできたおかげで楽に実装でき助かりました。 Data URIが使われているものはいろいろいあるので、それを触りたいときはChrome拡張で実装すると楽かもしれませんね。 みなさんもChrome拡張でよりよい生活をお過ごしください。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3