1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
# frozen_string_literal: true
require 'arbre/element/builder_methods'
require 'arbre/element/proxy'
require 'arbre/element_collection'
require 'ruby2_keywords'
module Arbre
class Element
include BuilderMethods
attr_reader :parent
attr_reader :children, :arbre_context
def initialize(arbre_context = Arbre::Context.new)
@arbre_context = arbre_context
@children = ElementCollection.new
@parent = nil
end
def assigns
arbre_context.assigns
end
def helpers
arbre_context.helpers
end
def tag_name
@tag_name ||= self.class.name.demodulize.downcase
end
def build(*args, &block)
# Render the block passing ourselves in
append_return_block(block.call(self)) if block
end
def add_child(child)
return unless child
if child.is_a?(Array)
child.each{|item| add_child(item) }
return @children
end
# If its not an element, wrap it in a TextNode
unless child.is_a?(Element)
child = Arbre::HTML::TextNode.from_string(child)
end
if child.respond_to?(:parent)
# Remove the child
child.parent.remove_child(child) if child.parent && child.parent != self
# Set ourselves as the parent
child.parent = self
end
@children << child
end
def remove_child(child)
child.parent = nil if child.respond_to?(:parent=)
@children.delete(child)
end
def <<(child)
add_child(child)
end
def children?
@children.any?
end
def parent=(parent)
@parent = parent
end
def parent?
!@parent.nil?
end
def ancestors
if parent?
[parent] + parent.ancestors
else
[]
end
end
# TODO: Shouldn't grab whole tree
def find_first_ancestor(type)
ancestors.find{|a| a.is_a?(type) }
end
def content=(contents)
clear_children!
add_child(contents)
end
def get_elements_by_tag_name(tag_name)
elements = ElementCollection.new
children.each do |child|
elements << child if child.tag_name == tag_name
elements.concat(child.get_elements_by_tag_name(tag_name))
end
elements
end
alias_method :find_by_tag, :get_elements_by_tag_name
def get_elements_by_class_name(class_name)
elements = ElementCollection.new
children.each do |child|
elements << child if child.class_list.include?(class_name)
elements.concat(child.get_elements_by_class_name(class_name))
end
elements
end
alias_method :find_by_class, :get_elements_by_class_name
def content
children.to_s
end
def html_safe
to_s
end
def indent_level
parent? ? parent.indent_level + 1 : 0
end
def each(&block)
[to_s].each(&block)
end
def inspect
to_s
end
def to_str
to_s
end
def to_s
content
end
def +(element)
case element
when Element, ElementCollection
else
element = Arbre::HTML::TextNode.from_string(element)
end
to_ary + element
end
def to_ary
ElementCollection.new [Proxy.new(self)]
end
alias_method :to_a, :to_ary
private
# Resets the Elements children
def clear_children!
@children.clear
end
# Implements the method lookup chain. When you call a method that
# doesn't exist, we:
#
# 1. Try to call the method on the current DOM context
# 2. Return an assigned variable of the same name
# 3. Call the method on the helper object
# 4. Call super
#
ruby2_keywords def method_missing(name, *args, &block)
if current_arbre_element.respond_to?(name)
current_arbre_element.send name, *args, &block
elsif assigns && assigns.has_key?(name)
assigns[name]
elsif helpers.respond_to?(name)
helpers.send(name, *args, &block)
else
super
end
end
end
end
|