日々のコンピュータ情報の集積と整理

Dr.ウーパのコンピュータ備忘録

2014年6月6日金曜日

Blogger:ラベルを構造的に表示する!ラベルを構造化すると新たな発見があるかも?

イントロダクション

Blogger の記事に様々なラベルを付与していたら、ラベルウィジットでラベルの一覧をクラウド形式で表示した場合に、大量のラベルが表示されて何が何だかわからなくなりました。



ラベルウィジット:クラウド形式


そこで、クラウド形式のラベルウィジットのラベルを構造化して表示できる JavaScript を作成してみました。

なお、本コードはクラウド形式でラベルを表示している Blogger のブログに対して有効です。リスト形式でラベルを表示しているものに対しては使えません。


コード

スタイルシート

以下のスタイルシートを Blogger のテンプレートのカスタマイズより、上級者向け→CSSを追加より、追加します。

.label-structure-item-level0
{
    font-size:24px;
    padding-left:0em;
    border-left-color:#d0d0ff;
    border-left-style:dotted;
    border-left-width:1px;
}
.label-structure-item-level1
{
    font-size:24px;
    padding-left:1em;
    border-left-color:#d8d8ff;
    border-left-style:dotted;
    border-left-width:1px;
}
.label-structure-item-level2
{
    font-size:18px;
    padding-left:1em;
    border-left-color:#e0e0ff;
    border-left-style:dotted;
    border-left-width:1px;
}
.label-structure-item-level3
{
    font-size:12px;
    padding-left:1em;
    border-left-color:#e8e8ff;
    border-left-style:dotted;
    border-left-width:1px;
}
.label-structure-item-level4
{
    font-size:12px;
    padding-left:1em;
    border-left-color:#f0f0ff;
    border-left-style:dotted;
    border-left-width:1px;
}


このスタイルシートはラベルの構造の階層ごとに定義しています。
例えば、label-structure-item-level0 であればトップレベルの階層を示しており、label-structure-item-level1はその下の階層を示しています。

現在この階層は 5 階層目 ( label-structure-item-level5 )まで定義していますが、次の JavaScript コードで定義する構造によっては、label-structure-item-level6 以降を更に追加する必要があります。

JavaScript コード

以下のコードを Blogger のテンプレートの HTML の編集より、</body> タグの上に設置します。

なお、

// ラベルの構造化データ
var labelStructure = new treeNode("All Labels", [
 ...
]);

の部分は、各 Blogger のブログのラベルの構造化データを作成してあげる必要があります。


labelStructure はツリー構造になっており、ツリー構造を構成する要素である treeNode は 値と子ノードの配列を持ちます。

値の部分にラベル名を指定します。
値のラベル名がブログ内に存在するラベル名だった場合には、そのラベルの一覧ページ(/search/label/ラベル名)へのリンクを設定します。

値のラベル名が存在しなかった場合、値のラベル名をテキストとして出力します。


値のラベル名は基本的にツリー構造内で重複できません。


子ノードの配列では treeNode の配列を持ちます。
子ノードが無い場合には、new treeNode(" ... ") というように、第2引数を省略します。


このラベルの構造化データで定義されていないラベル名については、未分類として最後に出力されます。


この treeNode については記事「JavaScript:ツリー構造を作成するための構造:とてもシンプル」にて詳しく説明しています。


以上のようにして、ラベルの構造を作成しておきます。

このラベルの構造データは作るのが多少面倒かつ、作成に失敗する可能性があるので、ラベルウィジットの HTML と下記 JavaScript をローカルパソコンに作成した HTML ファイル内に張り付けてテストを行ってから、Blogger の HTML に張り付けた方が良いでしょう。


なお、structureLabel("Label1", labelStructure); として、第1引数に処理対象のラベルウィジットの id を与えています。ブログの環境によっては id が異なる場合もあるので、異なっていたらその id に変更してください。


      <!-- 構造化ラベル作成 START -->
      <script type='text/javascript'>
        //<![CDATA[
        <!--
    (function () {

        // --- Util ---

        /*
        タグ名から子要素のみを選択して取得する
        */
        function getChildElementsByTagName(obj, tagName) {
            var items = new Array();

            for (var i = 0; i < obj.childNodes.length; i++) {
                if (obj.childNodes[i].tagName !== void 0)          // undefined でなければ処理
                {
                    if (obj.childNodes[i].tagName.toLowerCase() == tagName.toLowerCase()) {
                        items.push(obj.childNodes[i]);
                    }
                }
            }

            return items;
        }

        /*
        イベントを追加
        参考:http://d.hatena.ne.jp/dayflower/20080516/1210917670
        */
        function append_event(e, type, handler) {
            if (e.addEventListener) {
                e.addEventListener(type, handler, false);
            } else {
                e.attachEvent('on' + type, handler);
            }
        }

        // --- Lib ---

        // ラベルのラベル名とカウントのペアー
        function CLabelItem(name, count) {
            this.name = name;
            this.count = count;
        }

        /*
        ラベルウィジェットから、ラベル名とカウントのペアーを取得する

        id_label_widget : ラベルウィジェットの id
        */
        function getLabelItems(id_label_widget) {
            var items = new Array();

            var obj_label_widget = document.getElementById(id_label_widget);

            // label ウィジェット内の、ラベル名と投稿数のペアーが収められている<span>要素の上位要素を取得
            var obj_label_widget_labels_tops = getChildElementsByTagName(obj_label_widget, "div");
            if (obj_label_widget_labels_tops.length == 1) {

                // ラベル名と投稿数のペアーが収められている<span>要素取得
                var obj_label_widget_labels_spans = getChildElementsByTagName(obj_label_widget_labels_tops[0], "span");

                for (var i = 0; i < obj_label_widget_labels_spans.length; i++) {
                    if (obj_label_widget_labels_spans[i].className.match(/^label-size label-size/)) {

                        var labelName;      // ラベル名
                        var count;          // カウント

                        // ラベル名の a タグが入っていることを確認
                        // カウント数の span タグがなかったら、count は空白とする
                        var obj_a_Tags = getChildElementsByTagName(obj_label_widget_labels_spans[i], "a");
                        if (obj_a_Tags.length != 1) {
                            continue;
                        }
                        labelName = obj_a_Tags[0].innerHTML;
                        labelName = labelName.replace(/^\s*([^\s].*)$/gm, "$1");         // 前方の空白を削除
                        labelName = labelName.replace(/^(.*[^\s])\s*$/gm, "$1");         // 後方の空白を削除

                        var obj_span_Tags = getChildElementsByTagName(obj_label_widget_labels_spans[i], "span");
                        if (obj_span_Tags.length != 1) {
                            count = "";
                        } else {
                            count = obj_span_Tags[0].innerHTML.replace(/[()]|\s/g, "");
                        }

                        items.push(new CLabelItem(labelName, count));
                    }
                }
            }


            // ラベル名からカウント数を取得するメソッドを追加
            items.getCount = function (name) {

                for (var i = 0; i < items.length; i++) {
                    if (items[i].name == name) {
                        return items[i].count;
                    }
                }

                return "";
            };

            return items;
        }


        // --- Main ---

        // ツリー構造用データ
        function treeNode(value, childNodes) {
            this.value = value;
            this.childNodes = childNodes;
        }

        // ラベルの構造化データ
        var labelStructure = new treeNode("All Labels", [
            new treeNode("Windows", [
                new treeNode("Chrome"),
                new treeNode("compact"),
                new treeNode("Debugging Tools for Windows"),
                new treeNode("Excel"),
                new treeNode("Firefox"),
                new treeNode("Flash"),
                new treeNode("fsuitl"),
                new treeNode("HDD"),
                new treeNode("HydraVision"),
                new treeNode("IE", [
                    new treeNode("IE9")
                ]),
                new treeNode("IIS"),
                new treeNode("IME"),
                new treeNode("Microsoft Excel 2010"),
                new treeNode("PowerPoint", [
                    new treeNode("Microsoft PowerPoint 2010")
                ]),
                new treeNode("Word", [
                    new treeNode("Microsoft Word 2010")
                ]),
                new treeNode("Photoshop", [
                    new treeNode("Adobe Photoshop Elements 2.0")
                ]),
                new treeNode("Screen Capture (by Google)"),
                new treeNode("Skype"),
                new treeNode("Visual Studio", [
                    new treeNode("Visual Studio 2010")
                ]),
                new treeNode("Windows Live Messenger"),
                new treeNode("Windows Live Writer"),
                new treeNode("Windows Live ムービーメーカー"),
                new treeNode("Windows Vista"),
                new treeNode("Windows8"),
                new treeNode("Windows8.1"),
                new treeNode("Yahoo!スマホマネージャー"),
                new treeNode("インストール失敗"),
                new treeNode("クリップボード"),
                new treeNode("コピー"),
                new treeNode("コマンドプロンプト"),
                new treeNode("コンボボックス"),
                new treeNode("シンボリックリンク"),
                new treeNode("スクリーンキャプチャ"),
                new treeNode("スタートメニュー"),
                new treeNode("テキストエディタ"),
                new treeNode("デスクトップ仮想化"),
                new treeNode("ドライバ"),
                new treeNode("ハングアップ"),
                new treeNode("バッチファイル"),
                new treeNode("ブルースクリーン"),
                new treeNode("プロセス"),
                new treeNode("ホットキー"),
                new treeNode("リモートデスクトップ"),
                new treeNode("仮想デスクトップ"),
                new treeNode("壁紙"),
                new treeNode("起動時間"),
                new treeNode("電卓")
            ]),
            new treeNode("Blogger", [
                new treeNode("アーカイブ"),
                new treeNode("パーマリンク"),
                new treeNode("ラベル"),
                new treeNode("人気の投稿"),
                new treeNode("投稿"),
                new treeNode("投稿数カウンタ"),
                new treeNode("新着情報"),
                new treeNode("目次"),
                new treeNode("見出し")
            ]),
            new treeNode("Programming", [
                new treeNode("C#"),
                new treeNode("CGI"),
                new treeNode("HTML", [
                    new treeNode("canvas"),
                    new treeNode("noscript"),
                    new treeNode("pre"),
                    new treeNode("SVG"),
                    new treeNode("textarea"),
                    new treeNode("属性")
                ]),
                new treeNode("CSS", [
                    new treeNode("text-align"),
                    new treeNode("スタイルシート")
                ]),
                new treeNode("JavaScript", [
                    new treeNode("Closure Compiler"),
                    new treeNode("JavaScriptで陥る罠"),
                    new treeNode("イベント")
                ]),
                new treeNode("Perl"),
                new treeNode("Python"),
                new treeNode("カンマ演算子"),
                new treeNode("コンセプトコード"),
                new treeNode("ソースコード"),
                new treeNode("テスト"),
                new treeNode("デザイン"),
                new treeNode("デベロッパーツール"),
                new treeNode("ドキュメント"),
                new treeNode("ハッカソン"),
                new treeNode("リリース"),
                new treeNode("変数宣言"),
                new treeNode("技術デモ"),
                new treeNode("文字の配置"),
                new treeNode("文字化け"),
                new treeNode("文字認識"),
                new treeNode("正規表現"),
                new treeNode("遅延ロード"),
                new treeNode("開発")
            ]),
            new treeNode("Computer", [
                new treeNode("Apple"),
                new treeNode("BIOS"),
                new treeNode("buffalo"),
                new treeNode("Google"),
                new treeNode("iOS"),
                new treeNode("iPad", [
                    new treeNode("iPad Air")
                ]),
                new treeNode("IT"),
                new treeNode("LinkStation"),
                new treeNode("Linux", [
                    new treeNode("Ubuntu")
                ]),
                new treeNode("Mac book Pro"),
                new treeNode("MDV-ASG8300B"),
                new treeNode("MEDIAS N-04C"),
                new treeNode("MEDIAS X N-04E"),
                new treeNode("microSD"),
                new treeNode("NVIDIA GeForce GTX 550 Ti"),
                new treeNode("PIO病"),
                new treeNode("QRコード"),
                new treeNode("ScanSnap"),
                new treeNode("SSD"),
                new treeNode("USB", [
                    new treeNode("USBマウス"),
                    new treeNode("USB切替機")
                ]),
                new treeNode("VAIO"),
                new treeNode("Wooo L32-V09"),
                new treeNode("おくだけ充電"),
                new treeNode("エラー"),
                new treeNode("グラフ"),
                new treeNode("コンピュータ化"),
                new treeNode("スマートフォン", [
                    new treeNode("テザリング"),
                    new treeNode("ドコモメール", [
                        new treeNode("ドコモメール(ブラウザ版)")
                    ]),
                    new treeNode("電話"),
                    new treeNode("電話帳")
                ]),
                new treeNode("ディスプレイ", [
                    new treeNode("ディスプレイドライバー")
                ]),
                new treeNode("ノートパソコン"),
                new treeNode("バグ"),
                new treeNode("バグフィックス"),
                new treeNode("バックアップ"),
                new treeNode("バッテリー"),
                new treeNode("パソコン周辺機器"),
                new treeNode("ヘッドホン"),
                new treeNode("ポータブルHDD"),
                new treeNode("マウスコンピュータ"),
                new treeNode("マルチディスプレイ"),
                new treeNode("マルチブラウザ"),
                new treeNode("メモリ不足"),
                new treeNode("メール"),
                new treeNode("モバイル"),
                new treeNode("レポート"),
                new treeNode("不具合"),
                new treeNode("作業自動化"),
                new treeNode("動画編集"),
                new treeNode("断線"),
                new treeNode("日本語入力"),
                new treeNode("機械化"),
                new treeNode("自炊"),
                new treeNode("表"),
                new treeNode("負荷"),
                new treeNode("障害対策"),
                new treeNode("音飛び"),
                new treeNode("騒音")
            ]),
            new treeNode("セキュリティ", [
                new treeNode("ウィルス対策", [
                    new treeNode("ウィルスバスター")
                ]),
                new treeNode("パスワード"),
                new treeNode("フィッシング"),
                new treeNode("脆弱性")
            ]),
            new treeNode("ネットワーク", [
                new treeNode("Amazon"),
                new treeNode("Blog"),
                new treeNode("DLNA"),
                new treeNode("DNS"),
                new treeNode("Feed"),
                new treeNode("ftp"),
                new treeNode("Google Chart"),
                new treeNode("Google Map"),
                new treeNode("GTmetrix"),
                new treeNode("LAN"),
                new treeNode("Linkwithin"),
                new treeNode("Marvell"),
                new treeNode("NAVERまとめ"),
                new treeNode("ping"),
                new treeNode("RSS"),
                new treeNode("slideshare"),
                new treeNode("SyntaxHighlighter"),
                new treeNode("Wake On Lan"),
                new treeNode("Web"),
                new treeNode("Webサーバ"),
                new treeNode("Webサービス", [
                    new treeNode("参照用リンク作成")
                ]),
                new treeNode("Web制作"),
                new treeNode("WiMAX"),
                new treeNode("YouTube"),
                new treeNode("zenback"),
                new treeNode("えきねっと"),
                new treeNode("インデクサ"),
                new treeNode("クロール"),
                new treeNode("ツイッター"),
                new treeNode("ニコニコ動画"),
                new treeNode("ネットワークアダプタ"),
                new treeNode("ビデオ通話"),
                new treeNode("ブラウザ"),
                new treeNode("ブログ", [
                    new treeNode("ブログパーツ"),
                    new treeNode("ブログ制作")
                ]),
                new treeNode("検索"),
                new treeNode("無料楽曲"),
                new treeNode("無線LAN", [
                    new treeNode("親機")
                ]),
                new treeNode("通信速度")
            ]),
            new treeNode("Android", [
                new treeNode("Nexus7")
            ]),
            new treeNode("ゲーム", [
                new treeNode("PS4"),
                new treeNode("SimCity"),
                new treeNode("ニンテンドー3DS")
            ]),
            new treeNode("ニュース", [
                new treeNode("時事")
            ]),
            new treeNode("特集", [
                new treeNode("「Blogger の各要素の周りに太い枠線を設置することで、パネルが並んでいるようなデザインにする」シリーズ"),
                new treeNode("「Bloggerの記事に目次をJavaScriptで自動的に付与する」シリーズ"),
                new treeNode("「ナビゲーションをでっかくして目立たせて使ってもらおう!」シリーズ")
            ]),
            new treeNode("その他", [
                new treeNode("ToDo"),
                new treeNode("おもしろい"),
                new treeNode("もっと読む"),
                new treeNode("アニメーション"),
                new treeNode("エイプリルフール"),
                new treeNode("カスタマイズ"),
                new treeNode("シンプル化"),
                new treeNode("トラブル"),
                new treeNode("ビジネス"),
                new treeNode("作業"),
                new treeNode("作業環境"),
                new treeNode("失敗"),
                new treeNode("契約"),
                new treeNode("対策検討中"),
                new treeNode("待ち合わせ"),
                new treeNode("復旧"),
                new treeNode("思いつき"),
                new treeNode("思想"),
                new treeNode("思考の罠"),
                new treeNode("提案"),
                new treeNode("改善案"),
                new treeNode("救い"),
                new treeNode("数学"),
                new treeNode("文章"),
                new treeNode("明るさ"),
                new treeNode("本"),
                new treeNode("発表資料"),
                new treeNode("罠"),
                new treeNode("翻訳"),
                new treeNode("通知")
            ])
        ]);




        /*
        ラベルを構造化した HTML を取得する

        labelItems : ラベル名とカウントのペアーの配列 : 使用した要素は削除されます
        labelStructure : ラベルの構造
        nest : 現在の構造のネスト
        */
        function getStructuredLabelHTMLCore(labelItems, labelStructure, nest) {

            var html = "";

            html += "<div class=\"label-structure-item label-structure-item-level" + nest + "\">";

            // ラベル構造に一致するラベル一覧が存在したら、ラベルへのリンク付きで項目名を出力する
            for (var i = 0; i < labelItems.length; i++) {
                if (labelStructure.value == labelItems[i].name) {

                    var labelLink = location.protocol + "//" + location.host + "/search/label/" + encodeURIComponent(labelItems[i].name);

                    html += "<a href=\"" + labelLink + "\">" + labelItems[i].name + "</a>";
                    if (labelItems[i].count != "") {
                        html += "<span> ( " + labelItems[i].count + " ) </span>";
                    }

                    break;
                }
            }
            if (i == labelItems.length) {
                html += labelStructure.value;
            } else {
                // 使用した要素を削除
                labelItems.splice(i, 1);
            }

            // 子構造があれば、子構造を出力
            if (labelStructure.childNodes) {
                for (var i = 0; i < labelStructure.childNodes.length; i++) {
                    html += getStructuredLabelHTMLCore(labelItems, labelStructure.childNodes[i], nest + 1);
                }
            }

            html += "</div>";

            return html;
        }

        /*
        ラベルを構造化した HTML を取得する

        labelItems : ラベル名とカウントのペアーの配列 : 使用した要素は削除されます
        labelStructure : ラベルの構造
        */
        function getStructuredLabelHTML(labelItems, labelStructure) {

            var html = getStructuredLabelHTMLCore(labelItems, labelStructure, 0);

            var labelStrcutureOtherChild = [];

            // 未分類のデータを出力
            if (labelItems.length > 0) {
                for (var i = 0; i < labelItems.length; i++) {
                    labelStrcutureOtherChild.push(new treeNode(labelItems[i].name));
                }
                var labelStrcutureOther = new treeNode("未分類", labelStrcutureOtherChild);
                html += getStructuredLabelHTMLCore(labelItems, labelStrcutureOther, 1);
            }

            return html;
        }


        var label_htmlCache = [];         // ラベルの HTML のキャッシュ

        /*
        ラベルを構造化する

        id_label_widget : ラベルウィジェットの id
        labelStructure : ラベルの構造
        */
        function structureLabel(id_label_widget, labelStructure) {

            // ラベル名とカウント数のペアの配列データ
            var labelItems = getLabelItems(id_label_widget);
            var obj_label_widget = document.getElementById(id_label_widget);

            // label ウィジェット内の、ラベル名と投稿数のペアーが収められている<span>要素の上位要素を取得
            var obj_label_widget_labels_tops = getChildElementsByTagName(obj_label_widget, "div");
            if (obj_label_widget_labels_tops.length == 1) {

                // ラベルを構造化した HTML を取得
                var html = getStructuredLabelHTML(labelItems, labelStructure);

                // HTML をキャッシュする
                label_htmlCache["default"] = obj_label_widget.innerHTML;
                label_htmlCache["structure"] = html;

                // ラベルの HTML の変更
                changeLabelHTML("structure");
            }

            /*
            ラベルの HTML の変更
            */
            function changeLabelHTML(mode) {

                if (mode == "default") {
                    obj_label_widget.innerHTML = "<div><a href=\"javascript:void(0);\" id=\"label-change-mode\">構造化ラベル</a> クラウドラベル</div>" + label_htmlCache[mode];

                    // クリック時のイベントの追加
                    append_event(document.getElementById("label-change-mode"), "click", function () { changeLabelHTML("structure") });
                } else {
                    obj_label_widget.innerHTML = "<div>構造化ラベル <a href=\"javascript:void(0);\" id=\"label-change-mode\">クラウドラベル</a></div>" + label_htmlCache[mode];

                    // クリック時のイベントの追加
                    append_event(document.getElementById("label-change-mode"), "click", function () { changeLabelHTML("default") });
                }
            }
        }

        structureLabel("Label1", labelStructure);

    })();
        //-->
        //]]>
      </script>
      <!-- 構造化ラベル作成 END -->


結果

以下のように構造化したラベルウィジットを作成することが出来ました。

構造化ラベル クラウドラベル
All Labels
ネットワーク ( 1 )
Amazon ( 3 )
Blog ( 3 )
DLNA ( 1 )
DNS ( 1 )
Feed ( 3 )
ftp ( 1 )
Google Chart ( 1 )
Google Map ( 1 )
GTmetrix ( 1 )
LAN ( 1 )
Linkwithin ( 2 )
Marvell ( 1 )
ping ( 2 )
RSS ( 2 )
slideshare ( 1 )
Wake On Lan ( 1 )
Web ( 2 )
Webサーバ ( 4 )
Web制作 ( 3 )
WiMAX ( 1 )
YouTube ( 1 )
zenback ( 2 )
クロール ( 1 )
ブラウザ ( 4 )
検索 ( 1 )
無料楽曲 ( 1 )
無線LAN ( 2 )
親機 ( 1 )
通信速度 ( 1 )
Android ( 6 )
Nexus7 ( 5 )
ゲーム ( 1 )
PS4 ( 1 )
SimCity ( 1 )
ニュース ( 5 )
時事 ( 2 )
その他
ToDo ( 1 )
トラブル ( 1 )
ビジネス ( 1 )
作業 ( 1 )
作業環境 ( 2 )
失敗 ( 2 )
契約 ( 1 )
復旧 ( 2 )
思いつき ( 1 )
思想 ( 1 )
思考の罠 ( 1 )
提案 ( 1 )
改善案 ( 1 )
救い ( 1 )
数学 ( 2 )
文章 ( 2 )
明るさ ( 1 )
( 2 )
発表資料 ( 1 )
( 2 )
翻訳 ( 1 )
通知 ( 1 )


このようにラベルを構造化したことで、ブログ訪問者が目的のラベルを見つけやすくなるかもしれません。


ラベルの配下のラベル一覧の開く・閉じるを行える機能を付与しました!





関連記事

関連記事を読み込み中...

同じラベルの記事を読み込み中...