SearchUI
シラサギでは以下のようなオブジェクト選択UIがあります。
- モーダルを展開しオブジェクトを選択可能
- 複数選択、単数選択にカスタマイズ可能
- モーダル内で検索可能
本ドキュメントでは Cms::Page の選択UIを構成する要素について説明します。
動作は管理画面の関連ページアドオンにて確認できます。

関連ページ選択の動作
- 選択リンクをクリック
- モーダルが展開される
- モーダル画面でページ名をクリック
- 元画面のHTMLに選択要素を追加しモーダルを閉じる
以下、各構成要素について記載します。
@SS_SearchUI
app/assets/javascripts/ss/lib/search_ui.coffee.erb
選択UIのJavaScriptです。
次の箇所で実行しています。
- モーダルの呼び出し側
- モーダル展開後のオブジェクト選択
class @SS_SearchUI
@anchorAjaxBox
@select: (item) ->
...
@selectItems: ->
...
@deselect: (e)->
...
@toggleSelectButton: ()->
...
@render: ()->
...
@modal: (options = {})->
...
@anchorAjaxBox- モーダル展開元リンクを保持しておく変数です。
@select- オブジェクトを単一選択する際に実行する関数です。
- モーダル内部でページの名前をクリックした際に実行されます。
@selectItems- オブジェクトを複数選択する際に実行する関数です。
@deselect- 選択状態を外す際に実行する関数です。
- ページ選択後の削除リンクに該当します。
@render- モーダルを呼び出す側の
viewでスクリプトを初期設定します。 ss/script.coffee.erbで呼び出しています。.ajax-selected(テーブル)要素に対して選択した項目を追加します。
- モーダルを呼び出す側の
@modal- モーダル内部の選択
viewでスクリプトを初期設定します。
- モーダル内部の選択
モーダル呼び出し側 view
app/views/cms/agents/addons/related_page/_form.html.erb
選択モーダルを呼び出す側のviewです。
アドオンの関連ページ選択部分になります。
<dl class="see mod-cms-related_pages">
<dt><%= @model.t :related_pages %><%= @model.tt :page_ids %></dt>
<dd>
<%= f.hidden_field "related_page_ids[]", value: "", class: "hidden-ids" %>
<%= link_to t("cms.apis.pages.index"), cms_apis_pages_path, class: "ajax-box" %>
</dd>
<dd>
<table class="index ajax-selected">
<thead>
<tr>
<th class="name"><%= @model.t :name %></th>
<th></th>
</tr>
</thead>
<tbody>
<% @item.related_pages.each do |page| %>
<tr data-id="<%= page.id %>">
<td><%= f.hidden_field "related_page_ids[]", value: page.id %> <%= page.name %></td>
<td><%= link_to t("views.button.delete"), "#", class: "deselect btn" %></td>
</tr>
<% end %>
<tr style="display:none" <%= raw(@item.present? ? "data-id=#{@item.id}" : "") %>></tr>
</tbody>
</table>
</dd>
</dl>
<%= f.hidden_field "related_page_ids[]", value: "", class: "hidden-ids" %>related_page_ids[]が保存すべき属性(input の name 属性) に対応します。class="hidden-ids"を付与し、@SS_SearchUIから取得できるようにしています。
<%= link_to t("cms.apis.pages.index"), cms_apis_pages_path, class: "ajax-box" %>- モーダル展開側コントローラへのリンクを設置しています。
- リンクに
class="ajax-box"を付けることで、モーダル展開となります。 - このリンクをクリックすることでオブジェクト(
Cms::Page)を選択するモーダルが出現します。
<table class="index ajax-selected">- 選択した要素が挿入されるテーブルになります。
class="ajax-selected"を付与し@SS_SearchUIから参照しています。- すでに保存済みの要素は
<% @item.related_pages.each do |page| %> ... <% end %>のブロックで展開しています。
<tr data-id="<%= page.id %>"> ... </tr>- 選択された要素に対応します。
- 選択対象のIDを
data-id属性として@SS_SearchUIで使用しています。
モーダル展開側 controller
app/controllers/concerns/cms/api_filter.rb
app/controllers/apis/pages_controller
モーダル展開側のコントローラとモジュールです。
Apisを含む命名規則としています。
module Cms::ApiFilter
extend ActiveSupport::Concern
include Cms::BaseFilter
include SS::CrudFilter
include SS::AjaxFilter
def index
@single = params[:single].present?
@multi = !@single
@items = @model.site(@cur_site).
search(params[:s]).
order_by(_id: -1).
page(params[:page]).per(50)
end
end
class Cms::Apis::PagesController < ApplicationController
include Cms::ApiFilter
model Cms::Page
def routes
@items = @model.routes
end
end
model- 選択対象となるオブジェクトの
classを設定しています。
- 選択対象となるオブジェクトの
@single- 単数選択時のオプションです。
@singleに値を入れていなければ複数選択となる想定です。- 現状、
apiによってサポートしている箇所、していない箇所があります。- 関連ページは現状複数選択のみなので未対応です。
- 拡張する場合は
viewに@singleのhidden_fieldを追加します。
#routesCms::Pageのroute属性一覧を返すアクションです。- 関連ページの選択には利用していません。
モーダル展開側 view
app/views/cms/apis/pages/index.html.erb
モーダル展開側(モーダル内部)のviewです。
<%= jquery do %> SS_SearchUI.modal(); <% end %>
<div class="search-ui-form">
<%= form_for :s, url: { action: :index }, html: { method: "GET", class: :search } do |f| %>
<%= f.text_field :name, value: params[:s].try(:[], :name) %>
<%= f.submit t("cms.apis.pages.search"), class: :btn %>
<% end %>
</div>
<table class="index">
<thead class="list-head">
<tr>
<th class="checkbox"><input type="checkbox" /></th>
<th class="name"><%= @model.t :name %></th>
<th class="filename"><%= @model.t :filename %></th>
<th class="updated"><%= @model.t :updated %></th>
</tr>
</thead>
<tbody class="items">
<% @items.each do |item| %>
<tr data-id="<%= item.id %>" class="list-item">
<td class="checkbox">
<input type="checkbox" name="ids[]" value="<%= item.id %>" />
</td>
<td class="name"><%= link_to item.name, "#", class: "select-item" %></td>
<td class="filename"><%= item.filename %></td>
<td class="updated"><%= item.updated.strftime("%Y/%m/%d %H:%M") %></td>
</tr>
<% end %>
</tbody>
</table>
<div class="search-ui-select">
<%= button_tag t("cms.apis.pages.select"), { type: :button, class: "select-items btn" } %>
</div>
<%= paginate @items if @items.try(:current_page) %>
<%= jquery do %> SS_SearchUI.modal(); <% end %>- モーダルの中では
@modalを呼び出して、以下のイベントをハンドルします。- 単数選択のクリックイベント
- 複数選択のクリックイベント
- 検索とフォームのサブミットイベント
- ページネーションのクリックイベント
- また、ページネーションに対応する為、既に選択されている項目はグレーアウトされます。
- モーダルの中では
<tr data-id="<%= item.id %>" class="list-item"> ... </tr>- 選択対象の要素です。
- 選択時、この要素の
data-id属性とtrタグをモーダル呼び出し側のviewにappendします。
<%= link_to item.name, "#", class: "select-item" %>- 単数選択のリンクです。
class="select-item"を付与しイベントをハンドルしています。
<%= button_tag t("cms.apis.pages.select"), { type: :button, class: "select-items btn" } %>- 複数選択のボタンです。
class="select-items"を付与しイベントをハンドルしています。
モーダル展開側 routes
config/routes/cms/routes_end.rb
モーダル展開側のコントローラにもルーティングが必要です。
以下に記述されています。
namespace "cms", path: ".s:site/cms" do
...
namespace "apis" do
...
get "pages" => "pages#index"
...
end
...
end