とりあえず書きなぐる

とりあえず、マイノリティーなプログラムを極力説明せずに書きなぐります

DateBoxでカレンダー入力とか

日付関連プラグインです
カレンダー等入力補助のDateBox
http://dev.jtsage.com/DateBox/
日付関連のたぶんド定番Moment.js
https://momentjs.com/

f:id:vzc00525:20190502142311p:plain
DateBoxにはd.tsは無いようなので自作です
moment.d.tsはGitHubで取れます
手元にあるのは2.11.1とかなり古いものでした
JavaScriptの日付関連はかなり怪しいのでmoment.jsは必須かと

DateBoxはデフォルトでは外観が結構残念なのでcssを弄くりまくります
このへんはお好みで
/Src/cm.css

/*
  DateBox
*/
.ui-popup > div.ui-datebox-container,
.ui-popup > div.ui-datebox-container {
  border: none;
}

div.ui-datebox-container {
  width: auto !important;
  padding: 0.3em;
}

  div.ui-datebox-container .ui-btn {
    font-weight: 400;
    font-size: 12.5px;
  }

  div.ui-datebox-container.ui-popup {
    padding-top: 1.5em;
  }

    /* Close Button */
    div.ui-datebox-container.ui-popup > .ui-btn:first-child {
      position: absolute;
      margin: 0.3em;
      top: 0;
      right: 0;
      left: auto;
      bottom: auto;
      padding: 0;
    }

  /* Header */
  div.ui-datebox-container .ui-header,
  div.ui-datebox-container .ui-datebox-header {
    display: none;
  }

  /* CalBox +- */
  div.ui-datebox-container .ui-datebox-gridplus > .ui-btn,
  div.ui-datebox-container .ui-datebox-gridminus > .ui-btn {
    margin: 0;
    padding: 0.48em;
  }

  /* Calbox Day,Week*/
  div.ui-datebox-container .ui-datebox-griddate {
    margin: 6px 3px;
    width: 30px;
    border-width: 0;
    text-shadow: none;
  }

    /* Calbox Today */
    div.ui-datebox-container .ui-datebox-griddate.ui-btn-c {
      background-color: #ccc;
    }

  /* Calbox Year,Month Select */
  div.ui-datebox-container .ui-datebox-cal-pickers > .ui-controlgroup > .ui-controlgroup-controls > .ui-select {
    width: 50% !important;
  }

/* Datebox */
div.ui-datebox-datebox-groups {
  margin: 0;
  width: 10em;
}

  /* Year */
  div.ui-datebox-datebox-groups > .ui-datebox-datebox-group:first-child {
    padding-left: 0;
  }

  /* Month */
  div.ui-datebox-datebox-groups > .ui-datebox-datebox-group:last-child {
    padding-right: 0;
  }

  /* Input */
  div.ui-datebox-datebox-groups > .ui-datebox-datebox-group > .ui-input-text {
    border: none;
  }

  div.ui-datebox-datebox-groups > .ui-datebox-datebox-group > .ui-input-text,
  div.ui-datebox-datebox-button {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
  }

/* Calbox */
div.ui-datebox-calbox .ui-datebox-grid > .ui-datebox-gridrow {
  white-space: nowrap;
}

日付選択カレンダー(CalBox)と年月選択(DateBox)、時刻選択(TimeBox)の3つ分です
Flip系のインターフェイスもありますが無視です

型定義はcm.tsに混ぜます
/Src/cm.ts

/*
 * DateBox
 */
interface JQuery {
    datebox(): JQuery;
    datebox(command: any): JQuery;
    datebox(command: string, name: string | boolean | Date): string;
    datebox(command: string, name: string, value: string | boolean | Date): JQuery;
}

input横のボタンからのポップアップでボタン色が押し込んだ状態から残らないので矯正
/Src/cm.ts

/*
 * DateBox
 */
namespace DateBox {
    "use strict";

    /*
     * ポップアップオープン、クローズ
     */
    $(document).on("popupafterclose popupafteropen", ".ui-datebox-container.ui-popup", function (event: Event) {
        $(".ui-input-clear").uiBtnActive(false);
    });
}

既存のCSSに引っ張られる部分があるので矯正
ボタンの背景色適用の例外を追加します

/*
  ThemeA BaseColor White
*/
.ui-page-theme-a .ui-btn:not(.ui-btn-active):not(.ui-btn-notheme),
.ui-page-theme-a .ui-bar-inherit:not(.ui-flipswitch-active):not(.ui-li-divider),
.ui-page-theme-a {
  background-color: #fff;
}

  .ui-page-theme-a .ui-btn:not(.ui-btn-active):not(.ui-btn-notheme):hover {
    background-color: #f6f6f6;
  }

プラグイン追加
ついでにpagecontainer用のパラメーター解析メソッドを用意しておきます
/Src/cm.ts

interface JQuery {

    ....

    uiBtnNoTheme(value: boolean): JQuery;
}
namespace JQuery {

    ....

    $.fn.uiBtnNoTheme = function (value: boolean): JQuery {
        if (value) {
            $(this).filter(".ui-btn").addClass("ui-btn-notheme");
            $(this).find(".ui-btn").addClass("ui-btn-notheme");
        } else {
            $(this).filter(".ui-btn").removeClass("ui-btn-notheme");
            $(this).find(".ui-btn").addClass("ui-btn-notheme");
        }
        return this;
    }
}

....

namespace cm {
    "use strict";

    ....

    export function getToPageId(ui: any): string {
        if (ui && ui.toPage.length > 0) {
            return ui.toPage[0].id;
        }
        return "";
    }
    export function getPrevPageId(ui: any): string {
        if (ui && ui.prevPage.length > 0) {
            return ui.prevPage[0].id;
        }
        return "";
    }

    ....

}


サンプルはmobileページの左パネルを使用します
/Src/mobile.ts
ヘッダー部

  <link rel="stylesheet" href="@Url.Content("~/Content/jtsage-datebox.min.css")" />
  <script type="text/javascript" src="@Url.Content("~/Scripts/jtsage-datebox.min.js")"></script>
  <script type="text/javascript" src="@Url.Content("~/Scripts/jtsage-datebox.i18n.ja.utf8.js")"></script>
  <script type="text/javascript" src="@Url.Content("~/Scripts/moment.min.js")"></script>

i18nローカライズ用のものらしいです
CDNは例えば

  @* datebox *@
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jtsage-datebox-jqm@4.4.1/jtsage-datebox.min.css" >
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jtsage-datebox-jqm@4.4.1/jtsage-datebox.min.js"></script>
  <script type="text/javascript" src="https://cdn.jtsage.com/jtsage-datebox/i18n/jtsage-datebox.i18n.ja.utf8.min.js"></script>
  @* moment *@  
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>

Body
inputからの選択とpopupを使った選択です

<body class="ui-nodisc-icon ui-alt-icon">

  <div data-role="page" id="page1">

    <div data-role="popup" data-history="false" id="popup1" data-arrow="true" data-overlay-theme="b">
      <input id="page1_calbox_popup" type="text" />
    </div>

    <div data-role="popup" data-history="false" id="popup2" data-arrow="true" data-overlay-theme="b">
      <input id="page1_datebox_popup" type="text" />
    </div>

    <div data-role="popup" data-history="false" id="popup3" data-arrow="true" data-overlay-theme="b">
      <input id="page1_timebox_popup" type="text" />
    </div>

    <div data-role="panel" data-position="left" data-display="overlay" data-position-fixed="true" id="menu-left">
      <ul data-role="listview">
        <li>
          <input type="text" id="page1_calbox" />
        </li>
        <li>
          <input type="text" id="page1_datebox" />
        </li>
        <li>
          <input type="text" id="page1_timebox" />
        </li>
        <li><a href="#" cmd="calbox1">カレンダーポップアップ</a></li>
        <li><a href="#" cmd="datebox1">年/月ポップアップ</a></li>
        <li><a href="#" cmd="timebox1">時:分ポップアップ</a></li>
        <li><a href="#">GGGGGGGGGG</a></li>
        <li><a href="#">HHHHHHHHHH</a></li>
        <li><a href="#">IIIIIIIIII</a></li>
        <li><a href="#">JJJJJJJJJJ</a></li>
        <li><a href="#">KKKKKKKKKK</a></li>
      </ul>
    </div>

    <div data-role="panel" data-position="right" data-display="overlay" data-position-fixed="true" id="menu-right">
      <ul data-role="listview">
        <li><a href="#">AAAAAAAAAA</a></li>
        <li><a href="#">BBBBBBBBBB</a></li>
        <li><a href="#">CCCCCCCCCC</a></li>
        <li><a href="#">DDDDDDDDDD</a></li>
        <li><a href="#">EEEEEEEEEE</a></li>
        <li><a href="#">FFFFFFFFFF</a></li>
        <li><a href="#">GGGGGGGGGG</a></li>
        <li><a href="#">HHHHHHHHHH</a></li>
        <li><a href="#">IIIIIIIIII</a></li>
        <li><a href="#">JJJJJJJJJJ</a></li>
        <li><a href="#">KKKKKKKKKK</a></li>
      </ul>
    </div>

    <div data-role="header" data-position="fixed" data-fullscreen="false" data-tap-toggle="false">
      <h1>Header</h1>
      <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-carat-l ui-btn-left" cmd="left"></a>
      <div class="ui-right-panel">
        <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-bars ui-toolbtn"></a>
        <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-carat-r" cmd="right"></a>
      </div>
      <div class="ui-toolbar" id="page1_toolbar1">
        <div class="ui-left-panel">
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-star"></a>
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-gear"></a>
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-search"></a>
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-edit"></a>
        </div>
        <div class="ui-right-panel">
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-bullets"></a>
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-camera"></a>
        </div>
      </div>
      <div data-role="navbar">
        <a href="#" class="ui-btn ui-btn-active">ホーム</a>
        <a href="#">設定</a>
        <a href="#">ヘルプ</a>
        <a href="#">問い合わせ</a>
      </div>
    </div>

    <div role="main" class="ui-content">
      <ul data-role="listview" data-icon="false">
        <li>
          <a href="#">
            <img src=@Url.Content("~/imgs/album-bb.jpg")>
            <h2>Broken Bells</h2>
            <p>Broken Bells</p>
          </a>
        </li>
        <li>
          <img src=@Url.Content("~/imgs/album-hc.jpg")>
          <h2>Warning</h2>
          <p>Hot Chip</p>
        </li>
        <li>
          <a href="#">
            <img src=@Url.Content("~/imgs/album-p.jpg")>
            <h2>Wolfgang Amadeus Phoenix</h2>
            <p>Phoenix</p>
          </a>
        </li>
        <li>
          <a href="#">
            <img src=@Url.Content("~/imgs/album-bb.jpg")>
            <h2>Broken Bells</h2>
            <p>Broken Bells</p>
          </a>
        </li>
        <li>
          <img src=@Url.Content("~/imgs/album-hc.jpg")>
          <h2>Warning</h2>
          <p>Hot Chip</p>
        </li>
        <li>
          <a href="#">
            <img src=@Url.Content("~/imgs/album-p.jpg")>
            <h2>Wolfgang Amadeus Phoenix</h2>
            <p>Phoenix</p>
          </a>
        </li>
      </ul>

    </div>

    <div data-role="footer" data-position="fixed" data-fullscreen="false" data-tap-toggle="false">
      <div class="ui-toolbar">
        <div class="ui-left-panel">
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-star"></a>
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-gear"></a>
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-search"></a>
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-edit"></a>
        </div>
        <div class="ui-right-panel">
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-bullets"></a>
          <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-camera"></a>
        </div>
      </div>
      <div data-role="navbar">
        <a href="#" class="ui-btn ui-btn-active">ホーム</a>
        <a href="#">設定</a>
        <a href="#">ヘルプ</a>
        <a href="#">問い合わせ</a>
      </div>
    </div>

  </div>
</body>

DateBoxはinputの拡張で、設定はhtmlでも行えますがtypescript側でやりますので特別変わった設定はありません

/Src/mobile.ts

....
/// <reference path="../scripts/typings/moment/moment.d.ts"/>

namespace Mobile {
    "use strict";

    ....

    namespace Page1 {
        let _panelLeft: JQuery;
        let _panelRight: JQuery;
        let _psLeft: PerfectScrollbar;
        let _psRight: PerfectScrollbar;
        let _calDate = "";
        let _monthDate = "";
        let _timeDate = "";

        $(document).on("pagecontainershow", function (event: Event, ui: any) {

            if (cm.getToPageId(ui) !== "page1") {
                return;
            }

            // サイドパネル
            _panelLeft = $("#menu-left");
            _panelRight = $("#menu-right");

            // スクロールバー
            _psLeft = new PerfectScrollbar(_panelLeft.children(".ui-panel-inner")[0]);
            _psRight = new PerfectScrollbar(_panelRight.children(".ui-panel-inner")[0]);

            // 日付、時刻入力
            $("#page1_calbox").datebox({
                mode: "calbox"
                , useFocus: false
                , useModal: false
                , overrideDateFormat: "%Y/%m/%d"
                , overrideCalHeaderFormat: "%Y/%m"
                , calUsePickers: true
                , themeDateToday: "c"
            });

            $("#page1_datebox").datebox({
                mode: "datebox"
                , useFocus: false
                , useModal: false
                , overrideDateFieldOrder: ["y", "m"]
                , overrideDateFormat: "%Y/%m"
            });

            $("#page1_timebox").datebox({
                mode: "timebox"
                , useFocus: false
                , useModal: false
                , overrideTimeOutput: "%k:%M"
            });

            $("#page1_calbox_popup").datebox({
                mode: "calbox"
                , calUsePickers: true
                , useInline: true
                , hideInput: true
                , overrideDateFormat: "%Y/%m/%d"
                , overrideCalHeaderFormat: "%Y/%m"
                , themeDateToday: "c"
            });

            $("#page1_datebox_popup").datebox({
                mode: "datebox"
                , useInline: true
                , hideInput: true
                , overrideDateFieldOrder: ["y", "m"]
                , overrideDateFormat: "%Y/%m"
            });

            $("#page1_timebox_popup").datebox({
                mode: "timebox"
                , useInline: true
                , hideInput: true
                , overrideTimeOutput: "%k:%M"
            });

            $(window).resize();
            mq.update();
        });

        /*
         * 左パネル
         */
        $(document).on("click", "#menu-left .ui-btn", function (event: Event) {
            let scope = this;
            let cmd = $(this).attr("cmd");
            switch (cmd) {
                case "calbox1":

                    // NG
                    // 現在日が選択されません
                    //$("#page1_calbox_popup").off("datebox").on("datebox", function (event: Event, passed: any) {
                    //});

                    $(document).off("datebox", "#page1_calbox_popup").on("datebox", "#page1_calbox_popup", function (event: Event, passed: any) {

                        console.log(passed.method);

                        if (passed.method === "set") {
                            if (Popup.isActive("popup1")) {
                                let dt = passed.date;
                                if (dt) {
                                    _calDate = moment(dt).format("YYYY/MM/DD");
                                    $(scope).text(passed.value);
                                }
                                Popup.close();
                                Panel.close();
                            }
                        }
                    });

                    if (moment(_calDate).isValid()) {
                        $("#page1_calbox_popup").datebox("setTheDate", moment(_calDate).toDate());
                    }

                    Popup.open("#popup1", {
                        positionTo: this
                        , closeButton: true
                        , positionFixed: true
                    });
                    $("#popup1").uiBtnNoTheme(true);

                    break;

                case "datebox1":

                    $("#page1_datebox_popup").off("datebox").on("datebox", function (event: Event, passed: any) {
                        if (passed.method === "set") {
                            if (Popup.isActive("popup2")) {
                                let dt = passed.date;
                                if (dt) {
                                    _monthDate = moment(dt).format("YYYY/MM/01");
                                    $(scope).text(passed.value);
                                }
                                Popup.close();
                                Panel.close();

                            }
                        }
                    });

                    if (moment(_monthDate).isValid()) {
                        $("#page1_datebox_popup").datebox("setTheDate", moment(_monthDate).toDate());
                    }

                    Popup.open("#popup2", {
                        positionTo: this
                        , closeButton: true
                        , positionFixed: true
                    });
                    $("#popup2").uiBtnNoTheme(true);

                    break;
                case "timebox1":

                    $("#page1_timebox_popup").off("datebox").on("datebox", function (event: Event, passed: any) {
                        if (passed.method === "set") {
                            if (Popup.isActive("popup3")) {
                                let dt = passed.date;
                                if (dt) {
                                    _timeDate = moment(dt).format("YYYY/MM/DD HH:mm:01");
                                    $(scope).text(passed.value);
                                }
                                Popup.close();
                                Panel.close();
                            }
                        }
                    });

                    if (moment(_timeDate).isValid()) {
                        $("#page1_timebox_popup").datebox("setTheDate", moment(_timeDate).toDate());
                    }

                    Popup.open("#popup3", {
                        positionTo: this
                        , closeButton: true
                        , positionFixed: true
                    });
                    $("#popup3").uiBtnNoTheme(true);

                    break;
            }
        });
    }
}

inputからの表示とPopup内での表示を用意しました
何故かカレンダーは$(document)からイベントを設定しないと選択日がマークされません
inputからの表示はBody下に挿入されます
Page内からの表示の場合はボタン色設定のcssに引きずられるのでuiBtnNoThemeを使って対象外とします