とりあえず書きなぐる

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

Popupをもう少しどうにかしてみる

Popupをもう少し拡張しておきます
位置指定オプションにx,y,x1,y1,x2,y2を追加します

  • x,yはポップアップ中心
  • x1,y1はwindow左上からポップアップ左上
  • x2,y2はwindow右下からポップアップ右下

を指定します

/Src/cm.ts

/*
 * ポップアップ
 */
interface PopupOptions {
    arrow?: boolean;
    x?: number;
    y?: number;
    x1?: number;	// x左端指定
    x2?: number;	// x右端指定
    y1?: number;	// y上端指定
    y2?: number;	// y下端指定
    positionFixed?: boolean;             // 位置固定
    restoreScrollPos?: boolean;		// スクロール位置復元
    focusSelector?: string | JQuery;	// フォーカス指定
    closeButton?: boolean;	// 閉じるボタン付加
    onHeightOverflow?(overflow: boolean): any;	// 高さ食み出しイベント
    onOpend?: any;
    onClosed?: any;	// 終了イベント
}

namespace Popup {
    "use strict";

    /*
     * コンテナ取得
     */
    export function getContainer(selector: string | JQuery): JQuery {
        return $(selector).closest(".ui-popup-container");
    }

    /*
     * オープン
     */
    export function open(selector: string | JQuery, options?: PopupOptions): JQuery {
        let pos: number = undefined;

        let target = $(selector);
        let Container = getContainer(target);

        // 閉じるボタン追加
        if (options && options.closeButton) {
            target.css("padding-top", "2em");

            let btn = $("<button>");
            btn.addClass("ui-btn ui-btn-icon-notext ui-icon-delete ui-popup-close");
            btn.css({
                "position": "absolute"
                , "margin": "0.3em"
                , "top": 0
                , "right": 0
                , "left": "auto"
                , "bottom": "auto"
                , "padding": 0
            });
            target.append(btn);
        }

	/*
	 * 位置変更
	 */
        target.off("popupbeforeposition").on("popupbeforeposition", function (event: Event, data: any) {
            // 位置固定
            if (options && options.positionFixed) {
                // Container.css("position", "fixed");
            }
            // 位置指定
            if (options) {
                if (options.positionTo) {	// 基準指定
                    delete data.x;
                    delete data.y;
                    data.positionTo = options.positionTo;	// リサイズ時の位置復元

                } else {

                    // 吹き出し有無判定
                    let hasArrow = (target.children(".ui-popup-arrow-container").length > 0);

                    // x座標
                    let cx: number = undefined;
                    if (!isNaN(options.x)) {
                        cx = options.x;
                    } else if (!hasArrow) {					// 吹き出し無しのみ左右端指定可
                        let winW = $(window).width();
                        let itmW = target.outerWidth();

                        if (!isNaN(options.x1)) {			// 左端指定
                            cx = options.x1 + (itmW / 2);
                        } else if (!isNaN(options.x2)) {		// 右端指定
                            cx = (winW - (itmW / 2)) - options.x2;
                        }
                    }

                    // y座標
                    let cy: number = undefined;
                    if (!isNaN(options.y)) {
                        cy = options.y;
                    } else if (!hasArrow) {					// 吹き出し無しのみ上下端指定可
                        let winH = $(window).height();
                        let itmH = target.outerHeight();

                        if (!isNaN(options.y1)) {
                            cy = options.y1 + (itmH / 2);					// 上端指定
                        } else if (!isNaN(options.y2)) {
                            cy = (winH - (itmH / 2)) - options.y2;			// 下端指定			
                        }
                    }

                    // リサイズ時の座標復元
                    if (!isNaN(cx) || !isNaN(cy)) {
                        delete data.positionTo;
                        if (!isNaN(cx)) {
                            data.x = cx;
                        }
                        if (!isNaN(cy)) {
                            data.y = cy;
                        }
                    }
                }
            }

            // 高さオーバーフローイベント
            if (options && options.onHeightOverflow) {
                let winH = $(window).height();
                let itmH = target.outerHeight();

                let overflow = false;
                if (itmH >= winH) {
                    overflow = true;
                }
                options.onHeightOverflow(overflow); // コールバック
            }
        });

	/*
	 * オープン後
	 */
        target.off("popupafteropen").on("popupafteropen", function (event: Event) {
            // フォーカス指定
            if (options && options.focusSelector) {
                let itm = $(options.focusSelector);
                itm.focus();
            }
            // 位置固定
            if (options && options.positionFixed) {
                Container.css({
                    "position": "fixed"
                    , "margin-top": -cm.getScrollTop()
                });
            }
            $(Window).resize();

            // オープン完了
            if (options && options.onOpend) {
                options.onOpend();			// コールバック
            }
        });

	/*
	 * クローズ
	 */
        target.off("popupafterclose").on("popupafterclose", function (event: Event) {
            // スクロール位置復元
            if (isNaN(pos) === false) {
                $.mobile.silentScroll(pos);
            }
            // 終了イベント
            if (options && options.onClosed) {
                options.onClosed();			// コールバック
            }
            // イベントハンドラ破棄
            target.off("popupbeforeposition")
                .off("popupafteropen")
                .off("popupafterclose");

            // コンテナ位置設定削除
            Container.css("position", "");

            target = null;
            Container = null;
        });

        // スクロール位置保持
        if (options && options.restoreScrollPos) {
            pos = cm.getScrollTop();
        }

        // オープン
        if (!options) {
            options = {
                transition: "fade"	// フェードイン
                , tolerance: "0"		// 余白なし
            };
        } else {
            if (!options.transition) {
                options.transition = "fade";
            }
            if (!options.tolerance) {
                options.tolerance = "0";
            }
        }
        target.popup(options).popup("open", options);

        return target;
    }

    /*
     * クローズ
     */
    export function close(): boolean {
        if ($(".ui-popup").isVisible() === true) {
            $(".ui-popup").popup("close");
            return true;
        }
        return false;
    }

    export function isActive(id?: string): boolean {
        if (id) {
            return ($("#" + id + "-popup.ui-popup-active").length > 0);
        } else {
            return ($(".ui-popup-active").length > 0);
        }
    }

    /*
     * クローズボタン押下
     */
    $(document).on("click", ".ui-btn.ui-popup-close", function (event: Event) {
        Popup.close();
    });
}

サンプルです
HomeのPage2に追加します

/Views/Home/Index.vbhtml

  <div data-role="page" id="page2">
    <div data-role="popup" data-history="false" id="page2_popup1" data-arrow="false">
      <ul data-role="listview" data-icon="false">
        <li><a href="#">アイテム1</a></li>
        <li><a href="#">アイテム2</a></li>
        <li><a href="#">アイテム3</a></li>
        <li><a href="#">アイテム4</a></li>
        <li><a href="#">アイテム5</a></li>
        <li><a href="#">アイテム6</a></li>
        <li><a href="#">アイテム7</a></li>
        <li><a href="#">アイテム8</a></li>
        <li><a href="#">アイテム9</a></li>
        <li><a href="#">アイテム10</a></li>
      </ul>
    </div>

    <div data-role="header" data-position="fixed" data-fullscreen="false" data-tap-toggle="false">
      <h1>Dialog</h1>
      <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-video" cmd="btn1">ボタン1</a>
      <a href="#" class="ui-btn ui-btn-icon-notext ui-icon-camera" cmd="btn2">ボタン2</a>
    </div>

    <div role="main" class="ui-content ui-form">
      <ul data-role="listview" data-inset="true" data-icon="false" class="split">
        <li>
          <div class="ui-field-contain em7">
            <label for="text-12">Text input:</label>
            <div>
              <input name="text-12" id="text-12" type="text" value="">
            </div>
          </div>
          <button class="ui-btn ui-btn-icon-notext ui-btn-split ui-icon-carat-d" cmd="popup1"></button>
        </li>
        <li>
          <div class="ui-field-contain em7">
            <label for="text-13">Text input clr:</label>
            <div>
              <input name="text-13" id="text-13" type="text" value="" data-clear-btn="true">
            </div>
          </div>
        </li>
        <li>
          <div class="ui-field-contain em7">
            <label for="search-8">Search:</label>
            <div>
              <input name="search-8" id="search-8" type="search" value="">
            </div>
          </div>
        </li>
        <li>
          <div class="ui-field-contain em7">
            <label for="textarea-12">Textarea:</label>
            <div>
              <textarea name="textarea-12" id="textarea-12" rows="8" cols="40"></textarea>
            </div>
          </div>
          <button class="ui-btn ui-btn-icon-notext ui-btn-split ui-icon-delete"></button>
        </li>
        <li>
          <div class="ui-field-contain em7">
            <label for="Switch">Flip switch:</label>
            <div>
              <input name="flip-checkbox-1" id="flip-checkbox-1" type="checkbox" data-role="flipswitch">
            </div>
          </div>
        </li>
      </ul>
    </div>

    <div data-role="footer" data-position="fixed" data-fullscreen="false" data-tap-toggle="false">
      <div class="ui-toolbar" id="page2_cmd">
        <div class="ui-left-panel">
          <a href="#" class="ui-btn" cmd="reset">リセット</a>
        </div>
        <div class="ui-right-panel">
          <a href="#" class="ui-btn ui-btn-active">OK</a>
          <a href="#page1" class="ui-btn">キャンセル</a>
        </div>
      </div>
    </div>
  </div>

/Src/home.ts

    namespace Page2 {

        $(document).on("click", "#page2 > .ui-header > .ui-btn", function (event: Event) {
            $(this).blur();
            let y1 = $("#page2 > .ui-header").outerHeight() + $(window).scrollTop();
            let cmd = $(this).attr("cmd");
            switch (cmd) {
                case "btn1":
                    Popup.open("#page2_popup1", {
                        x1: 0
                        , y1: y1
                        , positionFixed: true
                        , transition: "slidedown"
                    });
                    break;
                case "btn2":
                    Popup.open("#page2_popup1", {
                        x2: 0
                        , y1: y1
                        , transition: "slidedown"
                    });
                    break;
            }


        });

        $(document).on("click", "#page2 li > .ui-btn", function (event: Event) {
            let cmd = $(this).attr("cmd");
            switch (cmd) {
                case "popup1":
                    let pos = $(this).offset();

                    Popup.open("#page2_popup1", {
                        x2: $(window).width() - pos.left - $(this).outerWidth() - 1
                        , y1: pos.top + $(this).outerHeight()
                    });
                    break;
            }
        });

        $(document).on("click", "#page2 > .ui-footer .ui-btn", function (event: Event) {
            $(this).blur();

            let cmd = $(this).attr("cmd");
            switch (cmd) {
                case "reset":
                    let y2 = $("#page2 > .ui-footer").outerHeight() - $(window).scrollTop();
                    Popup.open("#page2_popup1", {
                        x1: 0
                        , y2: y2
                        , transition: "flip"
                        , positionFixed: true
                    });
                    break;
            }
        });
    }

ボタンのドロップダウンメニュー風にしたり出来るようになりました