2013-05-28 07:48:47 +08:00
|
|
|
class ExcerptParser < Nokogiri::XML::SAX::Document
|
|
|
|
|
|
|
|
attr_reader :excerpt
|
|
|
|
|
2013-06-04 04:12:24 +08:00
|
|
|
def initialize(length, options=nil)
|
2013-05-28 07:48:47 +08:00
|
|
|
@length = length
|
|
|
|
@excerpt = ""
|
|
|
|
@current_length = 0
|
2013-06-04 04:12:24 +08:00
|
|
|
options || {}
|
2013-05-28 07:48:47 +08:00
|
|
|
@strip_links = options[:strip_links] == true
|
2013-06-04 04:12:24 +08:00
|
|
|
@text_entities = options[:text_entities] == true
|
2013-06-06 06:54:46 +08:00
|
|
|
@markdown_images = options[:markdown_images] == true
|
2014-07-17 19:32:17 +08:00
|
|
|
@start_excerpt = false
|
2013-05-28 07:48:47 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.get_excerpt(html, length, options)
|
|
|
|
me = self.new(length,options)
|
|
|
|
parser = Nokogiri::HTML::SAX::Parser.new(me)
|
|
|
|
catch(:done) do
|
|
|
|
parser.parse(html) unless html.nil?
|
|
|
|
end
|
2013-06-05 00:05:36 +08:00
|
|
|
me.excerpt.strip!
|
2013-05-28 07:48:47 +08:00
|
|
|
me.excerpt
|
|
|
|
end
|
|
|
|
|
2014-07-25 10:15:43 +08:00
|
|
|
def escape_attribute(v)
|
|
|
|
v.gsub("&", "&")
|
|
|
|
.gsub("\"", """)
|
|
|
|
.gsub("<", "<")
|
|
|
|
.gsub(">", ">")
|
|
|
|
end
|
|
|
|
|
2013-06-06 06:54:46 +08:00
|
|
|
def include_tag(name, attributes)
|
2014-07-25 10:15:43 +08:00
|
|
|
characters("<#{name} #{attributes.map{|k,v| "#{k}=\"#{escape_attribute(v)}\""}.join(' ')}>", false, false, false)
|
2013-06-06 06:54:46 +08:00
|
|
|
end
|
|
|
|
|
2013-05-28 07:48:47 +08:00
|
|
|
def start_element(name, attributes=[])
|
|
|
|
case name
|
|
|
|
when "img"
|
2013-06-06 06:54:46 +08:00
|
|
|
|
|
|
|
# If include_images is set, include the image in markdown
|
|
|
|
characters("!") if @markdown_images
|
|
|
|
|
2013-05-28 07:48:47 +08:00
|
|
|
attributes = Hash[*attributes.flatten]
|
|
|
|
if attributes["alt"]
|
|
|
|
characters("[#{attributes["alt"]}]")
|
|
|
|
elsif attributes["title"]
|
|
|
|
characters("[#{attributes["title"]}]")
|
|
|
|
else
|
|
|
|
characters("[image]")
|
|
|
|
end
|
2013-06-06 06:54:46 +08:00
|
|
|
|
|
|
|
characters("(#{attributes['src']})") if @markdown_images
|
|
|
|
|
2013-05-28 07:48:47 +08:00
|
|
|
when "a"
|
|
|
|
unless @strip_links
|
2013-06-06 06:54:46 +08:00
|
|
|
include_tag(name, attributes)
|
2013-05-28 07:48:47 +08:00
|
|
|
@in_a = true
|
|
|
|
end
|
2014-02-20 16:48:30 +08:00
|
|
|
|
2013-05-28 07:48:47 +08:00
|
|
|
when "aside"
|
|
|
|
@in_quote = true
|
2014-02-20 16:48:30 +08:00
|
|
|
|
|
|
|
when "div", "span"
|
2014-07-17 19:32:17 +08:00
|
|
|
if attributes.include?(["class", "excerpt"])
|
2014-09-03 15:12:56 +08:00
|
|
|
@excerpt = ""
|
|
|
|
@current_length = 0
|
2014-07-17 19:32:17 +08:00
|
|
|
@start_excerpt = true
|
|
|
|
end
|
2014-02-20 16:48:30 +08:00
|
|
|
# Preserve spoilers
|
2014-07-17 19:32:17 +08:00
|
|
|
if attributes.include?(["class", "spoiler"])
|
2014-02-20 16:48:30 +08:00
|
|
|
include_tag("span", attributes)
|
|
|
|
@in_spoiler = true
|
|
|
|
end
|
2013-05-28 07:48:47 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def end_element(name)
|
|
|
|
case name
|
|
|
|
when "a"
|
|
|
|
unless @strip_links
|
|
|
|
characters("</a>",false, false, false)
|
|
|
|
@in_a = false
|
|
|
|
end
|
|
|
|
when "p", "br"
|
|
|
|
characters(" ")
|
|
|
|
when "aside"
|
|
|
|
@in_quote = false
|
2014-02-20 16:48:30 +08:00
|
|
|
when "div", "span"
|
2014-07-17 19:32:17 +08:00
|
|
|
throw :done if @start_excerpt
|
2014-02-20 16:48:30 +08:00
|
|
|
characters("</span>", false, false, false) if @in_spoiler
|
|
|
|
@in_spoiler = false
|
2013-05-28 07:48:47 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def characters(string, truncate = true, count_it = true, encode = true)
|
|
|
|
return if @in_quote
|
|
|
|
encode = encode ? lambda{|s| ERB::Util.html_escape(s)} : lambda {|s| s}
|
|
|
|
if count_it && @current_length + string.length > @length
|
|
|
|
length = [0, @length - @current_length - 1].max
|
|
|
|
@excerpt << encode.call(string[0..length]) if truncate
|
2013-06-04 04:12:24 +08:00
|
|
|
@excerpt << (@text_entities ? "..." : "…")
|
2013-05-28 07:48:47 +08:00
|
|
|
@excerpt << "</a>" if @in_a
|
|
|
|
throw :done
|
|
|
|
end
|
|
|
|
@excerpt << encode.call(string)
|
|
|
|
@current_length += string.length if count_it
|
|
|
|
end
|
|
|
|
end
|