人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

はてなブログPC版のサブカテゴリ機能の実装について

http://www.masaemon.jp/
上記ブログ(PC版)右サイドバー下段にカテゴリ一覧を表示しているのですが、カテゴリの量が多く縦長すぎるのが悩みです。そこで以下のようにできるか教えてください。

ーーーーーーーーーー
【現在】
【東京】上野・浅草・日暮里 (34)
【東京】両国・錦糸町・小岩 (2)
【東京】中野?西荻窪 (7)
…続く

【希望】
?東京
おでん
…続く

↓右三角をクリックすると↓

▼東京
【東京】上野・浅草・日暮里 (34)
【東京】両国・錦糸町・小岩 (2)
【東京】中野?西荻窪 (7)
…続く

ーーーーーーーーーー
【補足説明】
・月別アーカイブのように右三角(?)をクリックするとサブカテゴリを表示します。
・今後カテゴリが増えるにあたって、いちいち編集とかせず自動でサブカテゴリが反映できたりすると尚最高です。
・カテゴリ一覧をコンパクトに使い勝手のいいものにできればその方法を回答いただいてもOKです。
・回答には、実装結果を確認できるはてなブログURLが必須です。

1449280991
●拡大する


●質問者: 正衛門
●カテゴリ:インターネット ウェブ制作
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

質問者から

ベストな回答をいただいた場合は早期終了する場合があります。どうぞヨロシクお願いいたします。


1 ● a-kuma3
●300ポイント ベストアンサー

以下のコードを、「デザイン」の「ヘッダ」の「タイトル下」のところにペタッと。

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
(function($) {

$(function() {

 var re = /【(.*)】.*\((.*)\)/;
 var forEach = Array.prototype.forEach;
 var cat_name_map = {};
 forEach.call(document.querySelectorAll("div.hatena-module-category ul.hatena-urllist li a"), function(a) {
 var match = re.exec(a.textContent);
 if (match) {
 var cat = match[1];
 var ar = cat_name_map[cat];
 if (! ar) {
 ar = [0, 0];
 }
 ar[0] += 1;
 ar[1] += parseInt(match[2]);
 cat_name_map[cat] = ar;
 }
 });
 var cat_node_map = {};
 forEach.call(document.querySelectorAll("div.hatena-module-category ul.hatena-urllist li a"), function(a) {
 var match = re.exec(a.textContent);
 if (match) {
 var cat = match[1];
 if (cat_name_map[cat][0] > 1) {
 var original_item = a.parentNode;
 var new_item = document.createElement("LI");
 new_item.innerHTML = original_item.innerHTML;
 new_item.style.paddingLeft = "2em";
 var sub_category_list = cat_node_map[ cat ];
 if (! sub_category_list) {
 /*
 LI : original_item
 |
 V
 LI : sub_category_parent
 SPAN : arrow
 SPAN : label
 UL : sub_category_list
 LI : new_item
 */
 var sub_category_parent = document.createElement("LI");
 original_item.parentNode.insertBefore(sub_category_parent, original_item);
 var arrow = document.createElement("SPAN");
 arrow.innerHTML = "&#9654;";
 arrow.style.cursor = "pointer";
 arrow.onclick = function() {
 var sub_category_list = this.nextSibling.nextSibling;
 if (sub_category_list.style.display == "none") {
 this.innerHTML = "▼";
 sub_category_list.style.display = "";
 } else {
 this.innerHTML = "&#9654;";
 sub_category_list.style.display = "none";
 }
 };
 sub_category_parent.appendChild(arrow);
 var label = document.createElement("SPAN");
 label.innerHTML = cat + " (" + cat_name_map[cat][1] + ")";
 sub_category_parent.appendChild(label);
 sub_category_list = document.createElement("UL");
 sub_category_list.style.display = "none";
 sub_category_parent.appendChild(sub_category_list);
 cat_node_map[ cat ] = sub_category_list;
 }
 sub_category_list.appendChild(new_item);
 original_item.parentNode.removeChild(original_item);
 }
 }
 });

});

})(jQuery);
</script>

サブカテゴリは、【】でくくられたものを拾ってます。
サブカテゴリのカテゴリ数がひとつだけの場合には、折りたたむ意味がないので、そのまま表示するようにしました。
クリックできるのは、ちょっと狭いかなという気もしますが、三角のところだけにしてます。

・回答には、実装結果を確認できるはてなブログURLが必須です。

カテゴリのデータを作るのが大変面なので、id:thyself2005 さんのはてなブログで、Bookmarklet として動作確認しました。
こういう感じになります。
f:id:a-kuma3:20151206004212p:image




追記です。

1.今後【】でくくる複数のカテゴリを追加する場合、特に追加作業等発生せずそれらもサブカテゴリ化できるということでしょうか?

【】でくくられた文字を親カテゴリだと判断するようにしてますので、カテゴリが追加された場合には それに追従します。

2.カテゴリのクリックできる範囲と見た目を月別アーカイブの体裁に揃えることはできますか?
※例えば「? 東京 (XXX)」だと東京 (XXX)も青緑色の下線リンクとなっており、▶ と東京の間の間隔が半角スペース1個分くらい空いている感じです。

月別アーカイブの見た目に寄せることはできますが、月別アーカイブの場合には「年」をクリックしたときは ▶ をクリックしたときと違って、その年の一覧ページに飛びます。
「東京」というカテゴリーは実際にはありませんので、▶ をクリックしたときと同じ動作をするようにしてみました。

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
(function($) {

$(function() {

 var re = /【(.*)】.*\((.*)\)/;
 var forEach = Array.prototype.forEach;
 var cat_name_map = {};
 forEach.call(document.querySelectorAll("div.hatena-module-category ul.hatena-urllist li a"), function(a) {
 var match = re.exec(a.textContent);
 if (match) {
 var cat = match[1];
 var ar = cat_name_map[cat];
 if (! ar) {
 ar = [0, 0];
 }
 ar[0] += 1;
 ar[1] += parseInt(match[2]);
 cat_name_map[cat] = ar;
 }
 });
 var cat_node_map = {};
 forEach.call(document.querySelectorAll("div.hatena-module-category ul.hatena-urllist li a"), function(a) {
 var match = re.exec(a.textContent);
 if (match) {
 var cat = match[1];
 if (cat_name_map[cat][0] > 1) {
 var original_item = a.parentNode;
 var new_item = document.createElement("LI");
 new_item.innerHTML = original_item.innerHTML;
 new_item.style.paddingLeft = "2em";
 var sub_category_list = cat_node_map[ cat ];
 if (! sub_category_list) {
 /*
 LI : original_item
 |
 V
 LI : sub_category_parent
 SPAN : arrow
 SPAN : label
 UL : sub_category_list
 LI : new_item
 */
 var sub_category_parent = document.createElement("LI");
 original_item.parentNode.insertBefore(sub_category_parent, original_item);
 var arrow = document.createElement("SPAN");
 arrow.innerHTML = "&#9654;";
 arrow.style.marginRight = "0.5ex";
 arrow.style.cursor = "pointer";
 arrow.onclick = function() {
 var sub_category_list = this.nextSibling.nextSibling;
 if (sub_category_list.style.display == "none") {
 this.innerHTML = "▼";
 sub_category_list.style.display = "";
 } else {
 this.innerHTML = "&#9654;";
 sub_category_list.style.display = "none";
 }
 };
 sub_category_parent.appendChild(arrow);
 var label = document.createElement("SPAN");
 label.innerHTML = cat + " (" + cat_name_map[cat][1] + ")";
 label.style.textDecoration = "underline";
 label.style.color = "#0E4B84";
 label.style.cursor = "pointer";
 label.onclick = function() {
 this.previousSibling.onclick();
 };
 sub_category_parent.appendChild(label);
 sub_category_list = document.createElement("UL");
 sub_category_list.style.display = "none";
 sub_category_parent.appendChild(sub_category_list);
 cat_node_map[ cat ] = sub_category_list;
 }
 sub_category_list.appendChild(new_item);
 original_item.parentNode.removeChild(original_item);
 }
 }
 });

});

})(jQuery);
</script>

正衛門さんのコメント
さっそくの素晴らしい回答ありがとうございます。 以下、確認させていただけますでしょうか。 1.今後【】でくくる複数のカテゴリを追加する場合、特に追加作業等発生せずそれらもサブカテゴリ化できるということでしょうか? ※例:「【静岡】富士山周辺」というカテゴリを追加すると「【静岡】静岡市」とまとまりカテゴリ「?静岡」配下に富士山周辺と静岡市がまとめられますか? 2.カテゴリのクリックできる範囲と見た目を月別アーカイブの体裁に揃えることはできますか? ※例えば「? 東京 (XXX)」だと東京 (XXX)も青緑色の下線リンクとなっており、?と東京の間の間隔が半角スペース1個分くらい空いている感じです。 どうぞヨロシクお願いいたします。

a-kuma3さんのコメント
>> 1.今後【】でくくる複数のカテゴリを追加する場合、特に追加作業等発生せずそれらもサブカテゴリ化できるということでしょうか? << 【】でくくられた文字を親カテゴリだと判断するようにしてますので、カテゴリが追加された場合には それに追従します。 >> 2.カテゴリのクリックできる範囲と見た目を月別アーカイブの体裁に揃えることはできますか? ※例えば「? 東京 (XXX)」だと東京 (XXX)も青緑色の下線リンクとなっており、&#9654; と東京の間の間隔が半角スペース1個分くらい空いている感じです。 << 回答に追記しました。

a-kuma3さんのコメント
サブカテゴリの行間が空いてて、ちょっと間延びしますね。 月別アーカイブに合わせて、追記の回答の 30行目付近に paddingBottom の指定を入れた方がすっきりします。 >|javascript| var new_item = document.createElement("LI"); new_item.innerHTML = original_item.innerHTML; new_item.style.paddingLeft = "2em"; new_item.style.paddingBottom = 0; // ★これを追加 var sub_category_list = cat_node_map[ cat ]; if (! sub_category_list) { ||<

正衛門さんのコメント
ご回答&補足ありがとうございます。 ぽけっとしすてむさんの回答含め導入を検討しますが、導入が簡単な点、追記サポート(サブカテゴリの行間調整)も助かりそうなので、今回ベストアンサーといたします。

2 ● ぽけっとしすてむ
●200ポイント

f:id:psne:20151205223345j:image
※再掲

以下のコードをHTMLが挿入できる任意の場所に挿入します。
※記事内のみ表示される場所に貼り付けると、それ以外のページでは通常通りの表示になります。

<script>
(function(H,T,N,p,s,n,e){H.Htnpsne=H.Htnpsne||{};Htnpsne[s]=Htnpsne[s]||function(){(Htnpsne[s].q=Htnpsne[s].q||[]).push(arguments)};n=T.createElement(N);e=T.getElementsByTagName(N)[0];n.async=1;n.src=p;e.parentNode.insertBefore(n,e)})(window,document,"script","//niyari.github.io/hatenablog-modules/hb-subcat.min.js","SubCategory");
Htnpsne.SubCategory('setting', { 'pattern': '【(.+)】' });
</script>

サブカテゴリについては質問のとおりになるよう、【(親カテゴリ名)】となるように設定してありますが、

Htnpsne.SubCategory('setting', { 'pattern': '【(.+)】' });

こちらの部分を変更する事で任意の文字列で親カテゴリ、サブカテゴリを生成する事ができます。

/* 例:「親カテゴリ → サブカテゴリ」 という区切りの場合*/
Htnpsne.SubCategory('setting', { 'pattern': '(.+) → ' });

あまり例は無いと思いますが、複数のカテゴリーモジュールが設置されている場合でも動作するようになっています。

f:id:psne:20151206105804p:image

回答には、実装結果を確認できるはてなブログURLが必須です

動作確認用のはてなブログがありますが、プライベート利用の為、スクリーンショットにて回答とさせて頂きます。


正衛門さんのコメント
回答ありがとうございます。 以下、確認させていただけますでしょうか。 ちなみにコードは「デザイン」の「ヘッダ」の「タイトル下」に貼り付けてプレビューしてみました。 1.サブカテゴリ対象がひとつの場合、デフォルトで開いた状態となっていますが、こちらデフォルトで閉じるようにすることは可能でしょうか?もしくは id:a-kuma3 さんの実装例のように折りたたまずそのまま表示にすることは可能でしょうか? ※現在のカテゴリ状況だと「【大阪】大阪市 (1)」が「大阪 (1)」配下で開いた状態となってしまうため。 2.今後【】でくくる複数のカテゴリを追加する場合、特に追加作業等発生せずそれらもサブカテゴリ化できるということでしょうか? ※例:「【静岡】富士山周辺」というカテゴリを追加すると「【静岡】静岡市」とまとまりカテゴリ「?静岡」配下に富士山周辺と静岡市がまとめられますか? 3.カテゴリのクリックできる範囲と見た目を月別アーカイブの体裁に揃えることはできますか? ※例えば「? 東京 (XXX)」だと東京 (XXX)も青緑色の下線リンクとなっており、?と東京の間の間隔が半角スペース1個分くらい空いている感じです。 4.複数のカテゴリーモジュールにも対応とのことですが、現在のはてなブログ管理画面上ではカテゴリーモジュールはタイトルと並び替え順のみを指定できる仕様でして、可能であれば地域別、料理ジャンルとか複数に分けてそれぞれの配下に指定したカテゴリ・サブカテゴリが表示できれば最高なんですが、それだとさすがに自動化での対応は難しいですよね? 【例】 地域別カテゴリー(※名前は任意) 大阪大阪市 (1) ?東京 (215) 料理ジャンル別カテゴリー(※名前は任意) ?ラーメン (XXX) カレー (8) どうぞヨロシクお願いいたします。

ぽけっとしすてむさんのコメント
>> 1.サブカテゴリ対象がひとつの場合、デフォルトで開いた状態となっていますが、こちらデフォルトで閉じるようにすることは可能でしょうか? << 設定を追加しました。 >> 'openSub': '(サブカテゴリを開く設定)' << 設定は「all」「just」「close」(または、設定なし)の3つから選択します。 設定例: >|javascript| //サブカテゴリを全て開く Htnpsne.SubCategory('setting', { 'pattern': '【(.+)】', 'openSub': 'all' }); //サブカテゴリが一つだけの場合は開く Htnpsne.SubCategory('setting', { 'pattern': '【(.+)】', 'openSub': 'just' }); ||< >> 2.今後【】でくくる複数のカテゴリを追加する場合、特に追加作業等発生せずそれらもサブカテゴリ化できるということでしょうか? << パターン通りであれば可能です。 >> 3.カテゴリのクリックできる範囲と見た目を月別アーカイブの体裁に揃えることはできますか? << カスタマイズされたCSSを利用できる設定を追加しました。 >> 'userCSS': (設置者が用意したCSSを利用する) << 設定は「true」「false」(または、設定なし)から選択します。 設定例: >|javascript| //設置者が用意したカスタマイズされたCSSを利用する Htnpsne.SubCategory('setting', { 'pattern': '【(.+)】', 'userCSS': true }); //デフォルトのCSS利用する Htnpsne.SubCategory('setting', { 'pattern': '【(.+)】', 'userCSS': false }); ||< カスタムされたCSSの一例です。 >|css| .js-category-parent-title { padding-left: .3em; } .js-category-child li { display: none; } .js-category-toggle > span { cursor: pointer; } .js-category-parent-hide-button { display: none; } .js-category-parent-show-button { } .js-category-child-show .js-category-parent-hide-button { display: inline; } .js-category-child-show .js-category-parent-show-button { display: none; } .js-category-child-show .js-category-child li { display: block; border-bottom: none; padding: 0 1.5em; } ||< こちらをデザインCSS、または<style>タグで囲んでHTMLとして貼り付けると利用します。 >> 4.(略)地域別、料理ジャンルとか複数に分けてそれぞれの配下に指定したカテゴリ・サブカテゴリが表示できれば(後略) << カテゴリ生成時に、関連したクラスを出力していますので、それに合わせて追加のスクリプトとCSSにて対応できるかと思います。 >> class="hatena-module hatena-module-category" >> class="hatena-module-title" >> 表示されるカテゴリのタイトル (こちらのタイトル部分を利用) << << << 例えば、上記のタイトル部分を取得して、表示・非表示のクラスを指定する事で実現できるかと思います。 ※別機能になりますので、この回答では対応しません。

ぽけっとしすてむさんのコメント
こちらをデザインCSS、または >|html| <style> ... </style> ||< このようにstyleタグで囲んでHTMLとして貼り付けると利用できます。 >> 4.(略)地域別、料理ジャンルとか複数に分けてそれぞれの配下に指定したカテゴリ・サブカテゴリが表示できれば(後略) << カテゴリ生成時に、関連したクラスを出力していますので、それに合わせて追加のスクリプトとCSSにて対応できるかと思います。 >> class="hatena-module hatena-module-category" >> class="hatena-module-title" >> 表示されるカテゴリのタイトル (こちらのタイトル部分を利用) << << << 例えば、上記のタイトル部分を取得して、表示・非表示のクラスを指定する事で実現できるかと思います。 ※別機能になりますので、この回答では対応しません。

正衛門さんのコメント
ご回答ありがとうございます。 a-kuma3さんの回答含め導入を検討します。 取り急ぎ、本質問は終了とします。
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ