1
0
Fork 0
mirror of https://github.com/Oreolek/ifhub.club.git synced 2024-06-16 23:00:51 +03:00

Наброски функционала опросов, пока доступно только создание, без голосования

This commit is contained in:
Mzhelskiy Maxim 2014-02-04 20:48:53 +07:00
parent 46f90c06d5
commit 219a092c4a
18 changed files with 875 additions and 44 deletions

View file

@ -90,6 +90,12 @@ class ActionAjax extends Action {
$this->AddEventPreg('/^property$/i','/^tags$/','/^autocompleter$/','/^$/','EventPropertyTagsAutocompleter');
$this->AddEventPreg('/^validate$/i','/^captcha$/','/^$/','EventValidateCaptcha');
$this->AddEventPreg('/^poll$/i','/^modal-create$/','/^$/','EventPollModalCreate');
$this->AddEventPreg('/^poll$/i','/^modal-update/','/^$/','EventPollModalUpdate');
$this->AddEventPreg('/^poll$/i','/^create$/','/^$/','EventPollCreate');
$this->AddEventPreg('/^poll$/i','/^update$/','/^$/','EventPollUpdate');
$this->AddEventPreg('/^poll$/i','/^remove$/','/^$/','EventPollRemove');
}
@ -98,6 +104,179 @@ class ActionAjax extends Action {
**********************************************************************************
*/
protected function EventPollCreate() {
if (!$this->oUserCurrent) {
return parent::EventNotFound();
}
/**
* Создаем
*/
$oPoll=Engine::GetEntity('ModulePoll_EntityPoll');
$oPoll->_setValidateScenario('create');
$oPoll->_setDataSafe(getRequest('poll'));
$oPoll->setAnswersRaw(getRequest('answers'));
$oPoll->setTargetRaw(getRequest('target'));
$oPoll->setUserId($this->oUserCurrent->getId());
if ($oPoll->_Validate()) {
if ($oPoll->Add()) {
$oViewer=$this->Viewer_GetLocalViewer();
$oViewer->Assign('oPoll',$oPoll);
$this->Viewer_AssignAjax('sPollItem',$oViewer->Fetch("polls/poll.form.item.tpl"));
return true;
} else {
$this->Message_AddError($this->Lang_Get('common.error.save'),$this->Lang_Get('error'));
}
} else {
$this->Message_AddError($oPoll->_getValidateError(),$this->Lang_Get('error'));
}
}
protected function EventPollUpdate() {
if (!$this->oUserCurrent) {
return parent::EventNotFound();
}
if (!$oPoll=$this->Poll_GetPollById(getRequestStr('poll_id'))) {
return $this->EventErrorDebug();
}
/**
* Проверяем корректность target'а
*/
if ($oPoll->getTargetId()) {
if (!$this->Poll_CheckTarget($oPoll->getTargetType(),$oPoll->getTargetId())) {
return $this->EventErrorDebug();
}
} else {
$sTarget=isset($_REQUEST['target']['tmp']) ? $_REQUEST['target']['tmp'] : '';
if (!$this->Poll_IsAllowTargetType($oPoll->getTargetType()) or $oPoll->getTargetTmp()!=$sTarget) {
return $this->EventErrorDebug();
}
}
/**
* Обновляем
*/
$oPoll->_setValidateScenario('update');
$oPoll->_setDataSafe(getRequest('poll'));
$oPoll->setAnswersRaw(getRequest('answers'));
if ($oPoll->_Validate()) {
if ($oPoll->Update()) {
$oViewer=$this->Viewer_GetLocalViewer();
$oViewer->Assign('oPoll',$oPoll);
$this->Viewer_AssignAjax('sPollItem',$oViewer->Fetch("polls/poll.form.item.tpl"));
$this->Viewer_AssignAjax('iPollId',$oPoll->getId());
return true;
} else {
$this->Message_AddError($this->Lang_Get('common.error.save'),$this->Lang_Get('error'));
}
} else {
$this->Message_AddError($oPoll->_getValidateError(),$this->Lang_Get('error'));
}
}
protected function EventPollRemove() {
if (!$this->oUserCurrent) {
return parent::EventNotFound();
}
if (!$oPoll=$this->Poll_GetPollById(getRequestStr('id'))) {
return $this->EventErrorDebug();
}
/**
* Проверяем корректность target'а
*/
if ($oPoll->getTargetId()) {
if (!$this->Poll_CheckTarget($oPoll->getTargetType(),$oPoll->getTargetId())) {
return $this->EventErrorDebug();
}
} else {
if (!$this->Poll_IsAllowTargetType($oPoll->getTargetType()) or $oPoll->getTargetTmp()!=getRequestStr('tmp')) {
return $this->EventErrorDebug();
}
}
if (!$oPoll->isAllowRemove()) {
$this->Message_AddError('Этот опрос уже нельзя удалить');
}
/**
* Удаляем
*/
if ($oPoll->Delete()) {
return true;
} else {
$this->Message_AddError($this->Lang_Get('common.error.save'),$this->Lang_Get('error'));
}
}
protected function EventPollModalCreate() {
if (!$this->oUserCurrent) {
return $this->EventErrorDebug();
}
/**
* Проверяем корректность target'а
*/
$sTargetType=getRequestStr('target_type');
$sTargetId=getRequestStr('target_id');
$sTargetTmp=empty($_COOKIE['poll_target_tmp_'.$sTargetType]) ? getRequestStr('target_tmp') : $_COOKIE['poll_target_tmp_'.$sTargetType];
if ($sTargetId) {
$sTargetTmp=null;
if (!$this->Poll_CheckTarget($sTargetType,$sTargetId)) {
return $this->EventErrorDebug();
}
} else {
$sTargetId=null;
if (!$this->Poll_IsAllowTargetType($sTargetType)) {
return $this->EventErrorDebug();
}
if (!$sTargetTmp) {
$sTargetTmp=func_generator();
setcookie('poll_target_tmp_'.$sTargetType,$sTargetTmp, time()+24*3600,Config::Get('sys.cookie.path'),Config::Get('sys.cookie.host'));
}
}
$oViewer=$this->Viewer_GetLocalViewer();
$oViewer->Assign('sTargetType',$sTargetType);
$oViewer->Assign('sTargetId',$sTargetId);
$oViewer->Assign('sTargetTmp',$sTargetTmp);
$this->Viewer_AssignAjax('sText',$oViewer->Fetch("modals/modal.poll_create.tpl"));
}
protected function EventPollModalUpdate() {
if (!$this->oUserCurrent) {
return $this->EventErrorDebug();
}
if (!$oPoll=$this->Poll_GetPollById(getRequestStr('id'))) {
return $this->EventErrorDebug();
}
/**
* Проверяем корректность target'а
*/
if ($oPoll->getTargetId()) {
if (!$this->Poll_CheckTarget($oPoll->getTargetType(),$oPoll->getTargetId())) {
return $this->EventErrorDebug();
}
} else {
if (!$this->Poll_IsAllowTargetType($oPoll->getTargetType()) or $oPoll->getTargetTmp()!=getRequestStr('target_tmp')) {
return $this->EventErrorDebug();
}
}
$oViewer=$this->Viewer_GetLocalViewer();
$oViewer->Assign('oPoll',$oPoll);
$oViewer->Assign('sTargetTmp',getRequestStr('target_tmp'));
$this->Viewer_AssignAjax('sText',$oViewer->Fetch("modals/modal.poll_create.tpl"));
}
/**
* Ajax валидация каптчи
*/

View file

@ -159,7 +159,7 @@ class ActionContent extends Action {
/**
* Проверяем тип топика
*/
if (!$this->Topic_IsAllowTopicType($oTopic->getType())) {
if (!$oTopicType=$this->Topic_GetTopicType($oTopic->getType())) {
return parent::EventNotFound();
}
/**
@ -176,7 +176,7 @@ class ActionContent extends Action {
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('aBlogsAllow',$this->Blog_GetBlogsAllowByUser($this->oUserCurrent));
$this->Viewer_Assign('sTopicType',$oTopic->getType());
$this->Viewer_Assign('oTopicType',$oTopicType);
$this->Viewer_AddHtmlTitle($this->Lang_Get('topic_topic_edit'));
$this->Viewer_Assign('oTopicEdit', $oTopic);
@ -189,7 +189,7 @@ class ActionContent extends Action {
*/
protected function EventAdd() {
$sTopicType=$this->GetParam(0);
if (!$this->Topic_IsAllowTopicType($sTopicType)) {
if (!$oTopicType=$this->Topic_GetTopicType($sTopicType)) {
return parent::EventNotFound();
}
$this->sMenuSubItemSelect=$sTopicType;
@ -200,7 +200,7 @@ class ActionContent extends Action {
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('sTopicType',$sTopicType);
$this->Viewer_Assign('oTopicType',$oTopicType);
$this->Viewer_Assign('aBlogsAllow',$this->Blog_GetBlogsAllowByUser($this->oUserCurrent));
$this->Viewer_AddHtmlTitle($this->Lang_Get('topic_topic_create'));
$this->SetTemplateAction('add');
@ -211,12 +211,10 @@ class ActionContent extends Action {
$aTopicRequest=getRequest('topic');
if (!(isset($aTopicRequest['id']) and $oTopic=$this->Topic_GetTopicById($aTopicRequest['id']))) {
$this->Message_AddErrorSingle($this->Lang_Get('system_error'));
return;
return $this->EventErrorDebug();
}
if (!$this->Topic_IsAllowTopicType($oTopic->getType())) {
$this->Message_AddErrorSingle($this->Lang_Get('system_error'));
return;
return $this->EventErrorDebug();
}
/**
* Проверяем разрешено ли постить топик по времени
@ -230,8 +228,7 @@ class ActionContent extends Action {
* Если права на редактирование
*/
if (!$this->ACL_IsAllowEditTopic($oTopic,$this->oUserCurrent)) {
$this->Message_AddErrorSingle($this->Lang_Get('system_error'));
return;
return $this->EventErrorDebug();
}
/**
* Сохраняем старое значение идентификатора блога
@ -341,9 +338,8 @@ class ActionContent extends Action {
* TODO: Здесь нужна проверка прав на создание топика
*/
$sTopicType=getRequestStr('topic_type');
if (!$this->Topic_IsAllowTopicType($sTopicType)) {
$this->Message_AddErrorSingle($this->Lang_Get('system_error'));
return;
if (!$oTopicType=$this->Topic_GetTopicType($sTopicType)) {
return $this->EventErrorDebug();
}
/**
* Проверяем разрешено ли постить топик по времени
@ -421,6 +417,12 @@ class ActionContent extends Action {
* Фиксируем ID у media файлов топика
*/
$this->Media_ReplaceTargetTmpById('topic',$oTopic->getId());
/**
* Фиксируем ID у опросов
*/
if ($oTopicType->getParam('allow_poll')) {
$this->Poll_ReplaceTargetTmpById('topic',$oTopic->getId());
}
/**
* Добавляем автора топика в подписчики на новые комментарии к этому топику
*/

View file

@ -0,0 +1,51 @@
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
/**
* Используется для вывода списка опросов в форме редактирования объекта
*
* @package blocks
* @since 1.0
*/
class BlockPollFormItems extends Block {
/**
* Запуск обработки
*/
public function Exec() {
$sTargetType=$this->GetParam('target_type');
$sTargetId=$this->GetParam('target_id');
$sTargetTmp=empty($_COOKIE['poll_target_tmp_'.$sTargetType]) ? $this->GetParam('target_tmp') : $_COOKIE['poll_target_tmp_'.$sTargetType];
$aFilter=array('target_type'=>$sTargetType,'#order'=>array('id'=>'asc'));
if ($sTargetId) {
$sTargetTmp=null;
if (!$this->Poll_CheckTarget($sTargetType,$sTargetId)) {
return false;
}
$aFilter['target_id']=$sTargetId;
} else {
$sTargetId=null;
if (!$sTargetTmp or !$this->Poll_IsAllowTargetType($sTargetType)) {
return false;
}
$aFilter['target_tmp']=$sTargetTmp;
}
$aPollItems=$this->Poll_GetPollItemsByFilter($aFilter);
$this->Viewer_Assign('aPollItems',$aPollItems);
}
}

View file

@ -0,0 +1,55 @@
<?php
/**
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
class ModulePoll_EntityAnswer extends EntityORM {
protected $aValidateRules=array(
array('title','string','allowEmpty'=>false,'min'=>1,'max'=>250),
array('title','check_title'),
);
protected $aRelations=array(
'poll' => array(self::RELATION_TYPE_BELONGS_TO,'ModulePoll_EntityPoll','poll_id'),
);
protected function beforeSave() {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
}
return true;
}
protected function afterDelete() {
/**
* Удаляем голосования
*/
$aVoteItems=$this->Poll_GetVoteItemsByAnswerId($this->getId());
foreach($aVoteItems as $oVote) {
$oVote->Delete();
}
}
public function ValidateCheckTitle() {
$this->setTitle(htmlspecialchars($this->getTitle()));
return true;
}
}

View file

@ -0,0 +1,202 @@
<?php
/**
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
class ModulePoll_EntityPoll extends EntityORM {
protected $aValidateRules=array(
array('title','string','allowEmpty'=>false,'min'=>3,'max'=>250,'on'=>array('create','update')),
array('count_answer_max','number','allowEmpty'=>true,'integerOnly'=>true,'min'=>0,'on'=>array('create','update')),
array('type','check_type','on'=>array('create','update')),
array('answers_raw','check_answers_raw','on'=>array('create','update')),
array('target_raw','check_target_raw','on'=>array('create')),
array('title','check_title','on'=>array('create','update')),
);
protected $aRelations=array(
'answers' => array(self::RELATION_TYPE_HAS_MANY,'ModulePoll_EntityAnswer','poll_id'),
);
protected function beforeSave() {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
}
return true;
}
protected function afterSave() {
/**
* Сохраняем варианты
*/
if ($aAnswers=$this->getAnswersObject()) {
foreach($aAnswers as $oAnswer) {
$oAnswer->setPollId($this->getId());
$oAnswer->Save();
}
}
/**
* Удаляем варианты
*/
if ($aAnswers=$this->getAnswersObjectForRemove()) {
foreach($aAnswers as $oAnswer) {
$oAnswer->Delete();
}
}
}
protected function afterDelete() {
/**
* Удаляем варианты ответов
*/
$aAnswerItems=$this->Poll_GetAnswerItemsByPollId($this->getId());
foreach($aAnswerItems as $oAnswer) {
$oAnswer->Delete();
}
}
public function ValidateCheckTitle() {
$this->setTitle(htmlspecialchars($this->getTitle()));
return true;
}
public function ValidateCheckType() {
if (!$this->_isNew() and $this->getCountVote()) {
/**
* Запрещаем смену типа
*/
$this->setCountAnswerMax($this->_getOriginalDataOne('count_answer_max'));
return true;
}
$iCount=$this->getCountAnswerMax();
if ($this->getType()=='one') {
$this->setCountAnswerMax(1);
return true;
} else {
if ($iCount<2) {
return 'Максимальное количество вариантов ответа должно быть больше одного';
}
}
return true;
}
public function ValidateCheckAnswersRaw() {
if (!$this->_isNew() and !$this->isAllowUpdate()) {
return true;
}
$aAnswersRaw=$this->getAnswersRaw();
if (!is_array($aAnswersRaw)) {
return 'Необходимо заполнить варианты ответов';
}
if (count($aAnswersRaw)<2) {
return 'Необходимо заполнить больше одного варианта ответов';
}
/**
* Здесь может быть два варианта - создание опроса или редактирование, при редактирование могут передаваться ID ответов
*/
if (!$this->_isNew()) {
$aAnswersOld=$this->Poll_GetAnswerItemsByFilter(array('poll_id'=>$this->getId(),'#index-from-primary'));
} else {
$aAnswersOld=array();
}
$aAnswers=array();
foreach($aAnswersRaw as $aAnswer) {
if ($this->_isNew() or !(isset($aAnswer['id']) and isset($aAnswersOld[$aAnswer['id']]) and $oAnswer=$aAnswersOld[$aAnswer['id']])) {
$oAnswer=Engine::GetEntity('ModulePoll_EntityAnswer');
}
if ($oAnswer->getId()) {
/**
* Фильтруем список старых ответов для будущего удаления оставшихся
*/
unset($aAnswersOld[$oAnswer->getId()]);
}
$oAnswer->setTitle(isset($aAnswer['title']) ? $aAnswer['title'] : '');
if (!$oAnswer->_Validate()) {
return $oAnswer->_getValidateError();
}
$aAnswers[]=$oAnswer;
}
$this->setAnswersObject($aAnswers);
foreach($aAnswersOld as $oAnswer) {
if ($oAnswer->getCountVote()) {
return 'Нельзя удалить вариант ответа, за который уже голосовали';
}
}
$this->setAnswersObjectForRemove($aAnswersOld);
return true;
}
public function ValidateCheckTargetRaw() {
$aTarget=$this->getTargetRaw();
$sTargetType=isset($aTarget['type']) ? $aTarget['type'] : '';
$sTargetId=isset($aTarget['id']) ? $aTarget['id'] : '';
$sTargetTmp=isset($aTarget['tmp']) ? $aTarget['tmp'] : '';
if ($sTargetId) {
$sTargetTmp=null;
if (!$this->Poll_CheckTarget($sTargetType,$sTargetId)) {
return 'Неверный тип объекта';
}
} else {
$sTargetId=null;
if (!$sTargetTmp or !$this->Poll_IsAllowTargetType($sTargetType)) {
return 'Неверный тип объекта';
}
if ($this->Poll_GetPollByFilter(array('target_tmp'=>$sTargetTmp,'target_type <>'=>$sTargetType))) {
return 'Временный идентификатор уже занят';
}
}
$this->setTargetType($sTargetType);
$this->setTargetId($sTargetId);
$this->setTargetTmp($sTargetTmp);
return true;
}
/**
* Проверяет доступность опроса для изменения
* Важно понимать, что здесь нет проверки на права доступа
*
* @return bool
*/
public function isAllowUpdate() {
$iTime=$this->getDateCreate();
if ((time()-strtotime($iTime))>Config::Get('module.poll.time_limit_update')) {
return false;
}
return true;
}
/**
* Проверяет возможность удаления опроса, не пользователем, а в принципе
* Важно понимать, что здесь нет проверки на права доступа
*
* @return bool
*/
public function isAllowRemove() {
if ($this->getCountVote() || $this->getCountAbstain()) {
return false;
}
return true;
}
}

View file

@ -0,0 +1,39 @@
<?php
/**
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
class ModulePoll_EntityVote extends EntityORM {
protected $aValidateRules=array(
);
protected $aRelations=array(
);
protected function beforeSave() {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
}
return true;
}
}

View file

@ -70,6 +70,17 @@ class ModuleTopic extends Module {
public function GetTopicTypes($bOnlyCode=false) {
return $bOnlyCode ? array_keys($this->aTopicTypes) : $this->aTopicTypes;
}
/**
* Возвращает объект типа топика, поиск только среди активных типов
*
* @param string $sType
*
* @return null
*/
public function GetTopicType($sType) {
return isset($this->aTopicTypes[$sType]) ? $this->aTopicTypes[$sType] : null;
}
/**
* Проверяет разрешен ли данный тип топика
*

View file

@ -463,6 +463,17 @@ class ModuleTopic_EntityTopic extends Entity {
public function getPropertyTargetType() {
return 'topic_'.$this->getType();
}
/**
* Возвращает объект типа топика
*
* @return ModuleTopic_EntityTopicType|null
*/
public function getTypeObject() {
if (!$this->_getDataOne('type_object')) {
$this->_aData['type_object']=$this->Topic_GetTopicTypeByCode($this->getType());
}
return $this->_getDataOne('type_object');
}
/***************************************************************************************************************************************************
* методы расширения типов топика

View file

@ -32,10 +32,21 @@ class ModuleTopic_EntityTopicType extends Entity {
array('name, name_many','string','max'=>200,'min'=>1,'allowEmpty'=>false),
array('code','regexp','pattern'=>"#^[a-z0-9_]{1,30}$#",'allowEmpty'=>false),
array('code','code_unique'),
array('params','check_params'),
array('name','check_name'),
array('name_many','check_name_many'),
);
public function ValidateCheckParams() {
$aParamsResult=array();
$aParams=$this->getParamsArray();
$aParamsResult['allow_poll']=(isset($aParams['allow_poll']) and $aParams['allow_poll']) ? true : false;
$this->setParams($aParamsResult);
return true;
}
public function ValidateCheckName() {
$this->setName(htmlspecialchars($this->getName()));
return true;
@ -82,7 +93,7 @@ class ModuleTopic_EntityTopicType extends Entity {
* @return null
*/
public function getParam($sName) {
$aParams=$this->getParams();
$aParams=$this->getParamsArray();
return isset($aParams[$sName]) ? $aParams[$sName] : null;
}

View file

@ -205,6 +205,10 @@ $config['module']['wall']['per_page'] = 10; // Число сообщени
$config['module']['wall']['text_max'] = 250; // Ограничение на максимальное количество символов в одном сообщении на стене
$config['module']['wall']['text_min'] = 1; // Ограничение на минимальное количество символов в одном сообщении на стене
/**
* Модуль опросов (Poll)
*/
$config['module']['poll']['time_limit_update'] = 60*60*30; // Время в секундах, в течении которого можно изменять опрос
/**
* Модуль Media
*/

View file

@ -44,11 +44,16 @@ ls.poll = (function ($) {
// Html варианта ответа
sAddItemHtml: '<li class="poll-add-item js-poll-add-item">' +
'<input type="text" name="answer[]" class="poll-add-item-input js-poll-add-item-input">' +
'<input type="checkbox" disabled="disabled">' +
'<input type="hidden" name="answers[_NUMBER_][id]" value="_ANSWER_ID_">' +
'<input type="text" name="answers[_NUMBER_][title]" class="poll-add-item-input js-poll-add-item-input" value="_ANSWER_TITLE_">' +
'<i class="icon-remove poll-add-item-remove js-poll-add-item-remove" title="' + ls.lang.get('delete') + '"></i>' +
'</li>'
};
this.aAnswersInit=[];
this.iCountAnswers=0;
/**
* Инициализация
*
@ -59,30 +64,6 @@ ls.poll = (function ($) {
this.options = $.extend({}, defaults, options);
// Добавление
$(this.options.sAddSelector).each(function () {
var oPollAdd = $(this);
// Добавление варианта
oPollAdd.find(self.options.sAddButtonSelector).on('click', function () {
self.addItem(oPollAdd);
}.bind(self));
// Добавление варианта по нажатию Ctrl + Enter
oPollAdd.on('keyup', self.options.sAddItemInputSelector, function (e) {
var key = e.keyCode || e.which;
if (e.ctrlKey && key == 13) {
self.addItem(oPollAdd);
}
});
// Удаление
oPollAdd.on('click', self.options.sAddItemRemoveSelector, function () {
self.removeItem(this);
});
});
// Голосование
$(this.options.sPollSelector).each(function () {
var oPoll = $(this),
@ -111,22 +92,119 @@ ls.poll = (function ($) {
});
};
this.initFormUpdate = function() {
this.initFormCreate();
};
this.initFormCreate = function() {
var self = this;
var oPollAdd=$('#form-poll-create').find(self.options.sAddSelector);
$.each(self.aAnswersInit,function(k,v){
self.addItem(oPollAdd,v);
});
$(this.options.sAddSelector).each(function () {
var oPollAdd = $(this);
// Добавление варианта
oPollAdd.find(self.options.sAddButtonSelector).on('click', function () {
self.addItem(oPollAdd);
}.bind(self));
// Добавление варианта по нажатию Ctrl + Enter
oPollAdd.on('keyup', self.options.sAddItemInputSelector, function (e) {
var key = e.keyCode || e.which;
if (e.ctrlKey && key == 13) {
self.addItem(oPollAdd);
}
});
// Удаление
oPollAdd.on('click', self.options.sAddItemRemoveSelector, function () {
self.removeItem(this);
});
});
};
this.createPoll = function(form,button) {
ls.ajax.submit(aRouter.ajax+'poll/create/', form, function(result){
$('#poll-form-items').append(result.sPollItem);
$('#modal-poll-create').modal('hide');
},{ submitButton: $(button) });
};
this.updatePoll = function(form,button) {
ls.ajax.submit(aRouter.ajax+'poll/update/', form, function(result){
$('#poll-form-item-'+result.iPollId).replaceWith(result.sPollItem);
$('#modal-poll-create').modal('hide');
},{ submitButton: $(button) });
};
this.removePoll = function(id,tmp) {
ls.ajax.load(aRouter.ajax+'poll/remove/', { id: id, tmp: tmp }, function(result){
if (result.bStateError) {
ls.msg.error(null, result.sMsg);
} else {
$('#poll-form-item-'+id).fadeOut('slow', function() {
$(this).remove();
});
}
});
return false;
};
/**
* Добавляет вариант ответа
*
* @param {Object} oPollAdd Блок добавления опроса
*/
this.addItem = function(oPollAdd) {
this.addItem = function(oPollAdd,params) {
var defaults = {
number: "0",
answer_id: '',
answer_title: '',
disable_remove: false,
disable_update: false
}
params = $.extend({}, defaults, params);
if(oPollAdd.find(this.options.sAddItemSelector).length == this.options.iMaxItems) {
ls.msg.error(null, ls.lang.get('topic_question_create_answers_error_max'));
return false;
}
var self = this,
oNewItem = $(this.options.sAddItemHtml);
sTpl = this.options.sAddItemHtml;
sTpl = sTpl.replace(/_NUMBER_/g, this.iCountAnswers);
sTpl = sTpl.replace(/_ANSWER_ID_/g, params.answer_id);
sTpl = sTpl.replace(/_ANSWER_TITLE_/g, params.answer_title);
oNewItem = $(sTpl);
if (params.disable_remove) {
oNewItem.find(this.options.sAddItemRemoveSelector).remove();
}
if (params.disable_update) {
oNewItem.find(this.options.sAddItemInputSelector).attr('disabled','disabled');
}
oPollAdd.find(this.options.sAddListSelector).append(oNewItem);
oNewItem.find('input[type=text]').focus();
this.iCountAnswers++;
};
this.addItemInit = function(params) {
this.aAnswersInit.push(params);
};
this.clearItemInit = function() {
this.aAnswersInit=[];
};
/**

View file

@ -0,0 +1,7 @@
<div id="poll-form-items">
{if $aPollItems}
{foreach $aPollItems as $oPoll}
{include file="polls/poll.form.item.tpl" oPoll=$oPoll}
{/foreach}
{/if}
</div>

View file

@ -104,13 +104,21 @@
{* Показывает дополнительные поля *}
{$aBlockParams = []}
{$aBlockParams.target_type = 'topic_'|cat:$sTopicType}
{$aBlockParams.target_type = 'topic_'|cat:$oTopicType->getCode()}
{if $oTopicEdit}
{$aBlockParams.target_id = $oTopicEdit->getId()}
{/if}
{insert name="block" block="propertyUpdate" params=$aBlockParams}
{* Вставка опросов *}
{if $oTopicType->getParam('allow_poll')}
{include file='polls/poll.form.inject.tpl'
sTargetType = 'topic'
sTargetId = {($oTopicEdit) ? $oTopicEdit->getId() : '' }
}
{/if}
{* Запретить комментарии *}
{include file='forms/fields/form.field.checkbox.tpl'
sFieldName = 'topic[topic_forbid_comment]'
@ -134,7 +142,7 @@
{* Скрытые поля *}
{include file='forms/fields/form.field.hidden.tpl' sFieldName='topic_type' sFieldValue=$sTopicType}
{include file='forms/fields/form.field.hidden.tpl' sFieldName='topic_type' sFieldValue=$oTopicType->getCode()}
{* Кнопки *}

View file

@ -0,0 +1,80 @@
{**
* Создание опроса
*
* @styles css/modals.css
*}
{extends file='modals/modal_base.tpl'}
{block name='modal_id'}modal-poll-create{/block}
{block name='modal_class'}modal-poll-create js-modal-default{/block}
{block name='modal_title'}{if $oPoll}Редактирование опроса{else}Создание опроса{/if}{/block}
{block name='modal_content'}
<form action="" method="post" onsubmit="return false;" id="form-poll-create">
{* Заголовок топика *}
{include file='forms/fields/form.field.text.tpl'
sFieldName = 'poll[title]'
sFieldValue = {($oPoll) ? $oPoll->getTitle() : '' }
sFieldLabel = 'Название опроса'}
{if $oPoll and $oPoll->getCountVote()}
{$bDisableChangeType=true}
{/if}
Пользователь может выбрать:
<label><input type="radio" name="poll[type]" value="one" {if !$oPoll or $oPoll->getCountAnswerMax()==1}checked="checked"{/if} {if $bDisableChangeType}disabled="disabled"{/if}> один вариант</label>
<label><input type="radio" name="poll[type]" value="many" {if $oPoll and $oPoll->getCountAnswerMax()>1}checked="checked"{/if} {if $bDisableChangeType}disabled="disabled"{/if}>
несколько вариантов
</label>
{include file='forms/fields/form.field.text.tpl'
sFieldName = 'poll[count_answer_max]'
sFieldValue = {($oPoll) ? $oPoll->getCountAnswerMax() : 2 }
bFieldIsDisabled = $bDisableChangeType }
<div class="fieldset poll-add js-poll-add">
<header class="fieldset-header">
<h3 class="fieldset-title">{$aLang.topic_question_create_answers}</h3>
</header>
<ul class="fieldset-body poll-add-list js-poll-add-list">
<script type="text/javascript">
ls.poll.clearItemInit();
{if $oPoll}
{$aAnswers=$oPoll->getAnswers()}
{foreach $aAnswers as $oAnswer}
ls.poll.addItemInit({
'answer_title': {json var=$oAnswer->getTitle()},
'answer_id': {json var=$oAnswer->getId()},
'disable_update': {json var=!$oPoll->isAllowUpdate()},
'disable_remove': {json var=(!$oPoll->isAllowUpdate() || $oAnswer->getCountVote()) } });
{/foreach}
{else}
ls.poll.addItemInit({ });
{/if}
</script>
</ul>
{if !$oPoll or $oPoll->isAllowUpdate()}
<footer class="fieldset-footer">
<button type="button" class="button button-primary js-poll-add-button" title="[Ctrl + Enter]">{$aLang.topic_question_create_answers_add}</button>
</footer>
{/if}
</div>
{if $oPoll}
{include file='forms/fields/form.field.hidden.tpl' sFieldName='poll_id' sFieldValue=$oPoll->getId()}
{else}
{include file='forms/fields/form.field.hidden.tpl' sFieldName='target[type]' sFieldValue=$sTargetType}
{include file='forms/fields/form.field.hidden.tpl' sFieldName='target[id]' sFieldValue=$sTargetId}
{/if}
{include file='forms/fields/form.field.hidden.tpl' sFieldName='target[tmp]' sFieldValue=$sTargetTmp}
</form>
{/block}
{block name='modal_footer_begin'}
<button type="submit" class="button button-primary" onclick="{if $oPoll}ls.poll.updatePoll('#form-poll-create',this);{else}ls.poll.createPoll('#form-poll-create',this);{/if}">{if $oPoll}{$aLang.common.save}{else}{$aLang.common.add}{/if}</button>
{/block}

View file

@ -0,0 +1,9 @@
<div>
<a href="#" data-type="modal-toggle" data-modal-url="{router page='ajax/poll/modal-create'}" data-modal-aftershow="ls.poll.initFormCreate();" data-param-target_type="{$sTargetType}" data-param-target_id="{$sTargetId}">Добавить опрос</a>
{$aBlockParams = []}
{$aBlockParams.target_type = $sTargetType}
{$aBlockParams.target_id = $sTargetId}
{insert name="block" block="pollFormItems" params=$aBlockParams}
</div>

View file

@ -0,0 +1,5 @@
<div id="poll-form-item-{$oPoll->getId()}">
Опрос: {$oPoll->getTitle()} &mdash;
<a href="#" data-type="modal-toggle" data-modal-url="{router page='ajax/poll/modal-update'}" data-modal-aftershow="ls.poll.initFormUpdate();" data-param-id="{$oPoll->getId()}" data-param-target_tmp="{$oPoll->getTargetTmp()}">{$aLang.common.edit}</a>
<a href="#" onclick="return ls.poll.removePoll({$oPoll->getId()},'{$oPoll->getTargetTmp()}');">{$aLang.common.remove}</a>
</div>

@ -1 +1 @@
Subproject commit 28a6b6f3897ddcc48efa5f00ce384485a61ae49b
Subproject commit d4511e586d47416a1ba85222b5771d04fae7f629

View file

@ -399,3 +399,82 @@ CREATE TABLE IF NOT EXISTS `prefix_storage` (
INSERT INTO `prefix_property_target` ( `type`, `date_create`, `date_update`, `state`, `params`) VALUES
('topic_topic', '2014-01-31 12:01:34', NULL, 1, 'a:2:{s:6:"entity";s:23:"ModuleTopic_EntityTopic";s:4:"name";s:35:"Топик - Стандартный";}');
-- 04.02.2014
--
-- Структура таблицы `prefix_poll`
--
CREATE TABLE IF NOT EXISTS `prefix_poll` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`target_type` varchar(50) NOT NULL,
`target_id` int(11) DEFAULT NULL,
`target_tmp` varchar(50) DEFAULT NULL,
`title` varchar(500) NOT NULL,
`count_answer_max` tinyint(4) NOT NULL DEFAULT '1',
`count_vote` int(11) NOT NULL DEFAULT '0',
`count_abstain` int(11) NOT NULL DEFAULT '0',
`date_create` datetime NOT NULL,
`date_end` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `target_type_target_id` (`target_type`,`target_id`),
KEY `target_tmp` (`target_tmp`),
KEY `count_vote` (`count_vote`),
KEY `count_abstain` (`count_abstain`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Структура таблицы `prefix_poll_answer`
--
CREATE TABLE IF NOT EXISTS `prefix_poll_answer` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`poll_id` int(11) NOT NULL,
`title` varchar(500) CHARACTER SET utf8 NOT NULL,
`count_vote` int(11) NOT NULL DEFAULT '0',
`date_create` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `poll_id` (`poll_id`),
KEY `count_vote` (`count_vote`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- --------------------------------------------------------
--
-- Структура таблицы `prefix_poll_vote`
--
CREATE TABLE IF NOT EXISTS `prefix_poll_vote` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`poll_id` int(11) NOT NULL,
`answer_id` int(11) DEFAULT NULL,
`user_id` int(11) NOT NULL,
`date_create` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `poll_id` (`poll_id`),
KEY `answer_id` (`answer_id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Ограничения внешнего ключа сохраненных таблиц
--
--
-- Ограничения внешнего ключа таблицы `prefix_poll_answer`
--
ALTER TABLE `prefix_poll_answer`
ADD CONSTRAINT `prefix_poll_answer_ibfk_1` FOREIGN KEY (`poll_id`) REFERENCES `prefix_poll` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Ограничения внешнего ключа таблицы `prefix_poll_vote`
--
ALTER TABLE `prefix_poll_vote`
ADD CONSTRAINT `prefix_poll_vote_ibfk_1` FOREIGN KEY (`poll_id`) REFERENCES `prefix_poll` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `prefix_poll_vote_ibfk_2` FOREIGN KEY (`answer_id`) REFERENCES `prefix_poll_answer` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;