require 'xmpp4r/xmppelement' module Jabber module XHTML NS_XHTML_IM = 'http://jabber.org/protocol/xhtml-im' NS_XHTML = 'http://www.w3.org/1999/xhtml' ## # XHTML-IM (XEP-0071) container # # The important methods are: # * HTML#contents= # * HTML#to_text class HTML < XMPPElement name_xmlns 'html', NS_XHTML_IM force_xmlns true ## # Initialize element with HTML contents (see HTML#contents=) def initialize(contents=[]) super() self.contents = contents end ## # Get first XHTML::Body child def body first_element('body') || add(Body.new) end ## # Replace first XHTML::Body child def body=(body) delete_elements('body') add(body) end ## # Replace first XHTML::Body child (chainable) def set_body(body) self.body = body self end ## # Set contents of this HTML document. The "contents" parameter can be: # * An Array of REXML::Element and Strings which will replace the current children of the body # * A single REXML::Element which will replace all other children of the body # * An instance of XHTML::Body which will replace the current body # * A String comprising an HTML fragment. This will be parsed, which could raise an Exception. # We must never send invalid XML over an XMPP stream. If you intend to put variable data in # your HTML, use something like Rails' Builder::XmlMarkup or Ramaze::Gestalt def contents=(contents) if contents.kind_of? String self.body = REXML::Document.new("<body xmlns='#{NS_XHTML}'>#{contents}</body>").root elsif contents.kind_of? Body self.body = contents elsif contents.kind_of? Array self.body = Body.new contents.each do |element| if element.kind_of? String body.add_text(element) else body.add(element) end end else self.body = Body.new body.add(contents) end end ## # HTML#contents= chainable def set_contents(contents) self.contents = contents self end ## # Convert contents of this XHTML container to plain text # for easy usage with an additional fall-back <body/> in message stanzas # # The resulting string is recursively composed of the text nodes of # all children. # This works because of the design criteria of HTML/XHTML: # readable content is not being put into attributes but as text children. # # If you require clickable links and proper information representation # then compose the text yourself! def to_text text_getter = nil # Create binding so that the following lambda can work recursively text_getter = lambda do |element| if element.kind_of? REXML::Text element.value elsif element.kind_of? REXML::Element element.children.collect { |child| text_getter.call(child) }.join end end text_getter.call(self) # Finally, execute and return results end end ## # HTML Body element, must be the only child of XHTML::HTML class Body < XMPPElement name_xmlns 'body', NS_XHTML force_xmlns true end end end