大きなボタンの数値入力を作ってみる
数値入力です
jQueryプラグインとして実装します
増減ボタンとスライダーを付加してみます
/Src/cm.ts
interface NumberSpinOptions { digits?: number; slider?: boolean; max?: number; min?: number; step?: number; width?: string; } interface JQuery { .... numberSpin(options: NumberSpinOptions): JQuery; numberSpin(): JQuery; } namespace JQuery { .... $.fn.numberSpin = function (options?: NumberSpinOptions): JQuery { if ($(this).length > 1) { for (let i = 0; i < $(this).length; i++) { $(this).eq(i).numberSpin(options); } return; } /* 初期化*/ let container = $(this).closest(".ui-input-text"); { container.css("padding-right", "").addClass("ui-input-has-spin"); container.children(".ui-btn-spin-group").remove(); let itm = container.next(".ui-slider"); if (itm.children(".ui-slider-spin").length > 0) { itm.remove(); } } let spinInput = container.children("input"); //オプション let opts: NumberSpinOptions = { digits: 0 , slider: false , max: 100 , min: 0 , step: 1 }; { // 少数桁 if ((options) && (typeof options.digits !== "undefined") && (options.digits >= 0)) { opts.digits = options.digits; } // スライダー表示 if ((options) && (typeof options.slider !== "undefined")) { opts.slider = options.slider; } // 最大値 if ((options) && (typeof options.max !== "undefined")) { opts.max = options.max; } else { let attrMax = parseFloat(spinInput.attr("max")); if (isNaN(attrMax) === false) { opts.max = attrMax; } } // 最小値 if ((options) && (typeof options.min !== "undefined")) { opts.min = options.min; } else { let attrMin = parseFloat(spinInput.attr("min")); if (isNaN(attrMin) === false) { opts.min = attrMin; } } // 増減値 if ((options) && (typeof options.step !== "undefined")) { opts.step = options.step; } else { let attrStep = parseFloat(spinInput.attr("step")); if (isNaN(attrStep) === false) { opts.step = attrStep; } } opts.step = Math.abs(opts.step); if ((options) && (options.width)) { container.css("max-width", options.width); } } spinInput.attr({ "min": opts.min , "max": opts.max , "step": opts.step }); /* * 増減ボタン作成 */ let spinGroup = $("<div class='ui-btn-spin-group'>"); let spinPlus = $("<a href='#' tabindex='-1' title='plus' class='ui-btn ui-btn-inline ui-btn-icon-notext ui-icon-plus ui-btn-spin-plus'>"); let spinMinus = $("<a href='#' tabindex='-1' title='miuns' class='ui-btn ui-btn-inline ui-btn-icon-notext ui-icon-minus ui-btn-spin-minus'>"); { // グループ追加 container.append(spinGroup); // ボタン追加 spinGroup.append(spinMinus); spinGroup.append(spinPlus); let r = 1; if (container.hasClass("ui-input-has-clear")) { r = container.outerWidth() - container.width(); } let h = spinInput.outerHeight() - 2; spinGroup.css({ top: 1 , height: h , right: r }); spinGroup.children(".ui-btn").outerHeight(h); container.css({ "padding-right": r + spinGroup.outerWidth() + 2 }); } /* * スライダー作成 */ let spinSlider: JQuery; if ((opts.slider) && (opts.min < opts.max)) { let content = ""; content += "<input"; content += " tabindex='-1'"; content += " type='range'"; content += " min='" + opts.min + "'"; content += " max='" + opts.max + "'"; content += " step='" + opts.step + "'"; content += " class='ui-slider-spin'"; content += ">"; spinSlider = $(content); container.after(spinSlider); spinSlider .enhanceWithin() .slider() .slider("refresh") .off("change") .on("change", function (event: Event) { let v = parseFloat(spinSlider.val()); spinInput.val(v); updateValue(0, false); }); spinSlider.closest(".ui-slider").find(".ui-btn").attr("tabindex", "-1"); } updateValue(0, false); /* * イベント */ { spinInput.off("blur").on("blur", function (event: Event) { updateValue(0, false); }); spinInput.off("keydown").on("keydown", function (event: JQueryKeyEventObject) { switch (event.which) { case 13: // Enter updateValue(0, true); // 表示 return false; case 38: // up updateValue(1, true); // 増 return false; case 40: // down updateValue(-1, true); // 減 return false; } }); spinPlus.off("click").on("click", function (event: Event) { updateValue(1, true); // 増 }); spinMinus.off("click").on("click", function (event: Event) { updateValue(-1, true); // 減 }); spinPlus.off("mousedown").on("mousedown", function (event: JQueryMouseEventObject) { setRepeatTimer(1); // リピート増 }); spinPlus.off("mouseup").on("mouseup", function (event: JQueryMouseEventObject) { setRepeatTimer(0); // リピート終了 }); spinPlus.off("mouseleave").on("mouseleave", function (event: JQueryMouseEventObject) { setRepeatTimer(0); // リピート終了 }); spinMinus.off("mousedown").on("mousedown", function (event: JQueryMouseEventObject) { setRepeatTimer(-1); // リピート減 }); spinMinus.off("mouseup").on("mouseup", function (event: JQueryMouseEventObject) { setRepeatTimer(0); // リピート終了 }); spinMinus.off("mouseleave").on("mouseleave", function (event: JQueryMouseEventObject) { setRepeatTimer(0); // リピート終了 }); } /* * 増減リピートタイマー設定 */ let delayTitmeHandle = 0; // リピート開始待ち let repeatTimerHandle = 0; // リピート間隔 function setRepeatTimer(off: number) { if (off) { // 設定 setRepeatTimer(0); delayTitmeHandle = setTimeout(function () { repeatTimerHandle = setInterval(function () { updateValue(off, true); }, 50); }, 1000); } else { // クリア if (delayTitmeHandle) { clearTimeout(delayTitmeHandle); delayTitmeHandle = 0; } if (repeatTimerHandle) { clearInterval(repeatTimerHandle); repeatTimerHandle = 0; } } } /* * 値更新 */ function updateValue(off: number, sel: boolean) { if (off > 0) { off = opts.step; } if (off < 0) { off = -opts.step; } let prev = parseFloat(spinInput.val()); let v = prev + off; if (isNaN(v)) { v = 0; } v = limitMax(v); v = limitMin(v); spinInput.val(v.toFixed(opts.digits)); if (spinSlider) { spinSlider.val(v).slider("refresh"); } if (sel) { spinInput.select(); } if (prev !== v) { spinInput.change(); } } /* * 最小値取得 */ function limitMin(value: number): number { if (opts.max <= opts.min) { return value; } return Math.max(value, opts.min); } /* * 最大値取得 */ function limitMax(value: number): number { if (opts.max <= opts.min) { return value; } return Math.min(value, opts.max); } return this; }; }
残念なことにもjQuery Mobile はHTML5を謳っていながらinputの一部typeに対応していないようです
無理やり矯正します
/Src/cm.ts
/* * Input HTML5対応 */ $(document).on("focusout", ".ui-input-text", function (event: Event) { $(this).removeClass("ui-focus"); });
/* Input */ .ui-input-has-spin > input, .ui-input-has-clear > input { border-right: 1px solid #ddd; padding-right: 0.4em; } /* Input Spin */ .ui-input-text > .ui-btn-spin-group { position: absolute; } .ui-input-text > .ui-btn-spin-group > .ui-btn { margin: 0; border-width: 0; } .ui-input-text.ui-input-has-spin { position: relative; } .ui-input-text.ui-input-has-clear.ui-input-has-spin > .ui-btn-spin-group { border-right: 1px solid #ddd; } /* Input Spin Slider */ input.ui-slider-spin { display: none; } input.ui-slider-spin + .ui-slider-track { margin-left: 15px; }
サンプル追加します
HomeのPage2に項目追加します
<li> <div class="ui-field-contain em7"> <label for="spin1">Spin input:</label> <div> <input name="spin1" id="spin1" type="number" value="" max="100" min="-100" step="2"> </div> </div> </li> <li> <div class="ui-field-contain em7"> <label for="spin2">Spin input clr:</label> <div> <input name="spin2" id="spin2" type="number" value="" max="100" min="0" step="0.5" data-clear-btn="true"> </div> </div> </li>
プラグインを適用します
namespace Page2 { $(document).on("pagecontainershow", function (event: Event, ui: any) { if (cm.getToPageId(ui) !== "page2") { return; } // 数値入力設定 $("#spin2").numberSpin({ digits: 2, slider: true }); $("#spin1").numberSpin(); }); .... }