first commit
This commit is contained in:
29
components/com_finder/helpers/route.php
Normal file
29
components/com_finder/helpers/route.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*
|
||||
* @phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
|
||||
*/
|
||||
|
||||
use Joomla\Component\Finder\Site\Helper\RouteHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Finder route helper class.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @deprecated 4.3 will be removed in 6.0
|
||||
* Use \Joomla\Component\Finder\Site\Helper\RouteHelper instead
|
||||
*/
|
||||
class FinderHelperRoute extends RouteHelper
|
||||
{
|
||||
}
|
||||
62
components/com_finder/src/Controller/DisplayController.php
Normal file
62
components/com_finder/src/Controller/DisplayController.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Finder\Site\Controller;
|
||||
|
||||
use Joomla\CMS\MVC\Controller\BaseController;
|
||||
use Joomla\Component\Finder\Administrator\Helper\LanguageHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Finder Component Controller.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
class DisplayController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Method to display a view.
|
||||
*
|
||||
* @param boolean $cachable If true, the view output will be cached. [optional]
|
||||
* @param array $urlparams An array of safe URL parameters and their variable types. Optional.
|
||||
* @see \Joomla\CMS\Filter\InputFilter::clean() for valid values.
|
||||
*
|
||||
* @return static This object is to support chaining.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public function display($cachable = false, $urlparams = [])
|
||||
{
|
||||
$input = $this->app->getInput();
|
||||
$cachable = true;
|
||||
|
||||
// Load plugin language files.
|
||||
LanguageHelper::loadPluginLanguage();
|
||||
|
||||
// Set the default view name and format from the Request.
|
||||
$viewName = $input->get('view', 'search', 'word');
|
||||
$input->set('view', $viewName);
|
||||
|
||||
// Don't cache view for search queries
|
||||
if ($input->get('q', null, 'string') || $input->get('f', null, 'int') || $input->get('t', null, 'array')) {
|
||||
$cachable = false;
|
||||
}
|
||||
|
||||
$safeurlparams = [
|
||||
'f' => 'INT',
|
||||
'lang' => 'CMD',
|
||||
];
|
||||
|
||||
return parent::display($cachable, $safeurlparams);
|
||||
}
|
||||
}
|
||||
101
components/com_finder/src/Controller/SuggestionsController.php
Normal file
101
components/com_finder/src/Controller/SuggestionsController.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Finder\Site\Controller;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\MVC\Controller\BaseController;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Suggestions \JSON controller for Finder.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
class SuggestionsController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Method to find search query suggestions. Uses awesomplete
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public function suggest()
|
||||
{
|
||||
$app = $this->app;
|
||||
$app->mimeType = 'application/json';
|
||||
|
||||
// Ensure caching is disabled as it depends on the query param in the model
|
||||
$app->allowCache(false);
|
||||
|
||||
$suggestions = $this->getSuggestions();
|
||||
|
||||
// Send the response.
|
||||
$app->setHeader('Content-Type', $app->mimeType . '; charset=' . $app->charSet);
|
||||
$app->sendHeaders();
|
||||
echo '{ "suggestions": ' . json_encode($suggestions) . ' }';
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to find search query suggestions for OpenSearch
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function opensearchsuggest()
|
||||
{
|
||||
$app = $this->app;
|
||||
$app->mimeType = 'application/json';
|
||||
$result = [];
|
||||
$result[] = $app->getInput()->request->get('q', '', 'string');
|
||||
|
||||
$result[] = $this->getSuggestions();
|
||||
|
||||
// Ensure caching is disabled as it depends on the query param in the model
|
||||
$app->allowCache(false);
|
||||
|
||||
// Send the response.
|
||||
$app->setHeader('Content-Type', $app->mimeType . '; charset=' . $app->charSet);
|
||||
$app->sendHeaders();
|
||||
echo json_encode($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to retrieve the data from the database
|
||||
*
|
||||
* @return array The suggested words
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
protected function getSuggestions()
|
||||
{
|
||||
$return = [];
|
||||
|
||||
$params = ComponentHelper::getParams('com_finder');
|
||||
|
||||
if ($params->get('show_autosuggest', 1)) {
|
||||
// Get the suggestions.
|
||||
$model = $this->getModel('Suggestions');
|
||||
$return = $model->getItems();
|
||||
}
|
||||
|
||||
// Check the data.
|
||||
if (empty($return)) {
|
||||
$return = [];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
101
components/com_finder/src/Helper/FinderHelper.php
Normal file
101
components/com_finder/src/Helper/FinderHelper.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Finder\Site\Helper;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\Component\Finder\Administrator\Indexer\Query;
|
||||
use Joomla\Database\ParameterType;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Helper class for Joomla! Finder components
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class FinderHelper
|
||||
{
|
||||
/**
|
||||
* Method to log searches to the database
|
||||
*
|
||||
* @param Query $searchquery The search query
|
||||
* @param integer $resultCount The number of results for this search
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public static function logSearch(Query $searchquery, $resultCount = 0)
|
||||
{
|
||||
if (!ComponentHelper::getParams('com_finder')->get('gather_search_statistics', 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (trim($searchquery->input) == '' && !$searchquery->empty) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialise our variables
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true);
|
||||
|
||||
// Sanitise the term for the database
|
||||
$temp = new \stdClass();
|
||||
$temp->input = trim(strtolower((string) $searchquery->input));
|
||||
$entry = new \stdClass();
|
||||
$entry->searchterm = $temp->input;
|
||||
$entry->query = serialize($temp);
|
||||
$entry->md5sum = md5($entry->query);
|
||||
$entry->hits = 1;
|
||||
$entry->results = $resultCount;
|
||||
|
||||
// Query the table to determine if the term has been searched previously
|
||||
$query->select($db->quoteName('hits'))
|
||||
->from($db->quoteName('#__finder_logging'))
|
||||
->where($db->quoteName('md5sum') . ' = ' . $db->quote($entry->md5sum));
|
||||
$db->setQuery($query);
|
||||
$hits = (int) $db->loadResult();
|
||||
|
||||
// Reset the $query object
|
||||
$query->clear();
|
||||
|
||||
// Update the table based on the results
|
||||
if ($hits) {
|
||||
$query->update($db->quoteName('#__finder_logging'))
|
||||
->set('hits = (hits + 1)')
|
||||
->where($db->quoteName('md5sum') . ' = ' . $db->quote($entry->md5sum));
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
} else {
|
||||
$query->insert($db->quoteName('#__finder_logging'))
|
||||
->columns(
|
||||
[
|
||||
$db->quoteName('searchterm'),
|
||||
$db->quoteName('query'),
|
||||
$db->quoteName('md5sum'),
|
||||
$db->quoteName('hits'),
|
||||
$db->quoteName('results'),
|
||||
]
|
||||
)
|
||||
->values('?, ?, ?, ?, ?')
|
||||
->bind(1, $entry->searchterm)
|
||||
->bind(2, $entry->query, ParameterType::LARGE_OBJECT)
|
||||
->bind(3, $entry->md5sum)
|
||||
->bind(4, $entry->hits, ParameterType::INTEGER)
|
||||
->bind(5, $entry->results, ParameterType::INTEGER);
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
154
components/com_finder/src/Helper/RouteHelper.php
Normal file
154
components/com_finder/src/Helper/RouteHelper.php
Normal file
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Finder\Site\Helper;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Finder route helper class.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
class RouteHelper
|
||||
{
|
||||
/**
|
||||
* Method to get the route for a search page.
|
||||
*
|
||||
* @param integer $f The search filter id. [optional]
|
||||
* @param string $q The search query string. [optional]
|
||||
*
|
||||
* @return string The search route.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public static function getSearchRoute($f = null, $q = null)
|
||||
{
|
||||
// Get the menu item id.
|
||||
$query = ['view' => 'search', 'q' => $q, 'f' => $f];
|
||||
$item = self::getItemid($query);
|
||||
|
||||
// Get the base route.
|
||||
$uri = clone Uri::getInstance('index.php?option=com_finder&view=search');
|
||||
|
||||
// Add the pre-defined search filter if present.
|
||||
if ($f !== null) {
|
||||
$uri->setVar('f', $f);
|
||||
}
|
||||
|
||||
// Add the search query string if present.
|
||||
if ($q !== null) {
|
||||
$uri->setVar('q', $q);
|
||||
}
|
||||
|
||||
// Add the menu item id if present.
|
||||
if ($item !== null) {
|
||||
$uri->setVar('Itemid', $item);
|
||||
}
|
||||
|
||||
return $uri->toString(['path', 'query']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the route for an advanced search page.
|
||||
*
|
||||
* @param integer $f The search filter id. [optional]
|
||||
* @param string $q The search query string. [optional]
|
||||
*
|
||||
* @return string The advanced search route.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public static function getAdvancedRoute($f = null, $q = null)
|
||||
{
|
||||
// Get the menu item id.
|
||||
$query = ['view' => 'advanced', 'q' => $q, 'f' => $f];
|
||||
$item = self::getItemid($query);
|
||||
|
||||
// Get the base route.
|
||||
$uri = clone Uri::getInstance('index.php?option=com_finder&view=advanced');
|
||||
|
||||
// Add the pre-defined search filter if present.
|
||||
if ($q !== null) {
|
||||
$uri->setVar('f', $f);
|
||||
}
|
||||
|
||||
// Add the search query string if present.
|
||||
if ($q !== null) {
|
||||
$uri->setVar('q', $q);
|
||||
}
|
||||
|
||||
// Add the menu item id if present.
|
||||
if ($item !== null) {
|
||||
$uri->setVar('Itemid', $item);
|
||||
}
|
||||
|
||||
return $uri->toString(['path', 'query']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the most appropriate menu item for the route based on the
|
||||
* supplied query needles.
|
||||
*
|
||||
* @param array $query An array of URL parameters.
|
||||
*
|
||||
* @return mixed An integer on success, null otherwise.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public static function getItemid($query)
|
||||
{
|
||||
static $items, $active;
|
||||
|
||||
// Get the menu items for com_finder.
|
||||
if (!$items || !$active) {
|
||||
$app = Factory::getApplication();
|
||||
$com = ComponentHelper::getComponent('com_finder');
|
||||
$menu = $app->getMenu();
|
||||
$active = $menu->getActive();
|
||||
$items = $menu->getItems('component_id', $com->id);
|
||||
$items = \is_array($items) ? $items : [];
|
||||
}
|
||||
|
||||
// Try to match the active view and filter.
|
||||
if ($active && @$active->query['view'] == @$query['view'] && @$active->query['f'] == @$query['f']) {
|
||||
return $active->id;
|
||||
}
|
||||
|
||||
// Try to match the view, query, and filter.
|
||||
foreach ($items as $item) {
|
||||
if (@$item->query['view'] == @$query['view'] && @$item->query['q'] == @$query['q'] && @$item->query['f'] == @$query['f']) {
|
||||
return $item->id;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to match the view and filter.
|
||||
foreach ($items as $item) {
|
||||
if (@$item->query['view'] == @$query['view'] && @$item->query['f'] == @$query['f']) {
|
||||
return $item->id;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to match the view.
|
||||
foreach ($items as $item) {
|
||||
if (@$item->query['view'] == @$query['view']) {
|
||||
return $item->id;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
584
components/com_finder/src/Model/SearchModel.php
Normal file
584
components/com_finder/src/Model/SearchModel.php
Normal file
@ -0,0 +1,584 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Finder\Site\Model;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Multilanguage;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Model\ListModel;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\Component\Finder\Administrator\Indexer\Query;
|
||||
use Joomla\String\StringHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Search model class for the Finder package.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
class SearchModel extends ListModel
|
||||
{
|
||||
/**
|
||||
* Context string for the model type
|
||||
*
|
||||
* @var string
|
||||
* @since 2.5
|
||||
*/
|
||||
protected $context = 'com_finder.search';
|
||||
|
||||
/**
|
||||
* The query object is an instance of Query which contains and
|
||||
* models the entire search query including the text input; static and
|
||||
* dynamic taxonomy filters; date filters; etc.
|
||||
*
|
||||
* @var Query
|
||||
* @since 2.5
|
||||
*/
|
||||
protected $searchquery;
|
||||
|
||||
/**
|
||||
* Maps each sorting field with a text label.
|
||||
*
|
||||
* @var string[]
|
||||
*
|
||||
* @since 4.3.0
|
||||
*/
|
||||
protected $sortOrderFieldsLabels = [
|
||||
'relevance.asc' => 'COM_FINDER_SORT_BY_RELEVANCE_ASC',
|
||||
'relevance.desc' => 'COM_FINDER_SORT_BY_RELEVANCE_DESC',
|
||||
'title.asc' => 'JGLOBAL_TITLE_ASC',
|
||||
'title.desc' => 'JGLOBAL_TITLE_DESC',
|
||||
'date.asc' => 'JDATE_ASC',
|
||||
'date.desc' => 'JDATE_DESC',
|
||||
'price.asc' => 'COM_FINDER_SORT_BY_PRICE_ASC',
|
||||
'price.desc' => 'COM_FINDER_SORT_BY_PRICE_DESC',
|
||||
'sale_price.asc' => 'COM_FINDER_SORT_BY_SALES_PRICE_ASC',
|
||||
'sale_price.desc' => 'COM_FINDER_SORT_BY_SALES_PRICE_DESC',
|
||||
];
|
||||
|
||||
/**
|
||||
* An array of all excluded terms ids.
|
||||
*
|
||||
* @var array
|
||||
* @since 2.5
|
||||
*/
|
||||
protected $excludedTerms = [];
|
||||
|
||||
/**
|
||||
* An array of all included terms ids.
|
||||
*
|
||||
* @var array
|
||||
* @since 2.5
|
||||
*/
|
||||
protected $includedTerms = [];
|
||||
|
||||
/**
|
||||
* An array of all required terms ids.
|
||||
*
|
||||
* @var array
|
||||
* @since 2.5
|
||||
*/
|
||||
protected $requiredTerms = [];
|
||||
|
||||
/**
|
||||
* Method to get the results of the query.
|
||||
*
|
||||
* @return array An array of Result objects.
|
||||
*
|
||||
* @since 2.5
|
||||
* @throws \Exception on database error.
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
$items = parent::getItems();
|
||||
|
||||
// Check the data.
|
||||
if (empty($items)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$results = [];
|
||||
|
||||
// Convert the rows to result objects.
|
||||
foreach ($items as $rk => $row) {
|
||||
// Build the result object.
|
||||
if (\is_resource($row->object)) {
|
||||
$result = unserialize(stream_get_contents($row->object));
|
||||
} else {
|
||||
$result = unserialize($row->object);
|
||||
}
|
||||
|
||||
$result->cleanURL = $result->route;
|
||||
|
||||
// Add the result back to the stack.
|
||||
$results[] = $result;
|
||||
}
|
||||
|
||||
// Return the results.
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the query object.
|
||||
*
|
||||
* @return Query A query object.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
// Return the query object.
|
||||
return $this->searchquery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to build a database query to load the list data.
|
||||
*
|
||||
* @return \Joomla\Database\DatabaseQuery A database query.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
protected function getListQuery()
|
||||
{
|
||||
// Create a new query object.
|
||||
$db = $this->getDatabase();
|
||||
$query = $db->getQuery(true);
|
||||
|
||||
// Select the required fields from the table.
|
||||
$query->select(
|
||||
$this->getState(
|
||||
'list.select',
|
||||
'l.link_id, l.object'
|
||||
)
|
||||
);
|
||||
|
||||
$query->from('#__finder_links AS l');
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
$groups = $this->getState('user.groups', $user->getAuthorisedViewLevels());
|
||||
$query->whereIn($db->quoteName('l.access'), $groups)
|
||||
->where('l.state = 1')
|
||||
->where('l.published = 1');
|
||||
|
||||
// Get the current date, minus seconds.
|
||||
$nowDate = $db->quote(substr_replace(Factory::getDate()->toSql(), '00', -2));
|
||||
|
||||
// Add the publish up and publish down filters.
|
||||
$query->where('(l.publish_start_date IS NULL OR l.publish_start_date <= ' . $nowDate . ')')
|
||||
->where('(l.publish_end_date IS NULL OR l.publish_end_date >= ' . $nowDate . ')');
|
||||
|
||||
$query->group('l.link_id');
|
||||
$query->group('l.object');
|
||||
|
||||
/*
|
||||
* Add the taxonomy filters to the query. We have to join the taxonomy
|
||||
* map table for each group so that we can use AND clauses across
|
||||
* groups. Within each group there can be an array of values that will
|
||||
* use OR clauses.
|
||||
*/
|
||||
if (!empty($this->searchquery->filters)) {
|
||||
// Convert the associative array to a numerically indexed array.
|
||||
$groups = array_values($this->searchquery->filters);
|
||||
$taxonomies = \call_user_func_array('array_merge', array_values($this->searchquery->filters));
|
||||
|
||||
$query->join('INNER', $db->quoteName('#__finder_taxonomy_map') . ' AS t ON t.link_id = l.link_id')
|
||||
->where('t.node_id IN (' . implode(',', array_unique($taxonomies)) . ')');
|
||||
|
||||
// Iterate through each taxonomy group.
|
||||
for ($i = 0, $c = \count($groups); $i < $c; $i++) {
|
||||
$query->having('SUM(CASE WHEN t.node_id IN (' . implode(',', $groups[$i]) . ') THEN 1 ELSE 0 END) > 0');
|
||||
}
|
||||
}
|
||||
|
||||
// Add the start date filter to the query.
|
||||
if (!empty($this->searchquery->date1)) {
|
||||
// Escape the date.
|
||||
$date1 = $db->quote($this->searchquery->date1);
|
||||
|
||||
// Add the appropriate WHERE condition.
|
||||
if ($this->searchquery->when1 === 'before') {
|
||||
$query->where($db->quoteName('l.start_date') . ' <= ' . $date1);
|
||||
} elseif ($this->searchquery->when1 === 'after') {
|
||||
$query->where($db->quoteName('l.start_date') . ' >= ' . $date1);
|
||||
} else {
|
||||
$query->where($db->quoteName('l.start_date') . ' = ' . $date1);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the end date filter to the query.
|
||||
if (!empty($this->searchquery->date2)) {
|
||||
// Escape the date.
|
||||
$date2 = $db->quote($this->searchquery->date2);
|
||||
|
||||
// Add the appropriate WHERE condition.
|
||||
if ($this->searchquery->when2 === 'before') {
|
||||
$query->where($db->quoteName('l.start_date') . ' <= ' . $date2);
|
||||
} elseif ($this->searchquery->when2 === 'after') {
|
||||
$query->where($db->quoteName('l.start_date') . ' >= ' . $date2);
|
||||
} else {
|
||||
$query->where($db->quoteName('l.start_date') . ' = ' . $date2);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by language
|
||||
if ($this->getState('filter.language')) {
|
||||
$query->where('l.language IN (' . $db->quote(Factory::getLanguage()->getTag()) . ', ' . $db->quote('*') . ')');
|
||||
}
|
||||
|
||||
// Get the result ordering and direction.
|
||||
$ordering = $this->getState('list.ordering', 'm.weight');
|
||||
$direction = $this->getState('list.direction', 'DESC');
|
||||
|
||||
/*
|
||||
* If we are ordering by relevance we have to add up the relevance
|
||||
* scores that are contained in the ordering field.
|
||||
*/
|
||||
if ($ordering === 'm.weight') {
|
||||
// Get the base query and add the ordering information.
|
||||
$query->select('SUM(' . $db->escape($ordering) . ') AS ordering');
|
||||
} else {
|
||||
/**
|
||||
* If we are not ordering by relevance, we just have to add
|
||||
* the unique items to the set.
|
||||
*/
|
||||
// Get the base query and add the ordering information.
|
||||
$query->select($db->escape($ordering) . ' AS ordering');
|
||||
}
|
||||
|
||||
$query->order('ordering ' . $db->escape($direction));
|
||||
|
||||
/*
|
||||
* If there are no optional or required search terms in the query, we
|
||||
* can get the results in one relatively simple database query.
|
||||
*/
|
||||
if (empty($this->includedTerms) && $this->searchquery->empty && $this->searchquery->input == '') {
|
||||
// Return the results.
|
||||
return $query;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are no optional or required search terms in the query and
|
||||
* empty searches are not allowed, we return an empty query.
|
||||
* If the search term is not empty and empty searches are allowed,
|
||||
* but no terms were found, we return an empty query as well.
|
||||
*/
|
||||
if (
|
||||
empty($this->includedTerms)
|
||||
&& (!$this->searchquery->empty || ($this->searchquery->empty && $this->searchquery->input != ''))
|
||||
) {
|
||||
// Since we need to return a query, we simplify this one.
|
||||
$query->clear('join')
|
||||
->clear('where')
|
||||
->clear('bounded')
|
||||
->clear('having')
|
||||
->clear('group')
|
||||
->where('false');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
$included = \call_user_func_array('array_merge', array_values($this->includedTerms));
|
||||
$query->join('INNER', $db->quoteName('#__finder_links_terms') . ' AS m ON m.link_id = l.link_id')
|
||||
->where('m.term_id IN (' . implode(',', $included) . ')');
|
||||
|
||||
// Check if there are any excluded terms to deal with.
|
||||
if (\count($this->excludedTerms)) {
|
||||
$query2 = $db->getQuery(true);
|
||||
$query2->select('e.link_id')
|
||||
->from($db->quoteName('#__finder_links_terms', 'e'))
|
||||
->where('e.term_id IN (' . implode(',', $this->excludedTerms) . ')');
|
||||
$query->where('l.link_id NOT IN (' . $query2 . ')');
|
||||
}
|
||||
|
||||
/*
|
||||
* The query contains required search terms.
|
||||
*/
|
||||
if (\count($this->requiredTerms)) {
|
||||
foreach ($this->requiredTerms as $terms) {
|
||||
if (\count($terms)) {
|
||||
$query->having('SUM(CASE WHEN m.term_id IN (' . implode(',', $terms) . ') THEN 1 ELSE 0 END) > 0');
|
||||
} else {
|
||||
$query->where('false');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the available sorting fields.
|
||||
*
|
||||
* @return array The sorting field objects.
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 4.3.0
|
||||
*/
|
||||
public function getSortOrderFields()
|
||||
{
|
||||
$sortOrderFields = [];
|
||||
$directions = ['asc', 'desc'];
|
||||
$app = Factory::getApplication();
|
||||
$params = $app->getParams();
|
||||
$sortOrderFieldValues = $params->get('shown_sort_order', [], 'array');
|
||||
|
||||
if ($params->get('show_sort_order', 0, 'uint') && !empty($sortOrderFieldValues)) {
|
||||
$defaultSortFieldValue = $params->get('sort_order', '', 'cmd');
|
||||
$queryUri = Uri::getInstance($this->getQuery()->toUri());
|
||||
|
||||
// If the default field is not included in the shown sort fields, add it.
|
||||
if (!\in_array($defaultSortFieldValue, $sortOrderFieldValues)) {
|
||||
array_unshift($sortOrderFieldValues, $defaultSortFieldValue);
|
||||
}
|
||||
|
||||
foreach ($sortOrderFieldValues as $sortOrderFieldValue) {
|
||||
foreach ($directions as $direction) {
|
||||
// The relevance has only descending direction. Except if ascending is set in the parameters.
|
||||
if ($sortOrderFieldValue === 'relevance' && $direction === 'asc' && $app->getParams()->get('sort_direction', 'desc') === 'desc') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sortOrderFields[] = $this->getSortField($sortOrderFieldValue, $direction, $queryUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Import Finder plugins
|
||||
PluginHelper::importPlugin('finder');
|
||||
|
||||
// Trigger an event, in case a plugin wishes to change the order fields.
|
||||
$app->triggerEvent('onFinderSortOrderFields', [&$sortOrderFields]);
|
||||
|
||||
return $sortOrderFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate and return a sorting field
|
||||
*
|
||||
* @param string $value The value based on which the results will be sorted.
|
||||
* @param string $direction The sorting direction ('asc' or 'desc').
|
||||
* @param Uri $queryUri The uri of the search query.
|
||||
*
|
||||
* @return \stdClass The sorting field object.
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 4.3.0
|
||||
*/
|
||||
protected function getSortField(string $value, string $direction, Uri $queryUri)
|
||||
{
|
||||
$sortField = new \stdClass();
|
||||
$app = Factory::getApplication();
|
||||
|
||||
// We have to clone the query uri. Otherwise the next elements will use the same.
|
||||
$queryUri = clone $queryUri;
|
||||
$queryUri->setVar('o', $value);
|
||||
$currentOrderingDirection = $app->getInput()->getWord('od', $app->getParams()->get('sort_direction', 'desc'));
|
||||
|
||||
// Validate the sorting direction and add it only if it is different than the set in the params.
|
||||
if (\in_array($direction, ['asc', 'desc']) && $direction != $app->getParams()->get('sort_direction', 'desc')) {
|
||||
$queryUri->setVar('od', StringHelper::strtolower($direction));
|
||||
}
|
||||
|
||||
$label = '';
|
||||
|
||||
if (isset($this->sortOrderFieldsLabels[$value . '.' . $direction])) {
|
||||
$label = Text::_($this->sortOrderFieldsLabels[$value . '.' . $direction]);
|
||||
}
|
||||
|
||||
$sortField->label = $label;
|
||||
$sortField->url = $queryUri->toString();
|
||||
$currentSortOrderField = $app->getInput()->getWord('o', $app->getParams()->get('sort_order', 'relevance'));
|
||||
$sortField->active = false;
|
||||
|
||||
if ($value === StringHelper::strtolower($currentSortOrderField) && $direction === $currentOrderingDirection) {
|
||||
$sortField->active = true;
|
||||
}
|
||||
|
||||
return $sortField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a store id based on model the configuration state.
|
||||
*
|
||||
* This is necessary because the model is used by the component and
|
||||
* different modules that might need different sets of data or different
|
||||
* ordering requirements.
|
||||
*
|
||||
* @param string $id An identifier string to generate the store id. [optional]
|
||||
* @param boolean $page True to store the data paged, false to store all data. [optional]
|
||||
*
|
||||
* @return string A store id.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
protected function getStoreId($id = '', $page = true)
|
||||
{
|
||||
// Get the query object.
|
||||
$query = $this->getQuery();
|
||||
|
||||
// Add the search query state.
|
||||
$id .= ':' . $query->input;
|
||||
$id .= ':' . $query->language;
|
||||
$id .= ':' . $query->filter;
|
||||
$id .= ':' . serialize($query->filters);
|
||||
$id .= ':' . $query->date1;
|
||||
$id .= ':' . $query->date2;
|
||||
$id .= ':' . $query->when1;
|
||||
$id .= ':' . $query->when2;
|
||||
|
||||
if ($page) {
|
||||
// Add the list state for page specific data.
|
||||
$id .= ':' . $this->getState('list.start');
|
||||
$id .= ':' . $this->getState('list.limit');
|
||||
$id .= ':' . $this->getState('list.ordering');
|
||||
$id .= ':' . $this->getState('list.direction');
|
||||
}
|
||||
|
||||
return parent::getStoreId($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to auto-populate the model state. Calling getState in this method will result in recursion.
|
||||
*
|
||||
* @param string $ordering An optional ordering field. [optional]
|
||||
* @param string $direction An optional direction. [optional]
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
protected function populateState($ordering = null, $direction = null)
|
||||
{
|
||||
// Get the configuration options.
|
||||
$app = Factory::getApplication();
|
||||
$input = $app->getInput();
|
||||
$params = $app->getParams();
|
||||
$user = $this->getCurrentUser();
|
||||
$language = $app->getLanguage();
|
||||
|
||||
$this->setState('filter.language', Multilanguage::isEnabled());
|
||||
|
||||
$request = $input->request;
|
||||
$options = [];
|
||||
|
||||
// Get the empty query setting.
|
||||
$options['empty'] = $params->get('allow_empty_query', 0);
|
||||
|
||||
// Get the static taxonomy filters.
|
||||
$options['filter'] = $request->getInt('f', $params->get('f', ''));
|
||||
|
||||
// Get the dynamic taxonomy filters.
|
||||
$options['filters'] = $request->get('t', $params->get('t', []), 'array');
|
||||
|
||||
// Get the query string.
|
||||
$options['input'] = $request->getString('q', $params->get('q', ''));
|
||||
|
||||
// Get the query language.
|
||||
$options['language'] = $request->getCmd('l', $params->get('l', $language->getTag()));
|
||||
|
||||
// Set the word match mode
|
||||
$options['word_match'] = $params->get('word_match', 'exact');
|
||||
|
||||
// Get the start date and start date modifier filters.
|
||||
$options['date1'] = $request->getString('d1', $params->get('d1', ''));
|
||||
$options['when1'] = $request->getString('w1', $params->get('w1', ''));
|
||||
|
||||
// Get the end date and end date modifier filters.
|
||||
$options['date2'] = $request->getString('d2', $params->get('d2', ''));
|
||||
$options['when2'] = $request->getString('w2', $params->get('w2', ''));
|
||||
|
||||
// Load the query object.
|
||||
$this->searchquery = new Query($options, $this->getDatabase());
|
||||
|
||||
// Load the query token data.
|
||||
$this->excludedTerms = $this->searchquery->getExcludedTermIds();
|
||||
$this->includedTerms = $this->searchquery->getIncludedTermIds();
|
||||
$this->requiredTerms = $this->searchquery->getRequiredTermIds();
|
||||
|
||||
// Load the list state.
|
||||
$this->setState('list.start', $input->get('limitstart', 0, 'uint'));
|
||||
$this->setState('list.limit', $input->get('limit', $params->get('list_limit', $app->get('list_limit', 20)), 'uint'));
|
||||
|
||||
/*
|
||||
* Load the sort ordering.
|
||||
* Currently this is 'hard' coded via menu item parameter but may not satisfy a users need.
|
||||
* More flexibility was way more user friendly. So we allow the user to pass a custom value
|
||||
* from the pool of fields that are indexed like the 'title' field.
|
||||
* Also, we allow this parameter to be passed in either case (lower/upper).
|
||||
*/
|
||||
$order = $input->getWord('o', $params->get('sort_order', 'relevance'));
|
||||
$order = StringHelper::strtolower($order);
|
||||
$this->setState('list.raworder', $order);
|
||||
|
||||
switch ($order) {
|
||||
case 'date':
|
||||
$this->setState('list.ordering', 'l.start_date');
|
||||
break;
|
||||
|
||||
case 'price':
|
||||
$this->setState('list.ordering', 'l.list_price');
|
||||
break;
|
||||
|
||||
case 'sale_price':
|
||||
$this->setState('list.ordering', 'l.sale_price');
|
||||
break;
|
||||
|
||||
case ($order === 'relevance' && !empty($this->includedTerms)):
|
||||
$this->setState('list.ordering', 'm.weight');
|
||||
break;
|
||||
|
||||
case 'title':
|
||||
$this->setState('list.ordering', 'l.title');
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->setState('list.ordering', 'l.link_id');
|
||||
$this->setState('list.raworder');
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the sort direction.
|
||||
* Currently this is 'hard' coded via menu item parameter but may not satisfy a users need.
|
||||
* More flexibility was way more user friendly. So we allow to be inverted.
|
||||
* Also, we allow this parameter to be passed in either case (lower/upper).
|
||||
*/
|
||||
$dirn = $input->getWord('od', $params->get('sort_direction', 'desc'));
|
||||
$dirn = StringHelper::strtolower($dirn);
|
||||
|
||||
switch ($dirn) {
|
||||
case 'asc':
|
||||
$this->setState('list.direction', 'ASC');
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->setState('list.direction', 'DESC');
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the match limit.
|
||||
$this->setState('match.limit', 1000);
|
||||
|
||||
// Load the parameters.
|
||||
$this->setState('params', $params);
|
||||
|
||||
// Load the user state.
|
||||
$this->setState('user.id', (int) $user->get('id'));
|
||||
$this->setState('user.groups', $user->getAuthorisedViewLevels());
|
||||
}
|
||||
}
|
||||
181
components/com_finder/src/Model/SuggestionsModel.php
Normal file
181
components/com_finder/src/Model/SuggestionsModel.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Finder\Site\Model;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Multilanguage;
|
||||
use Joomla\CMS\MVC\Model\ListModel;
|
||||
use Joomla\Component\Finder\Administrator\Indexer\Helper;
|
||||
use Joomla\Database\DatabaseQuery;
|
||||
use Joomla\String\StringHelper;
|
||||
use Joomla\Utilities\ArrayHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Suggestions model class for the Finder package.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
class SuggestionsModel extends ListModel
|
||||
{
|
||||
/**
|
||||
* Context string for the model type.
|
||||
*
|
||||
* @var string
|
||||
* @since 2.5
|
||||
*/
|
||||
protected $context = 'com_finder.suggestions';
|
||||
|
||||
/**
|
||||
* Method to get an array of data items.
|
||||
*
|
||||
* @return array An array of data items.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
// Get the items.
|
||||
$items = parent::getItems();
|
||||
|
||||
// Convert them to a simple array.
|
||||
foreach ($items as $k => $v) {
|
||||
$items[$k] = $v->term;
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to build a database query to load the list data.
|
||||
*
|
||||
* @return DatabaseQuery A database query
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
protected function getListQuery()
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
$groups = ArrayHelper::toInteger($user->getAuthorisedViewLevels());
|
||||
$lang = Helper::getPrimaryLanguage($this->getState('language'));
|
||||
|
||||
// Create a new query object.
|
||||
$db = $this->getDatabase();
|
||||
$termIdQuery = $db->getQuery(true);
|
||||
$termQuery = $db->getQuery(true);
|
||||
|
||||
// Limit term count to a reasonable number of results to reduce main query join size
|
||||
$termIdQuery->select('ti.term_id')
|
||||
->from($db->quoteName('#__finder_terms', 'ti'))
|
||||
->where('ti.term LIKE ' . $db->quote($db->escape(StringHelper::strtolower($this->getState('input')), true) . '%', false))
|
||||
->where('ti.common = 0')
|
||||
->where('ti.language IN (' . $db->quote($lang) . ', ' . $db->quote('*') . ')')
|
||||
->order('ti.links DESC')
|
||||
->order('ti.weight DESC');
|
||||
|
||||
$termIds = $db->setQuery($termIdQuery, 0, 100)->loadColumn();
|
||||
|
||||
// Early return on term mismatch
|
||||
if (!\count($termIds)) {
|
||||
return $termIdQuery;
|
||||
}
|
||||
|
||||
// Select required fields
|
||||
$termQuery->select('DISTINCT(t.term)')
|
||||
->from($db->quoteName('#__finder_terms', 't'))
|
||||
->whereIn('t.term_id', $termIds)
|
||||
->order('t.links DESC')
|
||||
->order('t.weight DESC');
|
||||
|
||||
// Join mapping table for term <-> link relation
|
||||
$mappingTable = $db->quoteName('#__finder_links_terms', 'tm');
|
||||
$termQuery->join('INNER', $mappingTable . ' ON tm.term_id = t.term_id');
|
||||
|
||||
// Join links table
|
||||
$termQuery->join('INNER', $db->quoteName('#__finder_links', 'l') . ' ON (tm.link_id = l.link_id)')
|
||||
->where('l.access IN (' . implode(',', $groups) . ')')
|
||||
->where('l.state = 1')
|
||||
->where('l.published = 1');
|
||||
|
||||
return $termQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a store id based on model the configuration state.
|
||||
*
|
||||
* This is necessary because the model is used by the component and
|
||||
* different modules that might need different sets of data or different
|
||||
* ordering requirements.
|
||||
*
|
||||
* @param string $id An identifier string to generate the store id. [optional]
|
||||
*
|
||||
* @return string A store id.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
protected function getStoreId($id = '')
|
||||
{
|
||||
// Add the search query state.
|
||||
$id .= ':' . $this->getState('input');
|
||||
$id .= ':' . $this->getState('language');
|
||||
|
||||
// Add the list state.
|
||||
$id .= ':' . $this->getState('list.start');
|
||||
$id .= ':' . $this->getState('list.limit');
|
||||
|
||||
return parent::getStoreId($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to auto-populate the model state. Calling getState in this method will result in recursion.
|
||||
*
|
||||
* @param string $ordering An optional ordering field.
|
||||
* @param string $direction An optional direction (asc|desc).
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
protected function populateState($ordering = null, $direction = null)
|
||||
{
|
||||
// Get the configuration options.
|
||||
$app = Factory::getApplication();
|
||||
$input = $app->getInput();
|
||||
$params = ComponentHelper::getParams('com_finder');
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
// Get the query input.
|
||||
$this->setState('input', $input->request->get('q', '', 'string'));
|
||||
|
||||
// Set the query language
|
||||
if (Multilanguage::isEnabled()) {
|
||||
$lang = Factory::getLanguage()->getTag();
|
||||
} else {
|
||||
$lang = Helper::getDefaultLanguage();
|
||||
}
|
||||
|
||||
$this->setState('language', $lang);
|
||||
|
||||
// Load the list state.
|
||||
$this->setState('list.start', 0);
|
||||
$this->setState('list.limit', 10);
|
||||
|
||||
// Load the parameters.
|
||||
$this->setState('params', $params);
|
||||
|
||||
// Load the user state.
|
||||
$this->setState('user.id', (int) $user->get('id'));
|
||||
}
|
||||
}
|
||||
49
components/com_finder/src/Service/Router.php
Normal file
49
components/com_finder/src/Service/Router.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Finder\Site\Service;
|
||||
|
||||
use Joomla\CMS\Application\SiteApplication;
|
||||
use Joomla\CMS\Component\Router\RouterView;
|
||||
use Joomla\CMS\Component\Router\RouterViewConfiguration;
|
||||
use Joomla\CMS\Component\Router\Rules\MenuRules;
|
||||
use Joomla\CMS\Component\Router\Rules\NomenuRules;
|
||||
use Joomla\CMS\Component\Router\Rules\StandardRules;
|
||||
use Joomla\CMS\Menu\AbstractMenu;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Routing class from com_finder
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
class Router extends RouterView
|
||||
{
|
||||
/**
|
||||
* Finder Component router constructor
|
||||
*
|
||||
* @param SiteApplication $app The application object
|
||||
* @param AbstractMenu $menu The menu object to work with
|
||||
*/
|
||||
public function __construct(SiteApplication $app, AbstractMenu $menu)
|
||||
{
|
||||
$search = new RouterViewConfiguration('search');
|
||||
$this->registerView($search);
|
||||
|
||||
parent::__construct($app, $menu);
|
||||
|
||||
$this->attachRule(new MenuRules($this));
|
||||
$this->attachRule(new StandardRules($this));
|
||||
$this->attachRule(new NomenuRules($this));
|
||||
}
|
||||
}
|
||||
88
components/com_finder/src/View/Search/FeedView.php
Normal file
88
components/com_finder/src/View/Search/FeedView.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Finder\Site\View\Search;
|
||||
|
||||
use Joomla\CMS\Document\Feed\FeedItem;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Search feed view class for the Finder package.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
class FeedView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* Method to display the view.
|
||||
*
|
||||
* @param string $tpl A template file to load. [optional]
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
// Get the application
|
||||
$app = Factory::getApplication();
|
||||
|
||||
// Adjust the list limit to the feed limit.
|
||||
$app->getInput()->set('limit', $app->get('feed_limit'));
|
||||
|
||||
// Get view data.
|
||||
$state = $this->get('State');
|
||||
$params = $state->get('params');
|
||||
$query = $this->get('Query');
|
||||
$results = $this->get('Items');
|
||||
$total = $this->get('Total');
|
||||
|
||||
// Push out the query data.
|
||||
$explained = HTMLHelper::_('query.explained', $query);
|
||||
|
||||
// Set the document title.
|
||||
$this->setDocumentTitle($params->get('page_title', ''));
|
||||
|
||||
// Configure the document description.
|
||||
if (!empty($explained)) {
|
||||
$this->getDocument()->setDescription(html_entity_decode(strip_tags($explained), ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
// Set the document link.
|
||||
$this->getDocument()->link = Route::_($query->toUri());
|
||||
|
||||
// If we don't have any results, we are done.
|
||||
if (empty($results)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the results to feed entries.
|
||||
foreach ($results as $result) {
|
||||
// Convert the result to a feed entry.
|
||||
$item = new FeedItem();
|
||||
$item->title = $result->title;
|
||||
$item->link = Route::_($result->route);
|
||||
$item->description = $result->description;
|
||||
|
||||
// Use Unix date to cope for non-english languages
|
||||
$item->date = (int) $result->start_date ? HTMLHelper::_('date', $result->start_date, 'U') : $result->indexdate;
|
||||
|
||||
// Loads item info into RSS array
|
||||
$this->getDocument()->addItem($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
340
components/com_finder/src/View/Search/HtmlView.php
Normal file
340
components/com_finder/src/View/Search/HtmlView.php
Normal file
@ -0,0 +1,340 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Finder\Site\View\Search;
|
||||
|
||||
use Joomla\CMS\Event\Finder\ResultEvent;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\View\GenericDataException;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Pagination\Pagination;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Profiler\Profiler;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Router\SiteRouterAwareInterface;
|
||||
use Joomla\CMS\Router\SiteRouterAwareTrait;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\Component\Finder\Administrator\Indexer\Query;
|
||||
use Joomla\Component\Finder\Site\Helper\FinderHelper;
|
||||
use Joomla\Filesystem\Path;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Search HTML view class for the Finder package.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView implements SiteRouterAwareInterface
|
||||
{
|
||||
use SiteRouterAwareTrait;
|
||||
|
||||
/**
|
||||
* The query indexer object
|
||||
*
|
||||
* @var Query
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
/**
|
||||
* The page parameters
|
||||
*
|
||||
* @var \Joomla\Registry\Registry|null
|
||||
*/
|
||||
protected $params = null;
|
||||
|
||||
/**
|
||||
* The model state
|
||||
*
|
||||
* @var \Joomla\Registry\Registry
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The logged in user
|
||||
*
|
||||
* @var \Joomla\CMS\User\User|null
|
||||
*/
|
||||
protected $user = null;
|
||||
|
||||
/**
|
||||
* The suggested search query
|
||||
*
|
||||
* @var string|false
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected $suggested = false;
|
||||
|
||||
/**
|
||||
* The explained (human-readable) search query
|
||||
*
|
||||
* @var string|null
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected $explained = null;
|
||||
|
||||
/**
|
||||
* The page class suffix
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected $pageclass_sfx = '';
|
||||
|
||||
/**
|
||||
* An array of results
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @since 3.8.0
|
||||
*/
|
||||
protected $results;
|
||||
|
||||
/**
|
||||
* The total number of items
|
||||
*
|
||||
* @var integer
|
||||
*
|
||||
* @since 3.8.0
|
||||
*/
|
||||
protected $total;
|
||||
|
||||
/**
|
||||
* The pagination object
|
||||
*
|
||||
* @var Pagination
|
||||
*
|
||||
* @since 3.8.0
|
||||
*/
|
||||
protected $pagination;
|
||||
|
||||
/**
|
||||
* Method to display the view.
|
||||
*
|
||||
* @param string $tpl A template file to load. [optional]
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
$this->params = $app->getParams();
|
||||
|
||||
// Get view data.
|
||||
$this->state = $this->get('State');
|
||||
$this->query = $this->get('Query');
|
||||
\JDEBUG ? Profiler::getInstance('Application')->mark('afterFinderQuery') : null;
|
||||
$this->results = $this->get('Items');
|
||||
\JDEBUG ? Profiler::getInstance('Application')->mark('afterFinderResults') : null;
|
||||
$this->sortOrderFields = $this->get('sortOrderFields');
|
||||
\JDEBUG ? Profiler::getInstance('Application')->mark('afterFinderSortOrderFields') : null;
|
||||
$this->total = $this->get('Total');
|
||||
\JDEBUG ? Profiler::getInstance('Application')->mark('afterFinderTotal') : null;
|
||||
$this->pagination = $this->get('Pagination');
|
||||
\JDEBUG ? Profiler::getInstance('Application')->mark('afterFinderPagination') : null;
|
||||
|
||||
// Flag indicates to not add limitstart=0 to URL
|
||||
$this->pagination->hideEmptyLimitstart = true;
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new GenericDataException(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
// Configure the pathway.
|
||||
if (!empty($this->query->input)) {
|
||||
$app->getPathway()->addItem($this->escape($this->query->input));
|
||||
}
|
||||
|
||||
// Check for a double quote in the query string.
|
||||
if (strpos($this->query->input, '"')) {
|
||||
$router = $this->getSiteRouter();
|
||||
|
||||
// Fix the q variable in the URL.
|
||||
if ($router->getVar('q') !== $this->query->input) {
|
||||
$router->setVar('q', $this->query->input);
|
||||
}
|
||||
}
|
||||
|
||||
// Run an event on each result item
|
||||
if (\is_array($this->results)) {
|
||||
$dispatcher = $this->getDispatcher();
|
||||
|
||||
// Import Finder plugins
|
||||
PluginHelper::importPlugin('finder', null, true, $dispatcher);
|
||||
|
||||
foreach ($this->results as $result) {
|
||||
$dispatcher->dispatch('onFinderResult', new ResultEvent('onFinderResult', [
|
||||
'subject' => $result,
|
||||
'query' => $this->query,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
// Log the search
|
||||
FinderHelper::logSearch($this->query, $this->total);
|
||||
|
||||
// Push out the query data.
|
||||
$this->suggested = HTMLHelper::_('query.suggested', $this->query);
|
||||
$this->explained = HTMLHelper::_('query.explained', $this->query);
|
||||
|
||||
// Escape strings for HTML output
|
||||
$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''));
|
||||
|
||||
// Check for layout override only if this is not the active menu item
|
||||
// If it is the active menu item, then the view and category id will match
|
||||
$active = $app->getMenu()->getActive();
|
||||
|
||||
if (isset($active->query['layout'])) {
|
||||
// We need to set the layout in case this is an alternative menu item (with an alternative layout)
|
||||
$this->setLayout($active->query['layout']);
|
||||
}
|
||||
|
||||
$this->prepareDocument();
|
||||
|
||||
\JDEBUG ? Profiler::getInstance('Application')->mark('beforeFinderLayout') : null;
|
||||
|
||||
parent::display($tpl);
|
||||
|
||||
\JDEBUG ? Profiler::getInstance('Application')->mark('afterFinderLayout') : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get hidden input fields for a get form so that control variables
|
||||
* are not lost upon form submission
|
||||
*
|
||||
* @return string A string of hidden input form fields
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
protected function getFields()
|
||||
{
|
||||
$fields = null;
|
||||
|
||||
// Get the URI.
|
||||
$uri = Uri::getInstance(Route::_($this->query->toUri()));
|
||||
$uri->delVar('q');
|
||||
$uri->delVar('o');
|
||||
$uri->delVar('t');
|
||||
$uri->delVar('d1');
|
||||
$uri->delVar('d2');
|
||||
$uri->delVar('w1');
|
||||
$uri->delVar('w2');
|
||||
$elements = $uri->getQuery(true);
|
||||
|
||||
// Create hidden input elements for each part of the URI.
|
||||
foreach ($elements as $n => $v) {
|
||||
if (is_scalar($v)) {
|
||||
$fields .= '<input type="hidden" name="' . $n . '" value="' . $v . '">';
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the layout file for a search result object.
|
||||
*
|
||||
* @param string $layout The layout file to check. [optional]
|
||||
*
|
||||
* @return string The layout file to use.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
protected function getLayoutFile($layout = null)
|
||||
{
|
||||
// Create and sanitize the file name.
|
||||
$file = $this->_layout . '_' . preg_replace('/[^A-Z0-9_\.-]/i', '', $layout);
|
||||
|
||||
// Check if the file exists.
|
||||
$filetofind = $this->_createFileName('template', ['name' => $file]);
|
||||
$exists = Path::find($this->_path['template'], $filetofind);
|
||||
|
||||
return ($exists ? $layout : 'result');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the document
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
protected function prepareDocument()
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
|
||||
// Because the application sets a default page title,
|
||||
// we need to get it from the menu item itself
|
||||
$menu = $app->getMenu()->getActive();
|
||||
|
||||
if ($menu) {
|
||||
$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
|
||||
} else {
|
||||
$this->params->def('page_heading', Text::_('COM_FINDER_DEFAULT_PAGE_TITLE'));
|
||||
}
|
||||
|
||||
$this->setDocumentTitle($this->params->get('page_title', ''));
|
||||
|
||||
if ($layout = $this->params->get('article_layout')) {
|
||||
$this->setLayout($layout);
|
||||
}
|
||||
|
||||
// Configure the document meta-description.
|
||||
if (!empty($this->explained)) {
|
||||
$explained = $this->escape(html_entity_decode(strip_tags($this->explained), ENT_QUOTES, 'UTF-8'));
|
||||
$this->getDocument()->setDescription($explained);
|
||||
} elseif ($this->params->get('menu-meta_description')) {
|
||||
$this->getDocument()->setDescription($this->params->get('menu-meta_description'));
|
||||
}
|
||||
|
||||
if ($this->params->get('robots')) {
|
||||
$this->getDocument()->setMetaData('robots', $this->params->get('robots'));
|
||||
}
|
||||
|
||||
// Check for OpenSearch
|
||||
if ($this->params->get('opensearch', 1)) {
|
||||
$ostitle = $this->params->get(
|
||||
'opensearch_name',
|
||||
Text::_('COM_FINDER_OPENSEARCH_NAME') . ' ' . $app->get('sitename')
|
||||
);
|
||||
$this->getDocument()->addHeadLink(
|
||||
Uri::getInstance()->toString(['scheme', 'host', 'port']) . Route::_('index.php?option=com_finder&view=search&format=opensearch'),
|
||||
'search',
|
||||
'rel',
|
||||
['title' => $ostitle, 'type' => 'application/opensearchdescription+xml']
|
||||
);
|
||||
}
|
||||
|
||||
// Add feed link to the document head.
|
||||
if ($this->params->get('show_feed_link', 1) == 1) {
|
||||
// Add the RSS link.
|
||||
$props = ['type' => 'application/rss+xml', 'title' => htmlspecialchars($this->getDocument()->getTitle())];
|
||||
$route = Route::_($this->query->toUri() . '&format=feed&type=rss');
|
||||
$this->getDocument()->addHeadLink($route, 'alternate', 'rel', $props);
|
||||
|
||||
// Add the ATOM link.
|
||||
$props = ['type' => 'application/atom+xml', 'title' => htmlspecialchars($this->getDocument()->getTitle())];
|
||||
$route = Route::_($this->query->toUri() . '&format=feed&type=atom');
|
||||
$this->getDocument()->addHeadLink($route, 'alternate', 'rel', $props);
|
||||
}
|
||||
}
|
||||
}
|
||||
89
components/com_finder/src/View/Search/OpensearchView.php
Normal file
89
components/com_finder/src/View/Search/OpensearchView.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Finder\Site\View\Search;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Document\Opensearch\OpensearchUrl;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\View\AbstractView;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* OpenSearch View class for Finder
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
class OpensearchView extends AbstractView
|
||||
{
|
||||
/**
|
||||
* Method to display the view.
|
||||
*
|
||||
* @param string $tpl A template file to load. [optional]
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
|
||||
$params = ComponentHelper::getParams('com_finder');
|
||||
$this->getDocument()->setShortName($params->get('opensearch_name', $app->get('sitename', '')));
|
||||
$this->getDocument()->setDescription($params->get('opensearch_description', $app->get('MetaDesc', '')));
|
||||
|
||||
// Prevent any output when OpenSearch Support is disabled
|
||||
if (!$params->get('opensearch', 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the URL for the search
|
||||
$searchUri = 'index.php?option=com_finder&view=search&q={searchTerms}';
|
||||
$suggestionsUri = 'index.php?option=com_finder&task=suggestions.opensearchsuggest&format=json&q={searchTerms}';
|
||||
$baseUrl = Uri::getInstance()->toString(['host', 'port', 'scheme']);
|
||||
$active = $app->getMenu()->getActive();
|
||||
|
||||
if ($active->component == 'com_finder') {
|
||||
$searchUri .= '&Itemid=' . $active->id;
|
||||
$suggestionsUri .= '&Itemid=' . $active->id;
|
||||
}
|
||||
|
||||
// Add the HTML result view
|
||||
$htmlSearch = new OpensearchUrl();
|
||||
$htmlSearch->template = $baseUrl . Route::_($searchUri, false);
|
||||
$this->getDocument()->addUrl($htmlSearch);
|
||||
|
||||
// Add the RSS result view
|
||||
$htmlSearch = new OpensearchUrl();
|
||||
$htmlSearch->template = $baseUrl . Route::_($searchUri . '&format=feed&type=rss', false);
|
||||
$htmlSearch->type = 'application/rss+xml';
|
||||
$this->getDocument()->addUrl($htmlSearch);
|
||||
|
||||
// Add the Atom result view
|
||||
$htmlSearch = new OpensearchUrl();
|
||||
$htmlSearch->template = $baseUrl . Route::_($searchUri . '&format=feed&type=atom', false);
|
||||
$htmlSearch->type = 'application/atom+xml';
|
||||
$this->getDocument()->addUrl($htmlSearch);
|
||||
|
||||
// Add suggestions URL
|
||||
if ($params->get('show_autosuggest', 1)) {
|
||||
$htmlSearch = new OpensearchUrl();
|
||||
$htmlSearch->template = $baseUrl . Route::_($suggestionsUri, false);
|
||||
$htmlSearch->type = 'application/x-suggestions+json';
|
||||
$this->getDocument()->addUrl($htmlSearch);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
components/com_finder/tmpl/search/default.php
Normal file
37
components/com_finder/tmpl/search/default.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
$this->document->getWebAssetManager()
|
||||
->useStyle('com_finder.finder')
|
||||
->useScript('com_finder.finder');
|
||||
|
||||
?>
|
||||
<div class="com-finder finder">
|
||||
<?php if ($this->params->get('show_page_heading')) : ?>
|
||||
<h1>
|
||||
<?php if ($this->escape($this->params->get('page_heading'))) : ?>
|
||||
<?php echo $this->escape($this->params->get('page_heading')); ?>
|
||||
<?php else : ?>
|
||||
<?php echo $this->escape($this->params->get('page_title')); ?>
|
||||
<?php endif; ?>
|
||||
</h1>
|
||||
<?php endif; ?>
|
||||
<div id="search-form" class="com-finder__form">
|
||||
<?php echo $this->loadTemplate('form'); ?>
|
||||
</div>
|
||||
<?php // Load the search results layout if we are performing a search. ?>
|
||||
<?php if ($this->query->search === true) : ?>
|
||||
<div id="search-results" class="com-finder__results">
|
||||
<?php echo $this->loadTemplate('results'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
312
components/com_finder/tmpl/search/default.xml
Normal file
312
components/com_finder/tmpl/search/default.xml
Normal file
@ -0,0 +1,312 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<metadata>
|
||||
<layout title="COM_FINDER_MENU_SEARCH_VIEW_DEFAULT_TITLE">
|
||||
<help
|
||||
key = "Menu_Item:_Search"
|
||||
/>
|
||||
<message>
|
||||
<![CDATA[COM_FINDER_MENU_SEARCH_VIEW_DEFAULT_TEXT]]>
|
||||
</message>
|
||||
</layout>
|
||||
|
||||
<fields name="request" addfieldprefix="Joomla\Component\Finder\Administrator\Field" >
|
||||
<fieldset name="request">
|
||||
<field
|
||||
name="q"
|
||||
type="text"
|
||||
label="COM_FINDER_PREFILL_SEARCH_LABEL"
|
||||
/>
|
||||
<field
|
||||
name="f"
|
||||
type="searchfilter"
|
||||
label="COM_FINDER_SELECT_FILTER_LABEL"
|
||||
default=""
|
||||
/>
|
||||
</fieldset>
|
||||
</fields>
|
||||
<fields name="params">
|
||||
<fieldset name="basic">
|
||||
<field
|
||||
name="show_date_filters"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SHOW_DATE_FILTERS_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JSHOW</option>
|
||||
<option value="0">JHIDE</option>
|
||||
</field>
|
||||
<field
|
||||
name="show_advanced"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SHOW_ADVANCED_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JSHOW</option>
|
||||
<option value="0">JHIDE</option>
|
||||
</field>
|
||||
<field
|
||||
name="expand_advanced"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_EXPAND_ADVANCED_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JYES</option>
|
||||
<option value="0">JNO</option>
|
||||
</field>
|
||||
<field type="spacer" />
|
||||
<field
|
||||
name="show_taxonomy"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SHOW_TAXONOMY_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JSHOW</option>
|
||||
<option value="0">JHIDE</option>
|
||||
</field>
|
||||
<field
|
||||
name="show_description"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SHOW_DESCRIPTION_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JSHOW</option>
|
||||
<option value="0">JHIDE</option>
|
||||
</field>
|
||||
<field
|
||||
name="description_length"
|
||||
type="number"
|
||||
label="COM_FINDER_CONFIG_DESCRIPTION_LENGTH_LABEL"
|
||||
filter="integer"
|
||||
default=""
|
||||
useglobal="true"
|
||||
/>
|
||||
<field
|
||||
name="show_image"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SHOW_IMAGE_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JSHOW</option>
|
||||
<option value="0">JHIDE</option>
|
||||
</field>
|
||||
<field
|
||||
name="image_class"
|
||||
type="text"
|
||||
label="COM_FINDER_CONFIG_IMAGE_CLASS_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
validate="CssIdentifier"
|
||||
showon="show_image!:0"
|
||||
/>
|
||||
<field
|
||||
name="link_image"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_LINKED_IMAGE_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
showon="show_image!:0"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
<field
|
||||
name="show_date"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SHOW_DATE_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JSHOW</option>
|
||||
<option value="0">JHIDE</option>
|
||||
</field>
|
||||
<field
|
||||
name="show_url"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SHOW_URL_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JSHOW</option>
|
||||
<option value="0">JHIDE</option>
|
||||
</field>
|
||||
<field type="spacer" />
|
||||
</fieldset>
|
||||
<fieldset name="advanced">
|
||||
<field
|
||||
name="show_pagination_limit"
|
||||
type="list"
|
||||
label="JGLOBAL_DISPLAY_SELECT_LABEL"
|
||||
validate="options"
|
||||
class="form-select-color-state"
|
||||
>
|
||||
<option value="">JGLOBAL_USE_GLOBAL</option>
|
||||
<option value="0">JHIDE</option>
|
||||
<option value="1">JSHOW</option>
|
||||
</field>
|
||||
<field
|
||||
name="show_pagination"
|
||||
type="list"
|
||||
label="JGLOBAL_PAGINATION_LABEL"
|
||||
validate="options"
|
||||
class="form-select-color-state"
|
||||
>
|
||||
<option value="">JGLOBAL_USE_GLOBAL</option>
|
||||
<option value="0">JHIDE</option>
|
||||
<option value="1">JSHOW</option>
|
||||
<option value="2">JGLOBAL_AUTO</option>
|
||||
</field>
|
||||
<field
|
||||
name="show_pagination_results"
|
||||
type="list"
|
||||
label="JGLOBAL_PAGINATION_RESULTS_LABEL"
|
||||
validate="options"
|
||||
class="form-select-color-state"
|
||||
>
|
||||
<option value="">JGLOBAL_USE_GLOBAL</option>
|
||||
<option value="0">JHIDE</option>
|
||||
<option value="1">JSHOW</option>
|
||||
</field>
|
||||
<field
|
||||
name="list_limit"
|
||||
type="list"
|
||||
label="JGLOBAL_LIST_LIMIT"
|
||||
default="20"
|
||||
validate="options"
|
||||
>
|
||||
<option value="5">J5</option>
|
||||
<option value="10">J10</option>
|
||||
<option value="15">J15</option>
|
||||
<option value="20">J20</option>
|
||||
<option value="25">J25</option>
|
||||
<option value="30">J30</option>
|
||||
<option value="50">J50</option>
|
||||
<option value="100">J100</option>
|
||||
<option value="0">JALL</option>
|
||||
</field>
|
||||
<field
|
||||
name="allow_empty_query"
|
||||
type="list"
|
||||
label="COM_FINDER_ALLOW_EMPTY_QUERY_LABEL"
|
||||
description="COM_FINDER_ALLOW_EMPTY_QUERY_DESC"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JYES</option>
|
||||
<option value="0">JNO</option>
|
||||
</field>
|
||||
<field
|
||||
name="show_suggested_query"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SHOW_SUGGESTED_QUERY_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JYES</option>
|
||||
<option value="0">JNO</option>
|
||||
</field>
|
||||
<field
|
||||
name="show_explained_query"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SHOW_EXPLAINED_QUERY_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
class="form-select-color-state"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">JYES</option>
|
||||
<option value="0">JNO</option>
|
||||
</field>
|
||||
<field
|
||||
name="sort_order"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SORT_ORDER_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
validate="options"
|
||||
>
|
||||
<option value="relevance">COM_FINDER_CONFIG_SORT_OPTION_RELEVANCE</option>
|
||||
<option value="title">COM_FINDER_CONFIG_SORT_OPTION_TITLE</option>
|
||||
<option value="date">COM_FINDER_CONFIG_SORT_OPTION_START_DATE</option>
|
||||
<option value="price">COM_FINDER_CONFIG_SORT_OPTION_LIST_PRICE</option>
|
||||
<option value="sale_price">COM_FINDER_CONFIG_SORT_OPTION_SALES_PRICE</option>
|
||||
</field>
|
||||
<field
|
||||
name="show_sort_order"
|
||||
type="radio"
|
||||
label="COM_FINDER_CONFIG_SHOW_SORT_ORDER_LABEL"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
default="0"
|
||||
>
|
||||
<option value="0">JHIDE</option>
|
||||
<option value="1">JSHOW</option>
|
||||
</field>
|
||||
<field
|
||||
name="shown_sort_order"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SORT_ORDER_FIELDS_LABEL"
|
||||
layout="joomla.form.field.list-fancy-select"
|
||||
multiple="true"
|
||||
validate="options"
|
||||
showon="show_sort_order:1"
|
||||
>
|
||||
<option value="relevance">COM_FINDER_CONFIG_SORT_OPTION_RELEVANCE</option>
|
||||
<option value="title">COM_FINDER_CONFIG_SORT_OPTION_TITLE</option>
|
||||
<option value="date">COM_FINDER_CONFIG_SORT_OPTION_START_DATE</option>
|
||||
<option value="price">COM_FINDER_CONFIG_SORT_OPTION_LIST_PRICE</option>
|
||||
<option value="sale_price">COM_FINDER_CONFIG_SORT_OPTION_SALES_PRICE</option>
|
||||
</field>
|
||||
<field
|
||||
name="sort_direction"
|
||||
type="list"
|
||||
label="COM_FINDER_CONFIG_SORT_DIRECTION_LABEL"
|
||||
default=""
|
||||
useglobal="true"
|
||||
validate="options"
|
||||
>
|
||||
<option value="desc">COM_FINDER_CONFIG_SORT_OPTION_DESCENDING</option>
|
||||
<option value="asc">COM_FINDER_CONFIG_SORT_OPTION_ASCENDING</option>
|
||||
</field>
|
||||
</fieldset>
|
||||
<fieldset name="integration">
|
||||
<field
|
||||
name="show_feed_link"
|
||||
type="list"
|
||||
label="JGLOBAL_SHOW_FEED_LINK_LABEL"
|
||||
validate="options"
|
||||
class="form-select-color-state"
|
||||
>
|
||||
<option value="">JGLOBAL_USE_GLOBAL</option>
|
||||
<option value="0">JHIDE</option>
|
||||
<option value="1">JSHOW</option>
|
||||
</field>
|
||||
</fieldset>
|
||||
</fields>
|
||||
</metadata>
|
||||
82
components/com_finder/tmpl/search/default_form.php
Normal file
82
components/com_finder/tmpl/search/default_form.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
/*
|
||||
* This segment of code sets up the autocompleter.
|
||||
*/
|
||||
if ($this->params->get('show_autosuggest', 1)) {
|
||||
$this->document->getWebAssetManager()->usePreset('awesomplete');
|
||||
$this->document->addScriptOptions('finder-search', ['url' => Route::_('index.php?option=com_finder&task=suggestions.suggest&format=json&tmpl=component', false)]);
|
||||
|
||||
Text::script('JLIB_JS_AJAX_ERROR_OTHER');
|
||||
Text::script('JLIB_JS_AJAX_ERROR_PARSE');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<form action="<?php echo Route::_($this->query->toUri()); ?>" method="get" class="js-finder-searchform">
|
||||
<?php echo $this->getFields(); ?>
|
||||
<fieldset class="com-finder__search word mb-3">
|
||||
<legend class="com-finder__search-legend visually-hidden">
|
||||
<?php echo Text::_('COM_FINDER_SEARCH_FORM_LEGEND'); ?>
|
||||
</legend>
|
||||
<div class="form-inline">
|
||||
<label for="q" class="me-2">
|
||||
<?php echo Text::_('COM_FINDER_SEARCH_TERMS'); ?>
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="q" id="q" class="js-finder-search-query form-control" value="<?php echo $this->escape($this->query->input); ?>">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="icon-search icon-white" aria-hidden="true"></span>
|
||||
<?php echo Text::_('JSEARCH_FILTER_SUBMIT'); ?>
|
||||
</button>
|
||||
<?php if ($this->params->get('show_advanced', 1)) : ?>
|
||||
<?php HTMLHelper::_('bootstrap.collapse'); ?>
|
||||
<button class="btn btn-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#advancedSearch" aria-expanded="<?php echo ($this->params->get('expand_advanced', 0) ? 'true' : 'false'); ?>">
|
||||
<span class="icon-search-plus" aria-hidden="true"></span>
|
||||
<?php echo Text::_('COM_FINDER_ADVANCED_SEARCH_TOGGLE'); ?></button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<?php if ($this->params->get('show_advanced', 1)) : ?>
|
||||
<fieldset id="advancedSearch" class="com-finder__advanced js-finder-advanced collapse<?php if ($this->params->get('expand_advanced', 0)) {
|
||||
echo ' show';
|
||||
} ?>">
|
||||
<legend class="com-finder__search-advanced visually-hidden">
|
||||
<?php echo Text::_('COM_FINDER_SEARCH_ADVANCED_LEGEND'); ?>
|
||||
</legend>
|
||||
<?php if ($this->params->get('show_advanced_tips', 1)) : ?>
|
||||
<div class="com-finder__tips card card-outline-secondary mb-3">
|
||||
<div class="card-body">
|
||||
<?php echo Text::_('COM_FINDER_ADVANCED_TIPS_INTRO'); ?>
|
||||
<?php echo Text::_('COM_FINDER_ADVANCED_TIPS_AND'); ?>
|
||||
<?php echo Text::_('COM_FINDER_ADVANCED_TIPS_NOT'); ?>
|
||||
<?php echo Text::_('COM_FINDER_ADVANCED_TIPS_OR'); ?>
|
||||
<?php if ($this->params->get('tuplecount', 1) > 1) : ?>
|
||||
<?php echo Text::_('COM_FINDER_ADVANCED_TIPS_PHRASE'); ?>
|
||||
<?php endif; ?>
|
||||
<?php echo Text::_('COM_FINDER_ADVANCED_TIPS_OUTRO'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div id="finder-filter-window" class="com-finder__filter">
|
||||
<?php echo HTMLHelper::_('filter.select', $this->query, $this->params); ?>
|
||||
</div>
|
||||
</fieldset>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
129
components/com_finder/tmpl/search/default_result.php
Normal file
129
components/com_finder/tmpl/search/default_result.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Multilanguage;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\Component\Finder\Administrator\Helper\LanguageHelper;
|
||||
use Joomla\Component\Finder\Administrator\Indexer\Helper;
|
||||
use Joomla\Component\Finder\Administrator\Indexer\Taxonomy;
|
||||
use Joomla\String\StringHelper;
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
$show_description = $this->params->get('show_description', 1);
|
||||
|
||||
if ($show_description) {
|
||||
// Calculate number of characters to display around the result
|
||||
$term_length = StringHelper::strlen($this->query->input);
|
||||
$desc_length = $this->params->get('description_length', 255);
|
||||
$pad_length = $term_length < $desc_length ? (int) floor(($desc_length - $term_length) / 2) : 0;
|
||||
|
||||
// Make sure we highlight term both in introtext and fulltext
|
||||
$full_description = $this->result->description;
|
||||
if (!empty($this->result->summary) && !empty($this->result->body)) {
|
||||
$full_description = Helper::parse($this->result->summary . $this->result->body);
|
||||
}
|
||||
|
||||
// Find the position of the search term
|
||||
$pos = $term_length ? StringHelper::strpos(StringHelper::strtolower($full_description), StringHelper::strtolower($this->query->input)) : 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($full_description, ' ', $start > 0 ? $start - 1 : 0);
|
||||
$start = ($space && $space < $pos) ? $space + 1 : $start;
|
||||
|
||||
$description = HTMLHelper::_('string.truncate', StringHelper::substr($full_description, $start), $desc_length, true);
|
||||
}
|
||||
|
||||
$showImage = $this->params->get('show_image', 0);
|
||||
$imageClass = $this->params->get('image_class', '');
|
||||
$extraAttr = [];
|
||||
|
||||
if ($showImage && !empty($this->result->imageUrl) && $imageClass !== '') {
|
||||
$extraAttr['class'] = $imageClass;
|
||||
}
|
||||
|
||||
$icon = '';
|
||||
if (!empty($this->result->mime)) {
|
||||
$icon = '<span class="icon-file-' . $this->result->mime . '" aria-hidden="true"></span> ';
|
||||
}
|
||||
|
||||
|
||||
$show_url = '';
|
||||
if ($this->params->get('show_url', 1)) {
|
||||
$show_url = '<cite class="result__title-url">' . $this->baseUrl . Route::_($this->result->cleanURL) . '</cite>';
|
||||
}
|
||||
?>
|
||||
<li class="result__item">
|
||||
<?php if ($showImage && isset($this->result->imageUrl)) : ?>
|
||||
<figure class="<?php echo htmlspecialchars($imageClass, ENT_COMPAT, 'UTF-8'); ?> result__image">
|
||||
<?php if ($this->params->get('link_image') && $this->result->route) : ?>
|
||||
<a href="<?php echo Route::_($this->result->route); ?>">
|
||||
<?php echo HTMLHelper::_('image', $this->result->imageUrl, $this->result->imageAlt, $extraAttr); ?>
|
||||
</a>
|
||||
<?php else : ?>
|
||||
<?php echo HTMLHelper::_('image', $this->result->imageUrl, $this->result->imageAlt, $extraAttr); ?>
|
||||
<?php endif; ?>
|
||||
</figure>
|
||||
<?php endif; ?>
|
||||
<p class="result__title">
|
||||
<?php if ($this->result->route) : ?>
|
||||
<?php echo HTMLHelper::link(
|
||||
Route::_($this->result->route),
|
||||
'<span class="result__title-text">' . $icon . $this->result->title . '</span>' . $show_url,
|
||||
[
|
||||
'class' => 'result__title-link'
|
||||
]
|
||||
); ?>
|
||||
<?php else : ?>
|
||||
<?php echo $this->result->title; ?>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<?php if ($show_description && $description !== '') : ?>
|
||||
<p class="result__description">
|
||||
<?php if ($this->result->start_date && $this->params->get('show_date', 1)) : ?>
|
||||
<time class="result__date" datetime="<?php echo HTMLHelper::_('date', $this->result->start_date, 'c'); ?>">
|
||||
<?php echo HTMLHelper::_('date', $this->result->start_date, Text::_('DATE_FORMAT_LC3')); ?>
|
||||
</time>
|
||||
<?php endif; ?>
|
||||
<?php echo $description; ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php $taxonomies = $this->result->getTaxonomy(); ?>
|
||||
<?php if (count($taxonomies) && $this->params->get('show_taxonomy', 1)) : ?>
|
||||
<ul class="result__taxonomy">
|
||||
<?php foreach ($taxonomies as $type => $taxonomy) : ?>
|
||||
<?php if ($type == 'Language' && (!Multilanguage::isEnabled() || (isset($taxonomy[0]) && $taxonomy[0]->title == '*'))) : ?>
|
||||
<?php continue; ?>
|
||||
<?php endif; ?>
|
||||
<?php $branch = Taxonomy::getBranch($type); ?>
|
||||
<?php if ($branch->state == 1 && in_array($branch->access, $user->getAuthorisedViewLevels())) : ?>
|
||||
<?php $taxonomy_text = []; ?>
|
||||
<?php foreach ($taxonomy as $node) : ?>
|
||||
<?php if ($node->state == 1 && in_array($node->access, $user->getAuthorisedViewLevels())) : ?>
|
||||
<?php $taxonomy_text[] = $node->title; ?>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php if (count($taxonomy_text)) : ?>
|
||||
<li class="result__taxonomy-item result__taxonomy--<?php echo $type; ?>">
|
||||
<span><?php echo Text::_(LanguageHelper::branchSingular($type)); ?>:</span>
|
||||
<?php echo Text::_(LanguageHelper::branchSingular(implode(',', $taxonomy_text))); ?>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
96
components/com_finder/tmpl/search/default_results.php
Normal file
96
components/com_finder/tmpl/search/default_results.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
?>
|
||||
<?php // Display the suggested search if it is different from the current search. ?>
|
||||
<?php if (($this->suggested && $this->params->get('show_suggested_query', 1)) || ($this->explained && $this->params->get('show_explained_query', 1))) : ?>
|
||||
<div id="search-query-explained" class="com-finder__explained">
|
||||
<?php // Display the suggested search query. ?>
|
||||
<?php if ($this->suggested && $this->params->get('show_suggested_query', 1)) : ?>
|
||||
<?php // Replace the base query string with the suggested query string. ?>
|
||||
<?php $uri = Uri::getInstance($this->query->toUri()); ?>
|
||||
<?php $uri->setVar('q', $this->suggested); ?>
|
||||
<?php // Compile the suggested query link. ?>
|
||||
<?php $linkUrl = Route::_($uri->toString(['path', 'query'])); ?>
|
||||
<?php $link = '<a href="' . $linkUrl . '">' . $this->escape($this->suggested) . '</a>'; ?>
|
||||
<?php echo Text::sprintf('COM_FINDER_SEARCH_SIMILAR', $link); ?>
|
||||
<?php elseif ($this->explained && $this->params->get('show_explained_query', 1)) : ?>
|
||||
<?php // Display the explained search query. ?>
|
||||
<p role="alert">
|
||||
<?php echo Text::plural('COM_FINDER_QUERY_RESULTS', $this->total, $this->explained); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php // Display the 'no results' message and exit the template. ?>
|
||||
<?php if (($this->total === 0) || ($this->total === null)) : ?>
|
||||
<div id="search-result-empty" class="com-finder__empty">
|
||||
<h2><?php echo Text::_('COM_FINDER_SEARCH_NO_RESULTS_HEADING'); ?></h2>
|
||||
<?php $multilang = Factory::getApplication()->getLanguageFilter() ? '_MULTILANG' : ''; ?>
|
||||
<p><?php echo Text::sprintf('COM_FINDER_SEARCH_NO_RESULTS_BODY' . $multilang, $this->escape($this->query->input)); ?></p>
|
||||
</div>
|
||||
<?php // Exit this template. ?>
|
||||
<?php return; ?>
|
||||
<?php endif; ?>
|
||||
<?php // Display the 'Sort By' drop-down. ?>
|
||||
<?php if ($this->params->get('show_sort_order', 0) && !empty($this->sortOrderFields) && !empty($this->results)) : ?>
|
||||
<div id="search-sorting" class="com-finder__sorting">
|
||||
<?php echo $this->loadTemplate('sorting'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php // Activate the highlighter if enabled. ?>
|
||||
<?php if (!empty($this->query->highlight) && $this->params->get('highlight_terms', 1)) : ?>
|
||||
<?php
|
||||
// Allow a maximum of 10 tokens to be highlighted. Otherwise the URL can get too long.
|
||||
$this->document->getWebAssetManager()->useScript('highlight');
|
||||
$this->document->addScriptOptions(
|
||||
'highlight',
|
||||
[[
|
||||
'class' => 'js-highlight',
|
||||
'highLight' => array_slice($this->query->highlight, 0, 10),
|
||||
]]
|
||||
);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
<?php // Display a list of results ?>
|
||||
<ul id="search-result-list" class="js-highlight com-finder__results-list" start="<?php echo (int) $this->pagination->limitstart + 1; ?>">
|
||||
<?php $this->baseUrl = Uri::getInstance()->toString(['scheme', 'host', 'port']); ?>
|
||||
<?php foreach ($this->results as $i => $result) : ?>
|
||||
<?php $this->result = &$result; ?>
|
||||
<?php $this->result->counter = $i + 1; ?>
|
||||
<?php $layout = $this->getLayoutFile($this->result->layout); ?>
|
||||
<?php echo $this->loadTemplate($layout); ?>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php // Display the pagination ?>
|
||||
<div class="com-finder__navigation search-pagination">
|
||||
<?php if ($this->params->get('show_pagination', 1) > 0) : ?>
|
||||
<div class="com-finder__pagination w-100">
|
||||
<?php echo $this->pagination->getPagesLinks(); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($this->params->get('show_pagination_results', 1) > 0) : ?>
|
||||
<div class="com-finder__counter search-pages-counter">
|
||||
<?php // Prepare the pagination string. Results X - Y of Z ?>
|
||||
<?php $start = (int) $this->pagination->limitstart + 1; ?>
|
||||
<?php $total = (int) $this->pagination->total; ?>
|
||||
<?php $limit = (int) $this->pagination->limit * $this->pagination->pagesCurrent; ?>
|
||||
<?php $limit = (int) min($limit, $total); ?>
|
||||
<?php echo Text::sprintf('COM_FINDER_SEARCH_RESULTS_OF', $start, $limit, $total); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
46
components/com_finder/tmpl/search/default_sorting.php
Normal file
46
components/com_finder/tmpl/search/default_sorting.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage com_finder
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
?>
|
||||
<?php HTMLHelper::_('bootstrap.dropdown', '.dropdown-toggle'); ?>
|
||||
<div class="sorting">
|
||||
<label id="sorting_label" for="sorting_btn"><?php echo Text::_('COM_FINDER_SORT_BY'); ?></label>
|
||||
<div class="sorting__select btn-group">
|
||||
<?php foreach ($this->sortOrderFields as $sortOrderField) : ?>
|
||||
<?php if ($sortOrderField->active) : ?>
|
||||
<button id="sorting_btn" class="btn btn-secondary dropdown-toggle" type="button"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded="false" aria-controls="finder_sorting_list">
|
||||
<?php echo $this->escape($sortOrderField->label); ?>
|
||||
</button>
|
||||
<?php
|
||||
break;
|
||||
endif; ?>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<ul id="finder_sorting_list" class="sorting__list block dropdown-menu" role="listbox" aria-labelledby="finder_sorting_desc">
|
||||
<?php foreach ($this->sortOrderFields as $sortOrderField) : ?>
|
||||
<li class="sorting__list-li <?php echo $sortOrderField->active ? 'sorting__list-li-active' : ''; ?>">
|
||||
<a class="dropdown-item" role="option" href="<?php echo Route::_($sortOrderField->url);?>" <?php echo $sortOrderField->active ? 'aria-current="true"' : ''; ?>>
|
||||
<?php echo $this->escape($sortOrderField->label); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user