Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
rear / lib / rear / column.rb
Size: Mime:
class RearInput
  include RearConstants
  include RearUtils
  
  attr_reader :name, :string_name, :type
  attr_reader :dom_id, :css_class

  def initialize name, type = COLUMNS__DEFAULT_TYPE, attrs = {}, brand_new_item = nil, &proc
    @name, @string_name, @type = name, name.to_s, type
    @brand_new_item = brand_new_item
    @dom_id = ['Rear', 'Input', 'DOMIDFor', @string_name.capitalize.gsub(/\W/, ''), __id__].join
    @css_class = 'CSSClassFor' << @dom_id

    @pane_template = pane_template @type
    @pane_value    = proc do
      val = item[column.name]
      if val.is_a?(String)
        val.size > COLUMNS__PANE_MAX_LENGTH ?
          val[0..COLUMNS__PANE_MAX_LENGTH] + ' ...' : val
      else
        val
      end
    end

    @editor_template = editor_template @type
    @editor_value    = proc { item[column.name] }

    @active_options  = proc { item[column.name] }

    @html_attrs = Hash[[:*, :pane, :editor].map {|s| [s, {}]}]
    html_attrs(attrs)
    self.instance_exec(&proc) if proc
  end

  def name?
    return if disabled?
    return if readonly?
    multiple? || checkbox? ? '%s[]' % name : name.to_s
  end

  def label label = nil
    @label = label if label
    @label
  end

  def row row = nil
    @row = row.to_s if row
    @row 
  end

  def row?
    @row
  end

  def tab tab = nil
    @tab = tab.to_s if tab
    @tab 
  end

  def tab?
    @tab
  end

  # set HTML attributes to be used on current column on both pane and editor pages
  # @note will override any attrs set globally via `html_attrs` at class level
  def html_attrs attrs = {}
    set_html_attrs(attrs) if attrs.any?
    @html_attrs[:*] || {}
  end
  alias attrs html_attrs

  # set HTML attributes to be used on current column on pane pages
  # @note will override any attrs set globally via `pane_attrs` or `html_attrs` at class level
  def pane_attrs attrs = {}
    set_html_attrs(attrs, :pane) if attrs.any?
    pane_attrs? || html_attrs
  end

  def pane_attrs?
    (a = @html_attrs[:pane]) && a.any? && a
  end

  # set HTML attributes to be used on current column on editor pages
  # @note will override any attrs set globally via `editor_attrs` or `html_attrs` at class level
  def editor_attrs attrs = {}
    set_html_attrs(attrs, :editor) if attrs.any?
    editor_attrs? || html_attrs
  end

  def editor_attrs?
    (a = @html_attrs[:editor]) && a.any? && a
  end

  def pane_template template = nil, &proc
    caller.each {|l| puts l} if template == :integer
    if template
      @pane_template = 'pane/%s.slim' % template
    elsif template == false
      @pane_template = nil
    end
    @pane_template = proc if proc
    @pane_template
  end
  alias pane pane_template

  def pane_value &proc
    @pane_value = proc if proc
    @pane_value
  end

  def editor_template template = nil, &proc
    if template
      @editor_template = 'editor/%s.slim' % template
    elsif template == false
      @editor_template = nil
    end
    @editor_template = proc if proc
    @editor_template
  end
  alias editor editor_template

  def editor_value &proc
    @editor_value = proc if proc
    @editor_value
  end

  def value &proc
    pane_value   &proc
    editor_value &proc
  end

  def template *args, &proc
    pane_template *args, &proc
    editor_template *args, &proc
  end

  # required on :radio, :checkbox and :select columns.
  # options provided as Array or Hash
  # use an Array when keys are the same as values.
  # use a Hash when keys are different from values.
  # if block given it should return an Array of selected keys or a single key.
  # if block not given, no options will be selected.
  #
  # @example use an Array. will send 'Orange' to ORM
  #
  #   column :fruit, :select do
  #     options('Apple', 'Orange', 'Peach') { 'Orange' }
  #   end
  #
  #
  # @example use a Hash. will send '2' to ORM
  #   
  #    column :fruit, :select do
  #      options(1 => 'Apple', 2 => 'Orange', 3 => 'Peach') { 2 }
  #    end
  #
  # @note when using :checkbox type or :select type with :multiple option,
  #       Espresso will send an Array of keys to your ORM.
  #       usually ORM will handle received array automatically,
  #       however, if you want to send a string rather than array,
  #       use `before` callback to coerce the array into string.
  #
  # @example  this example will send ['Orange', 'Peach'] Array
  #           which will be caught by `before :save` callback
  #           and coerced into string
  #
  #    before :save do
  #      params[:fruit] = params[:fruit].join(',')
  #    end
  #    column :fruit, :select, :multiple => true do
  #      options('Apple', 'Orange', 'Peach') { ['Orange', 'Peach'] }
  #    end
  #
  # @example will send ['2', '3'] Array to your ORM
  #   column :fruit, :checkbox do
  #     options(1 => 'Apple', 2 => 'Orange', 3 => 'Peach') { [2, 3] }
  #   end
  #
  def options *args, &proc
    return @options || {} if args.empty?
    @options = args.inject({}) do |f,c|
      c.is_a?(Hash) ? f.merge(c) : f.merge(c => c)
    end
    @active_options = proc if proc
  end

  def active_options
    @active_options
  end

  def optioned?
    select? || checkbox? || radio?
  end

  def pane?
    @pane_template
  end

  def editor?
    @editor_template
  end

  def readonly!
    @readonly = true
  end

  def readonly?
    return if @brand_new_item
    @readonly
  end

  def disable!
    @disabled = true
  end
  alias disabled! disable!

  def disabled?
    @disabled
  end

  def multiple!
    @multiple = true
  end

  def multiple?
    @multiple
  end

  def checkbox?
    type == :checkbox
  end

  def select?
    type == :select
  end

  def radio?
    type == :radio
  end

  def textual?
    type == :text || type == :rte
  end

  def boolean?
    type == :boolean
  end

  # when ordering by some column, "ORDER BY" will use only the selected column.
  # this column-specific setup allow to order returned items by multiple columns.
  #
  # # @example
  #   class News
  #     include DataMapper::Resource
  #
  #     property :id, Serial
  #     property :name, String
  #     property :date, Date
  #     property :status, Integer
  #   end
  #
  #   Rear.register News do
  #     column :date do
  #       order_by :date, :id
  #     end
  #   end
  #
  # this method are also useful when you need to sort items by a "decorative" column,
  # meant a column that does not exists in db but you need it on pane pages
  # to render more informative rows.
  # For ex. display category of each article when rendering articles
  #
  # # @example
  #   class Article
  #     include DataMapper::Resource
  #     # ...
  #
  #     belongs_to :category
  #   end
  #
  #   Rear.register do
  #     # defining a "decorative" column to display categories of each article
  #     column :Categories do
  #       pane { item.categories.map {|c| c.name}.join(', ') }
  #       # when Categories column clicked on pane page,
  #       # we want articles to be sorted by category id
  #       order_by :category_id
  #     end
  #   end
  #
  # @note do not pass ordering vector when setting costom `order_by` for columns.
  #       vector will be added automatically, so pass only column names.
  #       if vector passed, ordering will broke badly.
  #
  def order_by *columns
    @order_by = columns if columns.any?
    @order_by || [name]
  end

  def order_by?
    @order_by
  end

  # allow to define a list of snippets you need to insert into edited content.
  # relevant only on :ace / :ckeditor columns.
  def snippets *snippets, &proc
    snippets.any? && @snippets = snippets
    proc && @snippets = proc
    @snippets
  end

  # various opts for CKEditor
  #
  # @param [Hash] opts
  # @option opts :path
  #   physical path to folder containing images/videos to be picked up by file browser
  # @option opts :prefix
  #   file browser will build URL to file/video by extracting
  #   path(set via `:path` option) from full path to file.
  #   that's it, if path is "/foo/bar"
  #   and full path to file is "/foo/bar/baz/image.jpg",
  #   the URL used in browser will be  "/baz/image.jpg".
  #   `:prefix` option allow to define a string to be prepended to "/baz/image.jpg".
  # @option opts :lang
  #   localizing CKEditors
  def ckeditor opts = {}
    @ckeditor_opts = opts
  end
  def ckeditor_opts; @ckeditor_opts || {}; end

  private
  def set_html_attrs html_attrs, scope = :*
    html_attrs = Hash[@html_attrs[scope].merge(html_attrs)]

    html_attrs.each_key do |k|
      readonly! if k == :readonly
      disabled! if k == :disabled
      multiple! if k == :multiple
    end
    html_attrs.delete(:readonly) if @brand_new_item
    
    html_attrs.delete(:pane)   == false && pane(false)
    html_attrs.delete(:editor) == false && editor(false)

    unless @label = html_attrs.delete(:label)
      @label = name.to_s.gsub(/_/, ' ')
      @label.capitalize! unless name == :id
      @label << '?' if type == :boolean
    end
    @row = html_attrs.delete(:row)
    (tab = html_attrs.delete(:tab)) && (@tab = tab.to_s)
    
    @html_attrs[scope] = normalize_html_attrs(html_attrs)
  end

end