やりたいこと
- Growi の映像の感想の記事に、Youtube を埋め込みたい
- Growi の書籍の感想の記事に、書籍の書影とアマゾンへのリンクを載せたい
- Growi のガジェットなんかの感想の記事に、アマゾンへのリンクを載せたい
- 具体的には、こんな風に Markdown に div タグを書くと、レタリング時に div タグの中身に、それぞれの ifreme や img を追加するようにしたい
<div class="modify" data-youtube='fnq9Pi_oOBw'></div> <div class="modify" data-isbn13='9784863542174'></div> <div class="modify" data-isbn10='4065260957'></div> <div class="modify" data-asin='B002JN4X68'></div>
- ややこしや
- amazon の書籍の URL は ISBN13 を ISBN10 化したものを指定する必要がある
- 逆に書影提供サイト ( https://hanmoto.com external_link )の API には、ISBM13 を指定する必要がある、
- あと、hanmoto.com の書影APIは、書影が無い本を指定すると CODE 404 (Not Found) を返すけど、同時にグレーの画像も返す。もうその制御はイイかな、hanmoto.com に書影が無い場合は素直に帰ってきたグレーの画像を表示することにした
実装
Henry IV (Willam Shakepeare)
GLENDOWER : I can call spirits from the vasty deep. (地獄の底から悪鬼を呼んでもいいんだぞ!)
HOTSPUR : Why, so can I, or so can any man; But will they come when you do call for them? (は?そんなのオレにだって、たいていの男にはできるだろ。で、お前さんに呼ばれて悪鬼が出て来るのかね?)
- そもそも SPA (React) なんで、Virtual DOM を DOM を連動させている。DOM を書き換えちゃダメ。一般的には
- でも、Growiは、画面からいろんな情報を入力する業務システムではない。一回レンダリングしたらそれで終わり。ということで、画面切り替え時に div タグを探してきて中に iframe や img を書き込めばよさそうだ
- で、画面切り替えのイベントってどうとるのさ? SPAは、直接リンクでも動くように (仮想)画面ごとに URL を変えていることに注目。Body が変わったときに URL も変わっていたら画面が切り替わったとみなすようにした。Thanks Raja! 1
- 結局こんな感じのコードを Growi のカスタムスクリプトに設定した。実際コードを書いてみると動かんもんだね。function をCall しても思い通りに動いてくれない。
- スマホで見た時にYoutubeの横幅を画面の横幅に縮めるために、カスタムCSSも設定する
- カスタムスクリプト
window.addEventListener('load', () => { // !Change it! const amazonLogo = '/attachment/665da85b2581380eb3a74536'; const isbn10to13 = (code) => { var newCode="978" + code.substring(0,9); return newCode + checksum13(newCode); }; const isbn13to10 = (code) => { const oldCode = code.substring(3,12); return oldCode + checksum10(oldCode); }; const checksum10 = (code) => { let sum=0; for( cnt=0 ; cnt<9 ; cnt++ ){ sum=sum + (code.charAt(cnt)-'0') * (10-cnt); } checksum = ( 11 - (sum % 11) ); return (checksum == 11 ? "0" : (checksum == 10 ? "X" : checksum)) ; }; const checksum13 = (code) => { var sum=0; for( cnt=0 ; cnt<12 ; cnt++ ){ sum=sum + (code.charAt(cnt)-'0') * (cnt%2==0 ? 1 : 3); } checksum = ( 10 - (sum % 10) ); return checksum; }; const handleUrlChange = () => { document.querySelectorAll('div.modify').forEach((dtag) => { try { if(0 < dtag.children.length) { // if there are already contents in dtag. return; } else if(dtag.dataset.youtube) { const movie_id = dtag.dataset.youtube; dtag.innerHTML = `<iframe class=\"youtube-16-9\" src=\"https://www.youtube.com/embed/${movie_id}\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>`; } else if(dtag.dataset.isbn13) { const isbn = dtag.dataset.isbn13.trim(); const asin = isbn13to10(isbn); dtag.innerHTML = `<a href=\"https://www.amazon.co.jp/o/ASIN/${asin}\"><img src=\"https://img.hanmoto.com/bd/img/${isbn}.jpg\" alt=\"${isbn}\"/></a>`; } else if(dtag.dataset.isbn10) { const asin = dtag.dataset.isbn10.trim(); const isbn = isbn10to13(asin); dtag.innerHTML = `<a href=\"https://www.amazon.co.jp/o/ASIN/${asin}\"><img src=\"https://img.hanmoto.com/bd/img/${isbn}.jpg\" alt=\"${isbn}\"/></a>`; } else if(dtag.dataset.asin) { const asin = dtag.dataset.asin; dtag.innerHTML = `<a href=\"https\://www.amazon.co.jp/o/ASIN/${asin}\"><img src=\"${amazonLogo}\" alt=\"${asin}\"/></a>`; } } catch (e) { console.log(e); } }); }; // ---- onload event ---- requestAnimationFrame((timestamp)=>{ handleUrlChange(); }); // ---- url change event (observe body changed) ---- let href = location.href; const observer = new MutationObserver((mutations) => { if (href == location.href) { return; } href = location.href; requestAnimationFrame((timestamp) => { handleUrlChange(); }); }); const config = { characterData: true, subtree: true }; observer.observe(document.body, config); });
- カスタムCSS
iframe.youtube-16-9 { width: 100%; height: auto; aspect-ratio: 1.78; max-width: 768px; }
実行サンプル
Youtube
書影 ISBN13 指定 & hanmoto.comが書影を持っていない
書影 ISBN10 指定 & hanmoto.comが書影を持っている
ガジェット
Footnotes
-
Detect React Route Change in Vanilla JavaScript, Raja Osama, https://rajaosama.me/blogs/detect-react-route-change-in-vanilla-js external_link ↩