Chris@909: module CodeRay Chris@909: module Encoders Chris@909: Chris@909: class HTML Chris@909: Chris@909: # This module is included in the output String of the HTML Encoder. Chris@909: # Chris@909: # It provides methods like wrap, div, page etc. Chris@909: # Chris@909: # Remember to use #clone instead of #dup to keep the modules the object was Chris@909: # extended with. Chris@909: # Chris@909: # TODO: Rewrite this without monkey patching. Chris@909: module Output Chris@909: Chris@909: attr_accessor :css Chris@909: Chris@909: class << self Chris@909: Chris@909: # Raises an exception if an object that doesn't respond to to_str is extended by Output, Chris@909: # to prevent users from misuse. Use Module#remove_method to disable. Chris@909: def extended o # :nodoc: Chris@909: warn "The Output module is intended to extend instances of String, not #{o.class}." unless o.respond_to? :to_str Chris@909: end Chris@909: Chris@909: def make_stylesheet css, in_tag = false # :nodoc: Chris@909: sheet = css.stylesheet Chris@909: sheet = <<-'CSS' if in_tag Chris@909: Chris@909: CSS Chris@909: sheet Chris@909: end Chris@909: Chris@909: def page_template_for_css css # :nodoc: Chris@909: sheet = make_stylesheet css Chris@909: PAGE.apply 'CSS', sheet Chris@909: end Chris@909: Chris@909: end Chris@909: Chris@909: def wrapped_in? element Chris@909: wrapped_in == element Chris@909: end Chris@909: Chris@909: def wrapped_in Chris@909: @wrapped_in ||= nil Chris@909: end Chris@909: attr_writer :wrapped_in Chris@909: Chris@909: def wrap_in! template Chris@909: Template.wrap! self, template, 'CONTENT' Chris@909: self Chris@909: end Chris@909: Chris@909: def apply_title! title Chris@909: self.sub!(/()(<\/title>)/) { $1 + title + $2 } Chris@909: self Chris@909: end Chris@909: Chris@909: def wrap! element, *args Chris@909: return self if not element or element == wrapped_in Chris@909: case element Chris@909: when :div Chris@909: raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil Chris@909: wrap_in! DIV Chris@909: when :span Chris@909: raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil Chris@909: wrap_in! SPAN Chris@909: when :page Chris@909: wrap! :div if wrapped_in? nil Chris@909: raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? :div Chris@909: wrap_in! Output.page_template_for_css(@css) Chris@909: if args.first.is_a?(Hash) && title = args.first[:title] Chris@909: apply_title! title Chris@909: end Chris@909: self Chris@909: when nil Chris@909: return self Chris@909: else Chris@909: raise "Unknown value %p for :wrap" % element Chris@909: end Chris@909: @wrapped_in = element Chris@909: self Chris@909: end Chris@909: Chris@909: def stylesheet in_tag = false Chris@909: Output.make_stylesheet @css, in_tag Chris@909: end Chris@909: Chris@909: #-- don't include the templates in docu Chris@909: Chris@909: class Template < String # :nodoc: Chris@909: Chris@909: def self.wrap! str, template, target Chris@909: target = Regexp.new(Regexp.escape("<%#{target}%>")) Chris@909: if template =~ target Chris@909: str[0,0] = $` Chris@909: str << $' Chris@909: else Chris@909: raise "Template target <%%%p%%> not found" % target Chris@909: end Chris@909: end Chris@909: Chris@909: def apply target, replacement Chris@909: target = Regexp.new(Regexp.escape("<%#{target}%>")) Chris@909: if self =~ target Chris@909: Template.new($` + replacement + $') Chris@909: else Chris@909: raise "Template target <%%%p%%> not found" % target Chris@909: end Chris@909: end Chris@909: Chris@909: end Chris@909: Chris@909: SPAN = Template.new '<span class="CodeRay"><%CONTENT%></span>' Chris@909: Chris@909: DIV = Template.new <<-DIV Chris@909: <div class="CodeRay"> Chris@909: <div class="code"><pre><%CONTENT%></pre></div> Chris@909: </div> Chris@909: DIV Chris@909: Chris@909: TABLE = Template.new <<-TABLE Chris@909: <table class="CodeRay"><tr> Chris@909: <td class="line-numbers" title="double click to toggle" ondblclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre><%LINE_NUMBERS%></pre></td> Chris@909: <td class="code"><pre><%CONTENT%></pre></td> Chris@909: </tr></table> Chris@909: TABLE Chris@909: Chris@909: PAGE = Template.new <<-PAGE Chris@909: <!DOCTYPE html> Chris@909: <html> Chris@909: <head> Chris@909: <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> Chris@909: <title> Chris@909: Chris@909: Chris@909: Chris@909: Chris@909: <%CONTENT%> Chris@909: Chris@909: Chris@909: PAGE Chris@909: Chris@909: end Chris@909: Chris@909: end Chris@909: Chris@909: end Chris@909: end