Bloggerのウィジェット用JavaScriptを止めて影響を受ける機能を必要なときに使う方法 結城永人 - 2022年2月6日 (日) Bloggerは世界で最も利用者が多いと共に非常に古いブログサービスで、常に改良されるけれども機能的に無駄な部分が残されていて今最も悲しいのがウィジェット用JavaScriptの外部ファイルとソースコードなんだ。 それ自体が重いどころか多くの機能が一つになっていてそうした標準のプログラムが必要なウィジェットなどを使ってなくても全てのブログにサーバーから自動的に記載されている。 ブログの表示速度などのパフォーマンスを考えると止めるのが最善ながら幾つかの重要な機能が使えなくなるのが悩ましい。しかし後から読み込む方法が全くないわけではない。初回画面を遅らせないことはブログのパフォーマンスでは最も重要だと思う。 ウィジェット用JavaScriptの影響を受ける機能を使わなければ止めて構わないけれども必要な場合でも最初に止めておいて一部の機能で必要なときだけ読み込んで使うのも面白いかも知れない。 A person walking on the roof by Jeremy Bishop / Unsplash 目次ウィジェット用JavaScriptを止める二つの方法BloggerのJavaScriptの設定をオフにするbodyの終了タグをコメントアウトするウィジェット用JavaScriptの影響を受ける機能停止した幾つかの機能を個別に動作させる方法ウィジェット用JavaScriptを必要なときに使うカスタマイズの共通と個別のソースコード ウィジェット用JavaScriptを止める二つの方法 Bloggerのウィジェット用JavaScriptは外部ファイルとソースコードがある。 ウィジェットのバージョンによって少し違う。 ウィジェット2 テーマのソースコードのhtmlタグにb:defaultwidgetversion='2'の記載があるもの。 公式テーマContempoSohoEmporioNotableEssential テーマのソースコードの最後に外部ファイル(www.blogger.com)とソースコードがサーバーから一つずつ挿入される。 ウィジェット1 テーマのソースコードのhtmlタグにb:version='2'の記載があるもの。 公式テーマSimpleDynamic ViewsPicture WindowAwesome Inc.WatermarkEtherealTravel テーマのソースコードの最後に二つの外部ファイル(apis.google.comとwww.blogger.com)と一つのソースコードサーバーから挿入される。 ウィジェット1のapis.google.comの外部ファイルは機能への影響は全く確認できず、終了したソーシャルメディアのGoogle+に関連した機能の残りかも知れない。 方法①BloggerのJavaScriptの設定をオフにする ブログのウィジェット用JavaScriptを外部ファイルもソースコードも完全に止めることができる。 HTML <html b:js='false'...> (中略) </html> ※太字が変更部分。 テンプレートのhtmlタグに「b:js='false'」を追加する。 Bloggerでのウィジェット用JavaScriptの設定のマークアップになり、値が「false」だとオフで。追加しないか値を「true」にするとオンだから反対にウィジェット用JavaScriptはソースコードに記載される。 方法に②bodyの終了タグをコメントアウトする ブログのウィジェット用JavaScriptの外部ファイルもソースコードも記載されるけれども外部ファイルの読み込みを止めることができる。 HTML <:!-- </body> --> </body> ※太字が変更部分。 テンプレートのbodyの終了タグの</body>をコメントアウトとしてHTMLのマークアップとして止めるとその直前に記載させるウィジェット用JavaScriptも同じようにコメントアウトして機能しなくなる。 文字は残るし、特にソースコードの方は物凄く長くてブログの状態や使用中のウィジェットやスニペットなどの情報が網羅さていてウィジェットやスニペットの使用を減らしても小さな画像一枚分は越える容量かも知れない。 しかしそれよりもブログのパフォーマンスを大きく下げ兼ねない外部ファイルの読み込みを止められるのは嬉しい。 Bloggerのウィジェット用JavaScriptの設定はオンのままだけど、すると管理画面のレイアウトを停止させず、従来通りに使うことができる。 ウィジェット用JavaScriptの影響を受ける機能 Bloggerのどんな機能がウィジェット用JavaScriptで動作しているかを調べてみた。 ウィジェット ブログアーカイブ:不具合ウィジェット1で階層が開けない。ウィジェット1でプルダウンメニューが飛べない。ブログの統計情報:停止フィード:停止登録用リンク:不具合アイテムが開けない。連絡フォーム:停止ウィキペディア:停止 投稿 ライトボックス:停止埋め込みコメント:不具合返信できない。 管理画面 レイアウト:条件付き停止設定がオンならば動作する。 他にもあるかも知れないけれども停止や不具合などの影響を確認できたものを挙げた。 停止した幾つかの機能を動作させる方法 Bloggerのパフォーマンスでは初回画面の表示速度が重要で、ウィジェット用JavaScriptを止めることで相当に改善できるけど、しかし必要な機能を必要なときだけ使うように後から挿入しても良いと思う。 一部はウィジェット用JavaScriptなしで動作させる方法を見付けた。 ウィジェット用JavaScriptを必要なときに使う ブログの状況によってソースコードが変わったり、外部ファイルのURLも一定ではないから後から使うとすれば設定で完全に止めるよりもコメントアウトでBloggerから記載されたデータを再利用する方が一般的に確実性が高いと思うので、そうした手法でプログラムを組むことにする。 管理画面のレイアウトが止まらないから利便性も高いと喜ぶ。 注意:ウィジェット用JavaScriptはBloggerはサーバーからブログに自動的に記載するものだし、万一、根本的に中身を変えられたらテンプレートのソースコードのプログラムでは即座に対応できない。 何年も一度もないことだし、たぶん大丈夫だろうけど、適切にやっても動作しなくなる可能性は否定できない。 カスタマイズの共通と個別のソースコード 最初から表示するのが普通のフィードやブログの統計情報などは除外す。 停止する機能で操作するものや後から表示されるものは読み込みを遅らせて使用する利点が大きいので、後から動作させる方法が見付かるかぎりは取り上げる。 ウィジェット用JavaScriptの外部ファイルは、一旦、読み込んでしまえば全ての機能が使えるようになるので、プログラムは停止した機能をチェックしながら一つでも必要になって読み込んだら使用したい全ての機能のインラインのソースコード(どれも短くてパフォーマンスへの影響は殆どない)もテンプレートに追加してチェックを終了するようにする。 カスタマイズのソースコードは基本的に共通のものに使用したい機能の種類を記載して後から読み込むための個別のチェックの開始と解除の二つのソースコードを追加して設置する。 一部の機能はウィジェット用JavaScriptなしでも動作させる方法が見付かったから使用したいのがそれだけならば他のソースコードは要らなくてもっと簡単に設置できる。 共通のソースコード JavaScript document.addEventListener("DOMContentLoaded", () => { <b:with value='data:widgets filter (w => w.type in 使用したい機能の種類)' var='widgets'> const bgjs = document.body.lastChild.previousSibling.textContent; function ldbgwd(event) { const jscd = document.createElement("script"); jscd.textContent = /_Widget.*rearrange\?blogID.*\);/.exec(bgjs) + <b:loop index='i' values='data:widgets' var='widget'>/_Widget.*<data:widget.type/>View.*<data:widget.id/>.*\);/.exec(bgjs)<b:eval expr='data:widgets.length - data:i > 1 ? " + " : ";"'/></b:loop> document.body.appendChild(jscd); /* チェック終了コード */ event.currentTarget.removeEventListener("load", ldbgwd); } function bgwdjs() { const bgwd = document.createElement("script"); bgwd.src = /https:\/\/www\.blogger\.com.*js/.exec(bgjs); bgwd.addEventListener("load", ldbgwd); document.body.appendChild(bgwd); } /* チェック開始コード */ </b:with>}); ※帯文字が編集部分。 使用したい機能の種類 連絡フォーム ContactFrom 埋め込みコメントの返信 Blog ライトボックス Blog ウィキペディア Wikipedia 入力する文字は一意に決められているので、勝手に変えてはならない。 一つの場合は半角二重引用符を使って入力する。 例_"ContactForm" 二つ以上の場合は個々に二重引用符を使って半角コンマで区切って全体に半角大括弧を使って入力する。 例_["ContactForm", "Blog"] ウィジェットは管理画面のレイアウトから、二つ以上、設定できる場合があるけれども入力する機能の種類は同じものを繰り返す必要はない。 ブログに設置するには基本のソースコードをscriptタグで囲んでエラーにならないところ(BloggerのHTMLの基本構造)、他のソースコードに支障を来さないためにはbodyの終了タグ(コメントアウトした場合はコメントアウト)の直前に記載する。 <script> 共通のソースコード <script> さらに個別のソースコードを追加して初めて動作するけれども編集するのは共通のソースコードの内側だけだからブログへ記載する場所は変わらない。 僕が提供している非公式テーマのImaginaryではソースコードの最後のscriptタグの中に追加しても他のプログラムと干渉しないことが分かっている。 <script> document.addEventListener("DOMContentLoaded", () => { (中略) </b:if> 共通のソースコード });</script> 共通のソースコードの最初と最後の部分の「document.addEventListener("DOMContentLoaded", () => {」と「});」は重複してそのままだとエラーなるから必ず外さなくてはならない。 その他、同じ変数が使える部分があり、共通と個別のソースコードの「document.body」は「bdis」に変えると統一される。 個別のソースコード 共通のソースコードが必要なもの 連絡フォーム埋め込みコメントの返信ライトボックスウィキペディア 単体で使用するもの ブログアーカイブの階層 ブログアーカイブのプルダウンメニュー 共通のソースコードが必要なものはチェックの開始と解除のソースコードを共通のソースコードの所定の場合に追加する。複数の場合は順番に並べて行く。 説明の「/* チェック終了コード */」と「/* チェック終了コード */」は消して構わない。 単体で使用できるものはそれだけならばカスタマイズの共通のソースコードと同じようにscriptタグで囲んでブログのbodyの終了タグの直前などの適切な場所に記載する。 カスタマイズの基本のソースコードと一緒に使うならば共通のソースコードに続けて(最後の「});」に入れず)同じscript内に記載する。 連絡フォーム 設置数によってチェック開始コードが異なる。 JavaScript /* チェック終了コード */ fcocfs.forEach(fcocf => fcocf.removeEventListener("focus", bgwdjs)); /* チェック開始コード */ const fcocfs = ContactForm1.querySelectorAll("input.contact-form-email, textarea.contact-form-email-message"); fcocfs.forEach(fcocf => fcocf.addEventListener("focus", bgwdjs)); /* チェック開始コード(二つ使う場合) */ const fcocfs = document.body.querySelectorAll("input.contact-form-email, textarea.contact-form-email-message"); fcocfs.forEach(fcocf => fcocf.addEventListener("focus", bgwdjs)); 必須項目のメールとメッセージを入力するときにウィジェット用JavaScriptを読み込む。 非公式テーマでは連絡フォームのメールとメッセージの要素とclassの「input.contact-form-email」と「textarea.contact-form-email-message」が一致しないと動作しない。 僕が提供している非公式テーマのImaginaryでは連絡フォームのモバイルでフローティングボタンを停止するために同じようなプログラムが最初から組み込まれているから連絡フォームのプログラムを追加する方が無駄がない。 共通のソースコード const bgjs = bdis.lastChild.previousSibling.textContent; let cfjs = false; function bgwdjs() { ※太字が変更部分。 二行目に新しい一文を追加する。 Imaginaryの最後のscript /* Contact form */ <b:if cond='data:widgets.ContactForm.first'> const fcpts = <b:eval expr='data:widgets.ContactForm.length == 1 ? "ContactForm1" : "bdis"'/>.querySelectorAll("input.contact-form-name, input.contact-form-email, textarea.contact-form-email-message"); function cffnc(event) { if (!cfjs) bgwdjs(); <b:if cond='data:blog.isMobileRequest'> if (!sbct.classList.contains("slider")) { if (comment_button) comment_button.classList.add("invisible"); back_button.classList.add("invisible"); } event.target.addEventListener("blur", () => { if (!sbct.classList.contains("slider")) { if (comment_button) comment_button.classList.remove("invisible"); back_button.classList.remove("invisible"); }}); <b:else/> fcpts.forEach(fcpt => fcpt.removeEventListener("focus", cffnc)); </b:if>} fcpts.forEach(fcpt => fcpt.addEventListener("focus", cffnc)); </b:if> /* Back button */ script内の「/* Contact form */」から「/* Back button */」までのソースコードを全て取り替える。 埋め込みコメントの返信 記事/追加ページのみ記載されるように振り分け済み。 JavaScript /* チェック終了コード */ <b:if cond='data:view.isSingleItem'>commentReplyObserver.disconnect();</b:if> /* チェック開始コード */ <b:if cond='data:view.isSingleItem'>const cmns = document.getElementById("comments"), cmhd = Blog1.querySelector("div.comment-thread"); let commentReplyObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) bgwdjs(); }); }, { rootMargin: "180px"}); if (cmns && cmhd) commentReplyObserver.observe(cmns);</b:if> スクロールでコメントの領域に到達したときにウィジェット用JavaScriptを読み込む。 非公式テーマではコメントの領域のidの「comments」と埋め込みコメントの要素とclassの「div.comment-thread」が一致しないと動作しない。 僕が提供している非公式テーマのImaginaryでは埋め込みコメントのコメントフォームの遅延読み込みのために同じようなプログラムが最初から組み込まれているから埋め込みコメントの返信に関しては一部を修正するだけで使用することができる。 共通のソースコード const bgjs = bdis.lastChild.previousSibling.textContent; let rljs = false; function bgwdjs() { ※太字が変更部分。 二行目に新しい一文を追加する。 個別のソースコード /* チェック終了コード */ <b:if cond='data:view.isSingleItem'>rljs = true;</b:if> ※太字が変更部分。 記事/追加ページに振り分けるb:ifタグのの中身を変える。チェック開始コードなくて代わりに使うためにImaginaryの埋め込みコメントのコードの一部を書き換える。 Imaginaryの最後のscript /* Sub content observer */ (中略) commentForm.style.height = "90px"; if (comments.querySelector("div.comment-thread")) { if (!rljs) bgwdjs(); comments.querySelectorAll("a.comment-reply").forEach(cmrl => { ※太字が変更部分。 ブログのソースコードの最後のscriptタグの「/* Sub content observer */」の途中に「if (!rljs) bgwdjs();」を追加する。 三ヵ所のカスタマイズによって埋め込みコメントの返信をウィジェット用JavaScriptを後から読み込んで動作させられる。 ライトボックス 画像ありの記事/追加ページのみ記載されるように振り分け済み。 JavaScript /* チェック終了コード */ <b:if cond='data:view.isSingleItem and data:view.isfeaturedImage'&agt;lbjs.click(); lbjs = true;</b:if> /* チェック開始コード */ <b:if cond='data:view.isSingleItem and data:view.isfeaturedImage'>const pimgs = Blog1.querySelectorAll("div.entry-content img"); pimgs.forEach(pimg => { if (pimg.parentElement.tagName === "A") { pimg.parentElement.addEventListener("click", event => { if(!lbjs) { event.preventDefault(); lbjs = event.target; bgwdjs(); }}); }});</b:if> ライトボックスの場合、ウィジェット用JavaScriptを挿入して解除した後も画像のクリック/タップからコンテンツを開けるようにしておかなくてはならないので、その機能を残すために共通のソースコードも少し編集する。 共通のソースコード 画像ありの記事/追加ページのみ記載されるように振り分け済み。 const bgjs = bdis.lastChild.previousSibling.textContent; <b:if cond='data:view.isSingleItem and data:view.isfeaturedImage'>let lbjs = false;</b:if> function bgwdjs() { ※太字が変更部分。 投稿画像をクリック/タップすると特有の大写しの画面になり、二つ以上ならば切り替えが可能になる。 チェック開始コードの「div.entry-content」が対象の画像が表示される要素とクラスで、非公式のテンプレートで合わない場合は書き換える必要がある。 ライトボックスを開くクリック/タップの対象は画像に自動的に付けられるリンクのaタグなので、投稿のカスタマイズで外していたりすると動作しない。 ウィキペディア 設置数によってチェックの終了と開始の両方のコードが異なる。 JavaScript /* チェック終了コード(一つ使う場合) */ fowp.removeEventListener("focus", bgwdjs); /* チェック開始コード(一つ使う場合) */ const fowp = Wikipedia1.querySelector("input.wikipedia-search-input"); fowp.addEventListener("focus", bgwdjs); /* チェック終了コード(二つ使う場合) */ fowps.forEach(fowp => fowp.removeEventListener("focus", bgwdjs)); /* チェック開始コード(二つ使う場合) */ const fowps = document.body.querySelectorAll("input.wikipedia-search-input"); fowps.forEach(fowp => fowp.addEventListener("focus", bgwdjs)); キーワードを入力するときにウィジェット用JavaScriptを読み込む。 非公式テーマでは検索窓の要素とclassの「input.wikipedia-search-input」が一致しないと動作しない。 ブログアーカイブの階層 ウィジェット1のテンプレートのブログアーカイブのデザインの一つだ。 プログラムはBloggerのウィジェット用JavaScriptなしで動作する。 JavaScript /* 全ての場合に共通する部分 */ if (dtps && !/\.*\/\d{4}\/?$/.test(ev.nextElementSibling.href) && loev.lastElementChild.tagName === "SPAN") { loev.insertAdjacentHTML("beforeend", "<ul><li><data:messages.loading.jsEscaped/></li></ul>"); fetch(ev.nextElementSibling.href).then(response => { if (!response.ok) throw 'connection failed'; return response.text(); }).then(text => { const file = new DOMParser().parseFromString(text, "text/html"), narcs = file.querySelectorAll("div.post"), ncona = file.querySelector("ul.posts").cloneNode(false); narcs.forEach(narc => { const cuoa = narc.querySelector("a.timestamp-link").href, topb = narc.querySelector("div.post-body").textContent, ctoa = narc.querySelector("h3") ? narc.querySelector("h3").innerHTML : "<a href=\"" + cuoa + "\">" + (topb.length <= 53 ? topb.substring(0) : topb.substring(0, 53) + "...") + "</a>", clona = document.createElement("li"); clona.insertAdjacentHTML("afterbegin", ctoa); ncona.appendChild(clona); }); return ncona; }).then(content => loev.replaceChild(content, loev.lastElementChild)).catch(() => loev.lastElementChild.remove()); } loev.classList.toggle("expand"); loev.classList.toggle("collapsed"); soev.classList.toggle("toggle-open"); soev.textContent = soev.classList.contains("toggle-open") ? "\u25bc\u00a0" : "\u25ba\u00a0"; }); }); /* 一つ目に設置したブログアーカイブの場合 */ const hracs = BlogArchive1_ArchiveList.querySelectorAll("a.toggle"), dtps = BlogArchive1_ArchiveList.querySelector("ul.posts"); hracs.forEach(hrac => { hrac.addEventListener("click", () => { const ev = event.currentTarget, loev = ev.parentElement, soev = ev.firstElementChild; /* 二つ目に設置したブログアーカイブの場合 */ const hracs = BlogArchive2_ArchiveList.querySelectorAll("a.toggle"), dtps = BlogArchive2_ArchiveList.querySelector("ul.posts"); hracs.forEach(hrac => { hrac.addEventListener("click", () => { const ev = event.currentTarget, loev = ev.parentElement, soev = ev.firstElementChild; /* 階層を二つ設置する場合 */ const hracs = document.body.querySelectorAll("div.BlogArchive a.toggle"), dtps1 = BlogArchive1_ArchiveList.querySelector("ul.posts"), dtps2 = BlogArchive2_ArchiveList.querySelector("ul.posts"); hracs.forEach(hrac => { hrac.addEventListener("click", () => { const ev = event.currentTarget, loev = ev.parentElement, soev = ev.firstElementChild, arch = ev.closest("div"), dtps = arch.id === "BlogArchive1_ArchiveList" && dtps1||arch.id === "BlogArchive2_ArchiveList" && dtps2 ? true : false; 長いので、分割して掲載する。共通の部分のソースコードを下にして三つの場合のソースコードのどれかを上に追加して使う。 階層の順番はブログアーカイブとして何番目に設置されたかで決まって階層だけの順番ではないから注意したい。 全てのブログアーカイブの一つ目に設置した階層は「一つ目に設置した」というソースコード、全てのブログアーカイブの二つ目に設置した階層は「二つの目に設置した」というソースコードを追加して使う。 ブログアーカイブを二つ設置して両方とも階層にする、すなわち階層を二つ設置するならば「二つ設置する場合」というソースコードを追加して使う。 ブログアーカイブのプルダウンメニュー ウィジェット1のテンプレートのブログアーカイブのデザインの一つだ。 プログラムはBloggerのウィジェット用JavaScriptなしで動作する。 JavaScript /* 一つ目に設置したブログアーカイブの場合 */ BlogArchive1_ArchiveMenu.addEventListener("change", () => { if (event.target.value) location.href = event.target.value; }); /* 二つ目に設置したブログアーカイブの場合 */ BlogArchive2_ArchiveMenu.addEventListener("change", () => { if (event.target.value) location.href = event.target.value; }); /* プルダウンメニューを二つ設置する場合 */ const pdms = document.body.querySelectorAll("div.BlogArchive select"); pdms.forEach(pdm => pdm.addEventListener("change", () => { if (event.target.value) location.href = event.target.value; })); ※一般的なプログラムなので、これだけ使うならば著作権の表記はしなくて構わない。 プルダウンメニューの順番はブログアーカイブとして何番目に追加されたかで決まってプルダウンメニューだけの順番ではないから注意したい。 全てのブログアーカイブの一つ目に設置したプルダウンメニューは「一つ目に設置した」というソースコード、全てのブログアーカイブの二つ目に設置したプルダウンメニューは「一つ目に設置した」というソースコードを使う。 ブログアーカイブを二つ設置して両方ともプルダウンメニューにする、すなわちプルダウンメニューを二つ設置するならば「二つ設置する場合」というソースコードを使う。 参考サイトRemove Default JavaScript [Widgets.js] from Blogger to Improve Loading Time【Blogger】標準 JS を無効にしつつレイアウト画面を動かすAttributs de réglages du fichier XML コメント 新しい投稿 前の投稿
コメント