鈴木うどんの横須賀おもしろ生活

撮った写真や思ったことや技術ネタなど。出来るだけ大きなディスプレイで見ると良いと思う。ここでの発言は個人の見解であり、所属する組織の公式見解ではありません。

Blog にはカレンダーを載せたいけれどはてなBlogにはそんなものは無いからJavaScriptで書いてみた

なかなかよい感じ。Windowの幅によってinner-containerよりちょこっとはみ出すのがキュート。カレンダーが埋まる様子が見えるとBlogを更新しようという気概が湧くと思う。2005年位のBlogはみんなカレンダーついていたような気がする。

ヘッダ下にcal-boxというidのdivを追加して以下のコードをフッタにくっつけた。jQuery使っているのでこれより前に<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>みたいな感じで読み込んでおく必要がある。

この手のモジュール的なもの、CSSも一緒に含みたいけれど別ファイルにするわけにもいかないし、どうしていいかよくわからなかったので今回は実験的に[]を使ってEmacsのjs-modeでインデントされてるっぽく見えるような感じで書いてみたけれどこの方法で良いかはかなり疑問。意見がほしい。

記事が存在するかは/archive/${year}/${day}をGETで取ってきてHTMLをパースしている。そんな感じで、コードとしてはそんなに難しいことはやっていないけれど、ただ泥臭い処理が多いので思ったよりも長くなった。クライマックスはnew Date(2014,1,32)みたいな存在しない日付でDateを初期化したら Type Error ではなくて自然な感じに2月1日のオブジェクトが返ってきた というところ。

!function($){
    "use strict";

    var CAL_DEFAULT_COLOR = "#000000";
    var CAL_SAT_COLOR = "#44abda";
    var CAL_SUN_COLOR = "#aa1204";

    var style_elm = document.createElement('style');
    style_elm.innerHTML = ['div#cal-box{',
                           [
                               'position:absolute',
                               'left:0',
                               'width:100%',
                               'text-align:center',
                               'white-space:nowrap',
                               'font-size:80%',
                           ].join(';'),
                          '}',
                           'div#cal-label{',
                           [
                               'display:inline-block',
                               'margin-left:1em',
                               'color:' + CAL_DEFAULT_COLOR,
                           ].join(';'),
                           '}',
                           'a.cal-block{',
                           [
                               'display:inline-block',
                               'width:'+ 2.4 + 'em',
                               'color:' + CAL_DEFAULT_COLOR,
                               'text-decoration:none',
                               'text-align:center'
                           ].join(';'),
                           '}',
                           'a.cal-block.disable{opacity: 0.2}',
                           'a.cal-block.active:hover{text-decoration:underline}',
                           'div.cal-day{',
                           [
                               'font-size:75%'
                           ].join(';'),
                           '}',
                           'div.cal-date{',
                           [
                           ].join(';'),
                           '}',
                           'a.cal-block.sat{',
                           [
                               "color:" + CAL_SAT_COLOR
                           ].join(';'),
                           "}",
                           'a.cal-block.sun{',
                           [
                               "color:" + CAL_SUN_COLOR
                           ].join(';'),
                           "}"
                          ].join('');
    var head_elm = document.getElementsByTagName('head')[0];
    head_elm.appendChild(style_elm);
    
    var createMonthDaysArray = function(year, month){
        var days = [];
        var day_count = 1;
        while(true){
            var date = new Date(year, month, day_count++);
            if(date.getMonth() !== month){
                return days;
            }
            days.push(date);
        }
    };
    var zeroPad = function(val, length){
        if((val = val.toString()).length >= length){
            return val;
        }
        var pad_length = length - val.length;
        var list = Array.apply(null, Array(pad_length));
        var zero = function(){return 0};
        return list.map(zero).concat([val]).join('');
    };
    var d2Day = function(d){
        var days_list = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
        return days_list[d];
    };
    var m2Month = function(m){
        var month_list = ['January', 'February', 'March', 'April', 'May', 
                          'June', 'July', 'August', 'September', 'October', 
                          'November', 'December'];
        return month_list[m];
    };
    var date2Elm = function(date){
        var pad_month = zeroPad(date.getMonth()+1, 2);
        var pad_date = zeroPad(date.getDate(),2);
        var href = '/' + ['entries', date.getFullYear(), pad_month, pad_date].join('/');
        var block_id = [date.getFullYear(), pad_month, pad_date].join('');
        var block_class = d2Day(date.getDay()).toLowerCase();
        return ['<a id="', block_id, '" class="cal-block ', block_class, '" href="', href, '">', 
                '<div class="cal-day">', d2Day(date.getDay()), '</div>', 
                '<div class="cal-date">', pad_date, '</div>', 
                '</a>'].join('');
    };
    var now = new Date();
    var year = now.getFullYear();
    var month = now.getMonth();
    $.ajax(
        {type:'GET',
         url:'/' + ['archive', year, month+1].join('/'),
         success: function(html){
             var actives = {};
             Array.prototype.forEach.call($('time', $.parseHTML(html)),function(elm){
                 actives[parseInt(elm.innerHTML.split(/-/)[2])] = true;
             });
             $(document).ready(function(){
                 var label = ['<div id="cal-label">', year.toString(), m2Month(month), '</div>'].join('');
                 var $cal_box = $('#cal-box');
                 $cal_box.html(label + createMonthDaysArray(year, month).map(date2Elm).join(''));;
                 Array.prototype.forEach.call($cal_box.find('a'),function(elm, count){
                     var date = count + 1;
                     var $elm = $(elm);
                     if(actives[date]){
                         $elm.addClass('active');
                     }else{
                         $elm.addClass('disable');
                         $elm.click(function(event){
                             event.preventDefault();
                         });
                     }
                 });
             });
         }
        });
}(jQuery);