Blog Archive をプルダウン表示にする
<!-- markdown-mode-on -->
<img alt="jettheme logo" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih6tkuCAB6zwNyTYCvTrA07cGstQGH7GBjCipsk3a6HoUiKVea-159v4oK4uq7qhXUjbbnX0Hm5Fds5sw7iiCzhqObJHwcnKQEf9-0iAqgpH6bSzH6FxQCVVBh-XrghyphenhyphenMUwaIjVewBQXI/s1600/jettheme-cover.png" style="
display: none;"/>
## 概要
Jettheme の Blog Archive は、「階層(HIERARCHY)」、「フラット(FLAT)」、「プルダウン(Menu)」の3スタイルある。手抜きかもしれないが、
- 「階層(HIERARCHY)」は、階層が1列縦に並んでいるだけで、見栄え、使い勝手ともに最悪だ。
- それに加えて、「プルダウン(Menu)」と「フラット(FLAT)」はと同じだ。(バグではなく仕様)
<img alt="Blog Archive" data-original-height="734" data-original-width="790" height="595" src="https://blogger.googleusercontent.com/img/a/AVvXsEg0dh0ajsTBtM9MpUyIiNLZ9yBekeYj1hc1jKblii4_mf_LYq3-iaejKRiKZehZXL4jy-PXlFLf7O35bapfYvcOiewzVZAwPIyPduOMXU99PnW-A6wstfTrhbVzAUR5VIaopO3mWwPA1bJ3GtpEglX5RAyobmy21NO5z_T5Anu2KyJN2Dgq2levWTLX4p_8=w640-h595" width="640"/>
<br/>
<br/>
他のデザインテーマで見られるようなプルダウンスタイルのBlog Archive を作ることにした。下記が完成したDIY Blog Archiveだ。
<br/>
<div style="text-align: center;">
<img alt="DIY Blog Archive" border="0" data-original-height="238" data-original-width="174" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlSZA_-vD5rtnlRTrek5gSQL1QsjRzDfuFb5Exg7_moEozsNRQKbd4JZqp2iF3qIXV_Tr-KdY738YAKQBW9oNGhtg-uAVdv1840mDFkhyACi4rATK0He6MkVc6kwz9qweBrJljmDck_Z24d8gFVEa-7OQCNOjbyte4gvAlGNQcW2zfXx_eTm3o1utk9Dnz/w468-h640/image.png" width="240"/>
</div>
<a name="more"></a>
## スクリプト
テーマxmlから、`
<b:includable id="JetBlogArchiveHierarchy" var="intervals">
`を探し、`
</b:includable>
` までを次のスクリプトと入れ替える。
<details>
<summary>Archiveスクリプト</summary>
```html
<b:includable id="JetBlogArchiveHierarchy" var="intervals">
<ul class="hierarchy list-unstyled border-start border-2 jt-border-light ps-2 mb-0 year-list">
<b:loop values="data:intervals" var="interval">
<li class="mb-2 pe-2 year-item">
<div class="hierarchy-toggle-wrap">
<button aria-expanded="false" class="toggle-button" type="button">▶</button>
<a class="text-reset fw-bold hover-text-primary archive-link" expr:href="data:interval.url">
<span class="archive-name"><data:interval.name></data:interval.name></span>
<span class="ms-1 fw-light fs-9">[<data:interval.post-count></data:interval.post-count>]</span>
</a>
</div>
<div class="hierarchy-content month-list" style="display: none;">
<b:include cond="data:interval.data" data="interval.data" name="JetBlogArchiveHierarchy"></b:include>
<b:if cond="data:interval.posts">
<ul class="hierarchy-posts list-unstyled border-start border-2 jt-border-light ps-2 mb-0 day-list">
<b:loop values="data:interval.posts" var="post">
<li><a class="text-reset fs-7 hover-text-primary" expr:href="data:post.url"><data:post.title></data:post.title></a></li>
</b:loop>
</ul>
</b:if>
</div>
</li>
</b:loop>
</ul>
<script type="text/javascript">
//<![CDATA[
window.onload = function () {
const buttons = document.querySelectorAll('.toggle-button');
buttons.forEach(button => {
button.addEventListener('click', function () {
const parentItem = this.closest('.year-item');
const monthList = parentItem.querySelector('.month-list');
if (monthList) {
const isExpanded = monthList.style.display === 'block';
monthList.style.display = isExpanded ? 'none' : 'block';
button.textContent = isExpanded ? '\u25B6' : '▼'; // Unicodeの右向き三角
button.setAttribute('aria-expanded', !isExpanded);
}
});
});
};
//]]>
</script>
<style type="text/css">
.month-list {
margin-left: 15px;
}
.day-list {
margin-left: 30px;
}
.hierarchy-toggle-wrap {
display: flex;
align-items: center;
gap: 0.3em;
}
.toggle-button {
color: inherit; /* 親要素から色を継承 */
background: none;
border: none;
font-size: 0.5em;
cursor: pointer;
padding: 0;
margin: 0;
line-height: 1;
}
.hierarchy-toggle-wrap:hover .toggle-button {
color: var(--jt-primary);
}
.archive-link {
display: inline-block;
text-decoration: none;
}
.archive-name {
vertical-align: middle;
}
</style>
</b:includable>
```
</details>
## 使い方(設定)
「管理画面」→「レイアウト」→「Sidebar」→「Blog Archive」→「編集」→「スタイル」→「**階層**」を選択する。
「階層(HIERARCHY)」の仕組み(データ授受、処理など)を使って、表示を変更しているので、「**階層**」を選択すると、この改造スクリプトが動く仕組みだ。
<div style="text-align: center;">
<img alt="Style" border="0" data-original-height="604" data-original-width="403" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0HNHV-8-bGOJx5gDl1QwyjYR6Zj5xa1U2upehAUCWH2fSnK13nBx_q7VEnX26witoXznIvVfwC7VXuEuYK9EtNHMitL5G_bCSvXQ6EYcsVC7GKR32zLcg1sfhevcrYUfhBz5MQ5aIZG3ffKY3w6hXHgf9KhO_zvxCXvd-vW917UalHtQYaqvWosN37e8T/s320/image.png" width="400"/>
</div>
## 蛇足
本来なら、「階層(HIERARCHY)」スタイルはそのままにして、オリジナルのコードには記述されていない「プルダウン(Menu)」を使うのがスマートな方法だ。
しかし残念ながら、この方法はうまく動くスクリプトを作ることができなかった。「プルダウン(Menu)」の選択をすると、アーカイブリストは表示されるのだが、プルダウンさせることがどうやってもできなかった。「**階層**」の仕組みをそのままコピーしてあてはめても、「**階層**」では正常に動くスクリプトが「**メニュー**」では動かない。
そこでしかたなく、単独で「**階層**」の仕組みを使うことにした。
## 十分じゃないけど、これが限界
機能上の不具合がある。
- 当該年(例えば、2025)では、"▶" をクリックすると、月ごとのアーカイブリストにプルダウンする。
- 当該月の"▶" をクリックすると、その月の投稿記事リストにプルダウンする。
- しかし、当該年以外の年で"▶" をクリックしても、なにも起こらない。プルダウンしない不具合がある。
これも対策できなかった。
年/月をクリックすると、その年や月の記事一覧が抽出される。この状態(**抽出された一覧の状態**)では、
- 当該年(例えば、2025)では、"▶" をクリックすると、月ごとのアーカイブリストにプルダウンする。
- 当該月の"▶" をクリックすると、その月の投稿記事リストにプルダウンする。
これらの動作は、
<b>
Jettheme 本来の動作(仕様)
</b>
のようだ。オリジナルの jettheme-v2.xml を一時的に導入して、それを確認した。
### 問題の根源
<b>1. JetThemeのデータ構造</b>
JetThemeが階層化されたアーカイブデータを生成する際に、**現在表示されている期間(年または月)以外の詳細な投稿記事リストを一度にすべて提供しない**ものと思われます。
つまり、**現在の表示とは異なる年や月では、`data:interval.data`や`data:interval.posts`が空、あるいは必要な情報を含んでいないため、HTML自体が生成されていない**のです。
<b>2. スクリプトの実行タイミングと対象 </b>
**JavaScriptのwindow.onloadはページが完全に読み込まれたときに一度だけ実行されます**。この時、JavaScriptは現時点(ページの初回読み込み時)でDOMに存在する要素にのみイベントリスナーを割り当てます。
問題の現象は、**現在の表示とは異なる年や月では、**一度クリックして「抽出された一覧の状態」にするまでは、その年/月の内部にある**月ごとのアーカイブリストや記事リストがそもそもHTMLとして存在しない**ため、JavaScriptが「▶」ボタンをクリックしても、表示/非表示を切り替える**対象の要素を見つけられない**ために発生しています。
「その年/月をクリックして、**その年や月の記事一覧が抽出された状態」にするとプルダウン表示できるのは、そのクリックによってJetThemeが必要なアーカイブデータを動的にロードし、DOMに要素が追加される**ためです。その後、JavaScriptがその新しく追加された要素を認識して動作するようになる、という流れです。
<b>3. 動的にデータ取得</b>
JetThemeの代わりに、スクリプトで各年や月の投稿リストを動的に取得するためには、「どの種類のデータ(年か月か)」と「どこからデータを取得するか(URL)」をJavaScriptに教える情報が不可欠になります。そのために`data-type`と`data-url`といったデータ属性をHTML要素に埋め込みます。
しかし、これらのデータ属性に埋め込むこと自体が、BloggerのXMLパーサーによってSyntaxErrorを引き起こし、スクリプトが機能しなくなります。
## 参考:ブログアーカイブ構成/ オリジナルの jettheme-v2.xml
以下は、
<img alt="Google Gemini Logo" height="32" src="https://upload.wikimedia.org/wikipedia/commons/8/8a/Google_Gemini_logo.svg" style="display: inline-block; vertical-align: baseline;" width="75"/>
で解析した内容になる。
ご指摘ありがとうございます。おっしゃる通り、オリジナルの Jettheme XML には `<b:includable id="JetBlogArchiveMenu">` は存在しません。私の説明に誤りがありました。深くお詫び申し上げます。
オリジナルの Jettheme XML におけるブログアーカイブの構成を説明します。
**オリジナルの Jettheme XML ブログアーカイブ構成(再説明):**
1. **`<b:widget-settings>`:** ブログアーカイブの表示スタイル (`<b:widget-setting name="showStyle">`) などの設定を格納。`HIERARCHY`(階層)、`FLAT`(フラットリスト)などの値を持ちます。`MENU`(プルダウンメニュー)に対応する `<b:widget-setting>` は通常、デフォルトでは存在しません。
2. **`<b:includable id="main">`:** ウィジェットの主要なレンダリング処理を記述。通常、`<b:include name="JetBlogArchive"></b:include>` を呼び出します。
3. **`<b:includable id="JetBlogArchive" var="this">`:** `showStyle` の値に基づいて、異なる表示形式の includable を条件分岐 (`<b:if>`) で呼び分けます。
* **`HIERARCHY` の場合:** `<b:include data="data" name="JetBlogArchiveHierarchy"></b:include>` を呼び出し、階層的なリストを表示。
* **`FLAT` の場合:** `<b:else></b:else>` ブロック内のコードが実行され、`<b:loop>` を用いて年月をフラットなリストとして表示する HTML 構造を直接記述。
* **`MENU` の場合:** オリジナルには `MENU` スタイルに対する明示的な処理は記述されていません。そのため、デフォルトでは `HIERARCHY` の条件に合致しない場合に実行される `<b:else></b:else>` ブロック(フラットリスト表示)が適用されると考えられます。
4. **`<b:includable id="JetBlogArchiveHierarchy" var="intervals">`:** 年月ごとの階層構造を持つリストを表示する HTML (`<ul>`, `<li>`) と、年月ごとのリンク (`<a>`)、投稿数を記述。必要に応じて、さらに月ごとのリストなどを再帰的に表示 (`<b:include data="interval.data" name="JetBlogArchiveHierarchy"></b:include>`)。
5. **`<b:includable id="JetWidgetTitle">`:** ウィジェットのタイトル部分 (`<h2>` など) を表示する共通 includable。
## 関連リンク
</h2></b:includable></a></li></ul></b:includable></b:loop></b:if></b:includable></b:includable></b:widget-setting></b:widget-setting></b:widget-settings></b:includable>