Skip to content

サイトの移動抑止・アーカイブ管理・サイト構成一覧 ​

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

サイト(フォルダやテーブル)の管理に関する小技をまとめます。

  • ドラッグ&ドロップによるサイトの誤移動を、スクリプトと拡張ナビゲーションメニューで防ぐ
  • 使わなくなったサイトを、CSS とスクリプトで「アーカイブ」のように隠す・切り替える
  • サイト構成の一覧を、階層付きで SQL(拡張 SQL の API)から取得する

サイトの移動を抑止する ​

サイトの管理権限を持つユーザは、ドラッグ&ドロップでサイトの階層移動や並べ替えができます。操作が簡単なぶん、ちょっとした誤操作で意図せず移動させてしまうことがあります。

仕組み ​

サイトの移動は jQuery UI の Sortable で実現されています。対象の要素に対して Sortable の有効・無効(disabled オプション)を切り替えれば、移動させる・させないを制御できます。

ここでは次の要件で実装します。

  • 最初は移動を無効にしておき、必要なときだけ有効にする
  • 有効・無効はナビゲーションメニューから切り替える
  1. body の中に、現在の状態を保持する hidden の input を追加します。body 内の hidden input にフラグや値を持たせるのはプリザンターでよく使われる方法で、$p.UserId などスクリプトで使える値の多くもこの input 群から取得されています。
  2. フラグを反転し、メニューの文言を差し替える関数を用意します。
  3. 移動できる要素(.nav-sites.sortable)にポインタが乗ったときに、フラグを見て Sortable を有効・無効に切り替えます。

設定 ​

拡張スクリプト と 拡張ナビゲーションメニュー として配置します。

js
if(!$('#SiteSortable').length){
    $('body').append('<input id="SiteSortable" name="SiteSortable" type="hidden" value="0">');
}

$p.naviMenuExtendDisableSorter = function(){
    if($('#SiteSortable').val() == 0){
        $('#SiteSortable').val(1);
        $('#SettingsMenu_DisableSorter a').text('ソートを無効にする');
        $p.closeSideMenu();
    }else{
        $('#SiteSortable').val(0);
        $('#SettingsMenu_DisableSorter a').text('ソートを有効にする');
        $p.closeSideMenu();
    }
}

$('.nav-sites.sortable').on('mouseenter pointerenter touchstart',function(){
    $(this).sortable($('#SiteSortable').val() == 0 ? 'disable' : 'enable');
});
json
{
 "TargetId": "SettingsMenu",
 "Action": "Append",
 "NavigationMenus": [
  {
   "ContainerId": "ExtendSettingsContainer",
   "MenuId": "ExtendSettingsMenu",
   "Name": "拡張管理",
   "Icon": "ui-icon ui-icon-gear",
   "ChildMenus": [
    {
     "MenuId": "SettingsMenu_DisableSorter",
     "Name": "ソートを有効にする",
     "Icon": "ui-icon ui-icon-radio-off",
     "Url": "javascript:$p.naviMenuExtendDisableSorter();",
     "ReferenceTypes": ["Sites"],
     "Actions": ["index"]
    }
   ]
  }
 ]
}

ReferenceTypes と Actions の指定により、メニューはサイト(フォルダ)の画面を表示しているときだけ表示されます。

サイトをアーカイブのように管理する ​

あまり使わないサイトや終了したプロジェクトのサイトなど、削除はできないが表示されていると邪魔なサイトを、その場で見えなくする方法です。アーカイブ用フォルダへ移動させる方法もありますが、アクセス権の管理がサイトの階層から離れる、所定の階層外に動かしたくない、といった場合に使えます。

「読取専用の場合は画面に表示しない」オプションとの比較 ​

読取専用の場合は画面に表示しない オプションを使い、管理者など必要最低限のユーザだけに書き込み権限を付与すれば、他のユーザの画面からはサイトが消えます。ただし完全に表示から消えるため、一時的に表示させることはできません。一時的に隠したいだけなら、次のスタイルとスクリプトの方法が向いています。

CSS で隠す ​

隠したいサイトを含むフォルダのテーブルの管理で、スタイルに次の CSS を設定します(サイト ID が 3482327 の場合)。

css
.nav-site[data-value="3482327"] {
    display:none;
}

スクリプトで表示を切り替える ​

CSS で display:none; にしているだけなので、jQuery で表示できます。

js
$('.nav-site').show();

toggle を使うと、「通常のサイト」と「アーカイブされたサイト」の表示を切り替えられます。「上へ」の要素も nav-site クラスを持っているため、:not(.to-parent) で除外しています。

js
$('.nav-site:not(.to-parent)').toggle();

ナビゲーションメニューに組み込む ​

拡張ナビゲーションメニュー で切り替えメニューを追加します。メニューの文言も同時に切り替えています。

json
{
 "TargetId": "SettingsMenu",
 "Action": "Append",
 "NavigationMenus": [
  {
   "ContainerId": "SiteArchiveContainer",
   "MenuId": "SiteArchiveMenu",
   "Name": "アーカイブ",
   "Icon": "ui-icon ui-icon-gear",
   "ChildMenus": [
    {
     "MenuId": "SiteArchive_ArchiveToggle",
     "Name": "アーカイブ表示",
     "Icon": "ui-icon ui-icon-arrowrefresh-1-w",
     "Url": "javascript:$('.nav-site:not(.to-parent)').toggle();$('#SiteArchive_ArchiveToggle a').text($('#SiteArchive_ArchiveToggle a').text() === 'アーカイブ表示' ? '通常表示' : 'アーカイブ表示');",
     "ReferenceTypes": ["Sites"],
     "Actions": ["index"]
    }
   ]
  }
 ]
}

TIP

非表示のスタイルを当てるときに、アーカイブ対象のサイトの背景色も変えておくと、アーカイブ表示に切り替えたときに見分けやすくなります。

サイト構成の一覧を取得する ​

Sites テーブルから、サイトの一覧を階層付きで取得するクエリです。再帰 CTE でタイトルを 親 > 子 > 孫 の形に連結しながら取り出します。

INFO

SQL Server の NVARCHAR(長さ指定なしの CAST は 30 文字)では切り詰められ、直前の親のタイトルだけを連結しても階層全体にならないため、NVARCHAR(4000) と親の FullName を使っています。PostgreSQL は text、MySQL は CHAR(4000) に変換します。PostgreSQL と MySQL では WITH RECURSIVE を使います(PostgreSQL、MySQL)。MySQL の例は 8.0 以降を対象とし、階層全体のタイトルが 4,000 文字に収まる前提です。

sql
WITH CTE AS (
    SELECT
        [SiteId],
        [ReferenceType],
        [Title],
        [ParentId],
        CAST([Title] AS NVARCHAR(4000))                       AS [FullName]
    FROM
        [Sites]
    WHERE
        [ParentId] = 0
    UNION ALL
    SELECT
        C.[SiteId],
        C.[ReferenceType],
        C.[Title],
        C.[ParentId],
        CAST((P.[FullName] + ' > ' + C.[Title]) AS NVARCHAR(4000)) AS [FullName]
    FROM
        [Sites] C
        INNER JOIN CTE P
            ON P.[SiteId] = C.[ParentId]
)
SELECT
    [SiteId],
    [ReferenceType],
    [FullName],
    [ParentId]
FROM
    CTE
ORDER BY
    [ParentId],
    [SiteId]
sql
WITH RECURSIVE CTE AS (
    SELECT
        "SiteId",
        "ReferenceType",
        "Title",
        "ParentId",
        CAST("Title" AS text)                       AS "FullName"
    FROM
        "Sites"
    WHERE
        "ParentId" = 0
    UNION ALL
    SELECT
        C."SiteId",
        C."ReferenceType",
        C."Title",
        C."ParentId",
        CAST((P."FullName" || ' > ' || C."Title") AS text) AS "FullName"
    FROM
        "Sites" C
        INNER JOIN CTE P
            ON P."SiteId" = C."ParentId"
)
SELECT
    "SiteId",
    "ReferenceType",
    "FullName",
    "ParentId"
FROM
    CTE
ORDER BY
    "ParentId",
    "SiteId"
sql
WITH RECURSIVE CTE AS (
    SELECT
        `SiteId`,
        `ReferenceType`,
        `Title`,
        `ParentId`,
        CAST(`Title` AS CHAR(4000))                       AS `FullName`
    FROM
        `Sites`
    WHERE
        `ParentId` = 0
    UNION ALL
    SELECT
        C.`SiteId`,
        C.`ReferenceType`,
        C.`Title`,
        C.`ParentId`,
        CAST(CONCAT(P.`FullName`, ' > ', C.`Title`) AS CHAR(4000)) AS `FullName`
    FROM
        `Sites` C
        INNER JOIN CTE P
            ON P.`SiteId` = C.`ParentId`
)
SELECT
    `SiteId`,
    `ReferenceType`,
    `FullName`,
    `ParentId`
FROM
    CTE
ORDER BY
    `ParentId`,
    `SiteId`

実行結果の例です。

SiteIdReferenceTypeFullNameParentId
3457307Sites[Sandbox]社内用0
3526345Results[Sandbox]社内用 > 記録テーブル(子テーブル)3457307
3526346Issues[Sandbox]社内用 > 期限付きテーブル(親テーブル)3457307
3578784Results[Sandbox]社内用 > ユーザ複数選択テスト3457307

拡張 SQL で API 化する ​

拡張 SQL の API 化 を使うと、この一覧を API で取得できます。定義ファイルと SQL ファイルを分けて配置します(SQL の中身は上のクエリと同じです)。

json
{
    "Name": "GetSiteList",
    "Api": true,
    "CommandText": "-- Write an arbitrary SQL statement."
}

使用中の DBMS の上記クエリ全文を GetSiteList.json.sql に保存します。

パンくずリストやサイトツリーなど、階層を持ったメニューを作るときに便利です。

関連ページ ​

変更履歴

第5版サイト階層の取得 SQL を3種類のDBMSに対応
第4版本文から元記事や以前の版への言及を除き、正しい動作だけを書く形に整理
第3版「機能の仕様と使いこなし」を 1.5.8.1 のソースで検証して修正
第2版記事のファイル名に並び順の番号を付け、元記事リンクを frontmatter の sources に移行
第1版「機能の仕様と使いこなし」セクションの記事を追加