/** * Method to parse a language/locale key and return a simple language string. * * @param string $lang The language/locale key. For example: en-GB * * @return string The simple language string. For example: en * * @since 2.5 */ public static function getPrimaryLanguage($lang) { static $data; // Only parse the identifier if necessary. if (!isset($data[$lang])) { if (is_callable(array('Locale', 'getPrimaryLanguage'))) { // Get the language key using the Locale package. $data[$lang] = Locale::getPrimaryLanguage($lang); } else { // Get the language key using string position. $data[$lang] = StringHelper::substr($lang, 0, StringHelper::strpos($lang, '-')); } } return $data[$lang]; }
/** * Plugin that adds a pagebreak into the text and truncates text at that point * * @param string $context The context of the content being passed to the plugin. * @param object &$row The article object. Note $article->text is also available * @param mixed &$params The article params * @param integer $page The 'page' number * * @return mixed Always returns void or true * * @since 1.6 */ public function onContentPrepare($context, &$row, &$params, $page = 0) { $canProceed = $context == 'com_content.article'; if (!$canProceed) { return; } $style = $this->params->get('style', 'pages'); // Expression to search for. $regex = '#<hr(.*)class="system-pagebreak"(.*)\\/>#iU'; $input = JFactory::getApplication()->input; $print = $input->getBool('print'); $showall = $input->getBool('showall'); if (!$this->params->get('enabled', 1)) { $print = true; } if ($print) { $row->text = preg_replace($regex, '<br />', $row->text); return true; } // Simple performance check to determine whether bot should process further. if (StringHelper::strpos($row->text, 'class="system-pagebreak') === false) { return true; } $view = $input->getString('view'); $full = $input->getBool('fullview'); if (!$page) { $page = 0; } if ($params->get('intro_only') || $params->get('popup') || $full || $view != 'article') { $row->text = preg_replace($regex, '', $row->text); return; } // Load plugin language files only when needed (ex: not needed if no system-pagebreak class exists). $this->loadLanguage(); // Find all instances of plugin and put in $matches. $matches = array(); preg_match_all($regex, $row->text, $matches, PREG_SET_ORDER); if ($showall && $this->params->get('showall', 1)) { $hasToc = $this->params->get('multipage_toc', 1); if ($hasToc) { // Display TOC. $page = 1; $this->_createToc($row, $matches, $page); } else { $row->toc = ''; } $row->text = preg_replace($regex, '<br />', $row->text); return true; } // Split the text around the plugin. $text = preg_split($regex, $row->text); if (!isset($text[$page])) { throw new Exception(JText::_('JERROR_PAGE_NOT_FOUND'), 404); } // Count the number of pages. $n = count($text); // We have found at least one plugin, therefore at least 2 pages. if ($n > 1) { $title = $this->params->get('title', 1); $hasToc = $this->params->get('multipage_toc', 1); // Adds heading or title to <site> Title. if ($title) { if ($page) { if ($page && @$matches[$page - 1][2]) { $attrs = JUtility::parseAttributes($matches[$page - 1][1]); if (@$attrs['title']) { $row->page_title = $attrs['title']; } } } } // Reset the text, we already hold it in the $text array. $row->text = ''; if ($style == 'pages') { // Display TOC. if ($hasToc) { $this->_createToc($row, $matches, $page); } else { $row->toc = ''; } // Traditional mos page navigation $pageNav = new JPagination($n, $page, 1); // Page counter. $row->text .= '<div class="pagenavcounter">'; $row->text .= $pageNav->getPagesCounter(); $row->text .= '</div>'; // Page text. $text[$page] = str_replace('<hr id="system-readmore" />', '', $text[$page]); $row->text .= $text[$page]; // $row->text .= '<br />'; $row->text .= '<div class="pager">'; // Adds navigation between pages to bottom of text. if ($hasToc) { $this->_createNavigation($row, $page, $n); } // Page links shown at bottom of page if TOC disabled. if (!$hasToc) { $row->text .= $pageNav->getPagesLinks(); } $row->text .= '</div>'; } else { $t[] = $text[0]; $t[] = (string) JHtml::_($style . '.start', 'article' . $row->id . '-' . $style); foreach ($text as $key => $subtext) { if ($key >= 1) { $match = $matches[$key - 1]; $match = (array) JUtility::parseAttributes($match[0]); if (isset($match['alt'])) { $title = stripslashes($match['alt']); } elseif (isset($match['title'])) { $title = stripslashes($match['title']); } else { $title = JText::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM', $key + 1); } $t[] = (string) JHtml::_($style . '.panel', $title, 'article' . $row->id . '-' . $style . $key); } $t[] = (string) $subtext; } $t[] = (string) JHtml::_($style . '.end'); $row->text = implode(' ', $t); } } return true; }
/** * Cloak all emails in text from spambots via Javascript. * * @param string &$text The string to be cloaked. * @param mixed &$params Additional parameters. Parameter "mode" (integer, default 1) * replaces addresses with "mailto:" links if nonzero. * * @return boolean True on success. */ protected function _cloak(&$text, &$params) { /* * Check for presence of {emailcloak=off} which is explicits disables this * bot for the item. */ if (StringHelper::strpos($text, '{emailcloak=off}') !== false) { $text = StringHelper::str_ireplace('{emailcloak=off}', '', $text); return true; } // Simple performance check to determine whether bot should process further. if (StringHelper::strpos($text, '@') === false) { return true; } $mode = $this->params->def('mode', 1); // Example: any@example.org $searchEmail = '([\\w\\.\\-\\+]+\\@(?:[a-z0-9\\.\\-]+\\.)+(?:[a-zA-Z0-9\\-]{2,10}))'; // Example: any@example.org?subject=anyText $searchEmailLink = $searchEmail . '([?&][\\x20-\\x7f][^"<>]+)'; // Any Text $searchText = '((?:[\\x20-\\x7f]|[\\xA1-\\xFF]|[\\xC2-\\xDF][\\x80-\\xBF]|[\\xE0-\\xEF][\\x80-\\xBF]{2}|[\\xF0-\\xF4][\\x80-\\xBF]{3})[^<>]+)'; // Any Image link $searchImage = "(<img[^>]+>)"; // Any Text with <span or <strong $searchTextSpan = '(<span[^>]+>|<span>|<strong>|<strong><span[^>]+>|<strong><span>)' . $searchText . '(</span>|</strong>|</span></strong>)'; // Any address with <span or <strong $searchEmailSpan = '(<span[^>]+>|<span>|<strong>|<strong><span[^>]+>|<strong><span>)' . $searchEmail . '(</span>|</strong>|</span></strong>)'; /* * Search and fix derivatives of link code <a href="http://mce_host/ourdirectory/email@example.org" * >email@example.org</a>. This happens when inserting an email in TinyMCE, cancelling its suggestion to add * the mailto: prefix... */ $pattern = $this->_getPattern($searchEmail, $searchEmail); $pattern = str_replace('"mailto:', '"http://mce_host([\\x20-\\x7f][^<>]+/)', $pattern); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[3][0]; $mailText = $regs[5][0]; // Check to see if mail text is different from mail addy $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText); // Ensure that attributes is not stripped out by email cloaking $replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search and fix derivatives of link code <a href="http://mce_host/ourdirectory/email@example.org" * >anytext</a>. This happens when inserting an email in TinyMCE, cancelling its suggestion to add * the mailto: prefix... */ $pattern = $this->_getPattern($searchEmail, $searchText); $pattern = str_replace('"mailto:', '"http://mce_host([\\x20-\\x7f][^<>]+/)', $pattern); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[3][0]; $mailText = $regs[5][0]; // Check to see if mail text is different from mail addy $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0); // Ensure that attributes is not stripped out by email cloaking $replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@example.org" * >email@example.org</a> */ $pattern = $this->_getPattern($searchEmail, $searchEmail); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0]; $mailText = $regs[4][0]; // Check to see if mail text is different from mail addy $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText); // Ensure that attributes is not stripped out by email cloaking $replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0]); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@amail.com" * ><anyspan >email@amail.com</anyspan></a> */ $pattern = $this->_getPattern($searchEmail, $searchEmailSpan); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0]; $mailText = $regs[4][0] . $regs[5][0] . $regs[6][0]; // Check to see if mail text is different from mail addy $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText); // Ensure that attributes is not stripped out by email cloaking $replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0])); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@amail.com"> * <anyspan >anytext</anyspan></a> */ $pattern = $this->_getPattern($searchEmail, $searchTextSpan); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0]; $mailText = $regs[4][0] . addslashes($regs[5][0]) . $regs[6][0]; $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0); // Ensure that attributes is not stripped out by email cloaking $replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0])); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@example.org"> * anytext</a> */ $pattern = $this->_getPattern($searchEmail, $searchText); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0]; $mailText = addslashes($regs[4][0]); $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0); // Ensure that attributes is not stripped out by email cloaking $replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0]); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@example.org"> * <img anything></a> */ $pattern = $this->_getPattern($searchEmail, $searchImage); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0]; $mailText = $regs[4][0]; $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0); // Ensure that attributes is not stripped out by email cloaking $replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0])); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@example.org"> * <img anything>email@example.org</a> */ $pattern = $this->_getPattern($searchEmail, $searchImage . $searchEmail); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0]; $mailText = $regs[4][0] . $regs[5][0]; $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText); // Ensure that attributes is not stripped out by email cloaking $replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0])); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@example.org"> * <img anything>any text</a> */ $pattern = $this->_getPattern($searchEmail, $searchImage . $searchText); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0]; $mailText = $regs[4][0] . addslashes($regs[5][0]); $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0); // Ensure that attributes is not stripped out by email cloaking $replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0])); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@example.org? * subject=Text">email@example.org</a> */ $pattern = $this->_getPattern($searchEmailLink, $searchEmail); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0] . $regs[3][0]; $mailText = $regs[5][0]; // Needed for handling of Body parameter $mail = str_replace('&', '&', $mail); // Check to see if mail text is different from mail addy $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText); // Ensure that attributes is not stripped out by email cloaking $replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@example.org? * subject=Text">anytext</a> */ $pattern = $this->_getPattern($searchEmailLink, $searchText); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0] . $regs[3][0]; $mailText = addslashes($regs[5][0]); // Needed for handling of Body parameter $mail = str_replace('&', '&', $mail); $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0); // Ensure that attributes is not stripped out by email cloaking $replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@amail.com?subject= Text" * ><anyspan >email@amail.com</anyspan></a> */ $pattern = $this->_getPattern($searchEmailLink, $searchEmailSpan); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0] . $regs[3][0]; $mailText = $regs[4][0] . $regs[5][0] . $regs[6][0] . $regs[7][0]; // Check to see if mail text is different from mail addy $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText); // Ensure that attributes is not stripped out by email cloaking $replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0])); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code <a href="mailto:email@amail.com?subject= Text"> * <anyspan >anytext</anyspan></a> */ $pattern = $this->_getPattern($searchEmailLink, $searchTextSpan); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[2][0] . $regs[3][0]; $mailText = $regs[4][0] . $regs[5][0] . addslashes($regs[6][0]) . $regs[7][0]; $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0); // Ensure that attributes is not stripped out by email cloaking $replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0])); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code * <a href="mailto:email@amail.com?subject=Text"><img anything></a> */ $pattern = $this->_getPattern($searchEmailLink, $searchImage); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[1][0] . $regs[2][0] . $regs[3][0]; $mailText = $regs[5][0]; // Needed for handling of Body parameter $mail = str_replace('&', '&', $mail); // Check to see if mail text is different from mail addy $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0); // Ensure that attributes is not stripped out by email cloaking $replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0])); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code * <a href="mailto:email@amail.com?subject=Text"><img anything>email@amail.com</a> */ $pattern = $this->_getPattern($searchEmailLink, $searchImage . $searchEmail); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[1][0] . $regs[2][0] . $regs[3][0]; $mailText = $regs[4][0] . $regs[5][0] . $regs[6][0]; // Needed for handling of Body parameter $mail = str_replace('&', '&', $mail); // Check to see if mail text is different from mail addy $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText); // Ensure that attributes is not stripped out by email cloaking $replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0])); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for derivatives of link code * <a href="mailto:email@amail.com?subject=Text"><img anything>any text</a> */ $pattern = $this->_getPattern($searchEmailLink, $searchImage . $searchText); while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[1][0] . $regs[2][0] . $regs[3][0]; $mailText = $regs[4][0] . $regs[5][0] . addslashes($regs[6][0]); // Needed for handling of Body parameter $mail = str_replace('&', '&', $mail); // Check to see if mail text is different from mail addy $replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0); // Ensure that attributes is not stripped out by email cloaking $replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0])); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0])); } /* * Search for plain text email addresses, such as email@example.org but not within HTML tags: * <img src="..." title="*****@*****.**"> or <input type="text" placeholder="*****@*****.**"> * The negative lookahead '(?![^<]*>)' is used to exclude this kind of occurrences */ $pattern = '~(?![^<>]*>)' . $searchEmail . '~i'; while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) { $mail = $regs[1][0]; $replacement = JHtml::_('email.cloak', $mail, $mode); // Replace the found address with the js cloaked email $text = substr_replace($text, $replacement, $regs[1][1], strlen($mail)); } return true; }
/** * Function to convert a sef route to an internal URI * * @param JUri &$uri The sef URI * * @return string Internal URI * * @since 3.2 * @deprecated 4.0 Attach your logic as rule to the main parse stage */ protected function parseSefRoute(&$uri) { $route = $uri->getPath(); // Remove the suffix if ($this->app->get('sef_suffix')) { if ($suffix = pathinfo($route, PATHINFO_EXTENSION)) { $route = str_replace('.' . $suffix, '', $route); } } // Get the variables from the uri $vars = $uri->getQuery(true); // Handle an empty URL (special case) if (empty($route)) { // If route is empty AND option is set in the query, assume it's non-sef url, and parse apropriately if (isset($vars['option']) || isset($vars['Itemid'])) { return $this->parseRawRoute($uri); } $item = $this->menu->getDefault($this->app->getLanguage()->getTag()); // If user not allowed to see default menu item then avoid notices if (is_object($item)) { // Set the information in the request $vars = $item->query; // Get the itemid $vars['Itemid'] = $item->id; // Set the active menu item $this->menu->setActive($vars['Itemid']); $this->setVars($vars); } return $vars; } // Parse the application route $segments = explode('/', $route); if (count($segments) > 1 && $segments[0] == 'component') { $vars['option'] = 'com_' . $segments[1]; $vars['Itemid'] = null; $route = implode('/', array_slice($segments, 2)); } else { // Get menu items. $items = $this->menu->getMenu(); $found = false; $route_lowercase = StringHelper::strtolower($route); $lang_tag = $this->app->getLanguage()->getTag(); // Iterate through all items and check route matches. foreach ($items as $item) { if ($item->route && StringHelper::strpos($route_lowercase . '/', $item->route . '/') === 0 && $item->type != 'menulink') { // Usual method for non-multilingual site. if (!$this->app->getLanguageFilter()) { // Exact route match. We can break iteration because exact item was found. if ($item->route == $route_lowercase) { $found = $item; break; } // Partial route match. Item with highest level takes priority. if (!$found || $found->level < $item->level) { $found = $item; } } elseif ($item->language == '*' || $item->language == $lang_tag) { // Exact route match. if ($item->route == $route_lowercase) { $found = $item; // Break iteration only if language is matched. if ($item->language == $lang_tag) { break; } } // Partial route match. Item with highest level or same language takes priority. if (!$found || $found->level < $item->level || $item->language == $lang_tag) { $found = $item; } } } } if (!$found) { $found = $this->menu->getDefault($lang_tag); } else { $route = substr($route, strlen($found->route)); if ($route) { $route = substr($route, 1); } } if ($found) { $vars['Itemid'] = $found->id; $vars['option'] = $found->component; } } // Set the active menu item if (isset($vars['Itemid'])) { $this->menu->setActive($vars['Itemid']); } // Set the variables $this->setVars($vars); // Parse the component route if (!empty($route) && isset($this->_vars['option'])) { $segments = explode('/', $route); if (empty($segments[0])) { array_shift($segments); } // Handle component route $component = preg_replace('/[^A-Z0-9_\\.-]/i', '', $this->_vars['option']); if (count($segments)) { $crouter = $this->getComponentRouter($component); $vars = $crouter->parse($segments); $this->setVars($vars); } } else { // Set active menu item if ($item = $this->menu->getActive()) { $vars = $item->query; } } return $vars; }
/** * Method to get the table of contents * * @return array Table of contents */ public function &getToc() { if (!is_null($this->toc)) { return $this->toc; } // Get vars $lang_tag = $this->getLangTag(); $help_search = $this->getHelpSearch(); // New style - Check for a TOC JSON file if (file_exists(JPATH_BASE . '/help/' . $lang_tag . '/toc.json')) { $data = json_decode(file_get_contents(JPATH_BASE . '/help/' . $lang_tag . '/toc.json')); // Loop through the data array foreach ($data as $key => $value) { $this->toc[$key] = JText::_('COM_ADMIN_HELP_' . $value); } // Sort the Table of Contents asort($this->toc); return $this->toc; } // Get Help files jimport('joomla.filesystem.folder'); $files = JFolder::files(JPATH_BASE . '/help/' . $lang_tag, '\\.xml$|\\.html$'); $this->toc = array(); foreach ($files as $file) { $buffer = file_get_contents(JPATH_BASE . '/help/' . $lang_tag . '/' . $file); if (!preg_match('#<title>(.*?)</title>#', $buffer, $m)) { continue; } $title = trim($m[1]); if (!$title) { continue; } // Translate the page title $title = JText::_($title); // Strip the extension $file = preg_replace('#\\.xml$|\\.html$#', '', $file); if ($help_search && StringHelper::strpos(StringHelper::strtolower(strip_tags($buffer)), StringHelper::strtolower($help_search)) === false) { continue; } // Add an item in the Table of Contents $this->toc[$file] = $title; } // Sort the Table of Contents asort($this->toc); return $this->toc; }
/** * Execute and display a template script. * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return mixed A string if successful, otherwise an Error object. */ public function display($tpl = null) { JLoader::register('SearchHelper', JPATH_COMPONENT_ADMINISTRATOR . '/helpers/search.php'); $app = JFactory::getApplication(); $uri = JUri::getInstance(); $error = null; $rows = null; $results = null; $total = 0; // Get some data from the model $areas = $this->get('areas'); $state = $this->get('state'); $searchword = $state->get('keyword'); $params = $app->getParams(); $menus = $app->getMenu(); $menu = $menus->getActive(); // Because the application sets a default page title, we need to get it right from the menu item itself if (is_object($menu)) { $menu_params = new Registry($menu->params); if (!$menu_params->get('page_title')) { $params->set('page_title', JText::_('COM_SEARCH_SEARCH')); } } else { $params->set('page_title', JText::_('COM_SEARCH_SEARCH')); } $title = $params->get('page_title'); if ($app->get('sitename_pagetitles', 0) == 1) { $title = JText::sprintf('JPAGETITLE', $app->get('sitename'), $title); } elseif ($app->get('sitename_pagetitles', 0) == 2) { $title = JText::sprintf('JPAGETITLE', $title, $app->get('sitename')); } $this->document->setTitle($title); if ($params->get('menu-meta_description')) { $this->document->setDescription($params->get('menu-meta_description')); } if ($params->get('menu-meta_keywords')) { $this->document->setMetadata('keywords', $params->get('menu-meta_keywords')); } if ($params->get('robots')) { $this->document->setMetadata('robots', $params->get('robots')); } // Built select lists $orders = array(); $orders[] = JHtml::_('select.option', 'newest', JText::_('COM_SEARCH_NEWEST_FIRST')); $orders[] = JHtml::_('select.option', 'oldest', JText::_('COM_SEARCH_OLDEST_FIRST')); $orders[] = JHtml::_('select.option', 'popular', JText::_('COM_SEARCH_MOST_POPULAR')); $orders[] = JHtml::_('select.option', 'alpha', JText::_('COM_SEARCH_ALPHABETICAL')); $orders[] = JHtml::_('select.option', 'category', JText::_('JCATEGORY')); $lists = array(); $lists['ordering'] = JHtml::_('select.genericlist', $orders, 'ordering', 'class="inputbox"', 'value', 'text', $state->get('ordering')); $searchphrases = array(); $searchphrases[] = JHtml::_('select.option', 'all', JText::_('COM_SEARCH_ALL_WORDS')); $searchphrases[] = JHtml::_('select.option', 'any', JText::_('COM_SEARCH_ANY_WORDS')); $searchphrases[] = JHtml::_('select.option', 'exact', JText::_('COM_SEARCH_EXACT_PHRASE')); $lists['searchphrase'] = JHtml::_('select.radiolist', $searchphrases, 'searchphrase', '', 'value', 'text', $state->get('match')); // Log the search JSearchHelper::logSearch($searchword, 'com_search'); // Limit searchword $lang = JFactory::getLanguage(); $upper_limit = $lang->getUpperLimitSearchWord(); $lower_limit = $lang->getLowerLimitSearchWord(); if (SearchHelper::limitSearchWord($searchword)) { $error = JText::sprintf('COM_SEARCH_ERROR_SEARCH_MESSAGE', $lower_limit, $upper_limit); } // Sanitise searchword if (SearchHelper::santiseSearchWord($searchword, $state->get('match'))) { $error = JText::_('COM_SEARCH_ERROR_IGNOREKEYWORD'); } if (!$searchword && !empty($this->input) && count($this->input->post)) { // $error = JText::_('COM_SEARCH_ERROR_ENTERKEYWORD'); } // Put the filtered results back into the model // for next release, the checks should be done in the model perhaps... $state->set('keyword', $searchword); if ($error == null) { $results = $this->get('data'); $total = $this->get('total'); $pagination = $this->get('pagination'); JLoader::register('ContentHelperRoute', JPATH_SITE . '/components/com_content/helpers/route.php'); for ($i = 0, $count = count($results); $i < $count; $i++) { $row =& $results[$i]->text; if ($state->get('match') == 'exact') { $searchwords = array($searchword); $needle = $searchword; } else { $searchworda = preg_replace('#\\xE3\\x80\\x80#s', ' ', $searchword); $searchwords = preg_split("/\\s+/u", $searchworda); $needle = $searchwords[0]; } $row = SearchHelper::prepareSearchContent($row, $needle); $searchwords = array_values(array_unique($searchwords)); $srow = strtolower(SearchHelper::remove_accents($row)); $hl1 = '<span class="highlight">'; $hl2 = '</span>'; $posCollector = array(); $mbString = extension_loaded('mbstring'); if ($mbString) { // E.g. german umlauts like ä are converted to ae and so // $pos calculated with $srow doesn't match for $row $correctPos = mb_strlen($srow) > mb_strlen($row); $highlighterLen = mb_strlen($hl1 . $hl2); } else { // E.g. german umlauts like ä are converted to ae and so // $pos calculated with $srow desn't match for $row $correctPos = StringHelper::strlen($srow) > StringHelper::strlen($row); $highlighterLen = StringHelper::strlen($hl1 . $hl2); } foreach ($searchwords as $hlword) { if ($mbString) { if (($pos = mb_strpos($srow, strtolower(SearchHelper::remove_accents($hlword)))) !== false) { // Iconv transliterates '€' to 'EUR' // TODO: add other expanding translations? $eur_compensation = $pos > 0 ? substr_count($row, "€", 0, $pos) * 2 : 0; $pos -= $eur_compensation; if ($correctPos) { // Calculate necessary corrections from 0 to current $pos $ChkRow = mb_substr($row, 0, $pos); $sChkRowLen = mb_strlen(strtolower(SearchHelper::remove_accents($ChkRow))); $ChkRowLen = mb_strlen($ChkRow); // Correct $pos $pos -= $sChkRowLen - $ChkRowLen; } // Collect pos and searchword $posCollector[$pos] = $hlword; } } else { if (($pos = StringHelper::strpos($srow, strtolower(SearchHelper::remove_accents($hlword)))) !== false) { // Iconv transliterates '€' to 'EUR' // TODO: add other expanding translations? $eur_compensation = $pos > 0 ? substr_count($row, "€", 0, $pos) * 2 : 0; $pos -= $eur_compensation; if ($correctPos) { // Calculate necessary corrections from 0 to current $pos $ChkRow = StringHelper::substr($row, 0, $pos); $sChkRowLen = StringHelper::strlen(strtolower(SearchHelper::remove_accents($ChkRow))); $ChkRowLen = StringHelper::strlen($ChkRow); // Correct $pos $pos -= $sChkRowLen - $ChkRowLen; } // Collect pos and searchword $posCollector[$pos] = $hlword; } } } if (count($posCollector)) { // Sort by pos. Easier to handle overlapping highlighter-spans ksort($posCollector); $cnt = 0; $lastHighlighterEnd = -1; foreach ($posCollector as $pos => $hlword) { $pos += $cnt * $highlighterLen; /* Avoid overlapping/corrupted highlighter-spans * TODO $chkOverlap could be used to highlight remaining part * of searchword outside last highlighter-span. * At the moment no additional highlighter is set.*/ $chkOverlap = $pos - $lastHighlighterEnd; if ($chkOverlap >= 0) { // Set highlighter around searchword if ($mbString) { $hlwordLen = mb_strlen($hlword); $row = mb_substr($row, 0, $pos) . $hl1 . mb_substr($row, $pos, $hlwordLen) . $hl2 . mb_substr($row, $pos + $hlwordLen); } else { $hlwordLen = StringHelper::strlen($hlword); $row = StringHelper::substr($row, 0, $pos) . $hl1 . StringHelper::substr($row, $pos, StringHelper::strlen($hlword)) . $hl2 . StringHelper::substr($row, $pos + StringHelper::strlen($hlword)); } $cnt++; $lastHighlighterEnd = $pos + $hlwordLen + $highlighterLen; } } } $result =& $results[$i]; if ($result->created) { $created = JHtml::_('date', $result->created, JText::_('DATE_FORMAT_LC3')); } else { $created = ''; } $result->text = JHtml::_('content.prepare', $result->text, '', 'com_search.search'); $result->created = $created; $result->count = $i + 1; } } // Check for layout override $active = JFactory::getApplication()->getMenu()->getActive(); if (isset($active->query['layout'])) { $this->setLayout($active->query['layout']); } // Escape strings for HTML output $this->pageclass_sfx = htmlspecialchars($params->get('pageclass_sfx')); $this->pagination =& $pagination; $this->results =& $results; $this->lists =& $lists; $this->params =& $params; $this->ordering = $state->get('ordering'); $this->searchword = $searchword; $this->origkeyword = $state->get('origkeyword'); $this->searchphrase = $state->get('match'); $this->searchareas = $areas; $this->total = $total; $this->error = $error; $this->action = $uri; parent::display($tpl); }
/** * Returns substring of characters around a searchword. * * @param string $text The source string. * @param integer $searchword Number of chars to return. * * @return string * * @since 1.5 */ public static function _smartSubstr($text, $searchword) { $lang = JFactory::getLanguage(); $length = $lang->getSearchDisplayedCharactersNumber(); $ltext = self::remove_accents($text); $textlen = StringHelper::strlen($ltext); $lsearchword = StringHelper::strtolower(self::remove_accents($searchword)); $wordfound = false; $pos = 0; while ($wordfound === false && $pos < $textlen) { if (($wordpos = @StringHelper::strpos($ltext, ' ', $pos + $length)) !== false) { $chunk_size = $wordpos - $pos; } else { $chunk_size = $length; } $chunk = StringHelper::substr($ltext, $pos, $chunk_size); $wordfound = StringHelper::strpos(StringHelper::strtolower($chunk), $lsearchword); if ($wordfound === false) { $pos += $chunk_size + 1; } } if ($wordfound !== false) { return ($pos > 0 ? '... ' : '') . StringHelper::substr($text, $pos, $chunk_size) . ' ...'; } else { if (($wordpos = @StringHelper::strpos($text, ' ', $length)) !== false) { return StringHelper::substr($text, 0, $wordpos) . ' ...'; } else { return StringHelper::substr($text, 0, $length); } } }
/** * Method to process the query input string and extract required, optional, * and excluded tokens; taxonomy filters; and date filters. * * @param string $input The query input string. * @param string $lang The query input language. * @param string $mode The query matching mode. * * @return boolean True on success. * * @since 2.5 * @throws Exception on database error. */ protected function processString($input, $lang, $mode) { // Clean up the input string. $input = html_entity_decode($input, ENT_QUOTES, 'UTF-8'); $input = StringHelper::strtolower($input); $input = preg_replace('#\\s+#mi', ' ', $input); $input = StringHelper::trim($input); $debug = JFactory::getConfig()->get('debug_lang'); /* * First, we need to handle string based modifiers. String based * modifiers could potentially include things like "category:blah" or * "before:2009-10-21" or "type:article", etc. */ $patterns = array('before' => JText::_('COM_FINDER_FILTER_WHEN_BEFORE'), 'after' => JText::_('COM_FINDER_FILTER_WHEN_AFTER')); // Add the taxonomy branch titles to the possible patterns. foreach (FinderIndexerTaxonomy::getBranchTitles() as $branch) { // Add the pattern. $patterns[$branch] = StringHelper::strtolower(JText::_(FinderHelperLanguage::branchSingular($branch))); } // Container for search terms and phrases. $terms = array(); $phrases = array(); // Cleared filter branches. $cleared = array(); /* * Compile the suffix pattern. This is used to match the values of the * filter input string. Single words can be input directly, multi-word * values have to be wrapped in double quotes. */ $quotes = html_entity_decode('‘’'', ENT_QUOTES, 'UTF-8'); $suffix = '(([\\w\\d' . $quotes . '-]+)|\\"([\\w\\d\\s' . $quotes . '-]+)\\")'; /* * Iterate through the possible filter patterns and search for matches. * We need to match the key, colon, and a value pattern for the match * to be valid. */ foreach ($patterns as $modifier => $pattern) { $matches = array(); if ($debug) { $pattern = substr($pattern, 2, -2); } // Check if the filter pattern is in the input string. if (preg_match('#' . $pattern . '\\s*:\\s*' . $suffix . '#mi', $input, $matches)) { // Get the value given to the modifier. $value = isset($matches[3]) ? $matches[3] : $matches[1]; // Now we have to handle the filter string. switch ($modifier) { // Handle a before and after date filters. case 'before': case 'after': // Get the time offset. $offset = JFactory::getApplication()->get('offset'); // Array of allowed when values. $whens = array('before', 'after', 'exact'); // The value of 'today' is a special case that we need to handle. if ($value === StringHelper::strtolower(JText::_('COM_FINDER_QUERY_FILTER_TODAY'))) { $value = JFactory::getDate('now', $offset)->format('%Y-%m-%d'); } // Try to parse the date string. $date = JFactory::getDate($value, $offset); // Check if the date was parsed successfully. if ($date->toUnix() !== null) { // Set the date filter. $this->date1 = $date->toSql(); $this->when1 = in_array($modifier, $whens) ? $modifier : 'before'; } break; // Handle a taxonomy branch filter. // Handle a taxonomy branch filter. default: // Try to find the node id. $return = FinderIndexerTaxonomy::getNodeByTitle($modifier, $value); // Check if the node id was found. if ($return) { // Check if the branch has been cleared. if (!in_array($modifier, $cleared)) { // Clear the branch. $this->filters[$modifier] = array(); // Add the branch to the cleared list. $cleared[] = $modifier; } // Add the filter to the list. $this->filters[$modifier][$return->title] = (int) $return->id; } break; } // Clean up the input string again. $input = str_replace($matches[0], '', $input); $input = preg_replace('#\\s+#mi', ' ', $input); $input = StringHelper::trim($input); } } /* * Extract the tokens enclosed in double quotes so that we can handle * them as phrases. */ if (StringHelper::strpos($input, '"') !== false) { $matches = array(); // Extract the tokens enclosed in double quotes. if (preg_match_all('#\\"([^"]+)\\"#mi', $input, $matches)) { /* * One or more phrases were found so we need to iterate through * them, tokenize them as phrases, and remove them from the raw * input string before we move on to the next processing step. */ foreach ($matches[1] as $key => $match) { // Find the complete phrase in the input string. $pos = StringHelper::strpos($input, $matches[0][$key]); $len = StringHelper::strlen($matches[0][$key]); // Add any terms that are before this phrase to the stack. if (StringHelper::trim(StringHelper::substr($input, 0, $pos))) { $terms = array_merge($terms, explode(' ', StringHelper::trim(StringHelper::substr($input, 0, $pos)))); } // Strip out everything up to and including the phrase. $input = StringHelper::substr($input, $pos + $len); // Clean up the input string again. $input = preg_replace('#\\s+#mi', ' ', $input); $input = StringHelper::trim($input); // Get the number of words in the phrase. $parts = explode(' ', $match); // Check if the phrase is longer than three words. if (count($parts) > 3) { /* * If the phrase is longer than three words, we need to * break it down into smaller chunks of phrases that * are less than or equal to three words. We overlap * the chunks so that we can ensure that a match is * found for the complete phrase and not just portions * of it. */ for ($i = 0, $c = count($parts); $i < $c; $i += 2) { // Set up the chunk. $chunk = array(); // The chunk has to be assembled based on how many // pieces are available to use. switch ($c - $i) { /* * If only one word is left, we can break from * the switch and loop because the last word * was already used at the end of the last * chunk. */ case 1: break 2; // If there words are left, we use them both as // the last chunk of the phrase and we're done. // If there words are left, we use them both as // the last chunk of the phrase and we're done. case 2: $chunk[] = $parts[$i]; $chunk[] = $parts[$i + 1]; break; // If there are three or more words left, we // build a three word chunk and continue on. // If there are three or more words left, we // build a three word chunk and continue on. default: $chunk[] = $parts[$i]; $chunk[] = $parts[$i + 1]; $chunk[] = $parts[$i + 2]; break; } // If the chunk is not empty, add it as a phrase. if (count($chunk)) { $phrases[] = implode(' ', $chunk); $terms[] = implode(' ', $chunk); } } } else { // The phrase is <= 3 words so we can use it as is. $phrases[] = $match; $terms[] = $match; } } } } // Add the remaining terms if present. if (!empty($input)) { $terms = array_merge($terms, explode(' ', $input)); } // An array of our boolean operators. $operator => $translation $operators = array('AND' => StringHelper::strtolower(JText::_('COM_FINDER_QUERY_OPERATOR_AND')), 'OR' => StringHelper::strtolower(JText::_('COM_FINDER_QUERY_OPERATOR_OR')), 'NOT' => StringHelper::strtolower(JText::_('COM_FINDER_QUERY_OPERATOR_NOT'))); // If language debugging is enabled you need to ignore the debug strings in matching. if (JDEBUG) { $debugStrings = array('**', '??'); $operators = str_replace($debugStrings, '', $operators); } /* * Iterate through the terms and perform any sorting that needs to be * done based on boolean search operators. Terms that are before an * and/or/not modifier have to be handled in relation to their operator. */ for ($i = 0, $c = count($terms); $i < $c; $i++) { // Check if the term is followed by an operator that we understand. if (isset($terms[$i + 1]) && in_array($terms[$i + 1], $operators)) { // Get the operator mode. $op = array_search($terms[$i + 1], $operators); // Handle the AND operator. if ($op === 'AND' && isset($terms[$i + 2])) { // Tokenize the current term. $token = FinderIndexerHelper::tokenize($terms[$i], $lang, true); $token = $this->getTokenData($token); // Set the required flag. $token->required = true; // Add the current token to the stack. $this->included[] = $token; $this->highlight = array_merge($this->highlight, array_keys($token->matches)); // Skip the next token (the mode operator). $this->operators[] = $terms[$i + 1]; // Tokenize the term after the next term (current plus two). $other = FinderIndexerHelper::tokenize($terms[$i + 2], $lang, true); $other = $this->getTokenData($other); // Set the required flag. $other->required = true; // Add the token after the next token to the stack. $this->included[] = $other; $this->highlight = array_merge($this->highlight, array_keys($other->matches)); // Remove the processed phrases if possible. if (($pk = array_search($terms[$i], $phrases)) !== false) { unset($phrases[$pk]); } if (($pk = array_search($terms[$i + 2], $phrases)) !== false) { unset($phrases[$pk]); } // Remove the processed terms. unset($terms[$i]); unset($terms[$i + 1]); unset($terms[$i + 2]); // Adjust the loop. $i += 2; continue; } elseif ($op === 'OR' && isset($terms[$i + 2])) { // Tokenize the current term. $token = FinderIndexerHelper::tokenize($terms[$i], $lang, true); $token = $this->getTokenData($token); // Set the required flag. $token->required = false; // Add the current token to the stack. if (count($token->matches)) { $this->included[] = $token; $this->highlight = array_merge($this->highlight, array_keys($token->matches)); } else { $this->ignored[] = $token; } // Skip the next token (the mode operator). $this->operators[] = $terms[$i + 1]; // Tokenize the term after the next term (current plus two). $other = FinderIndexerHelper::tokenize($terms[$i + 2], $lang, true); $other = $this->getTokenData($other); // Set the required flag. $other->required = false; // Add the token after the next token to the stack. if (count($other->matches)) { $this->included[] = $other; $this->highlight = array_merge($this->highlight, array_keys($other->matches)); } else { $this->ignored[] = $other; } // Remove the processed phrases if possible. if (($pk = array_search($terms[$i], $phrases)) !== false) { unset($phrases[$pk]); } if (($pk = array_search($terms[$i + 2], $phrases)) !== false) { unset($phrases[$pk]); } // Remove the processed terms. unset($terms[$i]); unset($terms[$i + 1]); unset($terms[$i + 2]); // Adjust the loop. $i += 2; continue; } } elseif (isset($terms[$i + 1]) && array_search($terms[$i], $operators) === 'OR') { // Skip the next token (the mode operator). $this->operators[] = $terms[$i]; // Tokenize the next term (current plus one). $other = FinderIndexerHelper::tokenize($terms[$i + 1], $lang, true); $other = $this->getTokenData($other); // Set the required flag. $other->required = false; // Add the token after the next token to the stack. if (count($other->matches)) { $this->included[] = $other; $this->highlight = array_merge($this->highlight, array_keys($other->matches)); } else { $this->ignored[] = $other; } // Remove the processed phrase if possible. if (($pk = array_search($terms[$i + 1], $phrases)) !== false) { unset($phrases[$pk]); } // Remove the processed terms. unset($terms[$i]); unset($terms[$i + 1]); // Adjust the loop. $i++; continue; } elseif (isset($terms[$i + 1]) && array_search($terms[$i], $operators) === 'NOT') { // Skip the next token (the mode operator). $this->operators[] = $terms[$i]; // Tokenize the next term (current plus one). $other = FinderIndexerHelper::tokenize($terms[$i + 1], $lang, true); $other = $this->getTokenData($other); // Set the required flag. $other->required = false; // Add the next token to the stack. if (count($other->matches)) { $this->excluded[] = $other; } else { $this->ignored[] = $other; } // Remove the processed phrase if possible. if (($pk = array_search($terms[$i + 1], $phrases)) !== false) { unset($phrases[$pk]); } // Remove the processed terms. unset($terms[$i]); unset($terms[$i + 1]); // Adjust the loop. $i++; continue; } } /* * Iterate through any search phrases and tokenize them. We handle * phrases as autonomous units and do not break them down into two and * three word combinations. */ for ($i = 0, $c = count($phrases); $i < $c; $i++) { // Tokenize the phrase. $token = FinderIndexerHelper::tokenize($phrases[$i], $lang, true); $token = $this->getTokenData($token); // Set the required flag. $token->required = true; // Add the current token to the stack. $this->included[] = $token; $this->highlight = array_merge($this->highlight, array_keys($token->matches)); // Remove the processed term if possible. if (($pk = array_search($phrases[$i], $terms)) !== false) { unset($terms[$pk]); } // Remove the processed phrase. unset($phrases[$i]); } /* * Handle any remaining tokens using the standard processing mechanism. */ if (!empty($terms)) { // Tokenize the terms. $terms = implode(' ', $terms); $tokens = FinderIndexerHelper::tokenize($terms, $lang, false); // Make sure we are working with an array. $tokens = is_array($tokens) ? $tokens : array($tokens); // Get the token data and required state for all the tokens. foreach ($tokens as $token) { // Get the token data. $token = $this->getTokenData($token); // Set the required flag for the token. $token->required = $mode === 'AND' ? $token->phrase ? false : true : false; // Add the token to the appropriate stack. if (count($token->matches) || $token->required) { $this->included[] = $token; $this->highlight = array_merge($this->highlight, array_keys($token->matches)); } else { $this->ignored[] = $token; } } } return true; }
<?php /** * @package Joomla.Site * @subpackage mod_footer * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\String\StringHelper; $app = JFactory::getApplication(); $date = JFactory::getDate(); $cur_year = JHtml::_('date', $date, 'Y'); $csite_name = $app->get('sitename'); if (is_int(StringHelper::strpos(JText::_('MOD_FOOTER_LINE1'), '%date%'))) { $line1 = str_replace('%date%', $cur_year, JText::_('MOD_FOOTER_LINE1')); } else { $line1 = JText::_('MOD_FOOTER_LINE1'); } if (is_int(StringHelper::strpos($line1, '%sitename%'))) { $lineone = str_replace('%sitename%', $csite_name, $line1); } else { $lineone = $line1; } $moduleclass_sfx = htmlspecialchars($params->get('moduleclass_sfx'), ENT_COMPAT, 'UTF-8'); require JModuleHelper::getLayoutPath('mod_footer', $params->get('layout', 'default'));
/** * Get sanitized folder * * @param \Joomla\Registry\Registry &$params module params objects * * @return mixed */ public static function getFolder(&$params) { $folder = $params->get('folder'); $LiveSite = JUri::base(); // If folder includes livesite info, remove if (StringHelper::strpos($folder, $LiveSite) === 0) { $folder = str_replace($LiveSite, '', $folder); } // If folder includes absolute path, remove if (StringHelper::strpos($folder, JPATH_SITE) === 0) { $folder = str_replace(JPATH_BASE, '', $folder); } $folder = str_replace('\\', DIRECTORY_SEPARATOR, $folder); $folder = str_replace('/', DIRECTORY_SEPARATOR, $folder); return $folder; }
defined('_JEXEC') or die; use Joomla\String\StringHelper; // Get the mime type class. $mime = !empty($this->result->mime) ? 'mime-' . $this->result->mime : null; $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; // Find the position of the search term $pos = $term_length ? StringHelper::strpos(StringHelper::strtolower($this->result->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($this->result->description, ' ', $start > 0 ? $start - 1 : 0); $start = $space && $space < $pos ? $space + 1 : $start; $description = JHtml::_('string.truncate', StringHelper::substr($this->result->description, $start), $desc_length, true); } $route = $this->result->route; // Get the route with highlighting information. if (!empty($this->query->highlight) && empty($this->result->mime) && $this->params->get('highlight_terms', 1) && JPluginHelper::isEnabled('system', 'highlight')) { $route .= '&highlight=' . base64_encode(json_encode($this->query->highlight)); } ?> <li> <h4 class="result-title <?php echo $mime; ?> ">