update ver 3.31

This commit is contained in:
2026-03-05 23:02:54 +05:00
parent 5028022ae5
commit eed11761c7
11 changed files with 237 additions and 111 deletions

View File

@@ -1,14 +1,17 @@
### search
## Модуль Поиск v2.26.0
## Модуль Поиск 3.31.1
### Данный модуль позволяет организвать поиск необходимой информации на вашем сайте.
### Данный модуль позволяет организовать поиск необходимой информации на вашем сайте.
* Поиск информации осуществляется как по заголовкам документов, так и по содержимому. Для того, чтобы вывести форму для поиска на вашем сайте, разместите системный тег <strong>[mod_search]</strong> в нужном месте вашего шаблона сайта.
* Поиск информации осуществляется как по заголовкам документов, так и по содержимому. Для того, чтобы вывести форму для поиска на вашем сайте, разместите системный тег <strong>[mod_search]</strong> в нужном месте вашего шаблона сайта или шаблона рубрики.
* Не забудьте в разделе "Редактировать поля и права рубрики" активировать чекбоксы напротив полей, по которым вы хотите осуществлять поиск.
### Changelog:
05.03.2026 - версия 3.31.1 - Адаптация для версии AVE.CMS v3.31.1 ALT. Рефакторинг кода для работы в среде PHP-8.4, верстка публичной части модуля Bootstrap v5. Вы можете использовать файл mod_search_styles.css - подключается в основной шаблон при использовании модуля программно.
02.09.2019 - версия 2.26.0 - Адаптация для версии AVE.CMS v3.26
16.07.2016 - версия 2.1.1 - обновления от @MadDen

View File

@@ -86,26 +86,36 @@ class Search
* ВНЕШНИЕ МЕТОДЫ
*/
function searchResultGet($tpl_dir, $lang_file)
function searchResultGet($tpl_dir, $lang_file)
{
global $AVE_DB, $AVE_Template;
$AVE_Template->config_load($lang_file);
define('MODULE_TITLE', $AVE_Template->get_config_vars('SEARCH_RESULTS'));
// Подключаем CSS
$GLOBALS['user_header']['search_css'] = '<link rel="stylesheet" href="' . ABS_PATH . 'modules/search/css/mod_search_styles.css" type="text/css" />';
if (!defined('MODULE_TITLE')) {
define('MODULE_TITLE', $AVE_Template->get_config_vars('SEARCH_RESULTS'));
}
$stem_words = array();
$tmp = preg_replace('/[^\x20-\xFF]|[><!?.,;=-]/', ' ', $_REQUEST['query']);
// Проверяем существование query в запросе, чтобы не было Notice
$query_string = isset($_REQUEST['query']) ? $_REQUEST['query'] : '';
$tmp = preg_replace('/[^\x20-\xFF]|[><!?.,;=-]/', ' ', $query_string);
$this->_search_string = trim(preg_replace('/ +/', ' ', stripslashes($tmp)));
$this->_search_string = trim(preg_replace('/\s+/', ' ', stripslashes($tmp)));
// Определяем тип поиска (в заголовках или везде)
$type_search = (isset($_REQUEST['ts']) && $_REQUEST['ts'] == 1) ? 1 : 0;
if (mb_strlen($this->_search_string) > 2)
{
// экранирование для LIKE
$tmp = str_replace('\\', '\\\\', $this->_search_string);
$tmp = addcslashes(addslashes($tmp), '%_');
$tmp = preg_replace('/ +/', ' ', $tmp);
$tmp = preg_replace('/\s+/', ' ', $tmp);
$tmp = preg_split('/\s+/', $tmp);
$where = '';
@@ -171,12 +181,10 @@ class Search
$query_feld = $AVE_DB->Query($sql);
//Debug::_echo($sql);
$num = $AVE_DB->NumAllRows($sql);
$pages = @ceil($num / $limit);
$pages = (int)@ceil($num / $limit);
$sw = addslashes(mb_strtolower($this->_search_string));
$sw = addslashes(mb_strtolower($this->_search_string));
$exist = $AVE_DB->Query("
SELECT 1
@@ -207,23 +215,29 @@ class Search
search_count = 1
");
}
$page_nav = '';
if ($num > $limit)
{
$page_nav = '<a class="page_nav" href="index.php?module=search&amp;query='
. urlencode($this->_search_string)
. ($type_search ? '&amp;ts=1' : '')
. ($_REQUEST['or'] ? '&amp;or=1' : '')
. (isset($_REQUEST['or']) && $_REQUEST['or'] == 1 ? '&amp;or=1' : '')
. '&amp;page={s}">{t}</a>';
$page_nav = get_pagination($pages, 'page', $page_nav);
}
$AVE_Template->assign('q_navi', $page_nav);
}
if ($num > 0)
if ($num > 0 && isset($query_feld))
{
$modul_search_results = array();
array_walk($this->_stem_words, create_function('&$val','$val=preg_quote(stripslashes(stripslashes(str_replace("\"","&quot;",$val))),"/");'));
array_walk($this->_stem_words, function(&$val) {
$val = preg_quote(stripslashes(stripslashes(str_replace('"', "&quot;", $val))), "/");
});
$regex_snapshot = '/.{0,100}[^\s]*' . implode('[^\s]*.{0,100}|.{0,100}[^\s]*', $this->_stem_words) . '[^\s]*.{0,100}/iu';
$regex_highlight = '/[^\s]*' . implode('[^\s]*|[^\s]*', $this->_stem_words) . '[^\s]*/iu';
@@ -251,19 +265,21 @@ class Search
$row->Text = strip_tags($row->Text, $this->_allowed_tags);
$fo = array();
preg_match($regex_snapshot, $row->Text, $fo);
$row->Text = $type_search ? '' : '';
while (list($key, $val) = @each($fo))
preg_match_all($regex_snapshot, $row->Text, $fo);
$row->Text = '';
if (!empty($fo[0]) && !$type_search)
{
$row->Text .= $val . ($type_search ? '' : '');
foreach ($fo[0] as $val)
{
$row->Text .= $val . ' ... ';
}
}
if (1 == $this->_highlight && !empty($this->_stem_words))
{
$row->Text = @preg_replace($regex_highlight, "<strong class=\"mod_search_highlight\">$0</strong>", $row->Text);
$row->Text = preg_replace($regex_highlight, "<strong class=\"mod_search_highlight\">$0</strong>", $row->Text);
}
$row->document_alias = rewrite_link('index.php?id=' . $row->Id . '&amp;doc=' . (empty($row->document_alias) ? prepare_url($row->document_title) : $row->document_alias));

View File

@@ -0,0 +1,9 @@
.mod_search_highlight {
background-color: #fff3cd; /* Светло-желтый фон (Bootstrap warning light) */
color: #664d03; /* Темно-коричневый текст для контраста */
padding: 0 2px; /* Небольшие отступы по бокам */
border-radius: 3px; /* Скругление углов */
font-weight: 600; /* Делаем текст чуть жирнее */
border-bottom: 1px solid #ffe69c; /* Тонкая полоска снизу для акцента */
}
.bi .bi-sort-alpha-down {color: #F70101 !important}

View File

@@ -4,7 +4,7 @@
$module = array(
'ModuleSysName' => 'search',
'ModuleVersion' => '1.26.0',
'ModuleVersion' => '3.31.1',
'ModuleAutor' => 'AVE.cms Team',
'ModuleCopyright' => '&copy; 2007-' . date('Y') . ' AVE.cms',
'ModuleIsFunction' => 1,

View File

@@ -4,6 +4,7 @@ MODULE_DESCRIPTION = "Данный модуль позволяет орган
[module]
SEARCH_BUTTON = "Поиск"
SEARCH_PLACEHOLDER = "Поиск по сайту..."
SEARCH_IN_DESCRIPTION = "В тексте"
SEARCH_IN_TITLE = "В заголовках"
SEARCH_HELP = "<strong>Использование поиска</strong><br><br>Используйте знак &quot;<strong>+</strong>&quot; для строгого включения слова в поиск.<br>Используйте знак &quot;<strong>-</strong>&quot; для исключения слова из поиска.<br><br>Обязательно используйте пробел перед знаками &quot;<strong>+</strong>&quot; и &quot;<strong>-</strong>&quot;. "

View File

@@ -13,10 +13,20 @@ if (!defined('BASE_DIR')) exit;
function mod_search()
{
global $AVE_Template;
global $AVE_Template;
if (isset($_REQUEST['module']) && $_REQUEST['module'] == 'search') $AVE_Template->assign('hide', 1);
$AVE_Template->display(BASE_DIR . '/modules/search/templates/form.tpl');
$lang = preg_replace('/[^a-zA-Z0-9_-]/', '', $_SESSION['user_language'] ?? 'ru');
$lang_file = BASE_DIR . '/modules/search/lang/' . $lang . '.txt';
if (file_exists($lang_file)) {
$AVE_Template->config_load($lang_file, 'module');
}
if (isset($_REQUEST['module']) && $_REQUEST['module'] == 'search') {
$AVE_Template->assign('hide', 1);
}
$AVE_Template->display(BASE_DIR . '/modules/search/templates/form.tpl');
}
if (!defined('ACP') && (isset($_REQUEST['module']) && $_REQUEST['module'] == 'search'))

26
sql.php
View File

@@ -8,39 +8,35 @@
* @filesource
*/
if (!defined('BASE_DIR')) exit;
$module_sql_install = array();
$module_sql_deinstall = array();
$module_sql_update = array();
$module_sql_deinstall[] = "DROP TABLE IF EXISTS %%PRFX%%_module_search;";
$module_sql_deinstall[] = "DROP TABLE IF EXISTS `%%PRFX%%_module_search`;";
$module_sql_install[] = "CREATE TABLE %%PRFX%%_module_search (
$module_sql_install[] = "
CREATE TABLE IF NOT EXISTS `%%PRFX%%_module_search` (
`Id` int(10) unsigned NOT NULL auto_increment,
`search_query` char(255) NOT NULL,
`search_count` mediumint(5) unsigned NOT NULL default '0',
`search_found` mediumint(5) unsigned NOT NULL default '0',
PRIMARY KEY (`Id`),
UNIQUE KEY `search_query` (`search_query`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;";
) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;
";
// Обновление модуля
$module_sql_update[] = "
UPDATE
`%%PRFX%%_module`
SET
ModuleAveTag = '" . $modul['ModuleAveTag'] . "',
ModulePHPTag = '" . $modul['ModulePHPTag'] . "',
ModuleVersion = '" . $modul['ModuleVersion'] . "'
ModuleAveTag = '" . $module['ModuleAveTag'] . "',
ModulePHPTag = '" . $module['ModulePHPTag'] . "',
ModuleVersion = '" . $module['ModuleVersion'] . "'
WHERE
ModuleSysName = '" . $modul['ModuleSysName'] . "'
ModuleSysName = '" . $module['ModuleSysName'] . "'
LIMIT 1;
";
$module_sql_update[] = "
RENAME TABLE
`%%PRFX%%_modul_search`
TO
`%%PRFX%%_module_search`
";
?>

View File

@@ -1,5 +1,18 @@
<form class="search" method="get" action="{$ABS_PATH}">
<input type="hidden" name="module" value="search" />
<input type="text" id="query" class="search text" name="query" value="" />
<input type="submit" class="search button" value="Поиск" />
<form class="search-mini" method="get" action="{$ABS_PATH}">
<input type="hidden" name="module" value="search" />
<div class="input-group">
<input type="text"
id="query"
class="form-control"
name="query"
placeholder="{#SEARCH_PLACEHOLDER#}"
aria-label="{#SEARCH_BUTTON#}"
value="{$smarty.request.query|default:''|stripslashes|escape}" />
<button class="btn btn-primary" type="submit">
<i class="bi bi-search"></i>
<span class="d-none d-lg-inline ms-1">{#SEARCH_BUTTON#}</span>
</button>
</div>
</form>

View File

@@ -1,17 +1,52 @@
<div class="mod_search_big">
<form method="get" action="{$ABS_PATH}">
<input type="hidden" name="module" value="search" />
<input style="width:350px" class="query" name="query" type="text" value="{$smarty.request.query|stripslashes|escape}" />
<input type="submit" class="button" style="vertical-align: middle;" value="{#SEARCH_BUTTON#}" />&nbsp;
<input title="{#SEARCH_HELP#}" type="button" class="button" style="vertical-align: middle;" value="?" />
<br />
<div class="mod_search_compact mt-4">
<form method="get" action="{$ABS_PATH}" class="row g-2">
<input type="hidden" name="module" value="search" />
<div class="col-lg-7 col-md-10">
<div class="input-group">
<input class="form-control"
name="query"
type="text"
placeholder="{#SEARCH_BUTTON#}"
value="{$smarty.request.query|default:''|stripslashes|escape}" />
<button type="submit" class="btn btn-primary px-4">
<i class="bi bi-search"></i> {#SEARCH_BUTTON#}
</button>
</div>
</div>
<div style="margin-top:5px">
<input style="border:0px" type="radio" name="ts" value="0"{if $smarty.request.ts==0 || !$smarty.request.ts} checked="checked"{/if} />{#SEARCH_IN_DESCRIPTION#}
<input style="border:0px" type="radio" name="ts" value="1"{if $smarty.request.ts==1} checked="checked"{/if} />{#SEARCH_IN_TITLE#}
<div class="col-12 mt-2">
<div class="d-flex flex-wrap gap-3 align-items-center small text-muted">
<div class="search-options d-flex gap-2">
<div class="form-check">
<input class="form-check-input" type="radio" name="ts" id="ts0" value="0"
{if ($smarty.request.ts|default:0) == 0}checked{/if}>
<label class="form-check-label" for="ts0">{#SEARCH_IN_DESCRIPTION#}</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="ts" id="ts1" value="1"
{if ($smarty.request.ts|default:0) == 1}checked{/if}>
<label class="form-check-label" for="ts1">{#SEARCH_IN_TITLE#}</label>
</div>
</div>
<input style="border:0px" type="radio" name="or" value="0"{if $smarty.request.or==0 || !$smarty.request.or} checked="checked"{/if} />{#SEARCH_USE_AND#}
<input style="border:0px" type="radio" name="or" value="1"{if $smarty.request.or==1} checked="checked"{/if} />{#SEARCH_USE_OR#}
</div>
</form>
<div class="vr d-none d-md-block opacity-25" style="height: 15px;"></div>
<div class="search-logic d-flex gap-2">
<div class="form-check">
<input class="form-check-input" type="radio" name="or" id="or0" value="0"
{if ($smarty.request.or|default:0) == 0}checked{/if}>
<label class="form-check-label" for="or0">{#SEARCH_USE_AND#}</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="or" id="or1" value="1"
{if ($smarty.request.or|default:0) == 1}checked{/if}>
<label class="form-check-label" for="or1">{#SEARCH_USE_OR#}</label>
</div>
</div>
</div>
</div>
</form>
</div>

View File

@@ -1,16 +1,59 @@
<h2 id="page-heading">{#SEARCH_RESULTS#}</h2>
<h2 id="page-heading" class="mb-4">{#SEARCH_RESULTS#}</h2>
{if $no_results==1}
<p>{#SEARCH_NO_RESULTS#}</p>
{if $no_results == 1}
<div class="alert alert-light border">
{#SEARCH_NO_RESULTS#}
</div>
{else}
{if $q_navi}<div class="page_navigation_box">{#SEARCH_PAGES#} {$q_navi}</div>{/if}
{if $q_navi}
<div class="mb-4 small text-muted">
{#SEARCH_PAGES#}: {$q_navi}
</div>
{/if}
{foreach from=$searchresults item=result}
<h4><a href="{$result->document_alias}">{$result->document_title|escape}</a> {$result->document_published|date_format:$DATE_FORMAT|pretty_date}</h4>
<blockquote>{$result->Text}<br /><a href="{$result->document_alias}">{#SEARCH_VIEW#}</a> | <a target="_blank" href="{$result->document_alias}">{#SEARCH_VIEW_BLANK#}</a> {$result->document_count_view}</blockquote><br />
{/foreach}
<div class="search-results">
{foreach from=$searchresults item=result}
<div class="search-item mb-4" style="max-width: 700px;">
<div class="d-flex align-items-center mb-1">
<a href="{$result->document_alias}" class="text-success text-decoration-none small" style="font-size: 0.85rem;">
{if $ABS_PATH == "/" || $ABS_PATH == ""}
{* Собираем URL динамически на основе данных сервера *}
{if $smarty.server.HTTPS == 'on' || $smarty.server.SERVER_PORT == 443}https{else}http{/if}://{$smarty.server.HTTP_HOST}{$result->document_alias|replace:'//':'/'}
{else}
{* Если в ABS_PATH уже прописан путь, просто чистим лишние слеши *}
{$ABS_PATH|regex_replace:"/\/$/":""}{$result->document_alias}
{/if}
</a>
</div>
{if $q_navi}<div class="page_navigation_box">{#SEARCH_PAGES#} {$q_navi}</div>{/if}
<h4 class="mb-1">
<a href="{$result->document_alias}" class="text-primary text-decoration-none hover-underline" style="color: #1a0dab !important;">
{$result->document_title|escape}
</a>
</h4>
{if $result->Text}
<div class="text-dark mb-1" style="font-size: 0.95rem; color: #4d5156; line-height: 1.5;">
{$result->Text}
</div>
{/if}
<div class="text-muted" style="font-size: 0.85rem;">
<span class="me-3">Опубликован: {$result->document_published|date_format:$DATE_FORMAT|pretty_date}</span>
<span>Просмотров: {$result->document_count_view}</span>
</div>
</div>
{/foreach}
</div>
{if $q_navi}
<div class="mt-4 pt-3 border-top small text-muted">
{#SEARCH_PAGES#}: {$q_navi}
</div>
{/if}
{/if}
{include file="$inc_path/form_big.tpl"}
<div class="mt-5 bg-light p-4 border rounded shadow-sm">
<h6 class="mb-3 text-muted fw-bold">Новый поиск</h6>
{include file="$inc_path/form_big.tpl"}
</div>

View File

@@ -1,22 +1,21 @@
<script language="javascript">
$(document).ready(function(){ldelim}
$(".ConfirmClear").click(function(e){ldelim}
e.preventDefault();
var href = $(this).attr('href');
var title = '{#SEARCH_DELETE_ITEMS#}';
var confirm = '{#SEARCH_DELETE_CONFIRM#}';
jConfirm(
confirm,
title,
function(b){ldelim}
if (b){ldelim}
window.location = href;
{rdelim}
{rdelim}
);
{rdelim});
e.preventDefault();
var form = $(this).closest('form');
var title = '{#SEARCH_DELETE_ITEMS#}';
var confirm = '{#SEARCH_DELETE_CONFIRM#}';
jConfirm(
confirm,
title,
function(b){ldelim}
if (b){ldelim}
form.submit();
{rdelim}
{rdelim}
);
{rdelim});
{rdelim});
</script>
@@ -40,32 +39,33 @@ $(document).ready(function(){ldelim}
</div>
<div class="widget first">
<div class="head"><h5 class="iFrames">{#SEARCH_MODULE_NAME#}</h5></div>
<table cellpadding="0" cellspacing="0" width="100%" class="display" id="dinamTable">
<thead>
<tr>
<th width="60%">{#SEARCH_WORD#}</th>
<th width="20%">{#SEARCH_QUERIES#}</th>
<th width="20%">{#SEARCH_FOUND_DOCS#}</th>
</tr>
</thead>
<tbody>
<div class="head"><h5 class="iFrames">{#SEARCH_MODULE_NAME#}</h5></div>
<table cellpadding="0" cellspacing="0" width="100%" class="display" id="dinamTable">
<thead>
<tr>
<th width="60%" align="left" style="text-align: left; padding-left: 15px;">{#SEARCH_WORD#}</th>
<th width="20%">{#SEARCH_QUERIES#}</th>
<th width="20%">{#SEARCH_FOUND_DOCS#}</th>
</tr>
</thead>
<tbody>
{foreach from=$items item=item}
<tr class="gradeA">
<td align="center"><strong>{$item->search_query|escape}</strong></td>
<td align="center">{$item->search_count}</td>
<td align="center">{$item->search_found}</td>
</tr>
{/foreach}
</tbody>
</table>
<tr class="gradeA">
<td align="left" style="padding-left: 15px;"><strong>{$item->search_query|escape}</strong></td>
<td align="center">{$item->search_count}</td>
<td align="center">{$item->search_found}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
<div class="widget" style="margin-top: 0px;">
<div class="body aligncenter">
<form id="#form_submit" method="post" action="index.php?do=modules&action=modedit&mod=search&moduleaction=delwords&cp={$sess}">
<input href="index.php?do=modules&action=modedit&mod=search&moduleaction=delwords&cp={$sess}" type="button" class="basicBtn ConfirmClear" value="{#SEARCH_DELETE_ITEMS#}" />
</form>
<div class="body">
<form id="#form_submit" method="post" action="index.php?do=modules&action=modedit&mod=search&moduleaction=delwords&cp={$sess}">
<button type="submit" class="basicBtn ConfirmClear">
<i class="bi bi-trash"></i> {#SEARCH_DELETE_ITEMS#}
</button>
</form>
</div>
</div>
</div>