自分好みなin_place_editor(on super_inplace_control)を目指して

ツリー操作のサンプルの中で、in_place_editorを弄っていると、だんだん些細なことが気になってきた。

  1. ハイライト中にマウスオーバーしてさらにハイライト処理が実行されると、背景色が変化途中の黄色で終わってしまう...。
  2. テキスト編集する時に、フォームの後ろで改行されてしまう。常に1行で表示させたい。
  3. テキスト編集後のハイライトが、黄色→白→黒と変化するのが見苦しい。黄色→黒で変化して欲しい。
  4. テキスト保存時のプログレスイージケーターが、一瞬だけど、改行されてしまうのが見苦しい。

以下、自分好みを実現しようとして、理解できたこといろいろメモ。

in_place_editor_fieldが生成する基本のerb

  • super_inplace_controlの機能はRailsのヘルパメソッドを組み合わせて実現されていることに気付いた。(script.aculo.usAjax.InPlaceEditorには頼らずに)
  • 多少は使い慣れているRubyコードで書かれていると、(自分にとっては)生javascriptを読むより遥かに理解し易い。
  • in_place_editor_field(:tree, :name) で生成されるコードは、- 仮にTreeモデルで、:idが100、:nameが’root’のin_placeなアイテムなら - 以下のerbで表現される。

      • rootをクリックして編集モードへ


<%= content_tag(:span, 'root', 
                :onclick => update_page do |page|
                  page.hide "tree_name_100"
                  page.show "tree_name_100_form"
                end, 
                :onmouseover => visual_effect(:highlight, 'tree_name_100'), 
                :title => "Click to Edit", 
                :id => "tree_name_100" ,
                :class => "inplace_span" ) %>

<%= form_remote_tag(:url => { :action => 'set_tree_name_100', :id => 1 },
                    :method => :post,
                    :loading => update_page do |page|
                      page.show "loader_tree_name_100"
                      page.hide "tree_name_100_form"
                    end,
                    :complete => update_page do |page|
                      page.hide "loader_tree_name_100"
                    end,
                    :html => {:class => "in_place_editor_form", :id => "tree_name_100_form", :style => "display:none" } ) %>

  <%= text_field(:tree, :name) %>
  <%= submit_tag('OK', :class => "inplace_submit") %>
  <%= link_to_function("Cancel", 
                       update_page do |page|
                         page.show "tree_name_100"
                         page.hide "tree_name_100_form"
                       end, 
                       {:class => "inplace_cancel" } ) %>

</form>

<% content_tag(:div, :id => 'loader_tree_name_100', :class => 'inplace_loader', :style => "display:none") do %>
  <%= image_tag("spinner.gif") + "&nbsp;&nbsp;" + content_tag(:span, 'Saving...') %>
<% end %>
  • 試しに上記コードをコピーして、ビューに貼付けてみると、in_placeな動作が確認できた。
  • super_inplace_controlのコードの方は、様々なオプション設定に対応するためもう少し複雑だが...
  • 基本の雛形が理解できれば、あとは見慣れたerbなので、いくらでも自由にカスタマイズできそう。

super_inplace_controls.rbの修正

  • 課題:1. ハイライト中にマウスオーバーしてさらにハイライト処理が実行されると、背景色が変化途中の黄色で終わってしまう...。
    • ハイライト変化途中の黄色が、endcolor、restorecolorとして記憶されてしまうことが原因のようだ。
    • super_inplace_controls.rbから、修正したいメソッドだけ選択して、application_helper.rbにコピーした。
    • ハイライトのendcolor、restorecolorをオプション指定できるようにコードを修正した。(オレンジ色の部分が修正箇所)
  • 課題:2. テキスト編集する時に、フォームの後ろで改行されてしまう。常に1行で表示させたい。
    • 不要な改行コードを生成している行をコメントアウト。(retval << content_tag(:br)の部分)
# ---------- app/helpers/application_helper.rb ----------
module ApplicationHelper
...(中略)...
end
...(中略)...
module Flvorful  
  module SuperInplaceControls
    module HelperMethods
      protected  
      def in_place_field(field_type, object, method, options)
        object_name = object.to_s
        method_name = method.to_s
        @object = self.instance_variable_get("@#{object}") || options[:object] 
        display_text = set_display_text(@object, method_name, options)
        ret =  html_for_inplace_display(object_name, method_name, @object, display_text, options)
        ret << form_for_inplace_display(object_name, method_name, field_type, @object, options)
      end
      
      def html_for_inplace_display(object_name, method_name, object, display_text, opts)
        options = {}
        options.merge!(:startcolor => opts.delete(:startcolor)) if opts[:startcolor]
        options.merge!(:endcolor => opts.delete(:endcolor)) if opts[:endcolor]
        options.merge!(:restorecolor => opts.delete(:restorecolor)) if opts[:restorecolor]
        
        id_string = id_string_for(object_name, method_name, object)
        content_tag(:span, display_text, 
                    :onclick => update_page do |page|
                      page.hide "#{id_string}"
                      page.show "#{id_string }_form"
                    end, 
                    :onmouseover => visual_effect(:highlight, id_string, options), 
                    :title => "Click to Edit", 
                    :id => id_string ,
                    :class => "inplace_span #{"empty_inplace" if display_text.blank?}" 
                    )
      end

      def form_for_inplace_display(object_name, method_name, input_type, object, opts)
        retval = ""
        id_string = id_string_for(object_name, method_name, object)
        set_method = opts[:action] || "set_#{object_name}_#{method_name}"
        save_button_text = opts[:save_button_text] || "OK"
        loader_message = opts[:saving_text] || "Saving..."
        retval << form_remote_tag(:url => { :action => set_method, :id => object.id },
        :method => opts[:http_method] || :post,
        :loading => update_page do |page|
          page.show "loader_#{id_string}"
          page.hide "#{id_string}_form"
        end,
        :complete => update_page do |page|
          page.hide "loader_#{id_string}"
        end,
        :html => {:class => "in_place_editor_form", :id => "#{id_string}_form", :style => "display:none" } )

        retval << field_for_inplace_editing(object_name, method_name, object, opts, input_type )
        retval << content_tag(:br) if opts[:br]
        retval << submit_tag( save_button_text, :class => "inplace_submit")
        retval << link_to_function( "Cancel", update_page do |page|
          page.show "#{id_string}"
          page.hide "#{id_string}_form"
        end, {:class => "inplace_cancel" })
        retval << ""
        retval << invisible_loader( loader_message, "loader_#{id_string}", "inplace_loader")
        #retval << content_tag(:br)
      end
    end
  end
end

in_place_edit_forのオプション指定

  • 課題:3. テキスト編集後のハイライトが、黄色→白→黒と変化するのが見苦しい。黄色→黒で変化して欲しい。
    • in_place_edit_forのオプション指定で対応できた。
class TreesController < ApplicationController
  in_place_edit_for :tree, :name, :highlight_endcolor => "#444444"
...(中略)...

cssの設定

  • 課題:2. テキスト編集する時に、フォームの後ろで改行されてしまう。常に1行で表示させたい。
  • 課題:4. テキスト保存時のプログレスイージケーターが、一瞬だけど、改行されてしまうのが見苦しい。
    • テキスト編集時のフォームをすべてinlineに。
    • プログレスイージケーターもinlineに。
div.inplace_loader,
form.in_place_editor_form,
form.in_place_editor_form * {
    display: inline;
}

所感

  • super_inplace_controlはテキスト以外にも、チェックボックスラジオボタン、セレクトリスト、カレンダー等も利用できて、名前の通りホントにsuper。
  • in_place_editorは派手なGUIで毎回興味をそそられるのだが、実は最初からフォームを表示しておいて、Ajaxな更新をするだけでも十分なのではないか...。
  • そう思ったら、最初の「in_place_editor_fieldが生成する基本のerb」を雛形に、自分でヘルパメソッドを定義すれば良いのかもしれない。