ActiveRecord::Base.class_eval do include ActionView::Helpers::TagHelper, ActionView::Helpers::TextHelper, WhiteListHelper def self.format_attribute(attr_name) class << self; include ActionView::Helpers::TagHelper, ActionView::Helpers::TextHelper, WhiteListHelper; end define_method(:body) { read_attribute attr_name } define_method(:body_html) { read_attribute "#{attr_name}_html" } define_method(:body_html=) { |value| write_attribute "#{attr_name}_html", value } before_save :format_content end def dom_id [self.class.name.downcase.pluralize.dasherize, id] * '-' end protected def format_content body.strip! if body.respond_to?(:strip!) self.body_html = body.blank? ? '' : body_html_with_formatting end # 2013-09-04 (ADH): See "body_html_with_formatting" for ddetails. # FOOTNOTE_NAME_REGEXP = Regexp.new('^fnr?\d+$') # E.g. "fn30" or "fnr30" FOOTNOTE_HREF_REGEXP = Regexp.new('^#fnr?\d+$') # E.g. "#fn30" or "#fnr30" def body_html_with_formatting # 2013-09-04 (ADH): # # On the assumption we are called within a new Post or an edited Post, # generate a reasonably-likely-to-be-unique ID. We can't use the model # ID as in the "new" case it hasn't been saved yet so doesn't have one. # # We'll use this to patch up Textile footnote references. There's no # way to ask Textile to add a suffix to the IDs and names it generates, # so instead postprocess the output since we're being called for all # generated HTML nodes by the white list engine anyway (see # WhiteListHelper stuff in "config/environment.rb" for details). If we # don't do this, multiple posts on a page can contain the same foonote # IDs/names resulting in invalid HTML and useless HTML anchors. # # Since the ID is only used for that specific case, we're not *too* # worried if it turns out to be non-unique, but given it's based on # the time of day down to the microsecond and the post's user ID, it # is *extremely* unlikely that a real user would be able to generate # two posts with the same ID suffix for footnotes! # now = Time.now fn_id_sfx = "#{now.to_i}#{now.usec}#{self.user_id || 0}" # Generate the body by auto-linking, running through RedCloth and then # passing it to the white list engine which in turn calls back for all # of the HTML nodes. # body_html = auto_link body { |text| truncate(text, 50) } white_list(RedCloth.new(body_html).to_html) do | node, bad | if WhiteListHelper.bad_tags.include?(bad) node.to_s.gsub(/