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

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

2014年5月30日金曜日

Blogger:投稿の数が500件を超えていても、意識しないで投稿一覧を作成出来るようにしました

イントロダクション

記事「Blogger:投稿一覧をdocument.writelnではなく、要素のinnerHTMLに挿入することでページの表示を軽くする」では、記事一覧の作成をdocument.writelnではなく、要素のinnerHTMLに挿入することでページの表示を軽くしました。

今回は、document.writeln から innerHTML へ切り替えたことで、JavaScript の実行タイミングがページ表示中だけではなく、ページ表示後でも動作できるようになったため、投稿の数が500件を超えていても、意識しないで投稿一覧を作成出来るようにしてみます。


2014/6/5 追記:

ラベルの URL 生成部にバグがあったため修正しました。

誤:
var labelLink = location.protocol + "//" + location.host + "/" + label;

正:
var labelLink = location.protocol + "//" + location.host + "/search/label/" + encodeURIComponent(label);


何故、投稿の数が 500件を超えると問題があるかというと、フィードの読み込みで一回に取得できる投稿の数の上限が 500件のため、分割してフードを読みに行かなくてはならないからです。

そのため、記事が 500件の倍数を超えるごとに、フィードの読み込みの script タグを増やすというのが従来良く行われている方式でした。


そこで、わざわざ 記事が 500件の倍数を超えるごとに、フィードの読み込みの script タグを増やさなくてもいいように、コードを記載します。


コード

以下のコードを Blogger のページへ張り付けます。

なお、

var blogger_url = "http://upa-pc.blogspot.com";

となっている箇所を各自の Blogger の URL へ差し替えてください。

<div id="post-list-container">
記事一覧生成中...
</div>
<div id="post-list-gen-time">
</div>
<script type="text/javascript">
<!--
    // --- Util ---

    // JavaScript動的挿入
    function addScript(src) {

        var script = document.createElement('script');
        script.setAttribute("type", "text/javascript");
        script.setAttribute("src", src);

        header_setChild(script);
    }

    // <head>取得
    function getHeader() {
        return document.getElementsByTagName("head")[0];
    }

    // <head>に子要素を追加
    function header_setChild(child) {
        var head = getHeader();
        head.appendChild(child);
    }


    // --- Main ---

    var feedDataArray = [];         // フィードのデータ
    var max_results = 500;          // フィード取得件数(最大500)
    var blogger_url = "http://upa-pc.blogspot.com";



    // 記事一覧作成のトリガー
    (function () {

        loadFeed();
        
    })();

    // Feed の読み込み
    function loadFeed() {
        addScript(blogger_url + "/feeds/posts/summary?alt=json-in-script&callback=loadtoc&max-results=" + max_results + "&start-index=" + (max_results * feedDataArray.length + 1) + "&redirect=false");
    }

    function loadtoc(data) {

        // エントリーがある場合は、エントリーをストックし、次の記事の読み込み処理を実行
        if (data.feed.entry) {
            if (data.feed.entry.length > 0) {
                
                feedDataArray.push(data);

                // フィードの上限件数取得できていた場合、まだ投稿が残っている可能性があるので次のフィードを取得する
                if (data.feed.entry.length == max_results) {

                    // 次の feed の読み込み
                    loadFeed();
                    return;
                }
            }
        }

        // エントリーが無い・最後のエントリーまで読み込んだ場合
        // 全てのデータを読み込み終わったので、記事一覧を作成
        createPostsIndex();
    }

    function createPostsIndex() {
        
        // 処理時間計測
        var start_time = new Date();


        var html = "";

        html += "<ol>";
        for (var feedCount = 0; feedCount < feedDataArray.length; feedCount++) {

            var data = feedDataArray[feedCount];        // 処理対象のフィードの取り出し
            for (var i = 0; i < data.feed.entry.length; i++) {

                // リンク先の探索
                var href = "javascript:void(0);";
                for (var j = 0; j < data.feed.entry[i].link.length; j++) {
                    if (data.feed.entry[i].link[j].title == data.feed.entry[i].title.$t) {
                        href = data.feed.entry[i].link[j].href;
                    }
                }

                // ラベル一覧作成
                var labels = "";
                if (data.feed.entry[i].category) {
                    for (var j = 0; j < data.feed.entry[i].category.length; j++) {
                        var label = data.feed.entry[i].category[j].term;
                        var labelLink = location.protocol + "//" + location.host + "/search/label/" + encodeURIComponent(label);

                        labels += "<span><a href=\"" + labelLink + "\">" + label + "</a><span>";
                        if (j < data.feed.entry[i].category.length - 1) {
                            labels += ",";
                        }
                    }
                }

                html += "<li><a href=\"" + href + "\" title=\"" +
                    fixForAttributeTitle(escapeForAttributeText(data.feed.entry[i].summary.$t)) + "\">" +
                    escapeHTML(data.feed.entry[i].title.$t) + "</a><br />ラベル:" + labels + "<br /><br /></li>";


                // 記事のまとまりごとにラインを引く
                if ((i % 10) == 9) {
                    html += "<hr />";
                }
            }
        }

        html += "</ol>";


        var obj_output = document.getElementById("post-list-container");
        obj_output.innerHTML = html;


        // 処理時間計測
        var end_time = new Date();
        var process_span = end_time - start_time;    // 処理時間(ms)

        document.getElementById("post-list-gen-time").innerHTML = "<br />記事一覧の作成にかかった時間は " + process_span + " ms です。<br />";


        // テキストをエスケープ処理する
        function escapeHTML(html) {

            var div = document.createElement("div");
            if (div.innerText !== void 0) div.innerText = html;          // innerText が定義されていれば innerText へ設定
            else div.textContent = html;                                 // Firefox のように innerText がないブラウザ向け

            return div.innerHTML;
        }

        // 属性用にテキストをエスケープ処理する
        function escapeForAttributeText(html) {

            // " をエスケープ
            html = html.replace(/\&/g, "&amp;");

            html = html.replace(/\</g, "&lt;");
            html = html.replace(/\>/g, "&gt;");
            html = html.replace(/\"/g, "&quot;");
            html = html.replace(/\'/g, "&apos;");
            return html;
        }

        // 属性の title 用にテキストを整理する
        function fixForAttributeTitle(text) {

            text = text.replace(/(\r\n){2,}/g, "$1$1");
            text = text.replace(/(\r){2,}/g, "$1$1");
            text = text.replace(/(\n){2,}/g, "$1$1");

            return text;
        }
    }

//-->
</script>



動作としては、500件ごとにフィードを取得し、取得できた投稿の数が取得上限であれば、まだ取得できていない投稿があると判断し、次のフィードを取得しに行っています。

取得したフィードに投稿が含まれていない場合や、取得上限よりも投稿が少ない場合には最後のフィードと判断し、投稿一覧の作成を実行しています。


現在私のブログは投稿の数が 500件に満たないため、上限でのテストはできませんが、フィードの取得件数を 100 件に設定し、上記コードを実行したところ、分割してフィードを取得して、投稿一覧を作成できることを確認しました。


これで、このコードを張り付けておけば、Blogger の投稿の数がどんどん増えて行ったとしても、そのままのコードで全投稿を含んだ投稿一覧が作成できます。


次の改良

→ 新しい改良したコードがあります。
Blogger:JavaScript:大量の投稿があるブログでも、ページ表示時の負荷を抑えて投稿一覧(目次)を作成




関連記事

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

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