module ExpressTemplates
module Components
#
# Create an html table or ol (ordered list) for
# a model object representing a tree of similar objects.
#
# The objects must respond to :children.
#
# The block is passed a NodeBuilder which may accept field names.
#
# Example:
#
# ```ruby
# tree_for(:roles) do |role|
# role.name
# end
# ```
#
# If the view has an @roles variable with a Role having children,
# this will turn into markup such as the following:
#
#
# - SuperAdmin
#
# - Admin
#
# - Publisher
#
#
# - Auditor
#
#
#
#
#
#
class TreeFor < Container
def node_renderer
return (-> (node, renderer) {
ExpressTemplates::Indenter.for(:tree) do |ws, wsnl|
"#{wsnl}"+
_yield +
if node.children.any?
ExpressTemplates::Indenter.for(:tree) do |ws, wsnl|
"#{wsnl}" +
node.children.map do |child|
renderer.call(child, renderer)
end.join +
"#{wsnl}
"
end +
"#{wsnl}"
else
""
end
end
}).source.sub(/\W_yield\W/, compile_children.lstrip)
end
def compile
collection = _variablize(@options[:id])
member = @options[:id].to_s.singularize
return 'ExpressTemplates::Components::TreeFor.render_in(self) {
node_renderer = '+node_renderer.gsub(/node/, member)+'
ExpressTemplates::Indenter.for(:tree) do |ws, wsnl|
"#{ws}" +
'+collection+'.map do |'+member+'|
node_renderer.call('+member+', node_renderer)
end.join +
"#{wsnl}
\n"
end
}'
end
private
def _variablize(sym)
"@#{sym}"
end
end
end
end