-
-
Notifications
You must be signed in to change notification settings - Fork 74
/
element.rb
186 lines (150 loc) · 3.81 KB
/
element.rb
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
require 'arbre/element/builder_methods'
require 'arbre/element_collection'
module Arbre
class Element
include BuilderMethods
attr_accessor :parent
attr_reader :children, :arbre_context
def initialize(arbre_context = Arbre::Context.new)
@arbre_context = arbre_context
@children = ElementCollection.new
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
# 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_tag_name(tag_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
ElementCollection.new([self]) + element
end
def to_ary
ElementCollection.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
#
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