Changeset 116

Show
Ignore:
Timestamp:
01/17/2007 18:40:39 (22 months ago)
Author:
why
Message:
  • tippytippytepee/support.rb: added markaby support and prefix-erb tags for tippytippytepee!
  • tippytippytepee/tepee.rb: dastardly expose @env and @input to the script on each wiki page in a very sinister way.
Location:
trunk/examples/tippytippytepee
Files:
1 modified
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/examples/tippytippytepee/support.rb

    r100 r116  
    348348    list = [] 
    349349    s.each_line do |line| 
     350      line.gsub!(/^(%[#=]?)\s+(.+)/) { "\n<#$1\n#$2\n%>\n" } or 
    350351      line.gsub!(/(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>)/) do |m| 
    351352        "\n#{m}\n" 
     
    451452  end 
    452453end 
     454 
     455module Kernel 
     456  class << self 
     457    alias_method :blank_slate_method_added, :method_added 
     458 
     459    # Detect method additions to Kernel and remove them in the 
     460    # BlankSlate class. 
     461    def method_added(name) 
     462      blank_slate_method_added(name) 
     463      return if self != Kernel 
     464      Builder::BlankSlate.hide(name) 
     465    end 
     466  end 
     467end 
     468 
     469class Object 
     470  class << self 
     471    alias_method :blank_slate_method_added, :method_added 
     472 
     473    # Detect method additions to Object and remove them in the 
     474    # BlankSlate class. 
     475    def method_added(name) 
     476      blank_slate_method_added(name) 
     477      return if self != Object 
     478      Builder::BlankSlate.hide(name) 
     479    end 
     480  end 
     481end 
     482module Builder 
     483 
     484  # BlankSlate provides an abstract base class with no predefined 
     485  # methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>). 
     486  # BlankSlate is useful as a base class when writing classes that 
     487  # depend upon <tt>method_missing</tt> (e.g. dynamic proxies). 
     488  class BlankSlate 
     489    class << self 
     490 
     491      # Hide the method named +name+ in the BlankSlate class.  Don't 
     492      # hide +instance_eval+ or any method beginning with "__". 
     493      def hide(name) 
     494        undef_method name if 
     495          instance_methods.include?(name.to_s) and 
     496          name !~ /^(__|instance_eval)/ 
     497      end 
     498    end 
     499 
     500    instance_methods.each { |m| hide(m) } 
     501  end 
     502 
     503  module XChar # :nodoc: 
     504 
     505    # See 
     506    # http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows 
     507    # for details. 
     508    CP1252 = {                  # :nodoc: 
     509      128 => 8364,              # euro sign 
     510      130 => 8218,              # single low-9 quotation mark 
     511      131 =>  402,              # latin small letter f with hook 
     512      132 => 8222,              # double low-9 quotation mark 
     513      133 => 8230,              # horizontal ellipsis 
     514      134 => 8224,              # dagger 
     515      135 => 8225,              # double dagger 
     516      136 =>  710,              # modifier letter circumflex accent 
     517      137 => 8240,              # per mille sign 
     518      138 =>  352,              # latin capital letter s with caron 
     519      139 => 8249,              # single left-pointing angle quotation mark 
     520      140 =>  338,              # latin capital ligature oe 
     521      142 =>  381,              # latin capital letter z with caron 
     522      145 => 8216,              # left single quotation mark 
     523      146 => 8217,              # right single quotation mark 
     524      147 => 8220,              # left double quotation mark 
     525      148 => 8221,              # right double quotation mark 
     526      149 => 8226,              # bullet 
     527      150 => 8211,              # en dash 
     528      151 => 8212,              # em dash 
     529      152 =>  732,              # small tilde 
     530      153 => 8482,              # trade mark sign 
     531      154 =>  353,              # latin small letter s with caron 
     532      155 => 8250,              # single right-pointing angle quotation mark 
     533      156 =>  339,              # latin small ligature oe 
     534      158 =>  382,              # latin small letter z with caron 
     535      159 =>  376,              # latin capital letter y with diaeresis 
     536    } 
     537 
     538    # See http://www.w3.org/TR/REC-xml/#dt-chardata for details. 
     539    PREDEFINED = { 
     540      38 => '&amp;',            # ampersand 
     541      60 => '&lt;',             # left angle bracket 
     542      62 => '&gt;',             # right angle bracket 
     543    } 
     544 
     545    # See http://www.w3.org/TR/REC-xml/#charsets for details. 
     546    VALID = [ 
     547      [0x9, 0xA, 0xD], 
     548      (0x20..0xD7FF),  
     549      (0xE000..0xFFFD), 
     550      (0x10000..0x10FFFF) 
     551    ] 
     552  end 
     553 
     554end 
     555 
     556###################################################################### 
     557# Enhance the Fixnum class with a XML escaped character conversion. 
     558# 
     559class Fixnum 
     560  XChar = Builder::XChar if ! defined?(XChar) 
     561 
     562  # XML escaped version of chr 
     563  def xchr 
     564    n = XChar::CP1252[self] || self 
     565    n = 42 unless XChar::VALID.find {|range| range.include? n} 
     566    XChar::PREDEFINED[n] or (n<128 ? n.chr : "&##{n};") 
     567  end 
     568end 
     569 
     570 
     571###################################################################### 
     572# Enhance the String class with a XML escaped character version of 
     573# to_s. 
     574# 
     575class String 
     576  # XML escaped version of to_s 
     577  def to_xs 
     578    unpack('U*').map {|n| n.xchr}.join # ASCII, UTF-8 
     579  rescue 
     580    unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252 
     581  end 
     582end 
     583 
     584module Builder 
     585 
     586  # Generic error for builder 
     587  class IllegalBlockError < RuntimeError; end 
     588 
     589  # XmlBase is a base class for building XML builders.  See 
     590  # Builder::XmlMarkup and Builder::XmlEvents for examples. 
     591  class XmlBase < BlankSlate 
     592 
     593    # Create an XML markup builder. 
     594    # 
     595    # out::     Object receiving the markup.  +out+ must respond to 
     596    #           <tt><<</tt>. 
     597    # indent::  Number of spaces used for indentation (0 implies no 
     598    #           indentation and no line breaks). 
     599    # initial:: Level of initial indentation. 
     600    # 
     601    def initialize(indent=0, initial=0) 
     602      @indent = indent 
     603      @level  = initial 
     604    end 
     605     
     606    # Create a tag named +sym+.  Other than the first argument which 
     607    # is the tag name, the arguements are the same as the tags 
     608    # implemented via <tt>method_missing</tt>. 
     609    def tag!(sym, *args, &block) 
     610      self.__send__(sym, *args, &block) 
     611    end 
     612 
     613    # Create XML markup based on the name of the method.  This method 
     614    # is never invoked directly, but is called for each markup method 
     615    # in the markup block. 
     616    def method_missing(sym, *args, &block) 
     617      text = nil 
     618      attrs = nil 
     619      sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol) 
     620      args.each do |arg| 
     621        case arg 
     622        when Hash 
     623          attrs ||= {} 
     624          attrs.merge!(arg) 
     625        else 
     626          text ||= '' 
     627          text << arg.to_s 
     628        end 
     629      end 
     630      if block 
     631        unless text.nil? 
     632          raise ArgumentError, "XmlMarkup cannot mix a text argument with a block" 
     633        end 
     634        _capture_outer_self(block) if @self.nil? 
     635        _indent 
     636        _start_tag(sym, attrs) 
     637        _newline 
     638        _nested_structures(block) 
     639        _indent 
     640        _end_tag(sym) 
     641        _newline 
     642      elsif text.nil? 
     643        _indent 
     644        _start_tag(sym, attrs, true) 
     645        _newline 
     646      else 
     647        _indent 
     648        _start_tag(sym, attrs) 
     649        text! text 
     650        _end_tag(sym) 
     651        _newline 
     652      end 
     653      @target 
     654    end 
     655 
     656    # Append text to the output target.  Escape any markup.  May be 
     657    # used within the markup brakets as: 
     658    # 
     659    #   builder.p { |b| b.br; b.text! "HI" }   #=>  <p><br/>HI</p> 
     660    def text!(text) 
     661      _text(_escape(text)) 
     662    end 
     663     
     664    # Append text to the output target without escaping any markup. 
     665    # May be used within the markup brakets as: 
     666    # 
     667    #   builder.p { |x| x << "<br/>HI" }   #=>  <p><br/>HI</p> 
     668    # 
     669    # This is useful when using non-builder enabled software that 
     670    # generates strings.  Just insert the string directly into the 
     671    # builder without changing the inserted markup. 
     672    # 
     673    # It is also useful for stacking builder objects.  Builders only 
     674    # use <tt><<</tt> to append to the target, so by supporting this 
     675    # method/operation builders can use other builders as their 
     676    # targets. 
     677    def <<(text) 
     678      _text(text) 
     679    end 
     680     
     681    # For some reason, nil? is sent to the XmlMarkup object.  If nil? 
     682    # is not defined and method_missing is invoked, some strange kind 
     683    # of recursion happens.  Since nil? won't ever be an XML tag, it 
     684    # is pretty safe to define it here. (Note: this is an example of 
     685    # cargo cult programming, 
     686    # cf. http://fishbowl.pastiche.org/2004/10/13/cargo_cult_programming). 
     687    def nil? 
     688      false 
     689    end 
     690 
     691    private 
     692     
     693    def _escape(text) 
     694      text.to_xs 
     695    end 
     696 
     697    def _escape_quote(text) 
     698      _escape(text).gsub(%r{"}, '&quot;')  # " WART 
     699    end 
     700 
     701    def _capture_outer_self(block) 
     702      @self = eval("self", block) 
     703    end 
     704     
     705    def _newline 
     706      return if @indent == 0 
     707      text! "\n" 
     708    end 
     709     
     710    def _indent 
     711      return if @indent == 0 || @level == 0 
     712      text!(" " * (@level * @indent)) 
     713    end 
     714     
     715    def _nested_structures(block) 
     716      @level += 1 
     717      block.call(self) 
     718    ensure 
     719      @level -= 1 
     720    end 
     721  end 
     722  # Create XML markup easily.  All (well, almost all) methods sent to 
     723  # an XmlMarkup object will be translated to the equivalent XML 
     724  # markup.  Any method with a block will be treated as an XML markup 
     725  # tag with nested markup in the block. 
     726  # 
     727  # Examples will demonstrate this easier than words.  In the 
     728  # following, +xm+ is an +XmlMarkup+ object. 
     729  # 
     730  #   xm.em("emphasized")             # => <em>emphasized</em> 
     731  #   xm.em { xmm.b("emp & bold") }   # => <em><b>emph &amp; bold</b></em> 
     732  #   xm.a("A Link", "href"=>"http://onestepback.org") 
     733  #                                   # => <a href="http://onestepback.org">A Link</a> 
     734  #   xm.div { br }                    # => <div><br/></div> 
     735  #   xm.target("name"=>"compile", "option"=>"fast") 
     736  #                                   # => <target option="fast" name="compile"\> 
     737  #                                   # NOTE: order of attributes is not specified. 
     738  # 
     739  #   xm.instruct!                   # <?xml version="1.0" encoding="UTF-8"?> 
     740  #   xm.html {                      # <html> 
     741  #     xm.head {                    #   <head> 
     742  #       xm.title("History")        #     <title>History</title> 
     743  #     }                            #   </head> 
     744  #     xm.body {                    #   <body> 
     745  #       xm.comment! "HI"           #     <!-- HI --> 
     746  #       xm.h1("Header")            #     <h1>Header</h1> 
     747  #       xm.p("paragraph")          #     <p>paragraph</p> 
     748  #     }                            #   </body> 
     749  #   }                              # </html> 
     750  # 
     751  # == Notes: 
     752  # 
     753  # * The order that attributes are inserted in markup tags is 
     754  #   undefined.  
     755  # 
     756  # * Sometimes you wish to insert text without enclosing tags.  Use 
     757  #   the <tt>text!</tt> method to accomplish this. 
     758  # 
     759  #   Example: 
     760  # 
     761  #     xm.div {                          # <div> 
     762  #       xm.text! "line"; xm.br          #   line<br/> 
     763  #       xm.text! "another line"; xmbr   #    another line<br/> 
     764  #     }                                 # </div> 
     765  # 
     766  # * The special XML characters <, >, and & are converted to &lt;, 
     767  #   &gt; and &amp; automatically.  Use the <tt><<</tt> operation to 
     768  #   insert text without modification. 
     769  # 
     770  # * Sometimes tags use special characters not allowed in ruby 
     771  #   identifiers.  Use the <tt>tag!</tt> method to handle these 
     772  #   cases. 
     773  # 
     774  #   Example: 
     775  # 
     776  #     xml.tag!("SOAP:Envelope") { ... } 
     777  # 
     778  #   will produce ... 
     779  # 
     780  #     <SOAP:Envelope> ... </SOAP:Envelope>" 
     781  # 
     782  #   <tt>tag!</tt> will also take text and attribute arguments (after 
     783  #   the tag name) like normal markup methods.  (But see the next 
     784  #   bullet item for a better way to handle XML namespaces). 
     785  #    
     786  # * Direct support for XML namespaces is now available.  If the 
     787  #   first argument to a tag call is a symbol, it will be joined to 
     788  #   the tag to produce a namespace:tag combination.  It is easier to 
     789  #   show this than describe it. 
     790  # 
     791  #     xml.SOAP :Envelope do ... end 
     792  # 
     793  #   Just put a space before the colon in a namespace to produce the 
     794  #   right form for builder (e.g. "<tt>SOAP:Envelope</tt>" => 
     795  #   "<tt>xml.SOAP :Envelope</tt>") 
     796  # 
     797  # * XmlMarkup builds the markup in any object (called a _target_) 
     798  #   that accepts the <tt><<</tt> method.  If no target is given, 
     799  #   then XmlMarkup defaults to a string target. 
     800  #  
     801  #   Examples: 
     802  # 
     803  #     xm = Builder::XmlMarkup.new 
     804  #     result = xm.title("yada") 
     805  #     # result is a string containing the markup. 
     806  # 
     807  #     buffer = "" 
     808  #     xm = Builder::XmlMarkup.new(buffer) 
     809  #     # The markup is appended to buffer (using <<) 
     810  # 
     811  #     xm = Builder::XmlMarkup.new(STDOUT) 
     812  #     # The markup is written to STDOUT (using <<) 
     813  # 
     814  #     xm = Builder::XmlMarkup.new 
     815  #     x2 = Builder::XmlMarkup.new(:target=>xm) 
     816  #     # Markup written to +x2+ will be send to +xm+. 
     817  #    
     818  # * Indentation is enabled by providing the number of spaces to 
     819  #   indent for each level as a second argument to XmlBuilder.new. 
     820  #   Initial indentation may be specified using a third parameter. 
     821  # 
     822  #   Example: 
     823  # 
     824  #     xm = Builder.new(:ident=>2) 
     825  #     # xm will produce nicely formatted and indented XML. 
     826  #   
     827  #     xm = Builder.new(:indent=>2, :margin=>4) 
     828  #     # xm will produce nicely formatted and indented XML with 2 
     829  #     # spaces per indent and an over all indentation level of 4. 
     830  # 
     831  #     builder = Builder::XmlMarkup.new(:target=>$stdout, :indent=>2) 
     832  #     builder.name { |b| b.first("Jim"); b.last("Weirich) } 
     833  #     # prints: 
     834  #     #     <name> 
     835  #     #       <first>Jim</first> 
     836  #     #       <last>Weirich</last> 
     837  #     #     </name> 
     838  # 
     839  # * The instance_eval implementation which forces self to refer to 
     840  #   the message receiver as self is now obsolete.  We now use normal 
     841  #   block calls to execute the markup block.  This means that all 
     842  #   markup methods must now be explicitly send to the xml builder. 
     843  #   For instance, instead of 
     844  # 
     845  #      xml.div { strong("text") } 
     846  # 
     847  #   you need to write: 
     848  # 
     849  #      xml.div { xml.strong("text") } 
     850  # 
     851  #   Although more verbose, the subtle change in semantics within the 
     852  #   block was found to be prone to error.  To make this change a 
     853  #   little less cumbersome, the markup block now gets the markup 
     854  #   object sent as an argument, allowing you to use a shorter alias 
     855  #   within the block. 
     856  # 
     857  #   For example: 
     858  # 
     859  #     xml_builder = Builder::XmlMarkup.new 
     860  #     xml_builder.div { |xml| 
     861  #       xml.stong("text") 
     862  #     } 
     863  # 
     864  class XmlMarkup < XmlBase 
     865 
     866    # Create an XML markup builder.  Parameters are specified by an 
     867    # option hash. 
     868    # 
     869    # :target=><em>target_object</em>:: 
     870    #    Object receiving the markup.  +out+ must respond to the 
     871    #    <tt><<</tt> operator.  The default is a plain string target. 
     872    #     
     873    # :indent=><em>indentation</em>:: 
     874    #    Number of spaces used for indentation.  The default is no 
     875    #    indentation and no line breaks. 
     876    #     
     877    # :margin=><em>initial_indentation_level</em>:: 
     878    #    Amount of initial indentation (specified in levels, not 
     879    #    spaces). 
     880    #     
     881    # :escape_attrs=><b>OBSOLETE</em>:: 
     882    #    The :escape_attrs option is no longer supported by builder 
     883    #    (and will be quietly ignored).  String attribute values are 
     884    #    now automatically escaped.  If you need unescaped attribute 
     885    #    values (perhaps you are using entities in the attribute 
     886    #    values), then give the value as a Symbol.  This allows much 
     887    #    finer control over escaping attribute values. 
     888    #     
     889    def initialize(options={}) 
     890      indent = options[:indent] || 0 
     891      margin = options[:margin] || 0 
     892      super(indent, margin) 
     893      @target = options[:target] || "" 
     894    end 
     895     
     896    # Return the target of the builder. 
     897    def target! 
     898      @target 
     899    end 
     900 
     901    def comment!(comment_text) 
     902      _ensure_no_block block_given? 
     903      _special("<!-- ", " -->", comment_text, nil) 
     904    end 
     905 
     906    # Insert an XML declaration into the XML markup. 
     907    # 
     908    # For example: 
     909    # 
     910    #   xml.declare! :ELEMENT, :blah, "yada" 
     911    #       # => <!ELEMENT blah "yada"> 
     912    def declare!(inst, *args, &block) 
     913      _indent 
     914      @target << "<!#{inst}" 
     915      args.each do |arg| 
     916        case arg 
     917        when String 
     918          @target << %{ "#{arg}"} 
     919        when Symbol 
     920          @target << " #{arg}" 
     921        end 
     922      end 
     923      if block_given? 
     924        @target << " [" 
     925        _newline 
     926        _nested_structures(block) 
     927        @target << "]" 
     928      end 
     929      @target << ">" 
     930      _newline 
     931    end 
     932 
     933    # Insert a processing instruction into the XML markup.  E.g. 
     934    # 
     935    # For example: 
     936    # 
     937    #    xml.instruct! 
     938    #        #=> <?xml version="1.0" encoding="UTF-8"?> 
     939    #    xml.instruct! :aaa, :bbb=>"ccc" 
     940    #        #=> <?aaa bbb="ccc"?> 
     941    # 
     942    def instruct!(directive_tag=:xml, attrs={}) 
     943      _ensure_no_block block_given? 
     944      if directive_tag == :xml 
     945        a = { :version=>"1.0", :encoding=>"UTF-8" } 
     946        attrs = a.merge attrs 
     947      end 
     948      _special( 
     949        "<?#{directive_tag}", 
     950        "?>", 
     951        nil, 
     952        attrs, 
     953        [:version, :encoding, :standalone]) 
     954    end 
     955 
     956    # Insert a CDATA section into the XML markup. 
     957    # 
     958    # For example: 
     959    # 
     960    #    xml.cdata!("text to be included in cdata") 
     961    #        #=> <![CDATA[text to be included in cdata]]> 
     962    # 
     963    def cdata!(text) 
     964      _ensure_no_block block_given? 
     965      _special("<![CDATA[", "]]>", text, nil) 
     966    end 
     967     
     968    private 
     969 
     970    # NOTE: All private methods of a builder object are prefixed when 
     971    # a "_" character to avoid possible conflict with XML tag names. 
     972 
     973    # Insert text directly in to the builder's target. 
     974    def _text(text) 
     975      @target << text 
     976    end 
     977     
     978    # Insert special instruction.  
     979    def _special(open, close, data=nil, attrs=nil, order=[]) 
     980      _indent 
     981      @target << open 
     982      @target << data if data 
     983      _insert_attributes(attrs, order) if attrs 
     984      @target << close 
     985      _newline 
     986    end 
     987 
     988    # Start an XML tag.  If <tt>end_too</tt> is true, then the start 
     989    # tag is also the end tag (e.g.  <br/> 
     990    def _start_tag(sym, attrs, end_too=false) 
     991      @target << "<#{sym}" 
     992      _insert_attributes(attrs) 
     993      @target << "/" if end_too 
     994      @target << ">" 
     995    end 
     996     
     997    # Insert an ending tag. 
     998    def _end_tag(sym) 
     999      @target << "</#{sym}>" 
     1000    end 
     1001 
     1002    # Insert the attributes (given in the hash). 
     1003    def _insert_attributes(attrs, order=[]) 
     1004      return if attrs.nil? 
     1005      order.each do |k| 
     1006        v = attrs[k] 
     1007        @target << %{ #{k}="#{_attr_value(v)}"} if v 
     1008      end 
     1009      attrs.each do |k, v| 
     1010        @target << %{ #{k}="#{_attr_value(v)}"} unless order.member?(k) 
     1011      end 
     1012    end 
     1013 
     1014    def _attr_value(value) 
     1015      case value 
     1016      when Symbol 
     1017        value.to_s 
     1018      else 
     1019        _escape_quote(value.to_s) 
     1020      end 
     1021    end 
     1022 
     1023    def _ensure_no_block(got_block) 
     1024      if got_block 
     1025        fail IllegalBlockError, 
     1026          "Blocks are not allowed on XML instructions" 
     1027      end 
     1028    end 
     1029 
     1030  end 
     1031 
     1032  # Create a series of SAX-like XML events (e.g. start_tag, end_tag) 
     1033  # from the markup code.  XmlEvent objects are used in a way similar 
     1034  # to XmlMarkup objects, except that a series of events are generated 
     1035  # and passed to a handler rather than generating character-based 
     1036  # markup. 
     1037  # 
     1038  # Usage: 
     1039  #   xe = Builder::XmlEvents.new(hander) 
     1040  #   xe.title("HI")    # Sends start_tag/end_tag/text messages to the handler. 
     1041  # 
     1042  # Indentation may also be selected by providing value for the 
     1043  # indentation size and initial indentation level. 
     1044  # 
     1045  #   xe = Builder::XmlEvents.new(handler, indent_size, initial_indent_level) 
     1046  # 
     1047  # == XML Event Handler 
     1048  # 
     1049  # The handler object must expect the following events. 
     1050  # 
     1051  # [<tt>start_tag(tag, attrs)</tt>] 
     1052  #     Announces that a new tag has been found.  +tag+ is the name of 
     1053  #     the tag and +attrs+ is a hash of attributes for the tag. 
     1054  # 
     1055  # [<tt>end_tag(tag)</tt>] 
     1056  #     Announces that an end tag for +tag+ has been found. 
     1057  # 
     1058  # [<tt>text(text)</tt>] 
     1059  #     Announces that a string of characters (+text+) has been found. 
     1060  #     A series of characters may be broken up into more than one 
     1061  #     +text+ call, so the client cannot assume that a single 
     1062  #     callback contains all the text data. 
     1063  # 
     1064  class XmlEvents < XmlMarkup 
     1065    def text!(text) 
     1066      @target.text(text) 
     1067    end 
     1068 
     1069    def _start_tag(sym, attrs, end_too=false) 
     1070      @target.start_tag(sym, attrs) 
     1071      _end_tag(sym) if end_too 
     1072    end 
     1073 
     1074    def _end_tag(sym) 
     1075      @target.end_tag(sym) 
     1076    end 
     1077  end 
     1078end 
     1079 
     1080module Markaby 
     1081  VERSION = '0.5' 
     1082 
     1083  class InvalidXhtmlError < Exception; end 
     1084 
     1085  FORM_TAGS = [ :form, :input, :select, :textarea ] 
     1086  SELF_CLOSING_TAGS = [ :base, :meta, :link, :hr, :br, :param, :img, :area, :input, :col ] 
     1087  NO_PROXY = [ :hr, :br ] 
     1088 
     1089  # Common sets of attributes. 
     1090  AttrCore = [:id, :class, :style, :title] 
     1091  AttrI18n = [:lang, 'xml:lang'.intern, :dir] 
     1092  AttrEvents = [:onclick, :ondblclick, :onmousedown, :onmouseup, :onmouseover, :onmousemove,  
     1093      :onmouseout, :onkeypress, :onkeydown, :onkeyup] 
     1094  AttrFocus = [:accesskey, :tabindex, :onfocus, :onblur] 
     1095  AttrHAlign = [:align, :char, :charoff] 
     1096  AttrVAlign = [:valign] 
     1097  Attrs = AttrCore + AttrI18n + AttrEvents 
     1098 
     1099  # All the tags and attributes from XHTML 1.0 Strict 
     1100  class XHTMLStrict 
     1101    class << self 
     1102      attr_accessor :tags, :tagset, :forms, :self_closing, :doctype 
     1103    end 
     1104    @doctype = ["-//W3C//DTD XHTML 1.0 Strict//EN", "DTD/xhtml1-strict.dtd"] 
     1105    @tagset = { 
     1106      :html => AttrI18n + [:id, :xmlns], 
     1107      :head => AttrI18n + [:id, :profile], 
     1108      :title => AttrI18n + [:id], 
     1109      :base => [:href, :id], 
     1110      :meta => AttrI18n + [:id, :http, :name, :content, :scheme, 'http-equiv'.intern], 
     1111      :link => Attrs + [:charset, :href, :hreflang, :type, :rel, :rev, :media], 
     1112      :style => AttrI18n + [:id, :type, :media, :title, 'xml:space'.intern], 
     1113      :script => [:id, :charset, :type, :src, :defer, 'xml:space'.intern], 
     1114      :noscript => Attrs, 
     1115      :body => Attrs + [:onload, :onunload], 
     1116      :div => Attrs, 
     1117      :p => Attrs, 
     1118      :ul => Attrs, 
     1119      :ol => Attrs, 
     1120      :li => Attrs, 
     1121      :dl => Attrs, 
     1122      :dt => Attrs, 
     1123      :dd => Attrs, 
     1124      :address => Attrs, 
     1125      :hr => Attrs, 
     1126      :pre => Attrs + ['xml:space'.intern], 
     1127      :blockquote => Attrs + [:cite], 
     1128      :ins => Attrs + [:cite, :datetime], 
     1129      :del => Attrs + [:cite, :datetime], 
     1130      :a => Attrs + AttrFocus + [:charset, :type, :name, :href, :hreflang, :rel, :rev, :shape, :coords], 
     1131      :span => Attrs, 
     1132      :bdo => AttrCore + AttrEvents + [:lang, 'xml:lang'.intern, :dir], 
     1133      :br => AttrCore, 
     1134      :em => Attrs, 
     1135      :strong => Attrs, 
     1136      :dfn => Attrs, 
     1137      :code => Attrs, 
     1138      :samp => Attrs, 
     1139      :kbd => Attrs, 
     1140      :var => Attrs, 
     1141      :cite => Attrs, 
     1142      :abbr => Attrs, 
     1143      :acronym => Attrs, 
     1144      :q => Attrs + [:cite], 
     1145      :sub => Attrs, 
     1146      :sup => Attrs, 
     1147      :tt => Attrs, 
     1148      :i => Attrs, 
     1149      :b => Attrs, 
     1150      :big => Attrs, 
     1151      :small => Attrs, 
     1152      :object => Attrs + [:declare, :classid, :codebase, :data, :type, :codetype, :archive, :standby, :height, :width, :usemap, :name, :tabindex], 
     1153      :param => [:id, :name, :value, :valuetype, :type], 
     1154      :img => Attrs + [:src, :alt, :longdesc, :height, :width, :usemap, :ismap], 
     1155      :map => AttrI18n + AttrEvents + [:id, :class, :style, :title, :name], 
     1156      :area => Attrs + AttrFocus + [:shape, :coords, :href, :nohref, :alt], 
     1157      :form => Attrs + [:action, :method, :enctype, :onsubmit, :onreset, :accept, :accept], 
     1158      :label => Attrs + [:for, :accesskey, :onfocus, :onblur], 
     1159      :input => Attrs + AttrFocus + [:type, :name, :value, :checked, :disabled, :readonly, :size, :maxlength, :src, :alt, :usemap, :onselect, :onchange, :accept], 
     1160      :select => Attrs + [:name, :size, :multiple, :disabled, :tabindex, :onfocus, :onblur, :onchange], 
     1161      :optgroup => Attrs + [:disabled, :label], 
     1162      :option => Attrs + [:selected, :disabled, :label, :value], 
     1163      :textarea => Attrs + AttrFocus + [:name, :rows, :cols, :disabled, :readonly, :onselect, :onchange], 
     1164      :fieldset => Attrs, 
     1165      :legend => Attrs + [:accesskey], 
     1166      :button => Attrs + AttrFocus + [:name, :value, :type, :disabled], 
     1167      :table => Attrs + [:summary, :width, :border, :frame, :rules, :cellspacing, :cellpadding], 
     1168      :caption => Attrs, 
     1169      :colgroup => Attrs + AttrHAlign + AttrVAlign + [:span, :width], 
     1170      :col => Attrs + AttrHAlign + AttrVAlign + [:span, :width], 
     1171      :thead => Attrs + AttrHAlign + AttrVAlign, 
     1172      :tfoot => Attrs + AttrHAlign + AttrVAlign, 
     1173      :tbody => Attrs + AttrHAlign + AttrVAlign, 
     1174      :tr => Attrs + AttrHAlign + AttrVAlign, 
     1175      :th => Attrs + AttrHAlign + AttrVAlign + [:abbr, :axis, :headers, :scope, :rowspan, :colspan], 
     1176      :td => Attrs + AttrHAlign + AttrVAlign + [:abbr, :axis, :headers, :scope, :rowspan, :colspan], 
     1177      :h1 => Attrs, 
     1178      :h2 => Attrs, 
     1179      :h3 => Attrs, 
     1180      :h4 => Attrs, 
     1181      :h5 => Attrs, 
     1182      :h6 => Attrs 
     1183    } 
     1184 
     1185    @tags = @tagset.keys 
     1186    @forms = @tags & FORM_TAGS 
     1187    @self_closing = @tags & SELF_CLOSING_TAGS 
     1188  end 
     1189 
     1190  # Additional tags found in XHTML 1.0 Transitional 
     1191  class XHTMLTransitional 
     1192    class << self 
     1193      attr_accessor :tags, :tagset, :forms,