first commit
This commit is contained in:
459
components/com_jce/editor/extensions/search/link.php
Normal file
459
components/com_jce/editor/extensions/search/link.php
Normal file
@@ -0,0 +1,459 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2009-2022 Ryan Demmer. All rights reserved
|
||||
* @license GNU/GPL 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* JCE is free software. This version may have been modified pursuant
|
||||
* to the GNU General Public License, and as distributed it includes or
|
||||
* is derivative of works licensed under the GNU General Public License or
|
||||
* other free or open source software licenses
|
||||
*/
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
use Joomla\String\StringHelper;
|
||||
|
||||
class WFLinkSearchExtension extends WFSearchExtension
|
||||
{
|
||||
private $enabled = array();
|
||||
|
||||
protected function loadDefaultAdapter($plugin)
|
||||
{
|
||||
$app = JFactory::getApplication();
|
||||
|
||||
// create component name from plugin - special case for "contacts"
|
||||
$component = ($plugin == 'contacts') ? 'com_contact' : 'com_' . $plugin;
|
||||
|
||||
// check for associated component
|
||||
if (!JComponentHelper::isEnabled($component)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$adapter = __DIR__ . '/adapter/' . $plugin . '/' . $plugin . '.php';
|
||||
|
||||
if (!is_file($adapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
require_once $adapter;
|
||||
|
||||
// create classname, eg: PlgSearchContent
|
||||
$className = 'PlgWfSearch' . ucfirst($plugin);
|
||||
|
||||
if (!class_exists($className)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// simple plugin config
|
||||
$config = array(
|
||||
'name' => $plugin,
|
||||
'type' => 'search',
|
||||
'params' => array(
|
||||
'search_limit' => 10
|
||||
),
|
||||
);
|
||||
|
||||
// Joomla 4
|
||||
if (method_exists($app, 'getDispatcher')) {
|
||||
$dispatcher = $app->getDispatcher();
|
||||
$instance = new $className($dispatcher, (array) $config);
|
||||
$instance->registerListeners();
|
||||
} else {
|
||||
$dispatcher = JEventDispatcher::getInstance();
|
||||
$instance = new $className($dispatcher, (array) $config);
|
||||
}
|
||||
|
||||
$this->enabled[] = $plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor activating the default information of the class.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$request = WFRequest::getInstance();
|
||||
|
||||
$request->setRequest(array($this, 'doSearch'));
|
||||
$request->setRequest(array($this, 'getAreas'));
|
||||
|
||||
$wf = WFEditorPlugin::getInstance();
|
||||
|
||||
// get plugins
|
||||
$plugins = $wf->getParam('search.link.plugins', array());
|
||||
|
||||
// set defaults if empty
|
||||
if (empty($plugins)) {
|
||||
$plugins = array('categories', 'contacts', 'content', 'tags');
|
||||
}
|
||||
|
||||
// list core adapters
|
||||
$adapters = array('categories', 'contacts', 'content', 'tags', 'weblinks');
|
||||
|
||||
// check and load external search plugins
|
||||
foreach ($plugins as $plugin) {
|
||||
// process core search plugins
|
||||
if (in_array($plugin, $adapters)) {
|
||||
$this->loadDefaultAdapter($plugin);
|
||||
continue;
|
||||
}
|
||||
|
||||
// plugin must be enabled
|
||||
if (!JPluginHelper::isEnabled('search', $plugin)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check plugin imports correctly - plugin may have a db entry, but is missing files
|
||||
if (JPluginHelper::importPlugin('search', $plugin)) {
|
||||
$this->enabled[] = $plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function display()
|
||||
{
|
||||
parent::display();
|
||||
|
||||
$document = WFDocument::getInstance();
|
||||
$document->addScript(array('link'), 'extensions.search.js');
|
||||
$document->addStylesheet(array('link'), 'extensions.search.css');
|
||||
}
|
||||
|
||||
public function isEnabled()
|
||||
{
|
||||
$wf = WFEditorPlugin::getInstance();
|
||||
return (bool) $wf->getParam('search.link.enable', 1) && !empty($this->enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the search areas.
|
||||
*/
|
||||
public function getAreas()
|
||||
{
|
||||
$app = JFactory::getApplication('site');
|
||||
|
||||
$areas = array();
|
||||
$results = array();
|
||||
|
||||
$searchareas = $app->triggerEvent('onContentSearchAreas');
|
||||
|
||||
foreach ($searchareas as $area) {
|
||||
if (is_array($area)) {
|
||||
$areas = array_merge($areas, $area);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($areas as $k => $v) {
|
||||
$results[$k] = JText::_($v);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/*
|
||||
* Truncate search text
|
||||
* This method uses portions of components/com_finder/views/search/tmpl/default_result.php
|
||||
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
|
||||
*/
|
||||
private function truncateText($text, $searchword)
|
||||
{
|
||||
// Calculate number of characters to display around the result
|
||||
$term_length = StringHelper::strlen($searchword);
|
||||
|
||||
$lang = JFactory::getLanguage();
|
||||
$desc_length = $lang->getSearchDisplayedCharactersNumber();
|
||||
|
||||
$pad_length = $term_length < $desc_length ? (int) floor(($desc_length - $term_length) / 2) : 0;
|
||||
|
||||
// Find the position of the search term
|
||||
$pos = $term_length ? StringHelper::strpos(StringHelper::strtolower($text), StringHelper::strtolower($searchword)) : false;
|
||||
|
||||
// Find a potential start point
|
||||
$start = ($pos && $pos > $pad_length) ? $pos - $pad_length : 0;
|
||||
|
||||
// Find a space between $start and $pos, start right after it.
|
||||
$space = StringHelper::strpos($text, ' ', $start > 0 ? $start - 1 : 0);
|
||||
$start = ($space && $space < $pos) ? $space + 1 : $start;
|
||||
|
||||
$text = JHtml::_('string.truncate', StringHelper::substr($text, $start), $desc_length, false);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare search content by clean and truncating
|
||||
* This method uses portions of SearchHelper::prepareSearchContent from administrator/components/com_search/helpers/search.php
|
||||
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
|
||||
*/
|
||||
public function prepareSearchContent($text, $searchword)
|
||||
{
|
||||
// Replace line breaking tags with whitespace.
|
||||
$text = preg_replace("'<(br[^/>]*?/|hr[^/>]*?/|/(div|h[1-6]|li|p|td))>'si", ' ', $text);
|
||||
|
||||
// clean text
|
||||
$text = htmlspecialchars(strip_tags($text));
|
||||
|
||||
// remove shortcode
|
||||
$text = preg_replace('#{.+?}#', '', $text);
|
||||
|
||||
// truncate text based around searchword
|
||||
$text = $this->truncateText($text, $searchword);
|
||||
|
||||
// highlight searchword
|
||||
$text = preg_replace('#\b(' . preg_quote($searchword, '#') . ')\b#i', '<mark>$1</mark>', $text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/*
|
||||
* Render Search fields
|
||||
* This method uses portions of SearchViewSearch::display from components/com_search/views/search/view.html.php
|
||||
* @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
public function render()
|
||||
{
|
||||
if (!$this->isEnabled()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// built select lists
|
||||
$orders = array();
|
||||
$orders[] = JHtml::_('select.option', 'newest', JText::_('WF_SEARCH_NEWEST_FIRST'));
|
||||
$orders[] = JHtml::_('select.option', 'oldest', JText::_('WF_SEARCH_OLDEST_FIRST'));
|
||||
$orders[] = JHtml::_('select.option', 'popular', JText::_('WF_SEARCH_MOST_POPULAR'));
|
||||
$orders[] = JHtml::_('select.option', 'alpha', JText::_('WF_SEARCH_ALPHABETICAL'));
|
||||
$orders[] = JHtml::_('select.option', 'category', JText::_('WF_CATEGORY'));
|
||||
|
||||
$lists = array();
|
||||
$lists['ordering'] = JHtml::_('select.genericlist', $orders, 'ordering', 'class="inputbox"', 'value', 'text');
|
||||
|
||||
$searchphrases = array();
|
||||
$searchphrases[] = JHtml::_('select.option', 'all', JText::_('WF_SEARCH_ALL_WORDS'));
|
||||
$searchphrases[] = JHtml::_('select.option', 'any', JText::_('WF_SEARCH_ANY_WORDS'));
|
||||
$searchphrases[] = JHtml::_('select.option', 'exact', JText::_('WF_SEARCH_EXACT_PHRASE'));
|
||||
$lists['searchphrase'] = JHtml::_('select.radiolist', $searchphrases, 'searchphrase', '', 'value', 'text', 'all');
|
||||
|
||||
$view = $this->getView(array('name' => 'search', 'layout' => 'search'));
|
||||
|
||||
$view->searchareas = self::getAreas();
|
||||
$view->lists = $lists;
|
||||
|
||||
$view->display();
|
||||
}
|
||||
|
||||
private static function getSearchAreaFromUrl($url)
|
||||
{
|
||||
$query = parse_url($url, PHP_URL_QUERY);
|
||||
|
||||
if (empty($query)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
parse_str($query, $values);
|
||||
|
||||
if (!array_key_exists('option', $values)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
$language = JFactory::getLanguage();
|
||||
|
||||
$option = $values['option'];
|
||||
|
||||
// load system language file
|
||||
$language->load($option . '.sys', JPATH_ADMINISTRATOR);
|
||||
$language->load($option, JPATH_ADMINISTRATOR);
|
||||
|
||||
return JText::_($option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process search.
|
||||
*
|
||||
* @param type $query Search query
|
||||
* @return array Search Results
|
||||
*
|
||||
* This method uses portions of SearchController::search from components/com_search/controller.php
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved
|
||||
*/
|
||||
public function doSearch($query)
|
||||
{
|
||||
$wf = WFEditorPlugin::getInstance();
|
||||
|
||||
$results = array();
|
||||
|
||||
if (empty($query)) {
|
||||
return $results;
|
||||
}
|
||||
|
||||
// search area
|
||||
$area = null;
|
||||
|
||||
// available search areas
|
||||
$areas = $this->getAreas();
|
||||
|
||||
// query using a specific plugin
|
||||
if (strpos($query, ':') !== false) {
|
||||
preg_match('#^(' . implode('|', $areas) . ')\:(.+)#', $query, $matches);
|
||||
|
||||
if ($matches) {
|
||||
$area = array($matches[1]);
|
||||
$query = $matches[2];
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists('JSite')) {
|
||||
// Load JSite class
|
||||
JLoader::register('JSite', JPATH_SITE . '/includes/application.php');
|
||||
}
|
||||
|
||||
$app = JFactory::getApplication('site');
|
||||
$filter = JFilterInput::getInstance();
|
||||
$router = $app::getRouter('site');
|
||||
|
||||
// get router mode
|
||||
$sef = (int) $wf->getParam('search.link.sef_url', 0);
|
||||
|
||||
$limit = (int) $wf->getParam('search.link.limit', 50);
|
||||
|
||||
// set router off so a raw url is returned by the Search plugin
|
||||
if ($router) {
|
||||
//$router->setMode(0);
|
||||
}
|
||||
|
||||
// slashes cause errors, <> get stripped anyway later on. # causes problems.
|
||||
$searchword = trim(str_replace(array('#', '>', '<', '\\'), '', $filter->clean($query)));
|
||||
|
||||
$ordering = null;
|
||||
$searchphrase = 'all';
|
||||
|
||||
// if searchword enclosed in double quotes, strip quotes and do exact match
|
||||
if (substr($searchword, 0, 1) == '"' && substr($searchword, -1) == '"') {
|
||||
$searchword = substr($searchword, 1, -1);
|
||||
$searchphrase = 'exact';
|
||||
}
|
||||
|
||||
$searchphrase = $app->input->post->getWord('searchphrase', $searchphrase);
|
||||
|
||||
// get passed through ordering
|
||||
$ordering = $app->input->post->getWord('ordering', $ordering);
|
||||
|
||||
// get passed through area
|
||||
$area = $app->input->post->getCmd('areas', (array) $area);
|
||||
|
||||
if (empty($area)) {
|
||||
$area = null;
|
||||
}
|
||||
|
||||
// trigger search on loaded plugins
|
||||
$searches = $app->triggerEvent('onContentSearch', array(
|
||||
$searchword,
|
||||
$searchphrase,
|
||||
$ordering,
|
||||
$area,
|
||||
));
|
||||
|
||||
$rows = array();
|
||||
|
||||
foreach ($searches as $search) {
|
||||
$rows = array_merge((array) $rows, (array) $search);
|
||||
}
|
||||
|
||||
// get first 10
|
||||
$rows = array_slice($rows, 0, $limit);
|
||||
|
||||
$areas = array();
|
||||
|
||||
for ($i = 0, $count = count($rows); $i < $count; ++$i) {
|
||||
$row = &$rows[$i];
|
||||
|
||||
if (empty($row->href) || empty($row->title)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$area = isset($row->section) ? $row->section : self::getSearchAreaFromUrl($row->href);
|
||||
|
||||
if (!isset($areas[$area])) {
|
||||
$areas[$area] = array();
|
||||
}
|
||||
|
||||
$result = new StdClass;
|
||||
|
||||
if ($searchphrase == 'exact') {
|
||||
$searchwords = array($searchword);
|
||||
$needle = $searchword;
|
||||
} else {
|
||||
$searchworda = preg_replace('#\xE3\x80\x80#s', ' ', $searchword);
|
||||
$searchwords = preg_split("/\s+/u", $searchworda);
|
||||
$needle = $searchwords[0];
|
||||
}
|
||||
|
||||
// get anchors if any...
|
||||
$row->anchors = self::getAnchors($row->text);
|
||||
|
||||
// prepare and truncate search text
|
||||
$row->text = $this->prepareSearchContent($row->text, $needle);
|
||||
|
||||
// remove base url
|
||||
if (JURI::base(true) && strpos($row->href, JURI::base(true)) !== false) {
|
||||
$row->href = substr_replace($row->href, '', 0, strlen(JURI::base(true)) + 1);
|
||||
}
|
||||
|
||||
// remove the alias or ItemId from a link
|
||||
$row->href = self::route($row->href);
|
||||
|
||||
$result->title = $row->title;
|
||||
$result->text = $row->text;
|
||||
$result->link = $row->href;
|
||||
|
||||
if (!empty($row->anchors)) {
|
||||
$result->anchors = $row->anchors;
|
||||
}
|
||||
|
||||
$areas[$area][] = $result;
|
||||
}
|
||||
|
||||
if (!empty($areas)) {
|
||||
$results[] = $areas;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
private static function route($url)
|
||||
{
|
||||
$wf = WFEditorPlugin::getInstance();
|
||||
|
||||
if ((bool) $wf->getParam('search.link.remove_alias', 0)) {
|
||||
$url = WFLinkHelper::route($url);
|
||||
}
|
||||
|
||||
// remove Itemid if "home"
|
||||
$url = WFLinkHelper::removeHomeItemId($url);
|
||||
|
||||
// remove Itemid if set
|
||||
if ((bool) $wf->getParam('search.link.itemid', 1) === false) {
|
||||
$url = WFLinkHelper::removeItemId($url);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
private static function getAnchors($content)
|
||||
{
|
||||
preg_match_all('#<a([^>]+)(name|id)="([a-z]+[\w\-\:\.]*)"([^>]*)>#i', $content, $matches, PREG_SET_ORDER);
|
||||
|
||||
$anchors = array();
|
||||
|
||||
if (!empty($matches)) {
|
||||
foreach ($matches as $match) {
|
||||
if (strpos($match[0], 'href') === false) {
|
||||
$anchors[] = $match[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $anchors;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user