モーダルウィンドウでカレンダー(省略版)から年月日入力

  1. <!DOCTYPE html>
  2. <html lang="ja">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>モーダルウィンドウでカレンダー(省略版)から年月日入力</title>
  6. <script type="text/javascript" src="jquery-1.5.1.min.js"></script>
  7. <script type="text/javascript" src="knockout-2.1.0beta.js"></script>
  8. <script type="text/javascript">
  9.   // さぶるーちんず ===============================================
  10.   // 年月日の書式を整える
  11.   function convertDateFormat(date, type)
  12.   {
  13.     type = type || "yyyy/mm/dd";
  14.     
  15.     // いずれ各書式に対応させる予定
  16.     convertDate = "";
  17.     if (type == "yyyy/mm/dd")
  18.     {
  19.       tempY = date.getFullYear();
  20.       tempM = convertNumberDigits(2, date.getMonth()+1);
  21.       tempD = convertNumberDigits(2, date.getDate());
  22.       convertDate = tempY + "/" + tempM + "/" + tempD;
  23.     }
  24.     else if (type == "yyyy/mm")
  25.     {
  26.       tempY = date.getFullYear();
  27.       tempM = convertNumberDigits(2, date.getMonth()+1);
  28.       tempD = convertNumberDigits(2, date.getDate());
  29.       convertDate = tempY + "/" + tempM;
  30.     }
  31.     else
  32.     {
  33.       tempY = date.getFullYear();
  34.       tempM = convertNumberDigits(2, date.getMonth()+1);
  35.       tempD = convertNumberDigits(2, date.getDate());
  36.       convertDate = tempY + "/" + tempM + "/" + tempD;
  37.     }
  38.     return convertDate;
  39.   }
  40.   
  41.   // 桁数をそろえるために0を埋める
  42.   function convertNumberDigits(digit, num)
  43.   {
  44.     var src = new String(num);
  45.     var cnt = digit - src.length;
  46.     if (0 < cnt) {
  47.       while (cnt-- > 0) {
  48.         src = "0" + src;
  49.       }
  50.     }
  51.     return src;
  52.   }
  53.   /**
  54.    * 年月日に指定された数値を足して返す
  55.    * ymdDate:日付データ
  56.    * 追加する項目:年月日のどれか(ymd)
  57.    * 追加する数値
  58.    */
  59.   function addDate(ymdDate, target, add)
  60.   {
  61.     addNum = parseFloat(add);
  62.     
  63.     yea = ymdDate.getFullYear();
  64.     mon = ymdDate.getMonth();
  65.     day = ymdDate.getDate();
  66.     
  67.     if(target == "y")
  68.     {
  69.       yea += addNum;
  70.     }
  71.     else if(target == "m")
  72.     {
  73.       mon += addNum;
  74.     }
  75.     else if(target == "d")
  76.     {
  77.       day += addNum;
  78.     }
  79.     return new Date(yea, mon, day);
  80.   }
  81.   /**
  82.    * カレンダー用に日曜から1日、月末から土曜までを何かで埋め、配列にして返す
  83.    * year    表示するカレンダーの年
  84.    * month  表示するカレンダーの月
  85.    * Fill    日曜から1日まで、月末から土曜まで埋める文字
  86.    */
  87.   function convertDayOfCalendar(year, month, Fill)
  88.   {
  89.     // 月初と月末
  90.     var startMonth = new Date(year + "/" + month + "/1");
  91.     var endMonth   = addDate(new Date(year, month, 1), "d", -1);
  92.     
  93.     // カレンダー用に日にちを配列化:
  94.     DayArray = new Array();
  95.     
  96.     // 日曜~1日の空白を埋める。
  97.     for (i=0; i<startMonth.getDay(); i++)
  98.     {
  99.       DayArray.push(Fill);
  100.     }
  101.     
  102.     // 月初め(1日)~月末までを埋める
  103.     for (i=0; i<endMonth.getDate(); i++)
  104.     {
  105.       DayArray.push(i+1);
  106.     }
  107.     
  108.     // 月末~土曜の空白を埋める
  109.     if (endMonth.getDay() != 6)
  110.     {
  111.       startWeek = parseFloat(endMonth.getDay()) + 1;
  112.       for (i=startWeek; i<7; i++)
  113.       {
  114.         DayArray.push(Fill);
  115.       }
  116.     }
  117.     return DayArray;
  118.   }
  119.   /**
  120.    * カレンダー用に週単位で配列にして返す
  121.    */
  122.   function convertWeekOfCalendar(dayAry)
  123.   {
  124.     ary = new Array();
  125.     for (i=0, j=0, k=0; i<dayAry.length; i++)
  126.     {
  127.       j = parseInt(i/7);
  128.       k = i%7;
  129.       if (k == 0)
  130.       {
  131.         ary[j] = new Array();
  132.       }
  133.       // kが曜日、dayが日にち
  134.       ary[j].push({"num": k, "day": dayAry[i]});
  135.     }
  136.     return ary;
  137.   }
  138.   // カスタムバインディング ===============================================
  139.   // モーダルウィンドウのマスク
  140.   ko.bindingHandlers.koModalMask = {
  141.     update: function(element, valueAccessor, allBindingsAccessor)
  142.     {
  143.       // 現状の値と、サブプロパティ一覧の取得
  144.       var value = valueAccessor(), allBindings = allBindingsAccessor();
  145.       var valueUnwrapped = ko.utils.unwrapObservable(value);
  146.       
  147.       // サブプロパティ:
  148.       var maskBgColor = allBindings.maskBgColor || "#000"; // maskBgColor:マスクの背景色
  149.       var maskOpacity = allBindings.maskOpacity || "0.3";  // maskOpacity:maskOpacityマスクの不透明度
  150.       
  151.       // DOMをいじる
  152.       if (valueUnwrapped == false)
  153.       {
  154.         $(element).hide();
  155.       }
  156.       else
  157.       {
  158.         $(element).css({'width':$(window).width(), 'height':$(document).height()});
  159.         $(element).css({'backgroundColor': maskBgColor});
  160.         $(element).css({'position': 'absolute', 'left': '0', 'top': '0'});
  161.         $(element).css({'z-index': '9000'});
  162.         $(element).fadeTo(0, maskOpacity);
  163.       }
  164.     }
  165.   };
  166.   
  167.   // モーダルウィンドウ
  168.   ko.bindingHandlers.koModalWindow = {
  169.     update: function(element, valueAccessor, allBindingsAccessor)
  170.     {
  171.       // 現状の値と、サブプロパティ一覧の取得
  172.       var value = valueAccessor(), allBindings = allBindingsAccessor();
  173.       var valueUnwrapped = ko.utils.unwrapObservable(value);
  174.       
  175.       // サブプロパティ:modalBgColorの値をセット
  176.       var modalBgColor = allBindings.modalBgColor || "#fff";
  177.       
  178.       // DOMをいじる
  179.       if (valueUnwrapped == false)
  180.       {
  181.         $(element).hide();
  182.       }
  183.       else
  184.       {
  185.         $(element).css({'backgroundColor': modalBgColor});
  186.         $(element).css({'z-index': '9999'});
  187.         $(element).fadeIn(500);
  188.       }
  189.     }
  190.   };
  191.   // knockout.js ===============================================
  192.   function ViewModel() {
  193.     var self = this;
  194.     self.inputData = ko.observable("");
  195.     // モーダルウィンドウで使うヤツ
  196.     self.maskModal = ko.observable(false);    // マスク用
  197.     self.windowModal = ko.observable(false);  // ウィンドウ
  198.     // カレンダーで使うヤツ
  199.     var now = new Date();
  200.     self.year = ko.observable(now.getFullYear());
  201.     self.mont = ko.observable(now.getMonth() + 1);
  202.     // カレンダーの年月の表示
  203.     self.valYearMonth = ko.computed( function()
  204.     {
  205.       return convertDateFormat(new Date(self.year() + "/" + self.mont() + "/1"), "yyyy/mm");
  206.     }, this);
  207.     // カレンダー用に週ごとに配列化
  208.     self.weekData = ko.computed( function()
  209.     {
  210.       // カレンダー用に1日の前、月末の後に適当な文字を入れる。
  211.       dayDate = convertDayOfCalendar(self.year(), self.mont(), "");
  212.       
  213.       // 週単位で配列化
  214.       weekDate = convertWeekOfCalendar(dayDate);
  215.       
  216.       return weekDate;
  217.     }, this);
  218.     // clickバインディング:前月・翌月・今月([move]を月に足し引きする)
  219.     self.moveCal = function(move)
  220.     {
  221.       move = move || 0;
  222.       if (move == 0)
  223.       {
  224.         // 「0」だったら今月にする
  225.         dateCal = new Date();
  226.       }
  227.       else
  228.       {
  229.         // 「0」じゃないんだったら[move]を月に足し引きする
  230.         dateCal = addDate(new Date(self.year(), self.mont()-1, 1), "m", move)
  231.       }
  232.       
  233.       self.year(dateCal.getFullYear());
  234.       self.mont(dateCal.getMonth()+1);
  235.     }
  236.     // clickバインディング: モーダルウィンドウを開く(今月を表示)
  237.     self.openModal = function(data, event)
  238.     {
  239.       var now = new Date();
  240.       self.year(now.getFullYear());
  241.       self.mont(now.getMonth()+1);
  242.       
  243.       self.maskModal(true);
  244.       self.windowModal(true);
  245.     }
  246.     // clickバインディング: モーダルウィンドウを閉じる
  247.     self.closeModal = function(data, event)
  248.     {
  249.       self.maskModal(false);
  250.       self.windowModal(false);
  251.     }
  252.     // クリックされた日にちを入力:日にちの無いトコがクリックされたら何もしない。
  253.     self.addData = function(koData)
  254.     {
  255.       if (koData.day.toString().match(/^[0-9]+$/) != null)
  256.       {
  257.         ymd = convertDateFormat(new Date(self.year() + "/" + self.mont() + "/" + parseFloat(koData.day)), "yyyy/mm/dd");
  258.         self.inputData(ymd);
  259.         self.maskModal(false);
  260.         self.windowModal(false);
  261.       }
  262.     }
  263.     // 「今日」だけCSS追加
  264.     self.cToday = function(koData)
  265.     {
  266.       // 表示されたカレンダーの日にち:数字以外ならfalse
  267.       ymd = "";
  268.       if (koData.toString().match(/^[0-9]+$/) != null)
  269.       {
  270.         ymd = convertDateFormat(new Date(self.year() + "/" + self.mont() + "/" + parseFloat(koData)), "yyyy/mm/dd");
  271.       }
  272.       else
  273.       {
  274.         return false;
  275.       }
  276.       
  277.       // 今日の年月日
  278.       today = convertDateFormat(new Date(), "yyyy/mm/dd");
  279.       
  280.       // 表示されたカレンダーの日にちと今日の年月日が同じかチェック
  281.       if (ymd == today)
  282.       {
  283.         return true;
  284.       }
  285.       return false;
  286.     }
  287.   }
  288.   $(document).ready(function () {
  289.     ko.applyBindings(new ViewModel());
  290.   });
  291. </script>
  292. <style type="text/css">
  293. .inData
  294. {
  295.   position:absolute;
  296.   top:3px;
  297.   left:80px;
  298. }
  299. .inData:before{
  300.   content: "";
  301.   position: absolute;
  302.   top: 2px;
  303.   left: 0px;
  304.   border-top: 7px solid transparent;
  305.   border-bottom: 7px solid transparent;
  306.   border-right: 11px solid #999;
  307. }
  308. .inDataBox
  309. {
  310.   background:#f0f0f0;
  311.   border:1px solid #999;
  312.   padding:30px 10px 10px;
  313.   margin-left:10px;
  314. }
  315. .closeBtn
  316. {
  317.   position:absolute;
  318.   top:5px;
  319.   right:5px;
  320.   background:#666;
  321.   color:#fff;
  322.   font-weight:bold;
  323.   cursor:pointer;
  324.   font-size:10px;
  325. }
  326. .closeBtn:hover
  327. {
  328.   background:#ff0000;
  329. }
  330. .calendar
  331. {
  332.   border-collapse:collapse;
  333.   margin:0;
  334. }
  335. .calendar th, .calendar td
  336. {
  337.   border:1px solid #ccc;
  338.   padding:3px;
  339.   text-align:center;
  340.   cursor:pointer;
  341.   font-size:10pt;
  342. }
  343. .calendar th
  344. {
  345.   background:#ffddff;
  346. }
  347. .cToday
  348. {
  349.   font-weight:bold;
  350. }
  351. .calendar td:hover
  352. {
  353.   background:#ffddff;
  354. }
  355. .moveCal
  356. {
  357.   color:#0000ff;
  358.   cursor:pointer;
  359. }
  360. .moveCal:hover, .nowCal:hover
  361. {
  362.   color:#ff0000;
  363.   cursor:pointer;
  364. }
  365. .nowCal
  366. {
  367.   position:absolute;
  368.   bottom:0;
  369.   left:3px;
  370.   color:#0000ff;
  371.   cursor:pointer;
  372.   font-size:10pt;
  373. }
  374. </style>
  375. </head>
  376. <body>
  377. <!-- モーダルウィンドウのマスク用 -->
  378. <div data-bind="koModalMask: maskModal, maskOpacity: 0.15, click: closeModal"></div>
  379. <h1>モーダルウィンドウでカレンダー(省略版)から年月日入力</h1>
  380. <div style="position:relative;top:0;left:0;">
  381.   <input type="text" tabindex="1" data-bind="value: inputData" />
  382.   <button data-bind="click: openModal">モーダル</button><br />
  383.   <!-- ▼モーダルウィンドウ内 -->
  384.   <div class="inData" data-bind="koModalWindow: windowModal, modalBgColor: 'transparent'">
  385.     <div class="inDataBox">
  386.       <table class="calendar">
  387.       <caption>
  388.       <div style="position:relative;top:0;left:0;">
  389.       <span class="moveCal" data-bind="click: function(){moveCal(-1);}">&laquo;</span>
  390.       <span data-bind="text: valYearMonth"></span>
  391.       <span class="moveCal" data-bind="click: function(){moveCal(1);}">&raquo;</span>
  392.       <span class="nowCal" data-bind="click: function(){moveCal(0);}">今月</span>
  393.       </div>
  394.       </caption>
  395.       <thead><tr><th>日</th><th>月</th><th>火</th><th>水</th><th>木</th><th>金</th><th>土</th></tr></thead>
  396.       <tbody data-bind="foreach: weekData()">
  397.       <tr data-bind="foreach: $data">
  398.       <td data-bind="text: day, click: $root.addData, css: {'cToday': $root.cToday(day)}, style: num==0 ? {'color': 'red'}: {}"></td>
  399.       </tr>
  400.       </tbody>
  401.       </table>
  402.       <span class="closeBtn" data-bind="event: {click: $root.closeModal }, clickBubble: false">×</span>
  403.     </div>
  404.   </div>
  405.   <!-- ▲モーダルウィンドウ内 -->
  406. </div>
  407. <input type="text" tabindex="2" /><br />
  408. <button tabindex="2" data-bind="click: function(){alert('本来ならココにDBに書き込む処理とかする');}" />登録完了</button><br />
  409. <div style="font-size:10pt;text-align:right;margin-top:0.5em;">
  410. <a href="//tips.recatnap.info/" target="_top">PCスキルの小技・忘却防止メモ</a> -
  411. <a href="//tips.recatnap.info/wiki/" target="_top">PCスキルの小技・忘却防止メモのまとめ(wiki)</a>
  412. </div>
  413. <div style="font-size:10pt;text-align:center;margin-top:0.5em;padding:0.5em;border-top:1px solid #ccc;">
  414. Copyright &copy; 2009 by PCスキルの小技・忘却防止メモ. All rights reserved.
  415. </div>
  416. </body>
  417. </html>