/
tag.rb
184 lines (143 loc) · 3.86 KB
/
tag.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
require 'erb'
module Arbre
module HTML
class Tag < Element
attr_reader :attributes
def initialize(*)
super
@attributes = Attributes.new
end
def build(*args)
super
attributes = extract_arguments(args)
self.content = args.first if args.first
set_for_attribute(attributes.delete(:for))
attributes.each do |key, value|
set_attribute(key, value)
end
end
def extract_arguments(args)
if args.last.is_a?(Hash)
args.pop
else
{}
end
end
def set_attribute(name, value)
@attributes[name.to_sym] = value
end
def get_attribute(name)
@attributes[name.to_sym]
end
alias :attr :get_attribute
def has_attribute?(name)
@attributes.has_key?(name.to_sym)
end
def remove_attribute(name)
@attributes.delete(name.to_sym)
end
def id
get_attribute(:id)
end
# Generates and id for the object if it doesn't exist already
def id!
return id if id
self.id = object_id.to_s
id
end
def id=(id)
set_attribute(:id, id)
end
def add_class(class_names)
class_list.add class_names
end
def remove_class(class_names)
class_list.delete(class_names)
end
# Returns a string of classes
def class_names
class_list.to_s
end
def class_list
list = get_attribute(:class)
case list
when ClassList
list
when String
set_attribute(:class, ClassList.build_from_string(list))
else
set_attribute(:class, ClassList.new)
end
end
def to_s
indent(opening_tag, content, closing_tag).html_safe
end
private
def opening_tag
"<#{tag_name}#{attributes_html}>"
end
def closing_tag
"</#{tag_name}>"
end
INDENT_SIZE = 2
def indent(open_tag, child_content, close_tag)
spaces = ' ' * indent_level * INDENT_SIZE
html = ""
if no_child? || child_is_text?
if self_closing_tag?
html << spaces << open_tag.sub( />$/, '/>' )
else
# one line
html << spaces << open_tag << child_content << close_tag
end
else
# multiple lines
html << spaces << open_tag << "\n"
html << child_content # the child takes care of its own spaces
html << spaces << close_tag
end
html << "\n"
html
end
def self_closing_tag?
%w|meta link|.include?(tag_name)
end
def no_child?
children.empty?
end
def child_is_text?
children.size == 1 && children.first.is_a?(TextNode)
end
def attributes_html
attributes.any? ? " " + attributes.to_s : nil
end
def set_for_attribute(record)
return unless record
# set_attribute :id, ActionController::RecordIdentifier.dom_id(record, default_id_for_prefix)
# add_class ActionController::RecordIdentifier.dom_class(record)
set_attribute :id, dom_id_for(record)
add_class dom_class_name_for(record)
end
def dom_class_name_for(record)
if record.class.respond_to?(:model_name)
record.class.model_name.singular
else
record.class.name.underscore.gsub("/", "_")
end
end
def dom_id_for(record)
id = if record.respond_to?(:to_key)
record.to_key
elsif record.respond_to?(:id)
record.id
else
record.object_id
end
[default_id_for_prefix, dom_class_name_for(record), id].compact.join("_")
end
def default_id_for_prefix
nil
end
end
end
end