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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
from django import template
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from haystack.utils import importlib
register = template.Library()
class HighlightNode(template.Node):
def __init__(
self, text_block, query, html_tag=None, css_class=None, max_length=None
):
self.text_block = template.Variable(text_block)
self.query = template.Variable(query)
self.html_tag = html_tag
self.css_class = css_class
self.max_length = max_length
if html_tag is not None:
self.html_tag = template.Variable(html_tag)
if css_class is not None:
self.css_class = template.Variable(css_class)
if max_length is not None:
self.max_length = template.Variable(max_length)
def render(self, context):
text_block = self.text_block.resolve(context)
query = self.query.resolve(context)
kwargs = {}
if self.html_tag is not None:
kwargs["html_tag"] = self.html_tag.resolve(context)
if self.css_class is not None:
kwargs["css_class"] = self.css_class.resolve(context)
if self.max_length is not None:
kwargs["max_length"] = self.max_length.resolve(context)
# Handle a user-defined highlighting function.
if (
hasattr(settings, "HAYSTACK_CUSTOM_HIGHLIGHTER")
and settings.HAYSTACK_CUSTOM_HIGHLIGHTER
):
# Do the import dance.
try:
path_bits = settings.HAYSTACK_CUSTOM_HIGHLIGHTER.split(".")
highlighter_path, highlighter_classname = (
".".join(path_bits[:-1]),
path_bits[-1],
)
highlighter_module = importlib.import_module(highlighter_path)
highlighter_class = getattr(highlighter_module, highlighter_classname)
except (ImportError, AttributeError) as e:
raise ImproperlyConfigured(
"The highlighter '%s' could not be imported: %s"
% (settings.HAYSTACK_CUSTOM_HIGHLIGHTER, e)
)
else:
from haystack.utils.highlighting import Highlighter
highlighter_class = Highlighter
highlighter = highlighter_class(query, **kwargs)
highlighted_text = highlighter.highlight(text_block)
return highlighted_text
@register.tag
def highlight(parser, token):
"""
Takes a block of text and highlights words from a provided query within that
block of text. Optionally accepts arguments to provide the HTML tag to wrap
highlighted word in, a CSS class to use with the tag and a maximum length of
the blurb in characters.
Syntax::
{% highlight <text_block> with <query> [css_class "class_name"] [html_tag "span"] [max_length 200] %}
Example::
# Highlight summary with default behavior.
{% highlight result.summary with request.query %}
# Highlight summary but wrap highlighted words with a div and the
# following CSS class.
{% highlight result.summary with request.query html_tag "div" css_class "highlight_me_please" %}
# Highlight summary but only show 40 characters.
{% highlight result.summary with request.query max_length 40 %}
"""
bits = token.split_contents()
tag_name = bits[0]
if not len(bits) % 2 == 0:
raise template.TemplateSyntaxError(
"'%s' tag requires valid pairings arguments." % tag_name
)
text_block = bits[1]
if len(bits) < 4:
raise template.TemplateSyntaxError(
"'%s' tag requires an object and a query provided by 'with'." % tag_name
)
if bits[2] != "with":
raise template.TemplateSyntaxError(
"'%s' tag's second argument should be 'with'." % tag_name
)
query = bits[3]
arg_bits = iter(bits[4:])
kwargs = {}
for bit in arg_bits:
if bit == "css_class":
kwargs["css_class"] = next(arg_bits)
if bit == "html_tag":
kwargs["html_tag"] = next(arg_bits)
if bit == "max_length":
kwargs["max_length"] = next(arg_bits)
return HighlightNode(text_block, query, **kwargs)
|