読者です 読者をやめる 読者になる 読者になる

【スマホ表示に対応】はてなブログで同じカテゴリーの記事へのリンクを表示する

JavaScript プログラミング

二週間前に書いた同じカテゴリーの記事へのリンクを表示するスクリプトについて、 スマホやタブレットの表示にも対応できたので再度投稿します。

2014/02/01 18:39 追記

id bulldraさんが作成した「あわせて読みたい」のウィジェットで、 同じカテゴリーの記事の表示に対応されています。そちらをぜひご利用ください。

【追記あり】はてなブログで表示エントリのカテゴリに関係するエントリを「あわせて読みたい」として表示するウィジェット - 情報学の情緒的な私試論β

追記ここまで

仕様

  • 表示中の記事についてはリンクを表示しない
  • 対象となるカテゴリーの件数が1件しかない場合も表示しない
  • 複数のカテゴリーが設定されている場合は、先頭のカテゴリーを表示する
  • PCのみ表示する、スマホのみ表示するといった制御はなし
  • 使用しているテーマ*1によって、レイアウトや文字の大きさなどの調整が必要

課題

  • AndroidおよびAndroidのタブレットについては表示されない場合があるかも
  • 記事の投稿日付についてはURLから抽出できると思うけど、文字が長くなりそうなので未対応
  • スマホ側のCSSを変更する場合、デザインCSSではなく、記事下などにstyleタグやlinkタグをなど入れるしか方法がない

実装してみたら、デザインCSSに集約できないのは痛手でしたが、PCとスマホで個別にCSSを設定できるように、 スマホの出力時にはaタグにentry-title-spという名前でclassを付与してあります。CSSのサンプルもあわせて記載しました。

というわけで、以下がソースになります。前回と同じく、使用する場合は自己責任でお願いします。 変更等は自由にしてもらって構いません。どんな感じで表示されるのかは個別記事の一番下を参考にしてください。

2014/03/04 20:48 追記

PC表示でのカテゴリーページのCSSが変更されていたので直しました。

変更前: var elements = dom.querySelectorAll("a.entry-title");
変更後: var elements = dom.querySelectorAll("a.entry-title-link");

追記ここまで

2014/08/17 15:37 追記

スマホ表示でのカテゴリーページのHTMLやCSSが変更され、動作しなくなっていたので直しました。

修正

変更前: var elements = dom.querySelectorAll("li.entry-article a");
変更後: var elements = dom.querySelectorAll("a.entry-list-anchor-block");

変更前: elements[i].innerText = elements[i].childNodes[1].innerText;
変更後: elements[i].innerHTML = titles[i].innerText;

追加

var titles = dom.querySelectorAll("div.entry-title");

追記ここまで

2015/03/02 20:57 追記

カテゴリーへのリンクのURLが変更されており、下記の置き換えが不要になったので修正しました。

変更前: category_url = category_element.href.replace("/category","/archive/category");
変更後: category_url = category_element.href;

追記ここまで

ソース

<script type="text/javascript">
  var category_element = document.querySelector("div.categories a");
  var disp_entry_number = 5; // 記事を表示する件数

  if(category_element !== undefined && category_element != null) {
    category_url = category_element.href;
    category_title = category_element.text;
    var req = new XMLHttpRequest();

    req.onreadystatechange = function() {
      if (req.readyState == 4 && req.status == 200) {
        var dom = document.createElement("dom");
        dom.innerHTML = req.responseText;
        var agent = navigator.userAgent;

        if (agent.indexOf('iPhone') > 0 || agent.indexOf('iPod') > 0 || (agent.indexOf('Android') > 0 && agent.indexOf('Mobile') > 0)) {
          var elements = dom.querySelectorAll("a.entry-list-anchor-block");
          var titles = dom.querySelectorAll("h1.entry-title");
          for(var i=0; i<elements.length; i++) {
            elements[i].innerHTML = titles[i].innerText;
            elements[i].className = 'entry-title-sp';
          }
        }else{
          var elements = dom.querySelectorAll("a.entry-title-link");
        }

        if(elements.length > 1) {
          var ul = document.createElement("ul");

          if(disp_entry_number > elements.length) {
            disp_entry_number = elements.length;
          }

          for(var i=0; i<disp_entry_number; i++) {
            if(elements[i].href != location.href){
              var li = document.createElement("li");
              li.appendChild(elements[i]);
              ul.appendChild(li);
            }else if(elements.length > disp_entry_number) {
              disp_entry_number += 1;
            }
          }

          var category_entry = document.getElementById("category-entry");
          category_entry.innerHTML = "<h4>カテゴリー 「" + category_title + "」 の記事</h4>"; // リストの見出し
          category_entry.appendChild(ul);
        }
      }
    } 
    req.open('GET', category_url, true);
    req.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
    req.send();
  }
</script>

<div id="category-entry"></div>

以下はCSSのサンプルです。PCとスマホの両方に対応させたい場合はstyleタグで記事下などに。PCだけでよければデザインCSSに。

hr{
    border:none;
    border-top: 1px dashed #AAA;
    margin: 5px;
}

#category-entry h4{
    font-size: 100%;
    margin-top: 10px;
    margin-bottom:5px;
}

#category-entry ul{
    list-style-type: circle;
    margin-top: 0px;
    padding-left: 20px;
}

/* リンクの文字の設定 */

/* デザインCSSのみで統一したい場合 */
#category-entry a{
    font-size: 100%;
    line-height: 1.7em;
}

/* PCおよびタブレットの場合 */
a.entry-title{
    font-size: 110%;
    line-height: 1.7em;
}

/* スマホの場合 */
a.entry-title-sp{
    font-size: 80%;
    line-height: 1.7em;
}

直すべきところはまだたくさんありそうですが、機能としてはほぼ実現できたかなと。ユーザーエージェントの判定や、 querySelectorとかquerySelectorAllが、CSSベースで要素を抽出できて便利なのが分かったので、それだけでも収穫です。

参考

*1:僕が投稿時点で使っているのは公式テーマのEpicです