Javascript(jQuery)」カテゴリーアーカイブ

jQuery Javascript History.back()を判定

FirefoxでHistory.back()で戻った時ボタンが押せないと指摘を受けたので対策

// 画面からHistory.back()や戻るボタンで戻った場合
window.onpageshow = function() {
    // ボタンを押せる状態にする
    $('.btn').attr('disabled', false);
};
// 連打制御
$('.btn').click(function() {
    $('.btn').attr('disabled', true);
    $('#form_name').submit();
});

Window: pageshow イベント
ブラウザーの進む、戻るボタンを利用してこのページに戻ったときに実行させたい処理を書く。

summernoteで画像をアップロード

summernoteで画像をアップロードする方法を調べてみたが情報が古く自分で実装したのでまとめ。
画像をアップロードしたらエディタに画像を反映させるところまで解説します。

環境
summernote v0.8.12
XAMPP
PHP 7.3

読み込むファイル

<!-- include libraries(jQuery, bootstrap) -->
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet">
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js"></script>
<!-- include summernote css/js -->
<link href="summernote-master/dist/summernote.css" rel="stylesheet">
<script src="summernote-master/dist/summernote.min.js"></script>
<script src="summernote-master/dist/lang/summernote-ja-JP.js"></script>

<form method="post" enctype="multipart/form-data" action="">
  <textarea id="summernote" name="editordata"></textarea>
<input type="submit" name="send" value="送信する">

bootstrapはCDNでsummernoteは日本語で読み込んでいます。

画像ファイルのアップロード部

$(document).ready(function() {
    $('#summernote').summernote({
      lang: 'ja-JP',
        height: 200,
        callbacks: {
            onImageUpload: function(files) {
                sendFile(files[0]);
            },
        }
    });
});

function sendFile(file) {
    data = new FormData();
    data.append("file", file);
    $.ajax({
        data: data,
        type: "POST",
        url: "upimg.php",
        cache: false,
        contentType: false,
        processData: false,
    }).done(function(data, textStatus, jqXHR){
        $('#summernote').summernote('insertImage', 'http://localhost/develop.git/img/' + file.name);
    });
}

sendFileに渡すデータはfileだけなのとsummernoteで画像をアップしたらエディタに反映させるのはinsertImageで画像URLを指定しています。
その他は先人の知恵をお借りしました。

upimg.php

    move_uploaded_file($_FILES['file']['tmp_name'], "img/". $_FILES['file']['name']);

画像をアップしているだけなので
ファイル名が重複しないようしたりリサイズなどはこのファイルでするようにしましょう。

jQuery Table要素にappend

jQueryでTable要素にappendするときずれた位置に表示されてしまったのでまとめ

$(document).ready(function(){
    $('#foo').append('<tr>');
    $('#foo').append('<td>');
    $('#foo').append('ずれた位置に表示される');
    $('#foo').append('</td>');
    $('#foo').append('</tr>');
});

最初のtrタグをappendしたタイミングで/trされる。
tdタグについても同じくtdタグをappendしたタイミングで/tdされる。
なのでHTMLでみると以下のようになる

<table id="foo">
  <tr></tr>
  <td></td>
  ずれた位置に表示される
</table>

for文などで行と列が可変の場合とても面倒だが
tableにtrをappendする
trにtdをappendする

$(document).ready(function(){
    $('#foo').append('<tr id="bar"></tr>');
    $('#bar').append('<td>この書き方が正解</td>');
});

HTMLでみると以下のようになる

<table id="foo">
  <tr id="bar">
    <td>この書き方が正解</td>
  </tr>
</table>

なおtrをappendするタイミングで/trがされるので/trは省略できる。
tdタグについても同じくtdをappendするタイミングで/tdがされるので/tdは省略できる。
しかし/タグを省略して書くとプログラマとしては失格であるので/tr/tdでしっかりと閉じよう。
誰が見ても分かりやすいコードを書くように心がけよう。

jQuery 楽天 カレンダー

楽天のカレンダーが表示されなくなってたので自分で組みました。
1ヶ月毎に自動で切り替わる仕様です。

CSS

table.calbase_rakuten {
    background-color: #FFFFFF;
    border: 1px solid #CECECE;
    width: 100%;
    border-collapse: collapse;
    padding: 0px 0px 10px 0px;
}

table.calbase_rakuten * {
    font-size: 98%;
    color: #000000;
    border-collapse: collapse;
    padding: 0px;
    margin: 0px;
}

table.calbase_rakuten th {
    text-align: center;
}

th.caltitle_rakuten {
    font-size: 85%;
    padding: 10px 0px 0px 0px;
}

table.calframe_rakuten {
    border-collapse: collapse;
    margin: 10px 10px 0px 10px;
    table-layout: fixed;
    width: 178px;
}

table.calframe_rakuten th {
    text-align: center;
    padding: 0px 0px 3px 0px;
}

table.calframe_rakuten td {
    border: 1px solid #FFFFFF;
    background-color: #FFFFFF;
    width: 19px;
    height: 17px;
    text-align: center;
}

tr.weektitle_rakuten td {
    background-color: #EEEEEE;
}

td.event1day_rakuten {
    background-color: #FFC6C6 !important;
}

font.event1day_rakuten {
    color: #FFC6C6;
}

td.event2day_rakuten {
    background-color: #B5DAFF !important;
}

font.event2day_rakuten {
    color: #B5DAFF;
}

td.event3day_rakuten {
    background-color: #FEDE93 !important;
}

font.event3day_rakuten {
    color: #FEDE93;
}

table.event_rakuten {
    text-align: left;
    word-break: break-all;
    margin: 7px 10px 7px 10px;
    border-collapse: collapse;
    line-height: 120%;
    table-layout: fixed;
    width: 141px;
}

table.event_rakuten td {
    padding: 0px 0px 0px 0px;
}

table.text_rakuten {
    text-align: left;
    word-break: break-all;
    margin: 0px 10px 10px 10px;
    border-collapse: collapse;
    line-height: 120%;
    table-layout: fixed;
    width: 178px;
}

HTML

<table class="calbase_rakuten">
  <tr>
      <td align="center">
      <table>
        <tr>
          <td align="center">
            <table class="calframe_rakuten" id="forArea0">
              <tr>
                <th colspan="7"><span id="y0"></span>年<span id="m0"></span>月</th>
              </tr>
              <tr class="weektitle_rakuten">
                <td style="color:#BF0000">日</td>
                <td style="color:#000000">月</td>
                <td style="color:#000000">火</td>
                <td style="color:#000000">水</td>
                <td style="color:#000000">木</td>
                <td style="color:#000000">金</td>
                <td style="color:#1D54A7">土</td>
              </tr>
            </table>

            <table class="calframe_rakuten" id="forArea1">
              <tr>
                <th colspan="7"><span id="y1"></span>年<span id="m1"></span>月</th>
              </tr>
              <tr class="weektitle_rakuten">
                <td style="color:#BF0000">日</td>
                <td style="color:#000000">月</td>
                <td style="color:#000000">火</td>
                <td style="color:#000000">水</td>
                <td style="color:#000000">木</td>
                <td style="color:#000000">金</td>
                <td style="color:#1D54A7">土</td>
              </tr>
            </table>

          </td>
        </tr>
        <tr>
          <td colspan="2">
            <table class="event_rakuten">
              <tr><td><font class="event1day_rakuten">■</font> 休業日</td></tr>
              <tr><td><font class="event2day_rakuten">■</font> 受注・お問い合わせ業務のみ</td></tr>
              <tr><td><font class="event3day_rakuten">■</font> 発送業務のみ</td></tr>
            </table>
          </td>
        </tr>
        <tr>
          <td colspan="2">
            <table class="text_rakuten">
              <tr><td>
                ※ご注文は24時間年中無休で受け付けております。
              </td></tr>
            </table>
          </td>
        </tr>
      </table>
    </td>
  </tr>
</table>

Javascript

$(document).ready(function(){
    var dt = new Date();
    var echoCount = 2;
    var holidayDates = ['2019/3/21','2019/4/29','2019/4/30','2019/5/1','2019/5/2','2019/5/3','2019/5/4','2019/5/5','2019/5/6','2019/7/15','2019/8/11','2019/8/12','2019/9/16','2019/9/23','2019/10/14','2019/10/22','2019/11/3','2019/11/4','2019/11/23'];

    for (var i = 0; i < echoCount; i++) {
	    $('#y' + i).append(dt.getFullYear());
	    $('#m' + i).append(dt.getMonth() + 1);
	    createClendar(dt, '#forArea' + i, 'row' + i);
        var nextLastDay = new Date(dt.getFullYear(), dt.getMonth()+2, 0).getDate();
        if (nextLastDay <= dt.getDate()) {
	        dt.setDate(dt.getDate() + 1);
        } else {
            dt.setMonth(dt.getMonth() + 1);
        }
	}

    function createClendar(dt, areaName, rowName) {
        var lastDay = new Date(dt.getFullYear(), dt.getMonth()+1, 0).getDate();
        var row = 0;
        var k = 0;
        var a = dt.getDay();
        var beginMonth = new Date(dt.getFullYear(), dt.getMonth(), 1).getDay();
        if (beginMonth != 0) {
            var lateLastMonth = new Date(dt.getFullYear(), dt.getMonth(), 0).getDate();
            var beginMonth = new Date(dt.getFullYear(), dt.getMonth(), 1).getDay();
            var i = lateLastMonth - beginMonth + 1;
            var j = 0;
            $(areaName).append('<tr id="' + rowName + row + '"></tr>');
            for (i; i <= lateLastMonth; i++) {
                $('#' + rowName + row).append('<td style="color:#CECECE">' + i + '</td>');
                j++;
            }
            for (j; j < 7; j++) {
                k++;
                if (j == 0 || j == 6) {
                    $('#' + rowName + row).append('<td style="color:#1D54A7" class="event1day_rakuten">' + k + '</td>');
                } else if (holidayDates.some(function(e) {return e == dt.getFullYear() + '/' + (dt.getMonth()+1) + '/' + k})) {
                    $('#' + rowName + row).append('<td style="color:#BF0000" class="event1day_rakuten">' + k + '</td>');
                } else {
                    $('#' + rowName + row).append('<td style="color:#000000">' + k + '</td>');
                }
            }
        }
        for (var i = 0; i < 7; i++) {
        	k++;
        	if (i == 0) {
        		row++;
    	        $(areaName).append('<tr id="' + rowName + row + '"></tr>');
        	}
        	if (i == 0 || i == 6) {
                $('#' + rowName + row).append('<td style="color:#1D54A7" class="event1day_rakuten">' + k + '</td>');
            } else if (holidayDates.some(function(e) {return e == dt.getFullYear() + '/' + (dt.getMonth()+1) + '/' + k})) {
                $('#' + rowName + row).append('<td style="color:#BF0000" class="event1day_rakuten">' + k + '</td>');
            } else {
                $('#' + rowName + row).append('<td style="color:#000000">' + k + '</td>');
            }
        	if (i == 6) {
        	    i = -1;
        	}
    	    if (k >= lastDay) {
    	    	var forCount = 7 - new Date(dt.getFullYear(), dt.getMonth(), k).getDay();
        		for (j = 1; j < forCount; j++) {
    	            $('#' + rowName + row).append('<td style="color:#CECECE">' + j + '</td>');
        		}
    	    	break;
    	    }
        }
    }
});

まとめ

祝日判定をarray.someでしているがIE11で動かなかった。

if (holidayDates.some(e) => e == '2019/4/29') {
    // ie11で動かないよ
    // でもChromeとFirefoxでは動くよ
}
if (holidayDates.some(function(e) {return e == '2019/4/29'})) {
    // ie11でも動くよ
}

Javascript Dateで日付比較

最近Javascriptで土日祝日を飛ばして出荷日を自動表示する依頼があったのでまとめ

$(document).ready(function(){
    var dt = noonDecision();
    var w = dt.getDay();
    var wd = ['日', '月', '火', '水', '木', '金', '土'];
    var holidayDates = ['2019/3/21','2019/4/29','2019/4/30','2019/5/1','2019/5/2','2019/5/3','2019/5/4','2019/5/5','2019/5/6','2019/7/15','2019/8/11','2019/8/12','2019/9/16','2019/9/23','2019/10/14','2019/10/22','2019/11/3','2019/11/4','2019/11/23'];
    var startWork = '2020/01/01';
    var endWork = '2019/12/31';
    var errorFlg = true;

    if (new Date(dt.getFullYear(), dt.getMonth(), dt.getDate()).getTime() >= new Date(endWork).getTime()) {
        dt = new Date(startWork);
    }
    else {
        while (errorFlg) {
            // 祝日判定
            holidayDecision();
            // 土日判定
            satSunDecision();
        }
    }

    $('body').html('<center>' + (dt.getMonth()+1) + '月' + dt.getDate() + '日 (' + wd[dt.getDay()] + ')</center>');

    /**
    * 祝日判定
    **/
    function holidayDecision() {
        var checkDate = dt.getDate();
        for (var i = 0; i < holidayDates.length; i++) {
            if (new Date(dt.getFullYear(), dt.getMonth(), dt.getDate()).getTime() == new Date(holidayDates[i]).getTime()) {
                dt.setDate(dt.getDate() + 1);
            }
        }
        if (checkDate == dt.getDate()) {
            errorFlg = false;
        } else {
            errorFlg = true;
        }
    }

    /**
    * 土日判定
    **/
    function satSunDecision() {
        if (dt.getDay() == 6) {
            dt.setDate(dt.getDate() + 2);
            errorFlg = true;
        } else if (dt.getDay() == 0) {
            dt.setDate(dt.getDate() + 1);
            errorFlg = true;
        } 
    }

    /**
    * 正午判定
    * return Date
    **/
    function noonDecision() {
        var dt = new Date();
        var insObj = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(), 12, 0, 0);
        if (dt >= insObj) {
            dt.setDate(dt.getDate() + 1);
        }
        return dt;
    }
});

まとめ

whileで繰り返してるのはGWなど祝日明けが土日の場合と土日明けが祝日だったりするため。
祝日でも土日でもない場合に初めてwhile文を抜けます。

ややこしかったところ

月を取得するとき1月ならgetMonth()で0が取れてくるところ
(n – 1)なので+1をする。

オブジェクト生成するときは文字列を渡す場合と数値を渡す場合で結果が異なる。

new Date().getMonth(); // 3月だと2 (n-1)
new Date('2019/3/1').getMonth(); // 2
new Date(2019,3,1).getMonth(); // 3

公式
注: 引数 monthIndex は 0 から始まります。 つまり 1 月 = 0、 12 月 = 11 です。

日付比較は.getTimeを使う

if (new Date(2019, 3, 1).getTime() == new Date('2019/3/1').getTime()) {
    // false
}
if (new Date(2019, (3-1), 1).getTime() == new Date('2019/3/1').getTime()) {
    // true
}
// getTimeを使わないとfalseになる
var foo = new Date(2019, 3, 1);
var bar = new Date(2019, 3, 1);
if (foo == bar) {
    //false
}

曜日はgetDay()で数値が取れてくるだけなので別に文字列で曜日配列を作成する必要がある。
日曜日なら0,月曜日なら1・・・土曜日なら6

祝日は自分で定義する必要がある。

日付オブジェクトを作成するとき文字列を渡す場合YYYY/MM/DDかYYYY/M/D形式にするとよい。
(スラッシュ区切り)
Date.parseは使用しない。
公式
注: ブラウザごとに動作が異なり一貫性がないため、Date コンストラクタ (または同等の Date.parse) で日付文字列を解釈しないように強くすすめます。RFC 2822 形式の文字列のサポートは、慣例にすぎません。 ISO 8601 フォーマットのサポートは、日付のみの文字列 (例: “1970-01-01”) が地方時ではなくUTCとして扱われる点で異なります。

末日を取得するときはdに0を指定すると指定した月の末日が取れてくる。
new Date(2019, 2, 0).getDate()と渡すと28が取得できる。

日付に31以上の数値を渡すと月を繰り上げてくれる。

var foo = new Date(2019, (3-1), 33); // 3月は31日まで (n-1)で3月と認識させている
$('body').html((foo.getMonth() + 1) + '月'); // 33を渡すことにより繰り上がった結果4月
$('body').append(foo.getDate() + '日'); // 3月31日に33を渡すことにより繰り上がった結果2日

とてもややこしいですが月は0が1月扱いなのでDateオブジェクトを作成するときは-1
表示させるときは+1しています。

仮にDateオブジェクトを作成するときにMonthに-1をせず3を渡すと4月扱いとなりますので
2019年4月の末日は30日となり、33 – 30の計算でgetMonth()で繰り上がって4、getDate()では3が取得されます。