Skip to content

モーダルダイアログのラッパー ​

第4版作成 最終更新 (日本時間)
確認バージョン1.5.8.1

プリザンターには jQuery UI が組み込まれており、.dialog() メソッドをそのまま使えます。このページでは、.dialog() をラップして $p.modal.alert()・$p.modal.confirm()・$p.modal.prompt()・$p.modal.show() の形で呼び出せる軽量なラッパーを、拡張スタイルと拡張スクリプトの 2 ファイルで実装する方法を示します。 外部ライブラリは不要で、v1・v2 どちらのテーマでも利用できます。

前提: ダイアログは jQuery UI ベース ​

v2 テーマではデートピッカーが flatpickr に置き換わるなど jQuery UI 離れが進んでいますが、ダイアログ機能についてはテーマバージョンを問わず jquery-ui.min.js と jquery-ui.min.css が読み込まれています。$p.openDialog / $p.closeDialog も内部で .dialog() を呼んでおり、v2 テーマの style.scss でも .ui-dialog に CSS カスタムプロパティでスタイルを当てているため、ダイアログは引き続き jQuery UI ベースで動作します。

仕様 ​

項目内容
依存ライブラリなし(プリザンター標準の jQuery / jQuery UI のみ)
名前空間$p.modal に各メソッドを追加
メソッドalert / confirm / prompt / show の 4 種類
戻り値すべて jQuery Deferred(done / fail でコールバック)
スタイル拡張スタイルで jQuery UI のデフォルトテーマを上書き

メソッド一覧 ​

メソッド用途ボタン戻り値
$p.modal.alert(message, title)情報・警告の表示OKdone で OK 押下後の処理
$p.modal.confirm(message, title)操作の確認OK / キャンセルdone(OK) / fail(キャンセル)
$p.modal.prompt(message, title, defaultValue)テキスト入力OK / キャンセルdone(value)(入力値) / fail(キャンセル)
$p.modal.show(options)任意の HTML を表示自由に設定done(result) / fail

title を省略した場合の既定タイトルは、alert が「メッセージ」、confirm が「確認」、prompt が「入力」、show が「ダイアログ」です。

実装 ​

拡張機能配置先役割
拡張スタイルApp_Data/Parameters/ExtendedStyles/jQuery UI ダイアログの見た目を調整
拡張スクリプトApp_Data/Parameters/ExtendedScripts/$p.modal 名前空間にメソッドを追加

拡張スタイル ​

前半は v1 テーマ向けの固定値、後半は v2 テーマ向けに CSS カスタムプロパティ(--base-bg / --base-text / --btn-positive-bg など)で上書きする構成です。v2 テーマでは :root にカスタムプロパティが定義されているため自動でテーマの配色に切り替わり、v1 テーマではカスタムプロパティが未定義のため前半の固定値がそのまま使われます。

css
/* --- モーダルラッパー専用スタイル --- */

/* ── 共通 / v1テーマ向け(固定値) ─────────────── */

/* オーバーレイ */
.modal-wrapper-overlay {
  background: rgba(0, 0, 0, 0.5) !important;
  z-index: 10000 !important;
}

/* ダイアログ本体 */
.ui-dialog.modal-wrapper {
  border: none;
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
  padding: 0;
  z-index: 10001;
  font-family: inherit;
}

/* タイトルバー */
.ui-dialog.modal-wrapper .ui-dialog-titlebar {
  background: #fff;
  border: none;
  border-bottom: 1px solid #e0e0e0;
  border-radius: 8px 8px 0 0;
  padding: 16px 20px;
  font-size: 16px;
  font-weight: bold;
  color: #333;
}

/* 閉じるボタン非表示 */
.ui-dialog.modal-wrapper .ui-dialog-titlebar-close {
  display: none;
}

/* コンテンツ */
.ui-dialog.modal-wrapper .ui-dialog-content {
  padding: 20px;
  font-size: 14px;
  line-height: 1.7;
  color: #444;
}

/* メッセージテキスト */
.ui-dialog.modal-wrapper .mw-message {
  white-space: pre-wrap;
  word-break: break-word;
}

/* 入力欄 */
.ui-dialog.modal-wrapper .mw-input {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 14px;
  box-sizing: border-box;
  margin-top: 12px;
  color: #333;
  background: #fff;
}

.ui-dialog.modal-wrapper .mw-input:focus {
  outline: none;
  border-color: #1976d2;
  box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.2);
}

/* ボタン領域 */
.ui-dialog.modal-wrapper .ui-dialog-buttonpane {
  border-top: 1px solid #e0e0e0;
  padding: 12px 20px;
  background: #fafafa;
  border-radius: 0 0 8px 8px;
  margin-top: 0;
}

/* ボタン共通 */
.ui-dialog.modal-wrapper .ui-dialog-buttonpane button {
  border: none;
  border-radius: 4px;
  padding: 8px 24px;
  font-size: 14px;
  cursor: pointer;
  transition: background 0.2s;
  margin-left: 8px;
}

/* プライマリボタン(OK) */
.ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-primary {
  background: #1976d2;
  color: #fff;
}

.ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-primary:hover {
  background: #1565c0;
}

/* セカンダリボタン(キャンセル) */
.ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-secondary {
  background: #e0e0e0;
  color: #333;
}

.ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-secondary:hover {
  background: #bdbdbd;
}

/* ── v2テーマ向け(CSSカスタムプロパティで自動切替) ── */
/* v2テーマ(cerulean / green-tea / mandarin / midnight)では
   :root にカスタムプロパティが定義されるため以下で上書きされます。
   v1テーマではカスタムプロパティが未定義のため
   上の固定値がそのまま使われます。                        */

.ui-dialog.modal-wrapper {
  box-shadow: 0 8px 32px var(--base-shadow, rgba(0, 0, 0, 0.25));
}

.ui-dialog.modal-wrapper .ui-dialog-titlebar {
  background: var(--base-bg, #fff);
  border-bottom-color: var(--base-border, #e0e0e0);
  color: var(--base-text, #333);
}

.ui-dialog.modal-wrapper .ui-dialog-content {
  color: var(--base-text, #444);
}

.ui-dialog.modal-wrapper .mw-input {
  border-color: var(--base-border, #ccc);
  color: var(--base-text, #333);
  background: var(--base-bg, #fff);
}

.ui-dialog.modal-wrapper .mw-input:focus {
  border-color: var(--primaryColor, #1976d2);
}

.ui-dialog.modal-wrapper .ui-dialog-buttonpane {
  border-top-color: var(--base-border, #e0e0e0);
  background: var(--base-bg-light, #fafafa);
}

.ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-primary {
  background: var(--btn-positive-bg, #1976d2);
  color: var(--btn-positive-label, #fff);
}

.ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-primary:hover {
  background: var(--btn-positive-hover, #1565c0);
}

.ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-secondary {
  background: var(--btn-normal-bg, #e0e0e0);
  color: var(--btn-normal-label, #333);
}

.ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-secondary:hover {
  background: var(--btn-normal-hover, #bdbdbd);
}
  • .modal-wrapper クラスでスコープを限定し、プリザンター標準のダイアログに影響しないようにしています
  • jQuery UI が自動生成する .ui-dialog / .ui-dialog-titlebar / .ui-dialog-buttonpane を上書きしています
  • v2 テーマ(cerulean / green-tea / mandarin / midnight)では、後半のカスタムプロパティによってテーマの配色に切り替わります
  • .modal-wrapper-overlay クラスで jQuery UI のオーバーレイ(背景の半透明マスク)をカスタマイズします
  • z-index: 10000 以上にすることで、プリザンター標準の UI 要素より前面に表示されます
  • 閉じるボタン(×)は非表示にし、ボタン操作で明示的に閉じるようにしています

拡張スクリプト ​

js
$(function () {
  // ─── $p.modal 名前空間 ─────────────────────────────
  // 本体が用意した $p.modal を上書きせず、そこにメソッドを追加する
  $p.modal = $p.modal || {};

  // ─── 共通:ダイアログ生成 ──────────────────────────
  function createDialog(title, $content, buttons, options) {
    var dfd = $.Deferred();
    var $dlg = $('<div></div>').append($content);
    var dialogClass = 'modal-wrapper'
      + (options && options.dialogClass ? ' ' + options.dialogClass : '');

    $dlg.dialog($.extend({
      title: title,
      modal: true,
      width: 420,
      resizable: false,
      closeOnEscape: false,
      dialogClass: dialogClass,
      buttons: buttons(dfd, $dlg),
      create: function () {
        // オーバーレイにカスタムクラスを付与
        $(this).closest('.ui-dialog')
          .prev('.ui-widget-overlay')
          .addClass('modal-wrapper-overlay');
      },
      close: function () {
        $(this).dialog('destroy').remove();
        if (dfd.state() === 'pending') dfd.reject();
      }
    }, options || {}));

    return dfd.promise();
  }

  // ─── alert ─────────────────────────────────────────
  $p.modal.alert = function (message, title) {
    var $content = $('<div class="mw-message"></div>').text(message);
    return createDialog(title || 'メッセージ', $content, function (dfd, $dlg) {
      return [
        {
          text: 'OK',
          class: 'mw-primary',
          click: function () {
            dfd.resolve();
            $dlg.dialog('close');
          }
        }
      ];
    });
  };

  // ─── confirm ───────────────────────────────────────
  $p.modal.confirm = function (message, title) {
    var $content = $('<div class="mw-message"></div>').text(message);
    return createDialog(title || '確認', $content, function (dfd, $dlg) {
      return [
        {
          text: 'キャンセル',
          class: 'mw-secondary',
          click: function () {
            dfd.reject();
            $dlg.dialog('close');
          }
        },
        {
          text: 'OK',
          class: 'mw-primary',
          click: function () {
            dfd.resolve();
            $dlg.dialog('close');
          }
        }
      ];
    });
  };

  // ─── prompt ────────────────────────────────────────
  $p.modal.prompt = function (message, title, defaultValue) {
    var $content = $('<div></div>')
      .append($('<div class="mw-message"></div>').text(message))
      .append(
        $('<input type="text" class="mw-input">')
          .val(defaultValue || '')
      );

    return createDialog(title || '入力', $content, function (dfd, $dlg) {
      return [
        {
          text: 'キャンセル',
          class: 'mw-secondary',
          click: function () {
            dfd.reject();
            $dlg.dialog('close');
          }
        },
        {
          text: 'OK',
          class: 'mw-primary',
          click: function () {
            dfd.resolve($dlg.find('.mw-input').val());
            $dlg.dialog('close');
          }
        }
      ];
    }, {
      open: function () {
        var $input = $(this).find('.mw-input');
        $input.trigger('focus');
        $input.on('keydown', function (e) {
          if (e.key === 'Enter') {
            $(this).closest('.ui-dialog')
              .find('.mw-primary')
              .trigger('click');
          }
        });
      }
    });
  };

  // ─── show(汎用) ──────────────────────────────────
  $p.modal.show = function (options) {
    var opt = $.extend({
      title: 'ダイアログ',
      content: '',
      width: 420,
      buttons: []
    }, options);

    var $content = typeof opt.content === 'string'
      ? $('<div></div>').html(opt.content)
      : opt.content;

    return createDialog(opt.title, $content, function (dfd, $dlg) {
      if (!opt.buttons.length) {
        return [{
          text: '閉じる',
          class: 'mw-secondary',
          click: function () {
            dfd.resolve();
            $dlg.dialog('close');
          }
        }];
      }
      return opt.buttons.map(function (btn) {
        return {
          text: btn.text,
          class: btn.class || 'mw-secondary',
          click: function () {
            if (btn.action) {
              btn.action(dfd, $dlg);
            } else {
              dfd.resolve(btn.text);
              $dlg.dialog('close');
            }
          }
        };
      });
    }, { width: opt.width, dialogClass: opt.dialogClass || '' });
  };
});

$p.modal は本体が最初から用意しているオブジェクトです。_init.js で modal: {} として定義され(_init.js)、1.5.8.1 のソースでは id 属性を持つ <ui-modal> 要素が画面に追加されると、その要素が $p.modal[id] に登録されます(ui-modal.ts)。$p.modal = {} と代入すると、それまでに登録された要素が失われるため、上のコードでは既存のオブジェクトにメソッドを追加しています。登録は id が未登録のときだけ行われるため、alert などの名前を id に持つ <ui-modal> を置かない限り、追加したメソッドが上書きされることはありません。

共通関数 createDialog ​

すべてのメソッドの中核となる関数です。

引数型説明
titlestringダイアログのタイトル
$contentjQueryダイアログ本文の jQuery オブジェクト
buttonsfunctionDeferred と $dlg を受け取り、ボタン配列を返す関数
optionsobjectjQuery UI の追加オプション
  • $.Deferred() で非同期の結果を返します。ボタンが押されたら resolve(OK)または reject(キャンセル)を呼び、呼び出し側は .done() / .fail() で後続処理を書けます
  • close イベントでは destroy と remove で DOM をクリーンアップします。Escape キーや×ボタンで閉じた場合も reject されるため、キャンセル扱いになります

各メソッド ​

メソッド動作
alertメッセージと OK ボタンだけのダイアログ。OK で done
confirmOK とキャンセルの 2 ボタン。OK で done、キャンセルで fail
promptテキスト入力欄付き。OK で入力値が done に渡される。入力欄で Enter キーを押すと OK ボタンが押される
show任意の HTML コンテンツとボタンを設定できる汎用メソッド。ボタンを省略すると「閉じる」ボタンだけが表示される

show の options には title / content(HTML 文字列または jQuery オブジェクト)/ width / buttons / dialogClass を指定できます。buttons の各要素は text / class / action を持ち、action を省略したボタンはボタンの text で resolve してダイアログを閉じます。

使い方 ​

拡張スクリプトやスクリプトの中で $p.modal を呼び出します。

メッセージを表示する ​

js
$p.modal.alert('処理が完了しました。');

// タイトルを指定
$p.modal.alert('入力内容に不備があります。', '入力エラー');

確認してから処理を実行する ​

js
$p.modal.confirm('この操作は取り消せません。実行しますか?')
  .done(function () {
    // OK が押された場合の処理
    $p.send($('#UpdateButton'));
  });

fail でキャンセル時の処理も書けます。

js
$p.modal.confirm('レコードを削除しますか?', '削除確認')
  .done(function () {
    $p.send($('#DeleteButton'));
  })
  .fail(function () {
    console.log('キャンセルされました');
  });

テキストを入力してもらう ​

js
$p.modal.prompt('コメントを入力してください', 'コメント追加')
  .done(function (value) {
    // 入力された値を分類項目にセット
    $p.set($p.getControl('ClassA'), value);
  });

第 3 引数で初期値を指定できます。

js
$p.modal.prompt('理由を入力してください', '却下理由', '内容不備のため')
  .done(function (value) {
    $p.set($p.getControl('DescriptionA'), value);
    $p.send($('#UpdateButton'));
  });

自由なコンテンツを表示する ​

js
$p.modal.show({
  title: 'レコード情報',
  width: 500,
  content:
    '<table style="width:100%; border-collapse:collapse;">' +
      '<tr><th style="text-align:left; padding:4px;">ID</th>' +
          '<td style="padding:4px;">' + $p.getControl('ResultId').val() + '</td></tr>' +
      '<tr><th style="text-align:left; padding:4px;">状態</th>' +
          '<td style="padding:4px;">' + $p.getControl('Status').val() + '</td></tr>' +
    '</table>',
  buttons: [
    { text: 'コピー', class: 'mw-primary', action: function (dfd, $dlg) {
        navigator.clipboard.writeText($p.getControl('ResultId').val());
        dfd.resolve('copied');
        $dlg.dialog('close');
      }
    },
    { text: '閉じる', class: 'mw-secondary' }
  ]
}).done(function (result) {
  if (result === 'copied') {
    $p.modal.alert('ID をクリップボードにコピーしました。');
  }
});

イベントと組み合わせる ​

$p.events と組み合わせると、ボタンクリック時の確認ダイアログとして使えます。

js
$p.events.on_editor_load = function () {
  // 更新ボタンにハンドラを追加
  $('#UpdateButton').on('click', function (e) {
    e.preventDefault();
    e.stopImmediatePropagation();
    $p.modal.confirm('変更内容を保存しますか?', '保存確認')
      .done(function () {
        // 確認後に送信
        $p.send($('#UpdateButton'));
      });
    return false;
  });
};

カスタマイズ ​

ダイアログの幅 ​

alert・confirm・prompt の既定の幅は 420px です。拡張スクリプト内の createDialog 関数の width: 420 を変更するか、show メソッドの width オプションで個別に指定します。

ボタンの色 ​

v1 テーマ向けの固定値を変更します。v2 テーマではテーマの配色が自動で適用されるため、v2 テーマ向けセクションのフォールバック値もあわせて変更します。

diff
 /* v1テーマ向け(固定値) */
 .ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-primary {
-  background: #1976d2;
+  background: #2e7d32;
 }

 .ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-primary:hover {
-  background: #1565c0;
+  background: #1b5e20;
 }

 /* v2テーマ向け(CSS変数のフォールバック値もあわせて変更) */
 .ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-primary {
-  background: var(--btn-positive-bg, #1976d2);
+  background: var(--btn-positive-bg, #2e7d32);
 }

 .ui-dialog.modal-wrapper .ui-dialog-buttonpane button.mw-primary:hover {
-  background: var(--btn-positive-hover, #1565c0);
+  background: var(--btn-positive-hover, #1b5e20);
 }

タイトルバーの背景色 ​

diff
 /* v1テーマ向け(固定値) */
 .ui-dialog.modal-wrapper .ui-dialog-titlebar {
-  background: #fff;
+  background: #e3f2fd;
 }

 /* v2テーマ向け(CSS変数のフォールバック値もあわせて変更) */
 .ui-dialog.modal-wrapper .ui-dialog-titlebar {
-  background: var(--base-bg, #fff);
+  background: var(--base-bg, #e3f2fd);
 }

ブラウザ標準ダイアログとの比較 ​

項目ブラウザ標準(alert / confirm / prompt)$p.modal
見た目ブラウザ依存CSS でカスタマイズ可能
処理の流れ同期(ページが止まる)非同期(done / fail コールバック)
入力の種類テキストのみHTML で自由に構成可能
複数ボタン2 種類まで自由に追加可能
外部ライブラリ不要不要(jQuery UI を使用)
他のダイアログとの共存非対応(ブロック)対応

関連ページ ​

変更履歴

第4版本文から元記事や以前の版への言及を除き、正しい動作だけを書く形に整理
第3版「スクリプト」を 1.5.8.1 のソースで検証して修正
第2版記事のファイル名に並び順の番号を付け、元記事リンクを frontmatter の sources に移行
第1版「スクリプト」セクションの記事を追加