モーダルウィンドウでカレンダークラスを使用して年月日入力
- <!DOCTYPE html>
- <html lang="ja">
- <head>
- <meta charset="UTF-8">
- <title>モーダルウィンドウでカレンダークラスを使用して年月日入力</title>
- <script type="text/javascript" src="jquery-1.5.1.min.js"></script>
- <script type="text/javascript" src="knockout-2.1.0beta.js"></script>
- <script type="text/javascript">
- /* ==============================================================
- カレンダークラス
- ============================================================== */
- var ClassCalendar = function(argY, argM, argD)
- {
- // ===========================================================
- // メソッド:プライベート
- // 指定がなければ今日
- var now = new Date();
- var year = argY || now.getFullYear();
- var month = argM || now.getMonth() + 1;
- var day = argD || now.getDate();
- // 週単位で分割した日にち配列
- var weekAry = new Array();
- var fstWeek = 0; // 週初めの曜日(0:日曜~6:土曜)
- var fill = ""; // 日にちの入っていないとこにいれる文字
- // 曜日配列
- var weekLabelAry = new Array("日", "月", "火", "水", "木", "金", "土");
- // ===========================================================
- // パブリックメソッド:プロパティを変更
- /**
- * 年月日をdate()からセット
- * dateData 年月日
- */
- this.setYMDForDate = function(dateData)
- {
- year = dateData.getFullYear();
- month = dateData.getMonth() + 1;
- day = dateData.getDate();
- weekAry = new Array(); // 対象となる年月日が変わるなら配列は初期化
- }
- /**
- * 年月日のセット
- * argY, argM, argD 年月日
- */
- this.setYMD = function(argY, argM, argD)
- {
- year = argY;
- month = argM;
- day = argD;
- weekAry = new Array(); // 対象となる年月日が変わるなら配列は初期化
- }
- /**
- * 指定数だけ前後する
- * num nヶ月前 or 後ろ(負の値で前の月、正の値で次の月)
- * target 対象を「y(=n年)、m(=nヶ月)、d(=n日)」
- */
- this.setMoveYMD = function(num, target)
- {
- var target = target || "m";
- var moveMonth = addDate(new Date(year, month-1, day), target, num);
- year = moveMonth.getFullYear();
- month = moveMonth.getMonth() + 1;
- day = moveMonth.getDate();
- weekAry = new Array(); // 対象となる年月日が変わるなら配列は初期化
- }
- /**
- * 曜日をセット
- * weekKindAry 曜日のラベル配列
- */
- this.setWeekLabel = function(weekKindAry)
- {
- weekLabelAry = weekKindAry;
- }
- /**
- * スタートなる曜日を決める
- * start スタートとなる曜日を決める(0:日曜~6:土曜)
- */
- this.setStartWeekDay = function(start)
- {
- start = start || 0;
- if (0 <= parseFloat(start) && parseFloat(start) <= 6) {
- fstWeek = start;
- }
- else {
- // 曜日指定が0~6じゃないなら強制的に0
- fstWeek = 0;
- }
- weekAry = new Array(); // スタートなる曜日が変わるなら配列は初期化
- }
- /**
- * 空白日に埋める文字のセット
- * start スタートとなる曜日を決める(0:日曜~6:土曜)
- */
- this.setFill = function(addChar)
- {
- addChar = addChar || "";
- fill = addChar;
- weekAry = new Array(); // 区切り文字が変わるなら配列は初期化
- }
-
- // ===========================================================
- // パブリックメソッド
- /**
- * 現在の年月日の各値を取得
- * needVal 欲しい値(y,m,d)
- */
- this.getValueForDate = function (needVal)
- {
- var tempVal = "";
- if (needVal == "y") {
- tempVal = year;
- }
- else if (needVal == "m") {
- tempVal = month;
- }
- else {
- tempVal = day;
- }
- return tempVal;
- }
- /**
- * カレンダー用に変換した週の配列を取得:配列だけ欲しいとき用に。
- * addChar 「1日まで」と「月末以降」を埋める文字
- * start スタートとなる曜日を決める(0:日曜~6:土曜)
- */
- this.getWeekAry = function (addChar, start)
- {
- if (weekAry.length == 0)
- {
- this.setStartWeekDay(start);
- this.setFill(addChar);
- dayAryForCalendar();
- }
- return weekAry;
- }
- /**
- * 年月日の書式(yyyy/mm/dd等)を整えて返す
- * type 年月日の書式
- */
- this.convertDateFormat = function(type)
- {
- type = type || "yyyy/mm/dd";
- // いずれ各書式に対応させる予定
- if (type == "yyyy/mm") {
- tempM = convertNumberDigits(2, month);
- convertDate = year + "/" + tempM;
- }
- else {
- // 未対応記述とyyyy/mm/ddの場合
- tempM = convertNumberDigits(2, month);
- tempD = convertNumberDigits(2, day);
- convertDate = year + "/" + tempM + "/" + tempD;
- }
- return convertDate;
- }
- /**
- * カレンダー用の週配列をtableタグにする
- * weekKindAry 週単位にした日にちの配列
- */
- this.makeTableForCalendar = function(weekKindAry)
- {
- weekKindAry = weekKindAry || weekLabelAry;
- if (weekAry.length == 0) {
- dayAryForCalendar();
- }
- var tableTag = "";
- tableTag += '<table class="calendarTable">';
- // 年月
- tableTag += '<caption>';
- tableTag += year + "年" + month + "月";
- tableTag += '</caption>';
- // 曜日:指定された週初めから曜日を並び替え
- useWeekAry = convertWeekLabelOfCalendar(weekKindAry);
- tableTag += '<tr>';
- for (var i=0; i<useWeekAry.length; i++) {
- tableTag += '<th>';
- tableTag += useWeekAry[i];
- tableTag += '</th>';
- }
- tableTag += '</tr>';
- // 日にち
- var styleHol = "";
- var styleTod = "";
- for (var i=0; i<weekAry.length; i++) {
- tableTag += '<tr>';
- for (var j=0; j<weekAry[i].length; j++) {
- calClass = "";
- classHol = "";
- classTod = "";
- if (weekAry[i][j]["num"] == 0) {
- // 日曜
- classHol = 'calHol';
- }
- if (weekAry[i][j]["day"] == day) {
- // 今日
- classTod = ' calTod';
- }
- if (classHol != "" || classTod != "") {
- calClass = ' class="' + classHol + classTod + '"';
- }
- tableTag += '<td' + calClass + '>';
- tableTag += weekAry[i][j]["day"];
- tableTag += '</td>';
- }
- tableTag += '</tr>';
- }
- tableTag += '</table>';
- return tableTag;
- }
- // ===========================================================
- // プライベートメソッド
- /**
- * カレンダー用の配列を返す
- */
- var dayAryForCalendar = function()
- {
- // 「週初めから1日まで」と「月末から週末まで」を文字を埋める
- var dayAry = convertDayOfCalendar();
- // 1週ずつ分割していく
- weekAry = convertWeekOfCalendar(dayAry);
- }
- // 桁数をそろえるために0を埋める
- var convertNumberDigits = function(digit, num)
- {
- var src = new String(num);
- var cnt = digit - src.length; // 桁数(digit)から足りない文字数を調査
- if (0 < cnt) {
- while (cnt-- > 0) {
- src = "0" + src;
- }
- }
- return src;
- }
- // 指定された曜日を週初めとして空白日を埋める
- var convertDayOfCalendar = function ()
- {
- // 月初と月末のDate()
- var startMonth = new Date(year, month-1, 1);
- var endMonth = new Date(year, month, 0);
- // 指定された週初めの曜日から週末の曜日を求めておく
- endEeek = (fstWeek != 0) ? fstWeek - 1: 6;
- // カレンダー用に日にちを配列化:
- var DayArray = new Array();
- // 日曜(指定された週初めの曜日)~1日の空白を埋める。
- if (startMonth.getDay() < fstWeek) {
- diffWeekToFst = 7 - Math.abs(startMonth.getDay() - fstWeek);
- }
- else {
- diffWeekToFst = Math.abs(startMonth.getDay() - fstWeek);
- }
- for (i=0; i<diffWeekToFst; i++) {
- DayArray.push(fill);
- }
- // 月初め(1日)~月末までを埋める
- for (i=0; i<endMonth.getDate(); i++) {
- DayArray.push(i+1);
- }
- // 月末~土曜(指定された週末の曜日)の空白を埋める
- if (endMonth.getDay() != endEeek) {
- // 週初めから何日目か
- if (endMonth.getDay() < fstWeek) {
- diffWeekForEnd = 7 - Math.abs(endMonth.getDay() - fstWeek);
- }
- else {
- diffWeekForEnd = Math.abs(endMonth.getDay() - fstWeek);
- }
- // 週末まで何日あるか
- diffWeekFromEnd = 6 - diffWeekForEnd;
- for (i=0; i<diffWeekFromEnd; i++) {
- DayArray.push(fill);
- }
- }
- return DayArray;
- }
- // 年月日に指定された数値を足して返す
- var addDate = function (ymd, target, add)
- {
- var addNum = parseFloat(add);
- var addY = ymd.getFullYear();
- var addM = ymd.getMonth() + 1;
- var addD = ymd.getDate();
- // ymdが月末のときに使う
- var endMonthDay = new Date(addY , addM, 0).getDate();
- var tempD = addD;
- if(target == "y") {
- addY += addNum;
- }
- else if(target == "m") {
- addM += addNum;
- }
- else if(target == "d") {
- addD += addNum;
- }
- // 月末で、年・月を足したとき:月初めに変更して足し、最後に月末をセットする
- if ((target == "y" || target == "m") && tempD == endMonthDay) {
- // 月初めで年月を移動
- dateNoDay = new Date(addY, addM-1, 1);
- // 移動した年月の月末を取得
- var nextY = dateNoDay.getFullYear();
- var nextM = dateNoDay.getMonth() + 1;
- dateLast = new Date(nextY, nextM, 0).getDate();
- // 移動した年月の月末でDate()に変換
- tempDate = new Date(nextY, nextM-1, dateLast);
- }
- else {
- tempDate = new Date(addY , addM-1, addD);
- }
- return tempDate;
- }
- // カレンダー用に週単位で配列にして返す
- var convertWeekOfCalendar = function(dayAry)
- {
- var ary = new Array();
- for (var i=0, j=0, k=fstWeek; i<dayAry.length; i++, k++) {
- j = parseInt(i/7);
- if (i%7 == 0) {
- ary[j] = new Array();
- }
- if (6 < k) {
- k = 0;
- }
- // kが曜日、dayが日にち
- ary[j].push({"num": k, "day": dayAry[i]});
- }
- return ary;
- }
- // 指定されている週初めに合わせて曜日配列を入れ替える
- var convertWeekLabelOfCalendar = function(weekKindAry)
- {
- var ary = new Array();
- for (var i=0, j=fstWeek; i<7; i++, j++) {
- if (6 < j) {
- j = 0;
- }
- ary.push(weekKindAry[j]);
- }
- return ary;
- }
- }
-
- // カスタムバインディング ===============================================
- // モーダルウィンドウのマスク
- ko.bindingHandlers.koModalMask = {
- update: function(element, valueAccessor, allBindingsAccessor)
- {
- // 現状の値と、サブプロパティ一覧の取得
- var value = valueAccessor(), allBindings = allBindingsAccessor();
- var valueUnwrapped = ko.utils.unwrapObservable(value);
-
- // サブプロパティ:
- var maskBgColor = allBindings.maskBgColor || "#000"; // maskBgColor:マスクの背景色
- var maskOpacity = allBindings.maskOpacity || "0.3"; // maskOpacity:maskOpacityマスクの不透明度
-
- // DOMをいじる
- if (valueUnwrapped == false) {
- $(element).hide();
- }
- else {
- $(element).css({'width':$(window).width(), 'height':$(document).height()});
- $(element).css({'backgroundColor': maskBgColor});
- $(element).css({'position': 'absolute', 'left': '0', 'top': '0'});
- $(element).css({'z-index': '9000'});
- $(element).fadeTo(0, maskOpacity);
- }
- }
- };
-
- // モーダルウィンドウ
- ko.bindingHandlers.koModalWindow = {
- update: function(element, valueAccessor, allBindingsAccessor)
- {
- // 現状の値と、サブプロパティ一覧の取得
- var value = valueAccessor(), allBindings = allBindingsAccessor();
- var valueUnwrapped = ko.utils.unwrapObservable(value);
-
- // サブプロパティ:modalBgColorの値をセット
- var modalBgColor = allBindings.modalBgColor || "#fff";
-
- // DOMをいじる
- if (valueUnwrapped == false) {
- $(element).hide();
- }
- else {
- $(element).css({'backgroundColor': modalBgColor});
- $(element).css({'z-index': '9999'});
- $(element).fadeIn(500);
- }
- }
- };
-
- // knockout.js ===============================================
- function ViewModel() {
- var self = this;
- self.inputData = ko.observable("");
- // モーダルウィンドウで使うヤツ
- self.maskModal = ko.observable(false); // マスク用
- self.windowModal = ko.observable(false); // ウィンドウ
- // カレンダーのクラス
- self.calendar = new ClassCalendar();
- // カレンダーで使うヤツ
- var now = new Date();
- self.year = ko.observable(now.getFullYear());
- self.mont = ko.observable(now.getMonth() + 1);
- // カレンダーの年月の表示
- self.valYearMonth = ko.computed( function()
- {
- self.calendar.setYMD(self.year(), self.mont(), 1);
- return self.calendar.convertDateFormat("yyyy/mm");
- }, this);
- // カレンダー用に週ごとに配列化
- self.weekData = ko.computed( function()
- {
- self.calendar.setYMD(self.year(), self.mont(), 1);
- return self.calendar.getWeekAry();
- }, this);
- // clickバインディング:前月・翌月・今月([move]を月に足し引きする)
- self.moveCal = function(move)
- {
- move = move || 0;
- if (move == 0) {
- // 「0」だったら今月にする
- self.calendar.setYMDForDate(new Date());
- }
- else {
- // 「0」じゃないんだったら[move]を月に足し引きする
- self.calendar.setYMD(self.year(), self.mont(), 1);
- self.calendar.setMoveYMD(move);
- }
-
- self.year(self.calendar.getValueForDate("y"));
- self.mont(self.calendar.getValueForDate("m"));
- }
- // clickバインディング: モーダルウィンドウを開く(今月を表示)
- self.openModal = function(data, event)
- {
- var now = new Date();
- self.year(now.getFullYear());
- self.mont(now.getMonth()+1);
-
- self.maskModal(true);
- self.windowModal(true);
- }
- // clickバインディング: モーダルウィンドウを閉じる
- self.closeModal = function(data, event)
- {
- self.maskModal(false);
- self.windowModal(false);
- }
- // クリックされた日にちを入力:日にちの無いトコがクリックされたら何もしない。
- self.addData = function(koData)
- {
- if (koData.day.toString().match(/^[0-9]+$/) != null) {
- self.calendar.setYMD(self.year(), self.mont(), parseFloat(koData.day));
- var ymd = self.calendar.convertDateFormat("yyyy/mm/dd");
- self.inputData(ymd);
- self.maskModal(false);
- self.windowModal(false);
- }
- }
- // 「今日」だけCSS追加
- self.cToday = function(koDataDay)
- {
- // 表示されたカレンダーの日にち:数字以外ならfalse
- var ymd = "";
- if (koDataDay.toString().match(/^[0-9]+$/) != null) {
- self.calendar.setYMD(self.year(), self.mont(), parseFloat(koDataDay));
- ymd = self.calendar.convertDateFormat("yyyy/mm/dd");
- }
- else {
- return false;
- }
-
- // 今日の年月日
- self.calendar.setYMDForDate(new Date());
- var today = self.calendar.convertDateFormat("yyyy/mm/dd");
-
- // 表示されたカレンダーの日にちと今日の年月日が同じかチェック
- if (ymd == today) {
- return true;
- }
- return false;
- }
- }
- $(document).ready(function () {
- ko.applyBindings(new ViewModel());
- });
- </script>
- <style type="text/css">
- .inData
- {
- position:absolute;
- top:3px;
- left:80px;
- }
- .inData:before{
- content: "";
- position: absolute;
- top: 2px;
- left: 0px;
- border-top: 7px solid transparent;
- border-bottom: 7px solid transparent;
- border-right: 11px solid #999;
- }
- .inDataBox
- {
- background:#f0f0f0;
- border:1px solid #999;
- padding:30px 10px 10px;
- margin-left:10px;
- }
- .closeBtn
- {
- position:absolute;
- top:5px;
- right:5px;
- background:#666;
- color:#fff;
- font-weight:bold;
- cursor:pointer;
- font-size:10px;
- }
- .closeBtn:hover
- {
- background:#ff0000;
- }
- .calendar
- {
- border-collapse:collapse;
- margin:0;
- }
- .calendar th, .calendar td
- {
- border:1px solid #ccc;
- padding:3px;
- text-align:center;
- cursor:pointer;
- font-size:10pt;
- }
- .calendar th
- {
- background:#ffddff;
- }
- .cToday
- {
- font-weight:bold;
- }
- .calendar td:hover
- {
- background:#ffddff;
- }
- .moveCal
- {
- color:#0000ff;
- cursor:pointer;
- }
- .moveCal:hover, .nowCal:hover
- {
- color:#ff0000;
- cursor:pointer;
- }
- .nowCal
- {
- position:absolute;
- bottom:0;
- left:3px;
- color:#0000ff;
- cursor:pointer;
- font-size:10pt;
- }
- </style>
- </head>
- <body>
- <!-- モーダルウィンドウのマスク用 -->
- <div data-bind="koModalMask: maskModal, maskOpacity: 0.15, click: closeModal"></div>
- <h1>モーダルウィンドウでカレンダークラスを使用して年月日入力</h1>
- <div style="position:relative;top:0;left:0;">
- <input type="text" tabindex="1" data-bind="value: inputData" />
- <button data-bind="click: openModal">モーダル</button><br />
- <!-- ▼モーダルウィンドウ内 -->
- <div class="inData" data-bind="koModalWindow: windowModal, modalBgColor: 'transparent'">
- <div class="inDataBox">
- <table class="calendar">
- <caption>
- <div style="position:relative;top:0;left:0;">
- <span class="moveCal" data-bind="click: function(){moveCal(-1);}">«</span>
- <span data-bind="text: valYearMonth"></span>
- <span class="moveCal" data-bind="click: function(){moveCal(1);}">»</span>
- <span class="nowCal" data-bind="click: function(){moveCal(0);}">今月</span>
- </div>
- </caption>
- <thead><tr><th>日</th><th>月</th><th>火</th><th>水</th><th>木</th><th>金</th><th>土</th></tr></thead>
- <tbody data-bind="foreach: weekData()">
- <tr data-bind="foreach: $data">
- <td data-bind="text: day, click: $root.addData, css: {'cToday': $root.cToday(day)}, style: num==0 ? {'color': 'red'}: {}"></td>
- </tr>
- </tbody>
- </table>
- <span class="closeBtn" data-bind="event: {click: $root.closeModal }, clickBubble: false">×</span>
- </div>
- </div>
- <!-- ▲モーダルウィンドウ内 -->
- </div>
- <input type="text" tabindex="2" /><br />
- <button tabindex="2" data-bind="click: function(){alert('本来ならココにDBに書き込む処理とかする');}" />登録完了</button><br />
- <div style="font-size:10pt;text-align:right;margin-top:0.5em;">
- <a href="//tips.recatnap.info/" target="_top">PCスキルの小技・忘却防止メモ</a> -
- <a href="//tips.recatnap.info/wiki/" target="_top">PCスキルの小技・忘却防止メモのまとめ(wiki)</a>
- </div>
- <div style="font-size:10pt;text-align:center;margin-top:0.5em;padding:0.5em;border-top:1px solid #ccc;">
- Copyright © 2009 by PCスキルの小技・忘却防止メモ. All rights reserved.
- </div>
- </body>
- </html>