とりあえず書きなぐる

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

左右からパネル

パネルです
f:id:vzc00525:20190502174528p:plain

横からスライドしてくるパネルですが、NuGetから落ちてくるjQuery Mobileの古いd.tsには含まれていません
仕方がないので自力で追加しますが、たいしたものではないのでcm.tsに含めてしまいます
/Src/cm.ts

/*
 * Panel
 */
interface PanelOptions {
    animate?: boolean;
    defaults?: boolean;
    disabled?: boolean;
    dismissible?: boolean;
    display?: string;
    initSelector?: string;
    position?: string;
    positionFixed?: boolean;
    swipeClose?: boolean;
    theme?: string;
}
interface PanelEvents {
    create?: JQueryMobileEvent;
}
interface JQueryMobile extends JQueryMobileOptions {
    panel: any;
}
interface JQuery {
    panel(): JQuery;
    panel(command: string): JQuery;
    panel(command: string, name: string): string;
    panel(command: string, name: string, value: string): JQuery;
    panel(options: PanelOptions): JQuery;
    panel(events: PanelEvents): JQuery;
}

使いそうな分だけです

操作メソッドも追加します
/Src/cm.ts

/*
 * パネル
 */
namespace Panel {
    "use strict";
   /*
    * クローズ
    */
    export function close() {
        $(".ui-panel").panel("close");
    }
    /*
     * オープン
     */
    export function open(selector: string | JQuery): JQuery {
        let target = $(selector);
        switch (target.css("visibility")) {
            case "hidden":
            case "collapse":
                target.panel("open");
        }
        return target;
    }
    /*
     * 表示設定
     */
    export function setVisible(selector: string | JQuery, visible: boolean): JQuery {
        let target = $(selector);
        if (visible) {
            target.addClass("ui-panel-visible");
        } else {
            target.removeClass("ui-panel-visible");
        }
        return target;
    }
   /*
     * 高さ設定
     */
    export function setFixedHeight(selector: string | JQuery, height: number): JQuery {
        let target = $(selector);
        if (target.hasClass("ui-panel-fixed")) {
            let inner = target.children(".ui-panel-inner");
            inner.outerHeight(height - inner[0].offsetTop).css("overflow-y", "auto");
        }
        return target;
    }
}

「開く」、「閉じる」と強制表示、内側の高さ設定(スクロール用)

いくつかのモードが用意されていますがオーバーレイ以外使用しません
cssのその分だけ用意します
/Src/cm.css

/*
  Panel
*/
div.ui-panel {
  z-index: 1001;
}
  div.ui-panel.ui-panel-display-overlay.ui-panel-position-left {
    border-right: 1px solid #ddd;
  }
  div.ui-panel.ui-panel-display-overlay.ui-panel-position-right {
    border-left: 1px solid #ddd;
  }
/* Panel Visibled */
.ui-page > div.ui-panel.ui-panel-display-overlay.ui-panel-visible { /* overlay only */
  clip: auto;
  width: 17em;
  visibility: visible;
  -webkit-transform: translate3d(0,0,0);
  -moz-transform: translate3d(0,0,0);
  -ms-transform: translate3d(0,0,0);
  -o-transform: translate3d(0,0,0);
  transform: translate3d(0,0,0);
}
  .ui-page > div.ui-panel.ui-panel-display-overlay.ui-panel-visible.ui-panel-position-left {
    left: 0;
    right: auto;
  }
    .ui-page > div.ui-panel.ui-panel-display-overlay.ui-panel-visible.ui-panel-position-left ~ .ui-header,
    .ui-page > div.ui-panel.ui-panel-display-overlay.ui-panel-visible.ui-panel-position-left ~ .ui-content,
    .ui-page > div.ui-panel.ui-panel-display-overlay.ui-panel-visible.ui-panel-position-left ~ .ui-footer {
      margin-left: 17em;
      width: auto;
    }
  .ui-page > div.ui-panel.ui-panel-display-overlay.ui-panel-visible.ui-panel-position-right {
    right: 0;
    left: auto;
  }
    .ui-page > div.ui-panel.ui-panel-display-overlay.ui-panel-visible.ui-panel-position-right ~ .ui-header,
    .ui-page > div.ui-panel.ui-panel-display-overlay.ui-panel-visible.ui-panel-position-right ~ .ui-content,
    .ui-page > div.ui-panel.ui-panel-display-overlay.ui-panel-visible.ui-panel-position-right ~ .ui-footer {
      margin-right: 17em;
      width: auto;
    }

サンプルのhtmlです
/Views/Mobile/Index.html

<!DOCTYPE html>
<html>
<head>
  <title>Home</title>
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta charset="utf-8" />

  <link rel="stylesheet" href="@Url.Content("~/Content/jquery.mobile-1.4.5.min.css")" />
  <link rel="stylesheet" href="@Url.Content("~/Src/cm.css")" />
  <link rel="stylesheet" href="@Url.Content("~/Src/app.css")" />

  <script type="text/javascript" src="@Url.Content("~/Scripts/jquery-2.1.3.min.js")"></script>
  <script type="text/javascript" src="@Url.Content("~/Scripts/jquery.mobile-1.4.5.min.js")"></script>
  <script type="text/javascript" src="@Url.Content("~/Src/cm.js")"></script>
  <script type="text/javascript" src="@Url.Content("~/Src/mobile.js")"></script>

  <style type="text/css">
    .ui-header > .ui-title {
      background-color: Red;
      color: white;
      text-shadow: none;
    }
    .ui-btn-active{
      background-color: Red !important;
      text-shadow:none !important;
    }
  </style>
</head>
<body class="ui-nodisc-icon ui-alt-icon">

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

    <div data-role="panel" data-position="left" data-display="overlay" data-position-fixed="true" id="menu-left">
      <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="panel" data-position="right" data-display="overlay" 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>
</html>

パネルは左右を用意、やはりPage内に配置します

mobile.tsを用意します
/Src/mobile.ts

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

namespace Mobile {
    "use strict";
    /*
     * ページ表示前
    */
    $(document).on("pagecontainerbeforeshow", function (event: Event, ui: any) {
    });

    namespace Page1 {
        /*
         * ページ表示後
         /*/
        $(document).on("pagecontainershow", function (event: Event, ui: any) {

        });
    }
}

ソースの基本構造です
namespace html名 {
 namespace ページ名 {...}
 namespace ページ名 {...}
 namespace ページ名 {...}
}
ページ表示イベントはPagecontainer Widgetのものを使用します
スパゲッティ化しないようにページ毎に用意します
Pagecontainerやwindow系のイベントはフィルタが聞かないようなので

$(document).on("pagecontainershow", function (event: Event, ui: any) {
    if (cm.getActivePageId() !== "page1") {
        return;
    }
    // 以下、ページ固有処理
});

と、内部でフィルタします

サンプルは幅をウィンドウ広げていくと、サイドパネルが左、右と表示されていくようにします
レスポンシブにはMediaQueryを使用します
条件設定はCSSと同じになります

/Src/mobile.ts

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

namespace Mobile {
    "use strict";

    namespace mq {
        let mm = window.matchMedia("(min-width:28em) and (min-height:28em)");
        mm.addListener(function (event: MediaQueryList) {
            update();
        });
        export function isMatch(): boolean {
            return mm.matches;
        }
	/*
	 * パネルL
	 */
        export namespace PanelL {
            let panelL = window.matchMedia("(min-width:55em)");
            panelL.addListener(function (event: MediaQueryList) {
                update();
            });
            export function isVisible(): boolean {
                return panelL.matches;
            }
        }
	/*
	 * パネルR
	 */
        export namespace PanelR {
            let panelR = window.matchMedia("(min-width:80em)");
            panelR.addListener(function (event: MediaQueryList) {
                update();
            });
            export function isVisible(): boolean {
                return panelR.matches;
            }
        }
	/*
	 * 更新
	 */
        export function update() {
            if (mm.matches) {
                $(".ui-header .ui-toolbar").resetDisplay();
                $(".ui-header .ui-toolbtn").hide();
            } else {
                $(".ui-header .ui-toolbar").hide();
                $(".ui-header .ui-toolbtn").resetDisplay();
            }
            $(document).trigger("mq_responsive");
        }
    }

    /*
     * 表示前
     */
    $(document).on("pagecontainerbeforeshow", function (event: Event, ui: any) {
        mq.update();
    });

    namespace Page1 {
        let _panelLeft: JQuery;
        let _panelRight: JQuery;

        $(document).on("mq_responsive", function (event: Event) {
            if (cm.getActivePageId() !== "page1") {
                return;
            }
            Panel.setVisible(_panelLeft, mq.PanelL.isVisible());
            Panel.setVisible(_panelRight, mq.PanelR.isVisible());
        });

        $(document).on("pagecontainershow", function (event: Event, ui: any) {
            if (cm.getActivePageId() !== "page1") {
                return;
            }
            // サイドパネル
            _panelLeft = $("#menu-left");
            _panelRight = $("#menu-right");
            $(window).resize();
            mq.update();
        });
	/*
	 * ヘッダボタン押下
	 */
        $(document).on("click", "#page1 > .ui-header .ui-btn", function (event: Event) {
            let cmd = $(this).attr("cmd");
            switch (cmd) {
                case "left":
                    Panel.open(_panelLeft);
                    break;
                case "right":
                    Panel.open(_panelRight);
                    break;
            }
        });

        $(window).on("resize", function (event: Event) {
            if (cm.getActivePageId() !== "page1") {
                return;
            }
            // サイドパネルの高さ更新
            let h = $(window).outerHeight();
            Panel.setFixedHeight(_panelLeft, h);
            Panel.setFixedHeight(_panelRight, h);
        });
    }
}

しきい値(28em, 55em,80em)をまたぐ度に"mq_responsive"が発生します
28emを跨いでui-toolbarとui-toolbtnのどちらかを表示するようにしてみました
ui-toolbtnにメニューでもつけるべきなのですがそこはスルーで
addListenerしているのでグローバルにないと二重登録されるかもしれません
リサイズではPanelの内部の高さを設定しています