require "erector/xml_widget" module Erector # A Widget is the center of the Erector universe. # # To create a widget, extend Erector::Widget and implement the +content+ # method. Inside this method you may call any of the tag methods like +span+ # or +p+ to emit HTML/XML tags. # # You can also define a widget on the fly by passing a block to +new+. This # block will get executed when the widget's +content+ method is called. See # the userguide for important details about the scope of this block when run -- # http://erector.rubyforge.org/userguide.html#blocks # # To render a widget from the outside, instantiate it and call its +to_html+ # method. # # A widget's +new+ method optionally accepts an options hash. Entries in # this hash are converted to instance variables. # # You can add runtime input checking via the +needs+ macro. See #needs. # This mechanism is meant to ameliorate development-time confusion about # exactly what parameters are supported by a given widget, avoiding # confusing runtime NilClass errors. # # To call one widget from another, inside the parent widget's +content+ # method, instantiate the child widget and call the +widget+ method. This # assures that the same output stream is used, which gives better # performance than using +capture+ or +to_html+. It also preserves the # indentation and helpers of the enclosing class. # # In this documentation we've tried to keep the distinction clear between # methods that *emit* text and those that *return* text. "Emit" means that # it writes to the output stream; "return" means that it returns a string # like a normal method and leaves it up to the caller to emit that string if # it wants. # # This class extends AbstractWidget and includes several modules, # so be sure to check all of those places for API documentation for the # various methods of Widget: # # * AbstractWidget # * Element # * Attributes # * Text # * Needs # * Caching # * Externals # * AfterInitialize # # * HTML # * Convenience # * JQuery # * Sass # # Also read the API Cheatsheet in the user guide # at http://erector.rubyforge.org/userguide#apicheatsheet class HTMLWidget < Erector::XMLWidget include Erector::HTML include Erector::Convenience include Erector::JQuery include Erector::Sass if Object.const_defined?(:Sass) tag 'area', :self_closing tag 'base', :self_closing tag 'br', :self_closing tag 'col', :self_closing tag 'embed', :self_closing tag 'frame', :self_closing tag 'hr', :self_closing tag 'img', :self_closing, :inline tag 'input', :self_closing, :inline tag 'link', :self_closing tag 'meta', :self_closing tag 'param', :self_closing tag 'a', :inline tag 'abbr' tag 'acronym' tag 'address' tag 'article' tag 'aside' tag 'audio' tag 'b', :inline tag 'bdo' tag 'big' tag 'blockquote' tag 'body' tag 'button', :inline tag 'canvas' tag 'caption' tag 'center' tag 'cite' tag 'code' tag 'colgroup' tag 'command' tag 'datalist' tag 'dd' tag 'del' tag 'details' tag 'dfn' tag 'dialog' tag 'div' tag 'dl' tag 'dt' tag 'em' tag 'fieldset' tag 'figure' tag 'footer' tag 'form' tag 'frameset' tag 'h1' tag 'h2' tag 'h3' tag 'h4' tag 'h5' tag 'h6' tag 'head' tag 'header' tag 'hgroup' tag 'html' tag 'i', :inline tag 'iframe' tag 'ins' tag 'keygen' tag 'kbd' tag 'label' tag 'legend' tag 'li' tag 'map' tag 'mark' tag 'meter' tag 'nav' tag 'noframes' tag 'noscript' tag 'object' tag 'ol' tag 'optgroup' tag 'option' tag 'p' tag 'pre' tag 'progress' tag 'q' tag 'ruby' tag 'rt' tag 'rp' tag 's' tag 'samp' tag 'script' tag 'section' tag 'select', :inline tag 'small', :inline tag 'source' tag 'span', :inline tag 'strike' tag 'strong' tag 'style' tag 'sub' tag 'sup' tag 'table' tag 'tbody' tag 'td' tag 'textarea', :inline tag 'tfoot' tag 'th' tag 'thead' tag 'time' tag 'title' tag 'tr' tag 'tt' tag 'u' tag 'ul' tag 'var' tag 'video' # Emits a javascript block inside a +script+ tag, wrapped in CDATA # doohickeys like all the cool JS kids do. def javascript(value = nil, attributes = {}) if value.is_a?(Hash) attributes = value value = nil elsif block_given? && value raise ArgumentError, "You can't pass both a block and a value to javascript -- please choose one." end script(attributes.merge(:type => "text/javascript")) do # Shouldn't this be a "cdata" HtmlPart? # (maybe, but the syntax is specific to javascript; it isn't # really a generic XML CDATA section. Specifically, # ]]> within value is not treated as ending the # CDATA section by Firefox2 when parsing text/html, # although I guess we could refuse to generate ]]> # there, for the benefit of XML/XHTML parsers). output << raw("\n// ") output.append_newline # this forces a newline even if we're not in pretty mode end output << raw("\n") end # alias for AbstractWidget#render def to_html(options = {}) raise "Erector::Widget#to_html takes an options hash, not a symbol. Try calling \"to_html(:content_method_name=> :#{options})\"" if options.is_a? Symbol _render(options).to_s end # alias for #to_html # @deprecated Please use {#to_html} instead def to_s(*args) unless defined? @@already_warned_to_s $stderr.puts "Erector::Widget#to_s is deprecated. Please use #to_html instead. Called from #{caller.first}" @@already_warned_to_s = true end to_html(*args) end # Emits an XML instruction, which looks like this: def instruct(attributes={:version => "1.0", :encoding => "UTF-8"}) output << raw("") end # Emits an XML/HTML comment (<!-- ... -->) surrounding +text+ and/or # the output of +block+. see # http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.2.4 # # If +text+ is an Internet Explorer conditional comment condition such as # "[if IE]", the output includes the opening condition and closing # "[endif]". See http://www.quirksmode.org/css/condcom.html # # Since "Authors should avoid putting two or more adjacent hyphens inside # comments," we emit a warning if you do that. def comment(text = '') puts "Warning: Authors should avoid putting two or more adjacent hyphens inside comments." if text =~ /--/ conditional = text =~ /\[if .*\]/ rawtext "\n" end protected def sort_for_xml_declaration(attributes) # correct order is "version, encoding, standalone" (XML 1.0 section 2.8). # But we only try to put version before encoding for now. stringized = [] attributes.each do |key, value| stringized << [key.to_s, value] end stringized.sort{|a, b| b <=> a} end end public # Alias to make it easier to spell HtmlWidget = HTMLWidget end