1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
module HighlightHelper
include ERB::Util
# Implementation of rails' highlight that allows regex to be passed to
# the phrases parameter.
# https://github.com/rails/rails/pull/11793
def highlight_matches(text, phrases, options = {})
text = ActionController::Base.helpers.sanitize(text).try(:html_safe) if options.fetch(:sanitize, true)
if text.blank? || phrases.blank?
text
else
match = Array(phrases).map do |p|
Regexp === p ? p.to_s : Regexp.escape(p)
end.join('|')
if block_given?
text.gsub(/(#{match})(?![^<]*?>)/i) { |found| yield found }
else
highlighter = options.fetch(:highlighter, '<mark>\1</mark>')
text.gsub(/(#{match})(?![^<]*?>)/i, highlighter)
end
end.html_safe
end
# Highlight words, also escapes HTML (other than spans that we add)
def highlight_words(t, words, html = true)
if html
highlight_matches(h(t), words, :highlighter => '<span class="highlight">\1</span>').html_safe
else
highlight_matches(t, words, :highlighter => '*\1*')
end
end
def highlight_and_excerpt(t, words, excount, html = true)
newt = excerpt(t, words[0], :radius => excount)
if not newt
newt = excerpt(t, '', :radius => excount)
end
t = newt
t = highlight_words(t, words, html)
return t
end
def excerpt(text, phrase, options = {})
return unless text && phrase
separator = options.fetch(:separator, nil) || ""
case phrase
when Regexp
regex = phrase
else
regex = /#{Regexp.escape(phrase)}/i
end
return unless matches = text.match(regex)
phrase = matches[0]
unless separator.empty?
text.split(separator).each do |value|
if value.match(regex)
regex = phrase = value
break
end
end
end
first_part, second_part = text.split(phrase, 2)
prefix, first_part = cut_excerpt_part(:first, first_part, separator, options)
postfix, second_part = cut_excerpt_part(:second, second_part, separator, options)
affix = [first_part, separator, phrase, separator, second_part].join.strip
[prefix, affix, postfix].join
end
private
def cut_excerpt_part(part_position, part, separator, options)
return "", "" unless part
radius = options.fetch(:radius, 100)
omission = options.fetch(:omission, "...")
part = part.split(separator)
part.delete("")
affix = part.size > radius ? omission : ""
part = if part_position == :first
drop_index = [part.length - radius, 0].max
part.drop(drop_index)
else
part.first(radius)
end
return affix, part.join(separator)
end
end
|