From dd90eb2c7a1164ed8924c83c13138d568db5ea4e Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Wed, 31 Jul 2013 14:53:34 +0400 Subject: [PATCH] search keyword highlighting (combined mode only) --- classes/feeds.php | 3 ++- css/tt-rss.css | 5 +++++ include/functions.php | 51 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/classes/feeds.php b/classes/feeds.php index 0849a7a8..874f7678 100644 --- a/classes/feeds.php +++ b/classes/feeds.php @@ -255,6 +255,7 @@ class Feeds extends Handler_Protected { $last_error = $qfh_ret[3]; $last_updated = strpos($qfh_ret[4], '1970-') === FALSE ? make_local_datetime($qfh_ret[4], false) : __("Never"); + $highlight_words = $qfh_ret[5]; $vgroup_last_feed = $vgr_last_feed; @@ -509,7 +510,7 @@ class Feeds extends Handler_Protected { $tags = false; $line["content"] = sanitize($line["content"], - sql_bool_to_bool($line['hide_images']), false, $entry_site_url); + sql_bool_to_bool($line['hide_images']), false, $entry_site_url, $highlight_words); foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_CDM) as $p) { $line = $p->hook_render_article_cdm($line); diff --git a/css/tt-rss.css b/css/tt-rss.css index c79e28ad..e7514956 100644 --- a/css/tt-rss.css +++ b/css/tt-rss.css @@ -1168,3 +1168,8 @@ body#ttrssPrefs hr { position : relative; top : -2px; } + +span.highlight { + background-color : #ffff00; + color : #cc90cc; +} diff --git a/include/functions.php b/include/functions.php index deeb53bf..6ceb20ad 100644 --- a/include/functions.php +++ b/include/functions.php @@ -2204,6 +2204,7 @@ $keywords = explode(" ", $search); $query_keywords = array(); + $search_words = array(); foreach ($keywords as $k) { if (strpos($k, "-") === 0) { @@ -2223,6 +2224,7 @@ } else { array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + array_push($search_words, $k); } break; case "author": @@ -2232,6 +2234,7 @@ } else { array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + array_push($search_words, $k); } break; case "note": @@ -2246,6 +2249,7 @@ } else { array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + if (!$not) array_push($search_words, $k); } break; case "star": @@ -2258,6 +2262,7 @@ } else { array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + if (!$not) array_push($search_words, $k); } break; case "pub": @@ -2270,6 +2275,7 @@ } else { array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + if (!$not) array_push($search_words, $k); } break; default: @@ -2285,13 +2291,15 @@ } else { array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + + if (!$not) array_push($search_words, $k); } } } $search_query_part = implode("AND", $query_keywords); - return $search_query_part; + return array($search_query_part, $search_words); } function getParentCategories($cat, $owner_uid) { @@ -2327,6 +2335,7 @@ if (!$owner_uid) $owner_uid = $_SESSION["uid"]; $ext_tables_part = ""; + $search_words = array(); if ($search) { @@ -2339,7 +2348,7 @@ $search_query_part = "ref_id = -1 AND "; } else { - $search_query_part = search_to_sql($search); + list($search_query_part, $search_words) = search_to_sql($search); $search_query_part .= " AND "; } @@ -2747,11 +2756,11 @@ $result = db_query($select_qpart . $from_qpart . $where_qpart); } - return array($result, $feed_title, $feed_site_url, $last_error, $last_updated); + return array($result, $feed_title, $feed_site_url, $last_error, $last_updated, $search_words); } - function sanitize($str, $force_remove_images = false, $owner = false, $site_url = false) { + function sanitize($str, $force_remove_images = false, $owner = false, $site_url = false, $highlight_words = false) { if (!$owner) $owner = $_SESSION["uid"]; $res = trim($str); if (!$res) return ''; @@ -2852,7 +2861,41 @@ $doc->removeChild($doc->firstChild); //remove doctype $doc = strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes); + + if ($highlight_words) { + foreach ($highlight_words as $word) { + + $elements = $xpath->query('//*[contains(.,"'.$word.'")]'); + + foreach ($elements as $element) { + foreach ($element->childNodes as $child) { + + if (!$child instanceof DomText) continue; + + $fragment = $doc->createDocumentFragment(); + $text = $child->textContent; + $stubs = array(); + + while (($pos = stripos($text, $word)) !== false) { + $fragment->appendChild(new DomText(substr($text, 0, $pos))); + $word = substr($text, $pos, strlen($word)); + $highlight = $doc->createElement('span'); + $highlight->appendChild(new DomText($word)); + $highlight->setAttribute('class', 'highlight'); + $fragment->appendChild($highlight); + $text = substr($text, $pos + strlen($word)); + } + + if (!empty($text)) $fragment->appendChild(new DomText($text)); + + $element->replaceChild($fragment, $child); + } + } + } + } + $res = $doc->saveHTML(); + return $res; } -- 2.39.5