モーダルウィンドウでカレンダーから年月日入力:閉じるボタンとか装飾あり

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