Module: JquerySortableTreeHelper

Defined in:
app/helpers/jquery_sortable_tree_helper/render_tree_helper.rb,
app/helpers/jquery_sortable_tree_helper.rb,
app/helpers/jquery_sortable_tree_helper/render_optgroup_helper.rb,
app/helpers/jquery_sortable_tree_helper/render_sortable_tree_helper.rb,
app/helpers/jquery_sortable_tree_helper/render_nested_options_helper.rb,
app/helpers/jquery_sortable_tree_helper/render_expandable_tree_helper.rb,
app/helpers/jquery_sortable_tree_helper/render_indented_options_helper.rb

Overview

SECURITY note Prepare your data on server side for rendering or use h.html_escape(node.content) for escape potentially dangerous content

Defined Under Namespace

Modules: RenderExpandableTreeHelper, RenderIndentedOptionsHelper, RenderNestedOptionsHelper, RenderOptgroupHelper, RenderSortableTreeHelper, RenderTreeHelper

Constant Summary collapse

TREE_RENDERERS =

Ilya Zykin, [email protected], Russia [Ivanovo, Saint Petersburg] 2009-2014 github.com/the-teacher

{
  tree: RenderTreeHelper,
  sortable: RenderSortableTreeHelper,
  expandable: RenderExpandableTreeHelper,
  nested_options: RenderNestedOptionsHelper,
  indented_options: RenderIndentedOptionsHelper,
  optgroup: RenderOptgroupHelper
}.freeze

Instance Method Summary collapse

Instance Method Details

#add_new_node_form(options) ⇒ Object



76
77
78
79
80
81
82
83
84
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 76

def add_new_node_form(options)
  capture do
    form_for(options[:model].to_sym, form_for_options(options)) do |f|
      title_field = f.text_field options[:title].to_sym, required: true, class: 'form-control', placeholder: I18n.t('sortable_tree.title_of_new_node', default: "The #{options[:title]} of new #{options[:model]}")
      concat (:div, title_field, class: 'form-group')
      concat f.hidden_field :parent_id, value: options[:parent_id]
    end
  end
end

#base_dataObject



37
38
39
40
41
42
43
44
45
46
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 37

def base_data
  {
    model: params[:controller].singularize,
    title: 'title',
    max_levels: 5,
    parent_id: params[:parent_id],
    rebuild_url: send("rebuild_#{params[:controller]}_url"),
    url: url_for(controller: params[:controller], action: :show, id: ':id', format: :json)
  }
end

#base_optionsObject

Server Side Render Tree Helper



106
107
108
109
110
111
112
113
114
115
116
117
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 106

def base_options
  {
    id: :id,
    title: :title,
    node: nil,
    type: :tree,
    root: false,
    level: 0,
    namespace: [],
    controller: params[:controller]
  }
end

#build_children(tree, opts) ⇒ Object



119
120
121
122
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 119

def build_children(tree, opts)
  children = (opts[:boost][opts[:node].id.to_i] || [])
  children.reduce('') { |r, elem| r + build_server_tree(tree, opts.merge(node: elem, root: false, level: opts[:level].next)) }
end

#build_server_tree(tree, options = {}) ⇒ Object



138
139
140
141
142
143
144
145
146
147
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 138

def build_server_tree(tree, options = {})
  tree = [*tree]
  opts = merge_base_options(tree, options)

  if opts[:node]
    raw build_tree_html(self, opts[:render_module], opts.merge(children: build_children(tree, opts)))
  else
    raw (roots(tree) || []).reduce('') { |r, root| r + build_server_tree(tree, opts.merge(node: root, root: true, level: opts[:level].next)) }
  end
end

#build_tree_html(context, render_module, options = {}) ⇒ Object



25
26
27
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 25

def build_tree_html context, render_module, options = {}
  render_module::Render.new(context, options).render_node
end

#define_class_of_elements_of(tree) ⇒ Object

Common Base Methods



17
18
19
20
21
22
23
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 17

def define_class_of_elements_of tree
  case
    when tree.is_a?(ActiveRecord::Relation) then tree.name.to_s.underscore.downcase
    when tree.empty?                        then nil
    else tree.first.class.to_s.underscore.downcase
  end
end

#expandable_tree(tree, options = {}) ⇒ Object



94
95
96
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 94

def expandable_tree(tree, options = {})
  build_server_tree(tree, { type: :expandable }.merge(options))
end

#fake_node(options) ⇒ Object



52
53
54
55
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 52

def fake_node(options)
  options[:title] ||= 'title'
  OpenStruct.new(options[:title] => '', id: ':id', children: nil)
end

#form_for_options(options) ⇒ Object



67
68
69
70
71
72
73
74
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 67

def form_for_options(options)
  {
    html: { id: "new-#{options[:model]}-form" },
    url: send("#{options[:model].pluralize}_path", format: :json),
    method: :post,
    remote: true
  }
end

#indented_options(tree, options = {}) ⇒ Object



90
91
92
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 90

def indented_options(tree, options = {})
  build_server_tree(tree, { type: :indented_options }.merge(options))
end

#just_tree(tree, options = {}) ⇒ Object

Shortcuts



33
34
35
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 33

def just_tree(tree, options = {})
  build_server_tree(tree, { type: :tree }.merge!(options))
end

#merge_base_options(tree, options) ⇒ Object



129
130
131
132
133
134
135
136
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 129

def merge_base_options(tree, options)
  opts = base_options.merge(options)
  opts[:namespace] = [*opts[:namespace]]
  opts[:render_module] ||= TREE_RENDERERS[opts[:type]]
  opts[:klass] ||= define_class_of_elements_of(tree)
  opts[:boost] ||= tree.group_by { |item| item.parent_id.to_i }
  opts
end

#nested_options(tree, options = {}) ⇒ Object



86
87
88
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 86

def nested_options(tree, options = {})
  build_server_tree(tree, { type: :nested_options }.merge(options))
end

#optgroup(tree, options = {}) ⇒ Object



98
99
100
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 98

def optgroup(tree, options = {})
  build_server_tree(tree, { type: :optgroup }.merge(options))
end

#roots(tree) ⇒ Object



124
125
126
127
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 124

def roots(tree)
  min_parent_id = tree.map(&:parent_id).compact.min
  tree.select { |e| e.parent_id == min_parent_id }
end

#sortable_tree(tree, options = {}) ⇒ Object



57
58
59
60
61
62
63
64
65
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 57

def sortable_tree(tree, options = {})
  space(20) +
  add_new_node_form(base_data.merge(options)) +
  (:ol, build_tree_html(self, TREE_RENDERERS[:sortable], base_options.merge(options).merge({ node: fake_node(options) })), class: 'fake-node hidden', style: 'display: none;') +
  (:ol, build_server_tree(tree, { type: :sortable }.merge!(options)),
              class: 'sortable_tree',
              data: base_data.merge(options.slice(:parent_id, :model, :rebuild_url, :title, :max_levels))
  )
end

#space(height) ⇒ Object



48
49
50
# File 'app/helpers/jquery_sortable_tree_helper.rb', line 48

def space(height)
  (:div, ' '.html_safe, style: "height: #{height}px;")
end