update to ver. 3.31

This commit is contained in:
2026-03-29 18:38:12 +05:00
parent 663463f7fd
commit 455e8c4662
16 changed files with 909 additions and 569 deletions

View File

@@ -1,19 +1,17 @@
### poll
## Модуль Опросы/Голосование v1.26.1a
## Модуль Опросы/Голосование v3.31
### для AVE.CMS ALT ≥ v3.31
### Данный модуль предназачен для организации системы опросов на сайте.
### Данный модуль предназачен для организации системы опросов на сайте с возможностью оставлять комментарии.
* Возможности модуля позволяют создавать неограниченное количество опросных листов, а также неограниченное количество вопросов.
* Добавить в .htaccess (вне секции | Rewrite engine )<br>
### Poll<br>
RewriteRule ^poll-([0-9]+).html$ index.php?module=poll&action=result&pid=$1<br>
RewriteRule ^pollcomment-([0-9]+).html$ index.php?module=poll&action=form&pop=1&pid=$1<br>
RewriteRule ^poll-archive.html$ index.php?module=poll&action=archive<br>
### Changelog:
29.03.2026 - обновление модуля - версия 3.31 - рефакторинг кода для работы в ave.cms ALT v3.31. Добавлена Captcha. Реализована поддержка ЧПУ-алиасов для внутренних ссылок модуля.
04.09.2019 - версия 1.26.1а - адаптация для ave.cms 3.26
22.09.2013 - версия 1.1a

View File

@@ -1,7 +0,0 @@
Äîáàâèòü â .htaccess
## Poll
RewriteRule ^poll-([0-9]+).html$ index.php?module=poll&action=result&pid=$1
RewriteRule ^pollcomment-([0-9]+).html$ index.php?module=poll&action=form&pop=1&pid=$1
RewriteRule ^poll-archive.html$ index.php?module=poll&action=archive

View File

@@ -24,7 +24,7 @@
<div class="num"><a class="basicNum" href="index.php?do=modules&action=modedit&mod=poll&moduleaction=new&cp={$sess}">{#POLL_NEW_LINK#}</a></div>
</div>
<form method="post" action="index.php?do=modules&action=modedit&mod=poll&moduleaction=comments&id={$smarty.request.id|escape}&cp={$sess}&pop=1&sub=save&page={$smarty.request.page|escape}">
<form method="post" action="index.php?do=modules&action=modedit&mod=poll&moduleaction=comments&id={$smarty.request.id|escape}&cp={$sess}&pop=1&sub=save&page={$smarty.request.page|default:''|escape}">
<table cellpadding="0" cellspacing="0" width="100%" class="tableStatic mainForm">
<col width="10" />
<col width="150" />
@@ -35,36 +35,39 @@
<td>{#POLL_COMMENT_TITLE#}</td>
</tr>
</thead>
<tbody>
{foreach from=$items item=item}
<tr>
<td>
<input title="{#POLL_MARK_DELETE#}" name="del[{$item->id}]" type="checkbox" id="del[{$item->id}]" class="topDir" value="1">
</td>
<td nowrap="nowrap" valign="top">
{#POLL_COMMENT_AUTHOR#}<br />
<strong>{$item->poll_comment_author|escape}</strong>
<br />
<br />
{#POLL_COMMENT_DATE#}<br />
<strong>{$item->poll_comment_time|date_format:$DATE_FORMAT|pretty_date}</strong>
</td>
<td>
<div class="pr12">
<span class="dgrey">Тема</span>
<input name="comment_title[{$item->id}]" type="text" id="comment_title[{$item->id}]" value="{$item->poll_comment_title|escape}"><br />
<span class="dgrey">Комментарий</span>
<textarea name="comment_text[{$item->id}]" cols="50" rows="5" id="comment_text[{$item->id}]">{$item->poll_comment_text|escape}</textarea>
</div>
</td>
</tr>
{/foreach}
<tr>
<td class="third" colspan="3">
<input class="basicBtn" type="submit" value="{#POLL_BUTTON_SAVE#}" />
</td>
</tr>
</tbody>
<tbody>
{foreach from=$items item=item}
<tr>
<td valign="top" align="center" style="padding-top: 10px;">
<input title="{#POLL_MARK_DELETE#}" name="del[{$item->id}]" type="checkbox" id="del[{$item->id}]" class="topDir" value="1">
</td>
<td nowrap="nowrap" valign="top">
{#POLL_COMMENT_AUTHOR#}<br />
<strong>{$item->poll_comment_author|escape}</strong>
<br />
<br />
{#POLL_COMMENT_DATE#}<br />
<strong>{$item->poll_comment_time|date_format:$DATE_FORMAT|pretty_date}</strong>
</td>
<td>
<div class="pr12" style="padding: 5px 0;">
<span class="dgrey">Тема</span><br />
<input name="comment_title[{$item->id}]" type="text" id="comment_title[{$item->id}]" value="{$item->poll_comment_title|escape}" style="width: 100%; margin-bottom: 10px;"><br />
<span class="dgrey">Комментарий</span><br />
<textarea name="comment_text[{$item->id}]" cols="50" rows="5" id="comment_text[{$item->id}]" style="width: 100%;">{$item->poll_comment_text|escape}</textarea>
</div>
</td>
</tr>
{/foreach}
<tr>
<td class="third" colspan="3">
<input class="basicBtn" type="submit" value="{#POLL_BUTTON_SAVE#}" />
</td>
</tr>
</tbody>
</table>
</form>
</div>

View File

@@ -114,7 +114,7 @@ $(document).ready(function(){ldelim}
</script>
{if $smarty.request.moduleaction == 'new'}
{if isset($smarty.request.moduleaction) && $smarty.request.moduleaction == 'new'}
<div class="title"><h5>{#POLL_ADD_POLL#}</h5></div>
<div class="widget" style="margin-top: 0px;">
@@ -138,7 +138,7 @@ $(document).ready(function(){ldelim}
<li class="firstB"><a href="#" title="{#MAIN_PAGE#}">{#MAIN_PAGE#}</a></li>
<li><a href="index.php?do=modules&amp;cp={$sess}">{#MODULES_SUB_TITLE#}</a></li>
<li><a href="index.php?do=modules&action=modedit&mod=poll&moduleaction=1&cp={$sess}">{#POLL_MODULE_NAME#}</a></li>
{if $smarty.request.moduleaction == 'new'}
{if isset($smarty.request.moduleaction) && $smarty.request.moduleaction == 'new'}
<li><strong class="code">{#POLL_ADD_POLL#}</strong></li>
{else}
<li>{#POLL_EDIT#}</li>
@@ -153,7 +153,7 @@ $(document).ready(function(){ldelim}
<div class="widget first">
<div class="head">
<h5 class="iFrames">{if $smarty.request.id != ''}{#POLL_EDIT#}{else}{#POLL_ADD_POLL#}{/if}</h5>
<h5 class="iFrames">{if isset($smarty.request.id) && $smarty.request.id != ''}{#POLL_EDIT#}{else}{#POLL_ADD_POLL#}{/if}</h5>
</div>
<table cellpadding="0" cellspacing="0" width="100%" class="tableStatic mainForm">
@@ -164,28 +164,44 @@ $(document).ready(function(){ldelim}
<div class="pr12"><input name="poll_name" type="text" id="poll_name" value="{$row->poll_title|default:''}" size="20" /></div>
</td>
</tr>
<tr>
<tr>
<td>{#POLL_STATUS#}?</td>
<td colspan="3">
<input type="radio" name="poll_status" id="poll_status" {if $row->poll_status==1}checked{/if} value="1"/><label>{#POLL_YES#}</label>
<input type="radio" name="poll_status" id="poll_status" {if $row->poll_status==0}checked{/if} value="0" /><label>{#POLL_NO#}</label>
<input type="radio" name="poll_status" id="poll_status_on" {if isset($row->poll_status) && $row->poll_status == 1}checked{/if} value="1"/>
<label for="poll_status_on">{#POLL_YES#}</label>
<input type="radio" name="poll_status" id="poll_status_off" {if !isset($row->poll_status) || $row->poll_status == 0}checked{/if} value="0" />
<label for="poll_status_off">{#POLL_NO#}</label>
</td>
</tr>
<tr>
<td>{#POLL_CAN_COMMENT#}</td>
<td colspan="3">
<input type="radio" name="poll_can_comment" id="poll_can_comment" value="1" {if $row->poll_can_comment==1}checked{/if} /><label>{#POLL_YES#}</label>
<input type="radio" name="poll_can_comment" id="poll_can_comment" value="0" {if $row->poll_can_comment==0}checked{/if} /><label>{#POLL_NO#}</label>
<input type="radio" name="poll_can_comment" id="poll_can_comment_yes" value="1" {if isset($row->poll_can_comment) && $row->poll_can_comment == 1}checked{/if} />
<label for="poll_can_comment_yes">{#POLL_YES#}</label>
<input type="radio" name="poll_can_comment" id="poll_can_comment_no" value="0" {if !isset($row->poll_can_comment) || $row->poll_can_comment == 0}checked{/if} />
<label for="poll_can_comment_no">{#POLL_NO#}</label>
</td>
</tr>
<tr>
<td>{#POLL_ANTISPAM#}</td>
<td colspan="3">
<input type="radio" name="poll_anti_spam" id="poll_anti_spam_yes" value="1" {if isset($row->poll_anti_spam) && $row->poll_anti_spam == 1}checked{/if} />
<label for="poll_anti_spam_yes">{#POLL_YES#}</label>
<input type="radio" name="poll_anti_spam" id="poll_anti_spam_no" value="0" {if !isset($row->poll_anti_spam) || $row->poll_anti_spam == 0}checked{/if} />
<label for="poll_anti_spam_no">{#POLL_NO#}</label>
</td>
</tr>
<tr>
<td>{#POLL_START_TIME#}</td>
<td>
<input id="published" name="poll_published" type="text" value="{if $row->poll_end}{$row->poll_start|date_format:"%d.%m.%Y %H:%M"}{else}{$published|date_format:"%d.%m.%Y %H:%M"}{/if}" style="width: 150px;" />
<input id="published" name="poll_published" type="text" value="{if isset($row->poll_start) && $row->poll_start}{$row->poll_start|date_format:"%d.%m.%Y %H:%M"}{else}{$published|date_format:"%d.%m.%Y %H:%M"}{/if}" style="width: 150px;" />
</td>
<td>{#POLL_END_TIME#}</td>
<td>
<input id="expire" name="poll_expire" type="text" value="{if $row->poll_end}{$row->poll_end|date_format:"%d.%m.%Y %H:%M"}{else}{$expire|date_format:"%d.%m.%Y %H:%M"}{/if}" style="width: 150px;" />
<input id="expire" name="poll_expire" type="text" value="{if isset($row->poll_end) && $row->poll_end}{$row->poll_end|date_format:"%d.%m.%Y %H:%M"}{else}{$expire|date_format:"%d.%m.%Y %H:%M"}{/if}" style="width: 150px;" />
</td>
</tr>
<tr>
@@ -198,7 +214,7 @@ $(document).ready(function(){ldelim}
</tr>
</table>
{if $smarty.request.id != ''}
{if isset($smarty.request.id) && $smarty.request.id != ''}
</div>
<div class="widget first">
<div class="head">
@@ -221,7 +237,7 @@ $(document).ready(function(){ldelim}
</tr>
</thead>
<tbody id="itemsId">
{if $items}
{if isset($items) && $items}
{foreach from=$items item=item}
<tr data-id="item_{$item->id}">
<td>
@@ -260,7 +276,7 @@ $(document).ready(function(){ldelim}
</div>
</form>
{if $smarty.request.id != ''}
{if isset($smarty.request.id) && $smarty.request.id != ''}
<div class="widget first">
<div class="head">
<h5 class="iFrames">{#POLL_QUESTIONS_ADD#}</h5>

View File

@@ -27,7 +27,7 @@
<table cellpadding="0" cellspacing="0" width="100%" class="tableStatic mainForm">
<col width="20">
<col>
<col width="120">
<col width="160">
<col width="200">
<col width="200">
<col width="150">
@@ -58,7 +58,10 @@
</td>
<td>
<div class="pr12"><input type="text" value="[mod_poll:{$item->id}]" size="12" readonly></div>
<div style="display: flex; align-items: center; gap: 5px;"><input id="copy_{$item->id}" type="text" value="[mod_poll:{$item->id}]" size="12" readonly>
<a style="text-align: center; padding: 5px 3px 4px 3px;" class="whiteBtn copyBtn topDir" href="javascript:void(0);" data-clipboard-action="copy" data-clipboard-target="#copy_{$item->id}" title="{#BANNER_SET_COPY#}">
<img style="margin-top: -3px; position: relative; top: 1px; padding: 0 3px;" class="clippy" src="{$ABS_PATH}admin/templates/images/clippy.svg" width="13"></a>
</div>
</td>
<td align="center">
@@ -75,6 +78,12 @@
<a title="{#POLL_EDIT_POLL#}" href="index.php?do=modules&action=modedit&mod=poll&moduleaction=edit&cp={$sess}&id={$item->id}"><span class="icon_sprite ico_edit"></span></a>
</td>
<td width="1%" align="center">
<a title="{#POLL_EDIT_CMMENT#}" href="index.php?do=modules&action=modedit&mod=poll&moduleaction=comments&cp={$sess}&id={$item->id}">
<span class="icon_sprite ico_comment"></span>
</a>
</td>
<td width="1%" align="center">
<a title="{#POLL_DELETE#}" class="ConfirmDelete toprightpDir" dir="{#POLL_DELETE#}" name="{#POLL_DELETE_CONFIRM#}" href="index.php?do=modules&action=modedit&mod=poll&moduleaction=delete&cp={$sess}&id={$item->id}"><span class="icon_sprite ico_delete"></span></a>
</td>
@@ -99,4 +108,6 @@
{$page_nav}
</ul>
</div>
{/if}
{/if}
<script>var clipboard = new Clipboard('.copyBtn');</script>

View File

@@ -115,7 +115,7 @@ class Poll
}
}
/**
/**
* Учет результатов опроса
*
* @param int $pid идентификатор опроса
@@ -124,56 +124,86 @@ class Poll
{
global $AVE_DB;
$pid = (int)$pid;
$row = $AVE_DB->Query("
SELECT *
FROM " . PREFIX . "_module_poll
WHERE id = '" . $pid . "'
")->FetchRow();
if (!$row) return;
// Проверяем: если дата окончания установлена и она уже прошла
if ($row->poll_end > 0 && $row->poll_end < time())
{
// перенаправляем на страницу результатов, ничего не записывая в базу
header('Location: ' . $this->_pollLinkRewrite('index.php?module=poll&action=result&pid=' . $pid));
exit;
}
$poll_groups_id = empty($row->poll_groups_id) ? array() : explode(',', $row->poll_groups_id);
$poll_users_id = empty($row->poll_users_id) ? array() : explode(',', $row->poll_users_id);
$poll_users_ip = empty($row->poll_users_ip) ? array() : explode(',', $row->poll_users_ip);
$current_user_ip = empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR'];
$current_user_ip = $_SERVER['REMOTE_ADDR'] ?? '';
$back = $this->_pollLinkRewrite('index.php?module=poll&amp;action=result&amp;pid=' . $pid);
// убрал &amp; из ссылки редиректа
$back = $this->_pollLinkRewrite('index.php?module=poll&action=result&pid=' . $pid);
if (!(@in_array(UGROUP, $poll_groups_id)))
// Проверка прав группы
if (!in_array(UGROUP, $poll_groups_id))
{
header('Location:' . $back);
header('Location: ' . $back);
exit;
}
if (@in_array($current_user_ip, $poll_users_ip) ||
@in_array($_SESSION['user_id'], $poll_users_id) ||
$_COOKIE['poll_' . $pid] == '1')
// Проверка: голосовал ли уже
$already_voted = false;
if (in_array($current_user_ip, $poll_users_ip)) $already_voted = true;
if (isset($_SESSION['user_id']) && in_array($_SESSION['user_id'], $poll_users_id)) $already_voted = true;
if (isset($_COOKIE['poll_' . $pid]) && $_COOKIE['poll_' . $pid] == '1') $already_voted = true;
if ($already_voted)
{
header('Location:' . $back);
header('Location: ' . $back);
exit;
}
setcookie('poll_' . $pid, '1', time() + 3600 * 3600);
// Устанавливаем куку
setcookie('poll_' . $pid, '1', time() + 3600 * 3600, '/');
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_poll_items
SET poll_item_hits = poll_item_hits + 1
WHERE id = '" . (int)$_POST['p_item'] . "'
");
$p_item = (int)($_POST['p_item'] ?? 0);
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_poll
SET
poll_users_ip = CONCAT_WS(',', poll_users_ip, '" . $current_user_ip . "')
" . ((UGROUP != 2) ? ", poll_users_id = CONCAT_WS(',', poll_users_id, '" . $_SESSION['user_id'] . "')" : '') . "
WHERE
id = '" . $pid . "'
");
if ($p_item > 0)
{
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_poll_items
SET poll_item_hits = poll_item_hits + 1
WHERE id = '" . $p_item . "'
");
header('Location:' . $back);
// Обновляем список проголосовавших (IP и ID)
$sql_user_update = "";
if (UGROUP != 2 && isset($_SESSION['user_id'])) {
$sql_user_update = ", poll_users_id = CONCAT_WS(',', poll_users_id, '" . (int)$_SESSION['user_id'] . "')";
}
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_poll
SET
poll_users_ip = CONCAT_WS(',', poll_users_ip, '" . addslashes($current_user_ip) . "')
$sql_user_update
WHERE
id = '" . $pid . "'
");
}
// редирект
header('Location: ' . $back);
exit;
}
/**
/**
* Подробная информация и статистика опроса, комментарии пользователей
*
* @param string $tpl_dir путь к папке с шаблонами модуля
@@ -184,21 +214,37 @@ class Poll
{
global $AVE_DB, $AVE_Template;
if (empty($pid) && isset($_GET['pid'])) $pid = (int)$_GET['pid'];
if (empty($pid) && isset($_SERVER['REQUEST_URI'])) {
if (preg_match('/poll-(\d+)/', $_SERVER['REQUEST_URI'], $matches)) {
$pid = (int)$matches[1];
}
}
$pid = (int)$pid;
$AVE_Template->config_load($lang_file, 'showresult');
$AVE_Template->assign('comment_title', '');
$AVE_Template->assign('comment_text', '');
$AVE_Template->assign('errors', array());
// Обработка нового комментария
if (isset($_REQUEST['sub']) && $_REQUEST['sub'] == 'new')
{
$errors = $this->pollCommentNew($pid);
if (sizeof($errors) == 0)
if (empty($errors))
{
header('Location:' . $this->_pollLinkRewrite('index.php?module=poll&amp;action=result&amp;pid=' . $pid));
$redirect_url = 'index.php?module=poll&action=result&pid=' . $pid;
header('Location:' . $this->_pollLinkRewrite($redirect_url));
exit;
}
$AVE_Template->assign('errors', $errors);
}
// Основной запрос данных опроса
$poll = $AVE_DB->Query("
SELECT
poll.*,
@@ -207,7 +253,7 @@ class Poll
" . PREFIX . "_module_poll AS poll
LEFT JOIN
" . PREFIX . "_module_poll_items AS itm
ON poll_id = poll.id
ON itm.poll_id = poll.id
WHERE
poll.id = '" . $pid . "' AND
poll.poll_title != '' AND
@@ -216,32 +262,33 @@ class Poll
GROUP BY poll.id
")->FetchRow();
if ($poll === false) return;
if (!$poll) return;
// Варианты ответов
$items = array();
$votes_total = (int)$poll->votes;
$sql = $AVE_DB->Query("
SELECT
*,
" . ($poll->votes > 0 ? 'ROUND(poll_item_hits*100/' . $poll->votes . ')' : 0) . " AS sum
" . ($votes_total > 0 ? 'ROUND(poll_item_hits*100/' . $votes_total . ')' : 0) . " AS sum
FROM " . PREFIX . "_module_poll_items
WHERE poll_id = '" . $pid . "'
ORDER BY poll_item_position ASC
");
while ($row_items = $sql->FetchRow())
{
array_push($items, $row_items);
$items[] = $row_items;
}
// Комментарии
$comments = array();
if ($poll->poll_can_comment == 1)
{
//include_once(BASE_DIR . '/lib/markitup/sets/bbcode/markitup.bbcode-parser.php');
$comments = array();
$sql = $AVE_DB->Query("
SELECT
cmnt.*,
IFNULL(firstname, '') AS firstname,
IFNULL(lastname, '" . $AVE_Template->get_config_vars('POLL_GUEST') . "') AS lastname
IFNULL(usr.firstname, '') AS firstname,
IFNULL(usr.lastname, '" . addslashes($AVE_Template->get_config_vars('POLL_GUEST')) . "') AS lastname
FROM
" . PREFIX . "_module_poll_comments AS cmnt
LEFT JOIN
@@ -252,66 +299,65 @@ class Poll
");
while ($row_comments = $sql->FetchRow())
{
$row_comments->poll_comment_text = $row_comments->poll_comment_text;
array_push($comments, $row_comments);
$comments[] = $row_comments;
}
$poll->count_comments = $sql->NumRows();
}
// Проверка прав и кук
$poll_users_id = empty($poll->poll_users_id) ? array() : explode(',', $poll->poll_users_id);
$poll_users_ip = empty($poll->poll_users_ip) ? array() : explode(',', $poll->poll_users_ip);
$current_user_ip = empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR'];
$current_user_id = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : 0;
$current_user_ip = $_SERVER['REMOTE_ADDR'] ?? '';
$is_vote = 1;
if (@in_array($current_user_ip, $poll_users_ip) ||
@in_array($_SESSION['user_id'], $poll_users_id) ||
if (in_array($current_user_ip, $poll_users_ip) ||
($current_user_id > 0 && in_array($current_user_id, $poll_users_id)) ||
(isset($_COOKIE['poll_' . $pid]) && $_COOKIE['poll_' . $pid] == '1'))
{
$is_vote = 0;
}
$rights = 0;
$groups = array();
if ($poll->poll_groups_id != '')
$groups_names = array();
if (!empty($poll->poll_groups_id))
{
// фильтр ID групп (только цифры и запятые)
$safe_groups = preg_replace('/[^0-9,]/', '', $poll->poll_groups_id);
$sql = $AVE_DB->Query("
SELECT
user_group,
user_group_name
FROM
" . PREFIX . "_user_groups
WHERE
user_group IN(" . $poll->poll_groups_id . ")
SELECT user_group, user_group_name
FROM " . PREFIX . "_user_groups
WHERE user_group IN(" . $safe_groups . ")
");
while ($row_g = $sql->FetchRow())
{
if (UGROUP == $row_g->user_group) $rights = 1;
array_push($groups, $row_g->user_group_name);
$groups_names[] = $row_g->user_group_name;
}
}
$poll->can_vote = ($is_vote == 1 && $rights == 1) ? 1 : 0;
$poll->groups = implode(', ', $groups);
// Наполнение объекта для шаблона
$is_expired = ($poll->poll_end > 0 && $poll->poll_end < time()) ? 1 : 0;
$poll->can_vote = ($is_vote == 1 && $rights == 1 && $is_expired == 0) ? 1 : 0;
$poll->is_expired = $is_expired;
$poll->groups = implode(', ', $groups_names);
$poll->can_comment = ($poll->poll_status == 1 && $poll->poll_can_comment == 1 && $rights == 1) ? 1 : 0;
$poll->anti_spam = ($this->_antispam == 1 && function_exists('imagettftext') && function_exists('imagejpeg')) ? 1 : 0;
$poll->comment_max_chars = $this->_commentwords;
$poll->anti_spam = ($poll->poll_anti_spam == 1 && function_exists('imagettftext')) ? 1 : 0;
$poll->comment_max_chars = (int)$this->_commentwords;
$poll->items = $items;
$poll->comments = $comments;
$poll->formaction = 'index.php?module=poll&amp;action=vote&amp;pid=' . $pid;
$poll->link_result = $this->_pollLinkRewrite('index.php?module=poll&amp;action=result&amp;pid=' . $pid);
// $poll->link_archive = $this->_pollLinkRewrite('index.php?module=poll&amp;action=archive');
// $poll->link_comment = $this->_pollLinkRewrite('index.php?module=poll&amp;action=form&amp;pop=1&amp;pid=' . $pid);
// Ссылки
$poll->formaction = 'index.php?module=poll&action=vote&pid=' . $pid;
$poll->link_result = $this->_pollLinkRewrite('index.php?module=poll&action=result&pid=' . $pid);
$AVE_Template->assign('poll', $poll);
define('MODULE_SITE', $AVE_Template->get_config_vars('POLL_PAGE_TITLE_PREFIX') . $poll->poll_title);
define('MODULE_CONTENT', $AVE_Template->fetch($tpl_dir . 'result.tpl'));
if (!defined('MODULE_SITE')) define('MODULE_SITE', $AVE_Template->get_config_vars('POLL_PAGE_TITLE_PREFIX') . $poll->poll_title);
if (!defined('MODULE_CONTENT')) define('MODULE_CONTENT', $AVE_Template->fetch($tpl_dir . 'result.tpl'));
}
/**
/**
* Список завершенных и действующих опросов
*
* @param string $tpl_dir путь к папке с шаблонами модуля
@@ -321,13 +367,17 @@ class Poll
{
global $AVE_DB, $AVE_Template;
if (empty($_REQUEST['order']))
// Добавляем инициализацию для Smarty, чтобы убрать Warning в шаблоне
$req_order = isset($_REQUEST['order']) ? $_REQUEST['order'] : '';
$req_by = isset($_REQUEST['by']) ? $_REQUEST['by'] : '';
if (empty($req_order))
{
$order = 'poll_title';
}
else
{
switch ($_REQUEST['order'])
switch ($req_order)
{
case 'title':
$order = 'poll_title';
@@ -351,7 +401,7 @@ class Poll
}
}
if (isset($_REQUEST['by']) && $_REQUEST['by'] == 'desc')
if ($req_by == 'desc')
{
$order .= ' DESC';
}
@@ -372,25 +422,29 @@ class Poll
" . PREFIX . "_module_poll AS poll
LEFT JOIN
" . PREFIX . "_module_poll_items AS itm
ON poll_id = poll.id
ON itm.poll_id = poll.id
WHERE
poll.poll_title != '' AND
poll.poll_status = '1' AND
poll.poll_start < '" . time() . "'
poll.poll_start < '" . (int)time() . "'
GROUP BY poll.id
ORDER BY " . $order
);
while ($row = $sql->FetchRow())
{
$row->plink = $this->_pollLinkRewrite('index.php?module=poll&amp;action=result&amp;pid=' . $row->id);
$row->plink = $this->_pollLinkRewrite('index.php?module=poll&action=result&pid=' . (int)$row->id);
array_push($items, $row);
}
$AVE_Template->assign('items', $items);
$AVE_Template->assign('order', $req_order);
$AVE_Template->assign('by', $req_by);
$AVE_Template->config_load($lang_file, 'showarchive');
define('MODULE_SITE', $AVE_Template->get_config_vars('POLL_ARCHIVE_TITLE'));
define('MODULE_CONTENT', $AVE_Template->fetch($tpl_dir . 'archive.tpl'));
if (!defined('MODULE_SITE')) define('MODULE_SITE', $AVE_Template->get_config_vars('POLL_ARCHIVE_TITLE'));
if (!defined('MODULE_CONTENT')) define('MODULE_CONTENT', $AVE_Template->fetch($tpl_dir . 'archive.tpl'));
}
/**
@@ -424,7 +478,7 @@ class Poll
}
$AVE_Template->assign('max_chars', $this->_commentwords);
if ($this->_antispam == 1 && function_exists('imagettftext') && function_exists('imagejpeg'))
if (isset($row->poll_anti_spam) && $row->poll_anti_spam == 1 && function_exists('imagettftext') && function_exists('imagejpeg'))
{
$AVE_Template->assign('anti_spam', 1);
}
@@ -437,82 +491,96 @@ class Poll
$AVE_Template->display($tpl_dir . 'poll_form.tpl');
}
/**
* Метод создания нового комментария
/**
* Метод создания нового комментария (UTF-8 Only)
*
* @param string $tpl_dir путь к папке с шаблонами модуля
* @param string $lang_file путь к языковому файлу модуля
* @param int $pid идентификатор опроса
* @param int $pid идентификатор опроса
*/
function pollCommentNew($pid)
{
global $AVE_DB, $AVE_Template;
function pollCommentNew($pid)
{
global $AVE_DB, $AVE_Template;
$errors = array();
$errors = array();
$pid = (int)$pid;
if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] == 1)
{
$comment_title = iconv('utf-8', 'cp1251', $_POST['comment_title']);
$comment_text = iconv('utf-8', 'cp1251', $_POST['comment_text']);
}
else
{
$comment_title = $_POST['comment_title'];
$comment_text = $_POST['comment_text'];
}
$poll_settings = $AVE_DB->Query("
SELECT poll_anti_spam, poll_groups_id
FROM " . PREFIX . "_module_poll
WHERE id = '" . $pid . "'
AND poll_status = '1'
AND poll_can_comment = '1'
LIMIT 1
")->FetchRow();
$text = (mb_strlen($comment_text) > $this->_commentwords)
? mb_substr($comment_text, 0, $this->_commentwords) . '...'
: $comment_text;
if (!$poll_settings) {
$errors[] = $AVE_Template->get_config_vars('POLL_ERROR_PERM');
// Если это AJAX, отдаем ошибку сразу
if (isset($_REQUEST['ajax'])) { @ob_clean(); die('###ERR###' . end($errors)); }
return $errors;
}
if (mb_strlen($text) <= 10) $errors[] = $AVE_Template->get_config_vars('POLL_ENTER_TEXT');
if (empty($comment_title)) $errors[] = $AVE_Template->get_config_vars('POLL_ENTER_TITLE');
$comment_title = isset($_POST['comment_title']) ? trim(addslashes($_POST['comment_title'])) : '';
$comment_text = isset($_POST['comment_text']) ? trim(addslashes($_POST['comment_text'])) : '';
if ($this->_antispam == 1)
{
if (! (isset($_SESSION['captcha_keystring']) && isset($_POST['securecode'])
&& $_SESSION['captcha_keystring'] == $_POST['securecode']))
{
$errors[] = $AVE_Template->get_config_vars('POLL_ENTER_CODE');
}
$max_len = (int)$this->_commentwords;
$text = (mb_strlen($comment_text) > $max_len)
? mb_substr($comment_text, 0, $max_len) . '...'
: $comment_text;
unset($_SESSION['captcha_keystring']);
}
if (mb_strlen($text) < 5) $errors[] = $AVE_Template->get_config_vars('POLL_ENTER_TEXT');
if (empty($comment_title)) $errors[] = $AVE_Template->get_config_vars('POLL_ENTER_TITLE');
if (sizeof($errors) == 0)
{
$poll_groups_id = $AVE_DB->Query("
SELECT poll_groups_id
FROM " . PREFIX . "_module_poll
WHERE id = '" . $pid . "'
AND poll_status = '1'
AND poll_can_comment = '1'
")->GetCell();
if ($poll_settings->poll_anti_spam == 1 && function_exists('imagettftext'))
{
$session_captcha = $_SESSION['captcha_keystring'] ?? '';
$post_captcha = $_POST['securecode'] ?? '';
if (!empty($poll_groups_id) && in_array(UGROUP, explode(',', $poll_groups_id)))
{
$author_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 0;
$author_ip = empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR'];
if (empty($post_captcha) || $session_captcha !== $post_captcha)
{
$errors[] = $AVE_Template->get_config_vars('POLL_ENTER_CODE_ERR');
}
if (empty($errors)) {
unset($_SESSION['captcha_keystring']);
}
}
$AVE_DB->Query("
INSERT " . PREFIX . "_module_poll_comments
SET
poll_id = '" . $pid . "',
poll_comment_time = '" . time() . "',
poll_comment_author_id = '" . $author_id . "',
poll_comment_author_ip = '" . $author_ip . "',
poll_comment_title = '" . $comment_title . "',
poll_comment_text = '" . $text . "'
");
if (empty($errors))
{
$allowed_groups = explode(',', $poll_settings->poll_groups_id);
if (in_array(UGROUP, $allowed_groups))
{
$author_id = (int)($_SESSION['user_id'] ?? 0);
$author_ip = addslashes($_SERVER['REMOTE_ADDR'] ?? '');
return $errors;
}
$AVE_DB->Query("
INSERT INTO " . PREFIX . "_module_poll_comments
SET
poll_id = '" . $pid . "',
poll_comment_time = '" . time() . "',
poll_comment_author_id = '" . $author_id . "',
poll_comment_author_ip = '" . $author_ip . "',
poll_comment_title = '" . $comment_title . "',
poll_comment_text = '" . $text . "'
");
$errors[] = $AVE_Template->get_config_vars('POLL_ERROR_PERM');
}
if (isset($_REQUEST['ajax'])) { @ob_clean(); die('###OK###'); }
return array();
}
else
{
$errors[] = $AVE_Template->get_config_vars('POLL_ERROR_PERM');
}
}
return $errors;
}
// Если мы здесь и это AJAX — значит есть ошибки. Выплевываем их.
if (isset($_REQUEST['ajax'])) {
@ob_clean();
die('###ERR###' . implode('<br>', $errors));
}
return $errors;
}
/**
* Методы административной части
@@ -573,7 +641,7 @@ class Poll
$AVE_Template->assign('content', $AVE_Template->fetch($adm_dir . 'admin_forms.tpl'));
}
/**
/**
* Метод создания нового опроса
*
* @param string $adm_dir путь к папке с шаблонами модуля
@@ -618,25 +686,35 @@ class Poll
$_REQUEST['poll_expire'] = $this->_mktime($_REQUEST['poll_expire']);
$_REQUEST['poll_status'] = (!empty($_REQUEST['poll_status'])) ? (int)$_REQUEST['poll_status'] : '0';
$_REQUEST['poll_can_comment'] = (!empty($_REQUEST['poll_can_comment'])) ? (int)$_REQUEST['poll_can_comment'] : '0';
$_REQUEST['poll_anti_spam'] = (!empty($_REQUEST['poll_anti_spam'])) ? (int)$_REQUEST['poll_anti_spam'] : '0';
$AVE_DB->Query("
INSERT
INTO " . PREFIX . "_module_poll
SET
id = '',
poll_title = '" . $_REQUEST['poll_name'] . "',
poll_status = '" . $_REQUEST['poll_status'] . "',
poll_groups_id = '" . @implode(',', $_REQUEST['groups']) . "',
poll_users_id = '0',
poll_users_ip = '0',
id = '',
poll_title = '" . addslashes($_REQUEST['poll_name']) . "',
poll_status = '" . $_REQUEST['poll_status'] . "',
poll_groups_id = '" . @implode(',', $_REQUEST['groups']) . "',
poll_users_id = '0',
poll_users_ip = '0',
poll_can_comment = '" . $_REQUEST['poll_can_comment'] . "',
poll_start = '" . $_REQUEST['poll_published'] . "',
poll_end = '" . $_REQUEST['poll_expire'] . "'
poll_anti_spam = '" . $_REQUEST['poll_anti_spam'] . "',
poll_start = '" . $_REQUEST['poll_published'] . "',
poll_end = '" . $_REQUEST['poll_expire'] . "'
");
$iid = $AVE_DB->InsertId();
reportLog($_SESSION['user_name'] . ' - Добавил новый опрос (' . stripslashes($_REQUEST['poll_name']) . ')');
// ШТАТНОЕ ЧПУ
$AVE_DB->Query("INSERT INTO " . PREFIX . "_modules_aliases
(module_name, module_action, module_link, module_url, module_admin)
VALUES
('poll', 'result', 'index.php?module=poll&action=result&pid={$iid}', 'poll-{$iid}', '0'),
('poll', 'form', 'index.php?module=poll&action=form&pop=1&pid={$iid}', 'pollcomment-{$iid}', '0')
");
reportLog($_SESSION['user_name'] . ' - Добавил новый опрос (' . addslashes($_REQUEST['poll_name']) . ')');
header('Location:index.php?do=modules&action=modedit&mod=poll&moduleaction=edit&id=' . $iid . '&cp=' . SESSION);
exit;
@@ -753,61 +831,95 @@ class Poll
}
/**
* Метод записи изменений в опросе
*
* @param int $pid идентификатор опроса
*/
function pollSave($pid)
/**
* Метод записи изменений в опросе
*
* @param int $pid идентификатор опроса
*/
function pollSave($pid)
{
global $AVE_DB;
// Обработка основных полей опроса с экранированием и проверкой на существование
$poll_name = isset($_REQUEST['poll_name']) ? addslashes($_REQUEST['poll_name']) : '';
$poll_status = (int)($_REQUEST['poll_status'] ?? 0);
$poll_can_comment = (int)($_REQUEST['poll_can_comment'] ?? 0);
// НАША КАПЧА
$poll_anti_spam = (int)($_REQUEST['poll_anti_spam'] ?? 0);
$poll_published = $_REQUEST['poll_published'] ?? '';
$poll_expire = $_REQUEST['poll_expire'] ?? '';
// Обработка групп (приведение к массиву и склейка)
$groups = isset($_REQUEST['groups']) ? (array)$_REQUEST['groups'] : [];
$groups_list = addslashes(@implode(',', $groups));
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_poll
SET
poll_title = '" . $poll_name . "',
poll_status = '" . $poll_status . "',
poll_can_comment = '" . $poll_can_comment . "',
poll_anti_spam = '" . $poll_anti_spam . "',
poll_start = '" . $this->_mktime($poll_published) . "',
poll_end = '" . $this->_mktime($poll_expire) . "',
poll_groups_id = '" . $groups_list . "'
WHERE
id = '" . (int)$pid . "'
");
// Удаление отмеченных вариантов
if (!empty($_POST['del']) && is_array($_POST['del']))
{
global $AVE_DB;
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_poll
SET
poll_title = '" . $_REQUEST['poll_name'] . "',
poll_status = '" . $_REQUEST['poll_status'] . "',
poll_can_comment = '" . $_REQUEST['poll_can_comment'] . "',
poll_start = '" . $this->_mktime($_REQUEST['poll_published']) . "',
poll_end = '" . $this->_mktime($_REQUEST['poll_expire']). "',
poll_groups_id = '" . @implode(',', (array)$_REQUEST['groups']) . "'
WHERE
id = '" . $pid . "'
");
if (!empty($_POST['del']))
foreach ($_POST['del'] as $id => $field)
{
foreach ($_POST['del'] as $id => $field)
{
$AVE_DB->Query("
DELETE
FROM " . PREFIX . "_module_poll_items
WHERE id = '" . $id . "'
");
}
$AVE_DB->Query("
DELETE
FROM " . PREFIX . "_module_poll_items
WHERE id = '" . (int)$id . "'
");
}
}
// Обновление существующих вариантов ответов
if (!empty($_POST['item_title']) && is_array($_POST['item_title']))
{
foreach ($_POST['item_title'] as $id => $field)
{
if (!empty($field))
{
$item_title = addslashes($field);
$item_hits = (int)($_POST['poll_item_hits'][$id] ?? 0);
$item_color = addslashes($_POST['line_color'][$id] ?? '');
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_poll_items
SET
poll_item_title = '" . $field . "',
poll_item_hits = '" . $_POST['poll_item_hits'][$id] . "',
poll_item_color = '" . $_POST['line_color'][$id] . "'
poll_item_title = '" . $item_title . "',
poll_item_hits = '" . $item_hits . "',
poll_item_color = '" . $item_color . "'
WHERE
id = '" . $id . "'
id = '" . (int)$id . "'
");
}
}
header('Location:index.php?do=modules&action=modedit&mod=poll&moduleaction=edit&id=' . $pid . '&cp=' . SESSION);
exit;
}
/**
// ШТАТНОЕ ЧПУ
$AVE_DB->Query("INSERT IGNORE INTO " . PREFIX . "_modules_aliases
(module_name, module_action, module_link, module_url, module_admin)
VALUES
('poll', 'result', 'index.php?module=poll&action=result&pid=" . (int)$pid . "', 'poll-" . (int)$pid . "', '0'),
('poll', 'form', 'index.php?module=poll&action=form&pop=1&pid=" . (int)$pid . "', 'pollcomment-" . (int)$pid . "', '0')
");
reportLog($_SESSION['user_name'] . ' - Сохранил изменения в опросе (ID: ' . (int)$pid . ')');
header('Location:index.php?do=modules&action=modedit&mod=poll&moduleaction=edit&id=' . (int)$pid . '&cp=' . SESSION);
exit;
}
/**
* Метод удаления опроса
*
* @param int $pid идентификатор опроса
@@ -816,19 +928,33 @@ class Poll
{
global $AVE_DB;
$pid = (int)$pid;
// Удаляем все ЧПУ-ссылки опроса
$AVE_DB->Query("
DELETE
FROM " . PREFIX . "_module_poll
DELETE FROM " . PREFIX . "_modules_aliases
WHERE module_name = 'poll'
AND module_link IN (
'index.php?module=poll&action=result&pid=" . $pid . "',
'index.php?module=poll&action=form&pop=1&pid=" . $pid . "'
)
");
// Удаляем сам опрос
$AVE_DB->Query("
DELETE FROM " . PREFIX . "_module_poll
WHERE id = '" . $pid . "'
");
// Удаляем варианты ответов
$AVE_DB->Query("
DELETE
FROM " . PREFIX . "_module_poll_items
DELETE FROM " . PREFIX . "_module_poll_items
WHERE poll_id = '" . $pid . "'
");
// Удаляем комментарии к опросу
$AVE_DB->Query("
DELETE
FROM " . PREFIX . "_module_poll_comments
DELETE FROM " . PREFIX . "_module_poll_comments
WHERE poll_id = '" . $pid . "'
");
@@ -905,31 +1031,39 @@ class Poll
}
}
/**
* Формитрование метки времени по данным полученным из выпадающих списков
* сформированных Smarty {html_select_date} и {html_select_time}
/**
* Формирование метки времени по данным полученным из строки даты и времени
*
* @param string $date имя массива с значениями даты
* @param string $time имя массива с значениями времени
* @return unknown timestamp
* @param string $data строка вида "дд.мм.гггг чч:мм"
* @return int timestamp
*/
function _mktime($data=0)
function _mktime($data = '')
{
$data = explode(" ", $data);
$stamp[day] = explode(".", $data[0]);
$stamp[time] = explode(":", $data[1]);
if (empty($data)) return time();
if (!empty($stamp))
$data = explode(" ", $data);
// Инициализируем массив
$stamp = ['day' => [], 'time' => []];
$stamp['day'] = explode(".", $data[0]);
$stamp['time'] = isset($data[1]) ? explode(":", $data[1]) : [0, 0];
if (!empty($stamp['day']) && count($stamp['day']) == 3)
{
$timestamp = mktime(
$stamp[time][0],
$stamp[time][1],
(int)($stamp['time'][0] ?? 0),
(int)($stamp['time'][1] ?? 0),
0,
$stamp[day][1],
$stamp[day][0],
$stamp[day][2]
(int)$stamp['day'][1], // месяц
(int)$stamp['day'][0], // день
(int)$stamp['day'][2] // год
);
}
else
{
$timestamp = time();
}
return $timestamp;
}

View File

@@ -2,12 +2,25 @@
function PollRewrite($print_out)
{
$print_out = preg_replace('/index.php([?])module=poll&amp;action=result&amp;pid=(\d+)/', ABS_PATH . 'poll-\\2.html', $print_out);
$print_out = preg_replace('/index.php([?])module=poll&amp;action=form&amp;pop=1&amp;pid=(\d+)/', ABS_PATH . 'pollcomment-\\2.html', $print_out);
$print_out = preg_replace('/index.php([?])module=poll&amp;action=archive/', ABS_PATH . 'poll-archive.html', $print_out);
$print_out = str_replace(".html&amp;print=1", "-print.html", $print_out);
// учитываем суффикс из настроек
$suff = (defined('URL_SUFF')) ? URL_SUFF : '';
return $print_out;
// регулярка для Результатов (pid)
$print_out = preg_replace('/index\.php\?module=poll[&|&amp;]+action=result[&|&amp;]+pid=(\d+)/i', 'poll-$1' . $suff, $print_out);
// регулярка для Формы (pollcomment)
$print_out = preg_replace('/index\.php\?module=poll[&|&amp;]+action=form[&|&amp;]+pop=1[&|&amp;]+pid=(\d+)/i', 'pollcomment-$1' . $suff, $print_out);
// замена для Архива (учитываем оба варианта разделителя)
$print_out = preg_replace('/index\.php\?module=poll[&|&amp;]+action=archive/i', 'poll-archive' . $suff, $print_out);
// если есть ссылки на печать
if ($suff != '') {
$print_out = str_replace($suff . '&amp;print=1', '-print' . $suff, $print_out);
$print_out = str_replace($suff . '&print=1', '-print' . $suff, $print_out);
}
return $print_out;
}
?>

View File

@@ -4,7 +4,7 @@
$module = array(
'ModuleSysName' => 'poll',
'ModuleVersion' => '1.26.1a',
'ModuleVersion' => '3.31',
'ModuleAutor' => 'AVE.cms Team',
'ModuleCopyright' => '&copy; 2007-' . date('Y') . ' AVE.cms',
'ModuleStatus' => 1,

View File

@@ -1,6 +1,6 @@
[name]
MODULE_NAME = "Опросы"
MODULE_DESCRIPTION = "Данный модуль предназачен для организации системы опросов на сайте. Возможности модуля позволяют создавать неограниченное количество опросных листов, а также неограниченное количество вопросов. <br>Внимание! Для работы корректной работы модуля необходимо добавить в корневой .htaccess следующие строки<br> RewriteRule ^poll-([0-9]+).html$ index.php?module=poll&action=result&pid=$1 <br><br>RewriteRule ^pollcomment-([0-9]+).html$ index.php?module=poll&action=form&pop=1&pid=$1<br><br> RewriteRule ^poll-archive.html$ index.php?module=poll&action=archive "
MODULE_DESCRIPTION = "Данный модуль предназачен для организации системы опросов на сайте. Возможности модуля позволяют создавать неограниченное количество опросных листов, а также неограниченное количество вопросов."
[showpoll]
@@ -36,9 +36,16 @@ POLL_BUTTON_ADD_C = "Добавить"
POLL_CHARSET_LEFT = "осталось символов"
POLL_YOUR_NAME = "Имя"
POLL_SECURE_CODE = "Защитный код"
POLL_ERROR_NO_TITLE = "Пожалуйста, укажите заголовок комментария"
POLL_ERROR_NO_TEXT = "Пожалуйста, напишите комментарий длинной не менее 10 символов"
POLL_ERROR_NO_SCODE = "Пожалуйста, укажите защитный код"
POLL_ERROR_NO_TITLE = "Укажите заголовок комментария"
POLL_ERROR_NO_TEXT = "Текст комментария должен быть не менее 10 символов"
POLL_ERROR_NO_SCODE = "Введите защитный код с картинки"
POLL_ENTER_CODE_ERR = "Неверный защитный код!
POLL_COMMENT_TITEL = "Заголовок"
POLL_COMMENT_TITEL_PL = "Введите заголовок..."
POLL_COMMENT_TITEL_PLS = "Текст вашего сообщения..."
POLL_CAPTCHA_UPD_IMG = "Нажмите, чтобы обновить"
POLL_CAPTCHA_PL = "Код..."
POLL_CAPTCHA_P_ERR = "Ошибка:"
[showarchive]
POLL_ARCHIVE_HITS = "Мнений"
@@ -61,6 +68,8 @@ POLL_ENTER_CODE = "Пожалуйста, укажите защитны
POLL_ENTER_TEXT = "Пожалуйста, напишите комментарий длинной не менее 10 символов"
POLL_ENTER_TITLE = "Пожалуйста, укажите заголовок комментария"
POLL_SECURE_CODE = "Защитный код"
POLL_ENTER_CODE_ERR = "Вы ввели неверный защитный код!
POLL_ERROR_PERM = "У вас недостаточно прав для комментирования"
[showpolls]
POLL_ACTIONS = "Действия"
@@ -70,9 +79,10 @@ POLL_DELETE = "Удалить данный опрос"
POLL_DELETE_CONFIRM = "Вы уверены, что хотите удалить данный опрос?"
POLL_EDIT_POLL = "Редактировать данный опрос"
POLL_HITS_CMMENT = "Мнений/Комментариев"
POLL_EDIT_CMMENT = "Редактировать комментарий"
POLL_INACTIVE = "Опрос неактивен"
POLL_MODULE_NAME = "Опросы"
POLL_MODULE_TITLE = "В данном разделе представлены все существующие опросы в системе.<br>Внимание! Для работы корректной работы модуля необходимо добавить в корневой .htaccess следующие строки<br> RewriteRule ^poll-([0-9]+).html$ index.php?module=poll&action=result&pid=$1 <br>RewriteRule ^pollcomment-([0-9]+).html$ index.php?module=poll&action=form&pop=1&pid=$1<br> RewriteRule ^poll-archive.html$ index.php?module=poll&action=archive "
POLL_MODULE_TITLE = "В данном разделе представлены все существующие опросы в системе."
POLL_MODULE_ALL = "Список опросов"
POLL_NAME = "Тема опроса"
POLL_NEW_LINK = "Создать новый опрос"
@@ -107,6 +117,7 @@ POLL_QUESTIONS = "Варианты ответа"
POLL_QUESTIONS_ADD = "Добавить вариант"
POLL_QUESTION_NO_ITEMS = "Нет вариантов ответа"
POLL_POSITION_SUCCES = "Порядок сохранён"
POLL_ANTISPAM = "Использовать защитный код (Captcha)?"
[newpolls]
POLL_ADD_POLL = "Создание нового опроса"
@@ -131,6 +142,7 @@ POLL_STATUS = "Активный"
POLL_USER_GROUPS = "Группы пользователей, участвующие в опросе:"
POLL_YES = "Да"
POLL_MODULE_NAME = "Опросы"
POLL_ANTISPAM = "Использовать защитный код (Captcha)?"
[showcomments]
POLL_BUTTON_CLOSE = "Закрыть окно"
@@ -143,3 +155,4 @@ POLL_COMMENT_INFO = "Информация"
POLL_COMMENT_TITLE = "Содержимое комментария"
POLL_MARK_DELETE = "Отметить для удаления"
POLL_MODULE_NAME = "Опросы"
POLL_NEW_LINK = "Создать новый опрос"

View File

@@ -2,7 +2,6 @@
if(!defined('BASE_DIR')) exit;
function mod_poll($poll_id)
{
require_once(BASE_DIR . '/modules/poll/class/poll.php');
@@ -28,14 +27,17 @@ if (!defined('ACP')
$tpl_dir = BASE_DIR . '/modules/poll/templates/';
$lang_file = BASE_DIR . '/modules/poll/lang/' . $_SESSION['user_language'] . '.txt';
// получение PID для публичной части
$pid = (int)($_REQUEST['pid'] ?? 0);
switch ($_REQUEST['action'])
{
case 'result':
$poll->pollResultShow($tpl_dir, $lang_file, (int)$_REQUEST['pid']);
$poll->pollResultShow($tpl_dir, $lang_file, $pid);
break;
case 'vote':
$poll->pollVote((int)$_REQUEST['pid']);
$poll->pollVote($pid);
break;
case 'archive':
@@ -43,11 +45,11 @@ if (!defined('ACP')
break;
case 'form':
$poll->pollCommentShow($tpl_dir, $lang_file, (int)$_REQUEST['pid'], THEME_FOLDER);
$poll->pollCommentShow($tpl_dir, $lang_file, $pid, THEME_FOLDER);
break;
case 'comment':
$poll->pollCommentNew($tpl_dir, $lang_file, (int)$_REQUEST['pid']);
$poll->pollCommentNew($tpl_dir, $lang_file, $pid);
break;
}
}
@@ -62,6 +64,9 @@ if (defined('ACP') && !empty($_REQUEST['moduleaction']))
$adm_dir = BASE_DIR . '/modules/poll/admin/';
$lang_file = BASE_DIR . '/modules/poll/lang/' . $_SESSION['user_language'] . '.txt';
// получение ID для админки
$id = (int)($_REQUEST['id'] ?? 0);
switch ($_REQUEST['moduleaction'])
{
case '1':
@@ -73,29 +78,28 @@ if (defined('ACP') && !empty($_REQUEST['moduleaction']))
break;
case 'save_new':
$poll->pollNewItemSave((int)$_REQUEST['id']);
$poll->pollNewItemSave($id);
break;
case 'edit':
$poll->pollEdit($adm_dir, $lang_file, (int)$_REQUEST['id']);
$poll->pollEdit($adm_dir, $lang_file, $id);
break;
case 'save':
$poll->pollSave((int)$_REQUEST['id']);
$poll->pollSave($id);
break;
case 'delete':
$poll->pollDelete((int)$_REQUEST['id']);
$poll->pollDelete($id);
break;
case 'comments':
$poll->pollCommentEdit($adm_dir, $lang_file, (int)$_REQUEST['id']);
$poll->pollCommentEdit($adm_dir, $lang_file, $id);
break;
case 'sort':
$poll->pollSort((array)$_REQUEST['sort']);
$poll->pollSort((array)($_REQUEST['sort'] ?? []));
exit;
}
}
?>

127
sql.php
View File

@@ -5,7 +5,7 @@
*
* @package AVE.cms
* @subpackage mod_poll
* @since 1.1
* @since 3.31
* @filesource
*/
@@ -17,77 +17,82 @@ $module_sql_install = array();
$module_sql_deinstall = array();
$module_sql_update = array();
// Удаление модуля
$module_sql_deinstall[] = "DROP TABLE IF EXISTS %%PRFX%%_module_poll;";
$module_sql_deinstall[] = "DROP TABLE IF EXISTS %%PRFX%%_module_poll_comments;";
$module_sql_deinstall[] = "DROP TABLE IF EXISTS %%PRFX%%_module_poll_items;";
// --- 1. УДАЛЕНИЕ МОДУЛЯ ---
$module_sql_deinstall[] = "DROP TABLE IF EXISTS `%%PRFX%%_module_poll`;";
$module_sql_deinstall[] = "DROP TABLE IF EXISTS `%%PRFX%%_module_poll_comments`;";
$module_sql_deinstall[] = "DROP TABLE IF EXISTS `%%PRFX%%_module_poll_items`;";
// Установка модуля
$module_sql_install[] = "CREATE TABLE %%PRFX%%_module_poll (
id int(10) unsigned NOT NULL auto_increment,
poll_title varchar(255) NOT NULL default '',
poll_status enum('1','0') NOT NULL default '1',
poll_can_comment enum('0','1') NOT NULL default '0',
poll_groups_id tinytext,
poll_start int(10) unsigned NOT NULL default '0',
poll_end int(10) unsigned NOT NULL default '0',
poll_users_id text NOT NULL default '',
poll_users_ip text NOT NULL default '',
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
// При удалении модуля чистим ВСЕ алиасы, связанные с ним
$module_sql_deinstall[] = "DELETE FROM `%%PRFX%%_modules_aliases` WHERE module_name = 'poll';";
$module_sql_install[] = "CREATE TABLE %%PRFX%%_module_poll_comments (
id int(10) unsigned NOT NULL auto_increment,
poll_id int(10) NOT NULL,
poll_comment_author_id int(10) NOT NULL,
poll_comment_author_ip text NOT NULL default '',
poll_comment_time int(10) unsigned NOT NULL default '0',
poll_comment_title varchar(250) NOT NULL default '',
poll_comment_text text NOT NULL default '',
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
$module_sql_install[] = "CREATE TABLE %%PRFX%%_module_poll_items (
id int(10) unsigned NOT NULL auto_increment,
poll_id int(10) NOT NULL,
poll_item_title varchar(250) NOT NULL default '',
poll_item_hits int(10) NOT NULL default '0',
poll_item_color varchar(10) NOT NULL default '',
poll_item_position int(2) NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
// --- 2. УСТАНОВКА МОДУЛЯ ---
$module_sql_install[] = "
CREATE TABLE IF NOT EXISTS `%%PRFX%%_module_poll` (
`id` int(10) unsigned NOT NULL auto_increment,
`poll_title` varchar(255) NOT NULL default '',
`poll_status` enum('1','0') NOT NULL default '1',
`poll_can_comment` enum('0','1') NOT NULL default '0',
`poll_anti_spam` enum('0','1') NOT NULL default '0',
`poll_groups_id` tinytext,
`poll_start` int(10) unsigned NOT NULL default '0',
`poll_end` int(10) unsigned NOT NULL default '0',
`poll_users_id` text NOT NULL default '',
`poll_users_ip` text NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
";
// Обновление модуля
$module_sql_install[] = "
CREATE TABLE IF NOT EXISTS `%%PRFX%%_module_poll_comments` (
`id` int(10) unsigned NOT NULL auto_increment,
`poll_id` int(10) NOT NULL,
`poll_comment_author_id` int(10) NOT NULL,
`poll_comment_author_ip` text NOT NULL default '',
`poll_comment_time` int(10) unsigned NOT NULL default '0',
`poll_comment_title` varchar(250) NOT NULL default '',
`poll_comment_text` text NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
";
$module_sql_install[] = "
CREATE TABLE IF NOT EXISTS `%%PRFX%%_module_poll_items` (
`id` int(10) unsigned NOT NULL auto_increment,
`poll_id` int(10) NOT NULL,
`poll_item_title` varchar(250) NOT NULL default '',
`poll_item_hits` int(10) NOT NULL default '0',
`poll_item_color` varchar(10) NOT NULL default '',
`poll_item_position` int(2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
";
// ШТАТНОЕ ЧПУ
$module_sql_install[] = "
INSERT INTO `%%PRFX%%_modules_aliases`
SET module_name = 'poll',
module_action = 'archive',
module_link = 'index.php?module=poll&action=archive',
module_url = 'poll-archive',
module_admin = '0';
";
// --- 3. ОБНОВЛЕНИЕ МОДУЛЯ ---
$module_sql_update[] = "
UPDATE
`%%PRFX%%_module`
SET
ModuleAveTag = '" . $modul['ModuleAveTag'] . "',
ModulePHPTag = '" . $modul['ModulePHPTag'] . "',
ModuleVersion = '" . $modul['ModuleVersion'] . "'
ModuleAveTag = '" . (isset($module['ModuleAveTag']) ? $module['ModuleAveTag'] : '') . "',
ModulePHPTag = '" . (isset($module['ModulePHPTag']) ? $module['ModulePHPTag'] : '') . "',
ModuleVersion = '" . (isset($module['ModuleVersion']) ? $module['ModuleVersion'] : '') . "'
WHERE
ModuleSysName = '" . $modul['ModuleSysName'] . "'
ModuleSysName = 'poll'
LIMIT 1;
";
$module_sql_update[] = "
RENAME TABLE
`%%PRFX%%_modul_poll`
TO
`%%PRFX%%_module_poll`
";
// Добавляем поле poll_anti_spam, если его еще нет
$module_sql_update[] = "ALTER TABLE `%%PRFX%%_module_poll` ADD IF NOT EXISTS `poll_anti_spam` enum('0','1') NOT NULL DEFAULT '0' AFTER `poll_can_comment`";
$module_sql_update[] = "
RENAME TABLE
`%%PRFX%%_modul_poll_comments`
TO
`%%PRFX%%_module_poll_comments`
";
$module_sql_update[] = "
RENAME TABLE
`%%PRFX%%_modul_poll_items`
TO
`%%PRFX%%_module_poll_items`
";
?>

View File

@@ -1,24 +1,75 @@
<h2>{#POLL_ARCHIVE_TITLE#}</h2><br />
<br />
<div class="container my-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="mb-0 fw-bold text-dark">{#POLL_ARCHIVE_TITLE#}</h2>
</div>
<table width="100%" border="0" cellpadding="0" cellspacing="1">
<col>
<col width="100">
<col width="100">
<col width="100">
<tr>
<td class="mod_poll_table"><a href="index.php?module=poll&amp;action=archive&amp;order=title{if $smarty.request.order=='title' && $smarty.request.by!='desc'}&amp;by=desc{/if}">{#POLL_PUB_TITLE#}</a></td>
<td class="mod_poll_table" align="center"><a href="index.php?module=poll&amp;action=archive&amp;order=start{if $smarty.request.order=='start' && $smarty.request.by!='desc'}&amp;by=desc{/if}">{#POLL_PUB_START#}</a></td>
<td class="mod_poll_table" align="center"><a href="index.php?module=poll&amp;action=archive&amp;order=end{if $smarty.request.order=='end' && $smarty.request.by!='desc'}&amp;by=desc{/if}">{#POLL_PUB_END#}</a></td>
<td class="mod_poll_table" align="center"><a href="index.php?module=poll&amp;action=archive&amp;order=votes{if $smarty.request.order=='votes' && $smarty.request.by!='desc'}&amp;by=desc{/if}">{#POLL_ARCHIVE_HITS#}</a></td>
</tr>
{foreach from=$items item=item}
<tr class="{cycle name='1' values="mod_poll_first,mod_poll_second"}">
<td><a href="{$item->plink}">{$item->poll_title}</a></td>
<td align="center">{$item->poll_start|date_format:$DATE_FORMAT|pretty_date}</td>
<td align="center">{$item->poll_end|date_format:$DATE_FORMAT|pretty_date}</td>
<td align="center">{$item->votes}</td>
</tr>
{/foreach}
</table><br />
<br />
<div class="card shadow-sm border rounded-3 overflow-hidden">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead>
<tr class="fs-7 text-uppercase fw-bold">
<th class="ps-4 py-3" style="background-color: #6c757d !important; color: #ffffff !important;">
<a href="index.php?module=poll&action=archive&order=title{if $order=='title' && $by!='desc'}&by=desc{/if}"
class="text-white text-decoration-none d-flex align-items-center">
{#POLL_PUB_TITLE#}
{if $order=='title'}<i class="bi bi-sort-alpha-{if $by=='desc'}down{else}up{/if} ms-2"></i>{/if}
</a>
</th>
<th class="text-center py-3" style="background-color: #6c757d !important; color: #ffffff !important; width: 180px;">
<a href="index.php?module=poll&action=archive&order=start{if $order=='start' && $by!='desc'}&by=desc{/if}"
class="text-white text-decoration-none">
{#POLL_PUB_START#}
{if $order=='start'}<i class="bi bi-sort-numeric-{if $by=='desc'}down{else}up{/if} ms-1"></i>{/if}
</a>
</th>
<th class="text-center py-3" style="background-color: #6c757d !important; color: #ffffff !important; width: 180px;">
<a href="index.php?module=poll&action=archive&order=end{if $order=='end' && $by!='desc'}&by=desc{/if}"
class="text-white text-decoration-none">
{#POLL_PUB_END#}
{if $order=='end'}<i class="bi bi-sort-numeric-{if $by=='desc'}down{else}up{/if} ms-1"></i>{/if}
</a>
</th>
<th class="text-center pe-4 py-3" style="background-color: #6c757d !important; color: #ffffff !important; width: 120px;">
<a href="index.php?module=poll&action=archive&order=votes{if $order=='votes' && $by!='desc'}&by=desc{/if}"
class="text-white text-decoration-none">
{#POLL_ARCHIVE_HITS#}
{if $order=='votes'}<i class="bi bi-sort-down ms-1"></i>{/if}
</a>
</th>
</tr>
</thead>
<tbody class="fs-8 bg-white">
{foreach from=$items item=item}
<tr class="border-bottom">
<td class="ps-4 py-3">
<a href="{$item->plink}" class="text-decoration-none text-dark d-block fw-bold">
<i class="bi bi-bar-chart-fill me-2 text-secondary opacity-50"></i>{$item->poll_title|escape}
</a>
</td>
<td class="text-center text-muted small">
{$item->poll_start|date_format:$DATE_FORMAT|pretty_date}
</td>
<td class="text-center text-muted small">
{$item->poll_end|date_format:$DATE_FORMAT|pretty_date}
</td>
<td class="text-center pe-4">
<span class="badge rounded-pill bg-light text-secondary border px-3 py-2">{$item->votes}</span>
</td>
</tr>
{foreachelse}
<tr><td colspan="4" class="text-center py-5 text-muted">Архив пока пуст</td></tr>
{/foreach}
</tbody>
</table>
</div>
</div>
</div>
<style>
.fs-7 { font-size: 0.8rem; }
.fs-8 { font-size: 0.9rem; }
.table thead th { border: none !important; }
</style>

View File

@@ -1 +1,31 @@
(function($){$.fn.extend({limit:function(limit,element){var interval,f;var self=$(this);$(this).focus(function(){interval=window.setInterval(substring,100)});$(this).blur(function(){clearInterval(interval);substring()});substringFunction="function substring(){ var val = $(self).val();var length = val.length;if(length > limit){$(self).val($(self).val().substring(0,limit));}";if(typeof element!='undefined')substringFunction+="if($(element).html() != limit-length){$(element).html((limit-length<=0)?'0':limit-length);}";substringFunction+="}";eval(substringFunction);substring()}})})(jQuery);
(function initLimit() {
// Ждем, пока jQuery (или $) появится в глобальном окне
if (window.jQuery || window.$) {
var $ = window.jQuery || window.$;
$.fn.extend({
limit: function (limit, element) {
var self = $(this);
var $element = $(element);
var doSubstring = function () {
var val = self.val();
var length = val.length;
if (length > limit) {
self.val(val.substring(0, limit));
length = limit;
}
if ($element.length) {
var remaining = limit - length;
$element.html(remaining <= 0 ? '0' : remaining);
}
};
this.on('input focus blur keyup', doSubstring);
doSubstring();
}
});
} else {
// Если jQuery еще нет, проверяем снова через 50мс
setTimeout(initLimit, 50);
}
})();

View File

@@ -1,10 +1,29 @@
<p><strong>{$poll->poll_title}</strong></p>
<form method="post" action="{$formaction}">
<p>
{foreach from=$items item=item}
<input class="absmiddle" type="radio" name="p_item" value="{$item->id}" />&nbsp;{$item->poll_item_title}<br />
{/foreach}
</p>
<input type="submit" style="width:80px" class="button" value="{#POLL_BUTTON_VOTE#}" />&nbsp;
<input type="button" style="width:80px" class="button" value="{#POLL_PUB_RESULTS#}" onclick="location.href='{$formaction_result}';" />
</form>
<div class="card shadow-sm border-0 mb-4" style="max-width: 450px;">
<div class="card-header border-0 py-2 px-3" style="background-color: #4e5d6c;">
<h6 class="card-title mb-0 text-white text-uppercase fw-bold" style="font-size: 0.85rem; letter-spacing: 0.5px;">
{$poll->poll_title|escape}
</h6>
</div>
<div class="card-body p-3">
<form method="post" action="{$formaction}">
<div class="list-group list-group-flush mb-3">
{foreach from=$items item=item}
<label class="list-group-item d-flex align-items-center border-0 ps-0 py-2">
<input class="form-check-input me-3" type="radio" name="p_item" value="{$item->id}" required>
<span class="text-secondary" style="font-size: 0.95rem;">{$item->poll_item_title|escape}</span>
</label>
{/foreach}
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-start pt-2 border-top">
<button type="submit" class="btn btn-primary btn-sm px-4 shadow-sm">
<i class="bi bi-check-circle me-1"></i> {#POLL_BUTTON_VOTE#}
</button>
<button type="button" class="btn btn-outline-secondary btn-sm px-4" onclick="location.href='{$formaction_result}';">
{#POLL_PUB_RESULTS#}
</button>
</div>
</form>
</div>
</div>

View File

@@ -1,15 +1,49 @@
<p><strong>{$poll->poll_title}</strong></p>
<p>
{foreach from=$items item=item}
<div style="padding:2px">{$item->poll_item_title}</div>
<div style="width:98%;height:5px;padding:0">
<div style="display:block;background-color:{$item->poll_item_color};height:5px;width:{$item->sum|default:'0'}%"></div>
</div>
<small style="color:{$item->poll_item_color}">{#POLL_VOTES#} {$item->poll_item_hits} ({$item->sum|default:'0'}%)</small>
{/foreach}
</p>
{if $poll->message != ''}<p><small>{$poll->message}</small></p>{/if}
<form method="post">
<input type="button" class="button" style="width:100px" onclick="location.href='{$formaction_result}';" value="{#POLL_PUB_RESULTS#} ({$poll->sumhits})" />&nbsp;
<input type="button" class="button" style="width:50px" onclick="location.href='{$formaction_archive}';" value="{#POLL_VIEW_ARCHIVES#}" />
</form>
<div class="card shadow-sm border-0 mb-4" style="max-width: 450px;">
<div class="card-header bg-dark text-white">
<h6 class="card-title mb-0 fw-bold">{$poll->poll_title}</h6>
</div>
<div class="card-body">
<div class="poll-results mb-3">
{foreach from=$items item=item}
<div class="mb-3">
<div class="d-flex justify-content-between align-items-center mb-1">
<span class="small fw-medium">{$item->poll_item_title}</span>
<span class="badge text-dark bg-light border">{$item->sum|default:'0'}%</span>
</div>
<div class="progress" style="height: 8px;">
<div class="progress-bar"
role="progressbar"
style="width: {$item->sum|default:'0'}%; background-color: {$item->poll_item_color} !important;"
aria-valuenow="{$item->sum|default:'0'}"
aria-valuemin="0"
aria-valuemax="100">
</div>
</div>
<div class="mt-1">
<small class="text-muted" style="font-size: 0.75rem;">
<i class="bi bi-people me-1"></i>{#POLL_VOTES#} <strong>{$item->poll_item_hits}</strong>
</small>
</div>
</div>
{/foreach}
</div>
{if $poll->message != ''}
<div class="alert alert-info py-2 px-3 small mb-3">
<i class="bi bi-info-circle me-2"></i>{$poll->message}
</div>
{/if}
<div class="d-grid gap-2 d-md-flex justify-content-md-start pt-2 border-top">
<button type="button" class="btn btn-sm btn-outline-dark px-3" onclick="location.href='{$formaction_result}';">
{#POLL_PUB_RESULTS#} <span class="badge bg-secondary ms-1">{$poll->sumhits}</span>
</button>
<button type="button" class="btn btn-sm btn-link text-secondary text-decoration-none px-2" onclick="location.href='{$formaction_archive}';">
{#POLL_VIEW_ARCHIVES#}
</button>
</div>
</div>
</div>

View File

@@ -1,181 +1,197 @@
{literal}
<style>
#new fieldset {text-align:center; border:#ccc solid 1px;}
#new fieldset input {width:120px;}
#new .p_input label {float:left; width:10%; text-align:right; padding-right:.5em;}
#new .p_input input {width:40%;}
</style>
{/literal}
<script type="text/javascript" src="/modules/poll/templates/js/common.js"></script>
<script language="javascript">
$(document).ready(function() {ldelim}
$('#markItUpPost .markItUpHeader').append('{#POLL_CHARSET_LEFT#} - <span class="charsLeft" id="charsLeft_new"></span>');
$('#post').limit({$poll->comment_max_chars},'#charsLeft_new');
$('#new').submit(function() {ldelim}
if ($('#post_title').val() == '') {ldelim}
alert('{#POLL_ERROR_NO_TITLE#}');
$('#post_title').focus();
return false;
{rdelim}
var pftext = $('#new textarea').val();
if (pftext.length < 10) {ldelim}
alert("{#POLL_ERROR_SMALL_TEXT#}");
$('#new textarea').focus();
return false;
{rdelim}
<div class="poll-container container my-4">
<h2 class="mb-4 text-dark border-bottom pb-2">{$poll->poll_title|escape}</h2>
<div class="row">
<div class="col-md-8">
<div class="card shadow-sm mb-4">
<div class="card-header bg-dark text-white">
<h5 class="mb-0 small text-uppercase fw-bold">{#POLL_QUESTION_LIST#}</h5>
</div>
<div class="card-body p-0">
<ul class="list-group list-group-flush">
{foreach from=$poll->items item=item}
<li class="list-group-item py-3">
<div class="d-flex justify-content-between mb-1">
<span class="fw-medium">{$item->poll_item_title|escape}</span>
<span class="badge bg-secondary">{$item->poll_item_hits} {#POLL_RESULT_INFO#} ({$item->sum}%)</span>
</div>
<div class="progress" style="height: 10px;">
<div class="progress-bar bg-dark" role="progressbar"
style="width: {if $item->sum!=''}{$item->sum}%{else}1%{/if}; background-color:{$item->poll_item_color} !important;">
</div>
</div>
</li>
{/foreach}
</ul>
</div>
</div>
{if $poll->poll_can_comment == 1}
<div class="mt-5">
<div class="d-flex justify-content-between align-items-center mb-3">
<h4 class="mb-0 text-secondary">{#POLL_PUB_COMMENTS#}</h4>
<span class="badge rounded-pill bg-light text-dark border">{$poll->count_comments}</span>
</div>
{foreach from=$poll->comments item=comment}
<div class="card mb-3 border-0 shadow-sm bg-light" id="{$comment->id}">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-2 border-bottom pb-1">
<span class="fw-bold text-dark small">{$comment->lastname|escape} {$comment->firstname|escape}</span>
<small class="text-muted">{$comment->poll_comment_time|date_format:$TIME_FORMAT|pretty_date}</small>
</div>
<h6 class="card-title fw-bold">{$comment->poll_comment_title|escape}</h6>
<p class="card-text text-muted small mb-0">{$comment->poll_comment_text|nl2br}</p>
</div>
</div>
{/foreach}
{if $poll->can_comment == 1}
<div class="card mt-4 border-dark shadow-sm">
<div class="card-body">
<h5 class="card-title mb-3 text-uppercase small fw-bold text-dark">{#POLL_PUB_ADD_COMMENT#}</h5>
<div id="poll-error-container"></div>
<form id="new" method="post">
<input name="sub" type="hidden" value="new" />
<div class="mb-3">
<label class="form-label small fw-bold text-muted">{#POLL_COMMENT_TITEL#}</label>
<input type="text" name="comment_title" id="post_title" class="form-control"
value="{$smarty.post.comment_title|default:''|escape|stripslashes}" placeholder="{#POLL_COMMENT_TITEL_PL#}">
</div>
<div class="mb-3">
<label class="form-label small fw-bold text-muted text-end w-100 mb-1" id="markItUpPost">
{#POLL_CHARSET_LEFT#} <span class="badge bg-secondary" id="charsLeft_new"></span>
</label>
<textarea id="post" name="comment_text" class="form-control" rows="5" placeholder="{#POLL_COMMENT_TITEL_PLS#}">{$smarty.post.comment_text|default:''|escape|stripslashes}</textarea>
</div>
<div class="d-flex align-items-center justify-content-between bg-light p-3 rounded border">
{if $poll->anti_spam == 1}
if ($('#securecode').val() == '') {ldelim}
alert("{#POLL_ERROR_NO_SCODE#}");
$('#securecode').focus();
return false;
{rdelim}{/if}
{rdelim});
{rdelim});
</script>
<div class="d-flex align-items-center gap-3">
<div id="captcha-container">
<img src="{$ABS_PATH}inc/captcha.php?v={$smarty.now}"
alt="captcha"
class="rounded shadow-sm"
style="height: 45px; cursor: pointer;"
onclick="this.src='{$ABS_PATH}inc/captcha.php?v='+Math.random();"
title="{#POLL_CAPTCHA_UPD_IMG#}">
</div>
<input name="securecode" type="text" id="securecode"
class="form-control form-control-sm"
style="width: 100px;"
placeholder="{#POLL_CAPTCHA_PL#}"
autocomplete="off">
</div>
{/if}
<button name="submit" type="submit" class="btn btn-dark px-4">
{#POLL_BUTTON_ADD_C#}
</button>
</div>
</form>
</div>
</div>
{/if}
</div>
{/if}
</div>
<h2 id="page-heading">{$poll->poll_title|escape}</h2>
<div class="col-md-4">
<div class="card mb-4 bg-light border-0 shadow-sm">
<div class="card-header bg-secondary text-white fw-bold small">{#POLL_INFOS#}</div>
<div class="card-body p-0">
<table class="table table-sm table-borderless mb-0 small">
<tr class="border-bottom"><td class="ps-3 py-2 text-muted">{#POLL_ALL_HITS#}</td><td class="pe-3 text-end fw-bold">{$poll->votes}</td></tr>
<tr class="border-bottom"><td class="ps-3 py-2 text-muted">{#POLL_PUB_STATUS#}</td><td class="pe-3 text-end fw-bold text-uppercase fs-xs">{if $poll->poll_end > $smarty.now}<span class="text-success small">{#POLL_ACTIVE_INFO#}</span>{else}<span class="text-danger small">{#POLL_INACTIVE_INFO#}</span>{/if}</td></tr>
<tr class="border-bottom"><td class="ps-3 py-2 text-muted">{#POLL_STARTED#}</td><td class="pe-3 text-end fw-light">{$poll->poll_start|date_format:$TIME_FORMAT|pretty_date}</td></tr>
<tr class="border-bottom"><td class="ps-3 py-2 text-muted">{#POLL_ENDED#}</td><td class="pe-3 text-end fw-light">{$poll->poll_end|date_format:$TIME_FORMAT|pretty_date}</td></tr>
</table>
</div>
</div>
<div class="tablebox">
<table width="100%" border="0" cellpadding="5" cellspacing="1" bgcolor="#CCCCCC">
<col width="50%">
<col width="5%">
<col width="40%">
<col width="5%">
<thead>
<tr>
<th>{#POLL_QUESTION_LIST#}</th>
<th colspan="3">{#POLL_RESULT_INFO#}</th>
</tr>
</thead>
{foreach from=$poll->items item=item}
<tr class="{cycle name="1" values=",odd"}">
<td>{$item->poll_item_title|escape}</td>
<td><div align="center"> {$item->poll_item_hits} </div></td>
<td >
<div style="width:100%;height:12px;padding:0">
<div style="width:{if $item->sum!=""}{$item->sum}%{else}1%{/if};height:12px;background-color:{$item->poll_item_color}">
<img height="1" width="1" src="{$img_folder}/pixel.gif" alt="" />
</div>
</div>
</td>
<td class="{cycle name="pollerg4" values="mod_poll_first,mod_poll_second"}" width="5%" nowrap="nowrap"><div align="center"> {$item->sum} %</div></td>
</tr>
{/foreach}
</table>
<table width="100%" border="0" cellpadding="0" cellspacing="1" bgcolor="#cccccc">
<col width="170">
<thead>
<tr>
<th colspan="2">{#POLL_INFOS#}</th>
</tr>
</thead>
<tr class="odd">
<td>{#POLL_ALL_HITS#}</td>
<td>{$poll->votes}</td>
</tr>
<tr >
<td>{#POLL_PUB_STATUS#}</td>
<td>{if $poll->poll_end > $smarty.now}{#POLL_ACTIVE_INFO#}{else}{#POLL_INACTIVE_INFO#}{/if}</td>
</tr>
<tr class="odd">
<td>{#POLL_STARTED#}</td>
<td>{$poll->poll_start|date_format:$TIME_FORMAT|pretty_date}</td>
</tr>
<tr >
<td>{#POLL_ENDED#}</td>
<td>{$poll->poll_end|date_format:$TIME_FORMAT|pretty_date}</td>
</tr>
<tr class="odd">
<td>{#POLL_GROUPS_PERM#}</td>
<td>{$poll->groups|escape}</td>
</tr>
</table>
{if $poll->can_vote == 1}
<br />
<div style="padding:5px"><strong>{$poll->poll_title|escape}</strong></div>
<form method="post" action="{$poll->formaction}">
{foreach from=$poll->items item=item}
<div style="margin-left:5px"><input type="radio" name="p_item" value="{$item->id}" /> {$item->poll_item_title|escape}</div>
{/foreach}
<div style="padding:5px"><input type="submit" class="button" value="{#POLL_BUTTON_VOTE#}" /></div>
</form>
{/if}
{if $poll->can_vote == 1}
<div class="card border-primary shadow-sm">
<div class="card-body">
<h6 class="fw-bold mb-3">{#POLL_BUTTON_VOTE#}</h6>
<form method="post" action="{$poll->formaction}">
{foreach from=$poll->items item=item}
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="p_item" id="p_{$item->id}" value="{$item->id}">
<label class="form-check-label small" for="p_{$item->id}">{$item->poll_item_title|escape}</label>
</div>
{/foreach}
<button type="submit" class="btn btn-primary btn-sm w-100 mt-2 fw-bold">{#POLL_BUTTON_VOTE#}</button>
</form>
</div>
</div>
{/if}
</div>
</div>
</div>
{if $poll->poll_can_comment == 1}
<br />
<h6>{#POLL_PUB_COMMENTS#}</h6>
<script type="text/javascript">
(function waitJQ() {ldelim}
if (window.jQuery) {ldelim}
$(document).ready(function() {ldelim}
var maxChars = parseInt("{$poll->comment_max_chars}") || 1000;
if (typeof $.fn.limit == 'function') {ldelim}
$('#post').limit(maxChars, '#charsLeft_new');
{rdelim}
<a href="{$poll->link_result}#new">{#POLL_PUB_ADD_COMMENT#}</a> | {#POLL_ALL_COMMENTS#} {$poll->count_comments}<br />
<br />
var showError = function(message) {ldelim}
var html = '<div class="alert alert-danger alert-dismissible fade show shadow-sm mb-3">' +
'<strong>{#POLL_CAPTCHA_P_ERR#}</strong> ' + message +
'<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
$('#poll-error-container').html(html);
$('html, body').animate({ldelim}scrollTop: $('#poll-error-container').offset().top - 120{rdelim}, 300);
{rdelim};
{foreach from=$poll->comments item=comment}
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="mod_comment_box" id="{$comment->id}">
<tr>
<td class="mod_comment_header">
<div class="mod_comment_author">
{*#POLL_ADDED#*} <a href="#">{$comment->lastname|escape} {$comment->firstname|escape}</a> {$comment->poll_comment_time|date_format:$TIME_FORMAT|pretty_date}
</div>
</td>
</tr>
<tr>
<td class="mod_comment_text">
<strong>{$comment->poll_comment_title|escape}</strong><br />
{$comment->poll_comment_text}
</td>
</tr>
</table>
{/foreach}
$('#new').off('submit').on('submit', function(e) {ldelim}
e.preventDefault();
$('#poll-error-container').empty();
{if $poll->can_comment == 1}
<br />
{*<a name="new"></a>*}
{*<form id="new" method="post" action="index.php?module=poll&action=comment&pid={$poll->id}">*}
<form id="new" method="post">
<input name="sub" type="hidden" value="new" />
var title = $('#post_title').val() ? $('#post_title').val().trim() : '';
var text = $('#post').val() ? $('#post').val().trim() : '';
var code = $('#securecode').val() ? $('#securecode').val().trim() : '';
<div class="p_input">
<p>
<label>Заголовок</label>
<input type="text" name="comment_title" id="post_title" class="inputfield" size="80" value="{$smarty.post.comment_title|escape|stripslashes}" />
</p>
</div>
if (title === '') {ldelim} showError('{#POLL_ERROR_NO_TITLE#}'); return false; {rdelim}
if (text.length < 10) {ldelim} showError('{#POLL_ERROR_NO_TEXT#}'); return false; {rdelim}
if ($('#securecode').length > 0 && code === '') {ldelim} showError('{#POLL_ERROR_NO_SCODE#}'); return false; {rdelim}
<textarea id="post" name="comment_text" cols="80" rows="15">{$smarty.post.comment_text|escape|stripslashes}</textarea>
var $form = $(this);
$.ajax({ldelim}
url: '{$ABS_PATH}index.php?module=poll&action=result&pid={$poll->id}&ajax=1',
type: 'POST',
data: $form.serialize(),
success: function(response) {ldelim}
if (response.indexOf('###OK###') !== -1) {ldelim}
window.location.reload();
{rdelim}
else if (response.indexOf('###ERR###') !== -1) {ldelim}
var errorMsg = response.split('###ERR###')[1] || '{#POLL_ENTER_CODE_ERR#}';
showError(errorMsg);
if ($('img[alt="captcha"]').length) $('img[alt="captcha"]').trigger('click');
$('#securecode').val('');
{rdelim}
else {ldelim}
// Фолбэк на случай если сервер вернул ***
window.location.reload();
{rdelim}
{rdelim},
error: function(xhr) {ldelim}
showError('Системная ошибка: ' + xhr.status);
{rdelim}
{rdelim});
<fieldset>
{if $poll->anti_spam == 1}
<p>
<span id="captcha"><img src="{$ABS_PATH}inc/captcha.php" alt="" width="120" height="60" border="0" /></span><br />
<label>{#POLL_SECURE_CODE#}</label><br />
<input name="securecode" type="text" id="securecode" maxlength="10" /><br />
</p>
{/if}
<input name="submit" type="submit" class="button" value="{#POLL_BUTTON_ADD_C#}" />
</fieldset>
</form>
<script>
$(document).ready(function(){ldelim}
$('#new').submit(function(){ldelim}
$(this).ajaxSubmit({ldelim}
url: aveabspath+'index.php?module=poll&action=result&pid={$poll->id}&ajax=1',
success: function(){ldelim}
target = $('h6').offset().top;
$("html").animate({ldelim}scrollTop: target{rdelim}, 1100);
{rdelim},
timeout: 3000
{rdelim});
return false;
{rdelim});
{rdelim});
</script>
{/if}
{/if}
return false;
{rdelim});
{rdelim});
{rdelim} else {ldelim}
setTimeout(waitJQ, 50);
{rdelim}
{rdelim})();
</script>