File: tag.rb

package info (click to toggle)
ruby-arbre 1.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid
  • size: 440 kB
  • sloc: ruby: 1,716; makefile: 7
file content (191 lines) | stat: -rw-r--r-- 4,360 bytes parent folder | download
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
191
# frozen_string_literal: true
require 'erb'

module Arbre
  module HTML

    class Tag < Element
      attr_reader :attributes

      # See: http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
      SELF_CLOSING_ELEMENTS = [ :area, :base, :br, :col, :embed, :hr, :img, :input, :keygen, :link,
                            :menuitem, :meta, :param, :source, :track, :wbr ]

      def initialize(*)
        super
        @attributes = Attributes.new
      end

      def build(*args)
        super
        attributes = extract_arguments(args)
        self.content = args.first if args.first

        for_value = attributes[:for]
        unless for_value.is_a?(String) || for_value.is_a?(Symbol)
          set_for_attribute(attributes.delete(:for))
        end

        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?
        SELF_CLOSING_ELEMENTS.include?(tag_name.to_sym)
      end

      def no_child?
        children.empty?
      end

      def child_is_text?
        children.size == 1 && children.first.is_a?(TextNode)
      end

      def attributes_html
        " #{attributes}" if attributes.any?
      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