一覧の行に操作ボタン(参照コピー・コピー・移動・削除)を付ける
参照コピー・コピー・移動・削除は編集画面のコマンドにしかなく、一覧からは 1 件ずつ編集画面を開く必要があります。これらを一覧の各行のボタンから使えるようにする改修の設計メモです。本体の標準機能ではありません。
前提にした現行実装(1.5.8.1)
一覧の行
一覧の行は HtmlGrids.cs で <tr class="grid-row"> として出力され、data-id(レコード ID)、ロック中のレコードには data-locked="1" が付きます(HtmlGrids.cs)。
先頭のセルはモードで変わります(HtmlGrids.cs)。
| モード | 先頭のセル |
|---|---|
一覧で編集する(editRow) | 再読み込み(ReloadRow)と行のコピー(CopyRow、作成権限があるとき) |
| 通常 | チェックボックス(grid-check) |
行のセルをクリックすると、gridevents.js のハンドラが編集画面へ移動します。一覧に new-tab クラスがあれば別タブ、#EditorDialog があればダイアログで開きます(gridevents.js)。
編集画面のコマンド
HtmlCommands.cs の表示条件です。
| ボタン | controlId | 動作 | 表示条件 |
|---|---|---|---|
| コピー | OpenCopyDialogCommand | コピーのダイアログを開く($p.openDialog) | 作成権限、かつ AllowCopy(フォルダは常に) |
| 参照コピー | ReferenceCopyCommand | location.href で /items/{SiteId}/new?CopyFrom={Id} へ移動 | 作成権限、フォルダでない、AllowReferenceCopy |
| 移動 | MoveTargetsCommand | 移動先のダイアログ($p.moveTargets) | 更新権限、MoveTargets の設定あり |
| 削除 | DeleteCommand | $p.send で削除 | 削除権限 |
参照コピーは新規作成画面への移動なので、リンクにすれば別タブで開けます。コピーはダイアログでコメント・通知・リマインダーのコピー有無を選んでから(HtmlCopies.cs)サーバーで Copy を実行し、結果を編集画面に表示します。
設計
方針の比較
| 方針 | 内容 | 評価 |
|---|---|---|
1. 列の GridDesign で HTML を組む | 列の表示を [ColumnName] のプレースホルダで差し替える既存機能を使う | 値の表示用の仕組みで、権限による出し分けやボタンの処理を持たない |
| 2. 操作ボタン専用の列を足す(推奨) | 一覧の列として「操作」列を定義し、セルにボタンを出す | 一覧編集モードの先頭セルと同じ作りにできる |
操作列の定義
| 項目 | 値 |
|---|---|
| 列名 | _ActionButtons(先頭の _ で特殊な列と分かるようにする) |
| 表示名 | 操作 |
| 一覧に表示 | できる |
| 編集・ソート | できない |
テーブルの管理 > 一覧の「利用可能な列」に出し、有効にするだけで使えるようにします。GridSelectableOptions に追加し、列の詳細設定ダイアログでボタンごとの表示と別タブで開くかを選べるようにします。
| 設定 | 既定 |
|---|---|
| 参照コピーを表示 | オン |
| コピーを表示 | オン |
| 移動を表示 | オン |
| 削除を表示 | オン |
| 参照コピーを別タブで開く | オフ |
| コピーを別タブで開く | オフ |
各ボタンの動作
図を読み込み中…
改修箇所
| ファイル | 改修内容 |
|---|---|
Libraries/HtmlParts/HtmlGrids.cs | 列のループで _ActionButtons のときにボタンのセルを出す |
Libraries/Settings/Column.cs | 操作列を表すフラグ |
Libraries/Settings/SiteSettings.cs | 選べる列への追加、別タブ設定(例: GridActionNewTab) |
Libraries/Settings/ColumnUtilities.cs | 一覧の列定義に操作列を含める |
Models/Sites/SiteUtilities.cs | 一覧タブの設定 UI |
App_Data/Definitions/ の列定義 | 操作列の定義 |
新規 gridactions.js | 削除・移動・コピーのハンドラ |
ボタンの描画(案)
private static HtmlBuilder GridActionButtons(
this HtmlBuilder hb, Context context, SiteSettings ss, long dataId, bool isHistory)
{
return hb
.A(
href: $"{Locations.ItemNew(context: context, id: ss.SiteId)}?CopyFrom={dataId}",
target: ss.GridActionNewTab == true ? "_blank" : null,
title: Displays.ReferenceCopy(context: context),
css: "grid-action-button",
_using: !isHistory
&& context.CanCreate(ss: ss)
&& ss.AllowReferenceCopy == true)
.Button(
title: Displays.Copy(context: context),
controlCss: "grid-action-button",
onClick: $"$p.gridAction($(this), {dataId}, 'Copy');",
icon: "ui-icon-copy",
_using: !isHistory
&& context.CanCreate(ss: ss)
&& ss.AllowCopy == true)
.Button(
title: Displays.Move(context: context),
controlCss: "grid-action-button",
onClick: $"$p.gridMoveTargets($(this), {dataId});",
icon: "ui-icon-transferthick-e-w",
_using: !isHistory
&& ss.MoveTargets?.Any() == true
&& context.CanUpdate(ss: ss))
.Button(
title: Displays.Delete(context: context),
controlCss: "grid-action-button button-negative",
onClick: $"$p.gridDelete($(this), {dataId});",
icon: "ui-icon-trash",
_using: !isHistory && context.CanDelete(ss: ss));
}gridactions.js(案)
$p.gridDelete = function ($control, dataId) {
if (!confirm($p.display('ConfirmDelete'))) return;
var data = $p.getData($control);
data.Id = dataId;
$p.send($control, 'MainForm', 'Delete', 'delete');
};
$p.gridMoveTargets = function ($control, dataId) {
var data = $p.getData($control);
data.Id = dataId;
$p.send($control, 'MainForm', 'MoveTargets', 'get');
$p.openDialog($control, '.main-form');
};
$p.gridAction = function ($control, dataId, action) {
var data = $p.getData($control);
data.Id = dataId;
$p.send($control, 'MainForm', action, 'post');
};行クリックとの切り分け
ボタンのクリックで行のクリック(編集画面への移動)が起きないように、gridevents.js の .grid-row td のハンドラで、操作列のセルからのクリックを除外します。
$(document).on('click', '.grid-row td', function (event) {
if ($(event.target).closest('.grid-action-buttons').length > 0) return;
// 既存の処理
});権限とロック
ボタンはサーバー側で権限を見て、権限の無いボタンは HTML に出しません。
| ボタン | 権限 | 追加の条件 |
|---|---|---|
| 参照コピー | 作成 | AllowReferenceCopy |
| コピー | 作成 | AllowCopy |
| 移動 | 更新 | MoveTargets の設定あり |
| 削除 | 削除 | レコードがロックされていない |
ロック中のレコードは行の data-locked="1" を見て、移動・削除を押せなくします。送信は $p.send 経由にすれば、既存の CSRF 対策(フォームのトークン)がそのまま効きます。
ビュー単位で編集画面のコマンドを出し分ける CommandDisplayTypes(表示・非表示・無効・隠し)にも合わせるかは、最初はサイト設定での オン・オフだけにし、あとから考えます(View.cs)。
既存の機能との関係
| 機能 | 一覧編集モードの先頭セル | 操作列 |
|---|---|---|
| コピー | 行のその場コピー(CopyRow) | コピー(ダイアログ相当)または参照コピー |
| 再読み込み | ReloadRow | なし |
| 移動 | なし | 移動先のダイアログ |
| 削除 | なし | 確認して削除 |
| 参照コピー | なし | 新規作成画面へ |
一括削除・一括移動はチェックボックスの選択で行う既存の機能のまま残し、操作列は 1 件ずつの操作に使います。