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 get_attribute(:class) || set_attribute(:class, ClassList.new) 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 "" 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.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