diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/general_controller.rb | 2 | ||||
-rw-r--r-- | app/controllers/track_controller.rb | 10 | ||||
-rw-r--r-- | app/helpers/application_helper.rb | 22 | ||||
-rw-r--r-- | app/helpers/highlight_helper.rb | 98 | ||||
-rw-r--r-- | app/views/track_mailer/event_digest.text.erb | 2 |
5 files changed, 112 insertions, 22 deletions
diff --git a/app/controllers/general_controller.rb b/app/controllers/general_controller.rb index 28055ddbf..158492eb2 100644 --- a/app/controllers/general_controller.rb +++ b/app/controllers/general_controller.rb @@ -159,7 +159,7 @@ class GeneralController < ApplicationController end # Spelling and highight words are same for all three queries - @highlight_words = @request_for_spelling.words_to_highlight + @highlight_words = @request_for_spelling.words_to_highlight(:regex => true, :include_original => true) if !(@request_for_spelling.spelling_correction =~ /[a-z]+:/) @spelling_correction = @request_for_spelling.spelling_correction end diff --git a/app/controllers/track_controller.rb b/app/controllers/track_controller.rb index c15fb573d..83700a55b 100644 --- a/app/controllers/track_controller.rb +++ b/app/controllers/track_controller.rb @@ -154,7 +154,15 @@ class TrackController < ApplicationController request.format = 'xml' unless params[:format] respond_to do |format| format.json { render :json => @xapian_object.results.map { |r| r[:model].json_for_api(true, - lambda { |t| view_context.highlight_and_excerpt(t, @xapian_object.words_to_highlight, 150) } + lambda do |t| + view_context.highlight_and_excerpt( + t, + @xapian_object.words_to_highlight( + :regex => true, + :include_original => true), + 150 + ) + end ) } } format.any { render :template => 'track/atom_feed', :formats => ['atom'], diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 45b042354..49ce94951 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -22,6 +22,9 @@ module ApplicationHelper # Useful for sending emails include MailerHelper + # Extra highlight helpers + include HighlightHelper + # Copied from error_messages_for in active_record_helper.rb def foi_error_messages_for(*params) options = params.last.is_a?(Hash) ? params.pop.symbolize_keys : {} @@ -54,25 +57,6 @@ module ApplicationHelper end end - # Highlight words, also escapes HTML (other than spans that we add) - def highlight_words(t, words, html = true) - if html - highlight(h(t), words, :highlighter => '<span class="highlight">\1</span>').html_safe - else - highlight(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 locale_name(locale) return LanguageNames::get_language_name(locale) end diff --git a/app/helpers/highlight_helper.rb b/app/helpers/highlight_helper.rb new file mode 100644 index 000000000..a98f6f320 --- /dev/null +++ b/app/helpers/highlight_helper.rb @@ -0,0 +1,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 diff --git a/app/views/track_mailer/event_digest.text.erb b/app/views/track_mailer/event_digest.text.erb index a154f430f..f6e699e41 100644 --- a/app/views/track_mailer/event_digest.text.erb +++ b/app/views/track_mailer/event_digest.text.erb @@ -4,7 +4,7 @@ for track_thing, alert_results, xapian_object in @email_about_things main_text += track_thing.params[:title_in_email] + "\n" main_text += ("=" * track_thing.params[:title_in_email].size) + "\n\n" - @highlight_words = xapian_object.words_to_highlight + @highlight_words = xapian_object.words_to_highlight(:regex => true) for result in alert_results.reverse if result[:model].class.to_s == "InfoRequestEvent" event = result[:model] |