From 50188033d9b5694476c75bd079c00c60370a11c1 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Fri, 3 Jun 2016 17:12:22 +0200 Subject: [PATCH] Added poll management to quick reply/inline edit --- .../templates/__messageFormPoll.tpl | 2 +- .../templates/__messageFormPollInline.tpl | 73 ++++++++++++ .../templates/messageFormTabsInline.tpl | 4 + wcfsetup/install/files/js/WCF.Poll.js | 109 ++++++++++++++---- .../files/js/WoltLab/WCF/Date/Picker.js | 44 +++---- .../js/WoltLab/WCF/Ui/Message/InlineEditor.js | 18 ++- .../message/QuickReplyManager.class.php | 6 +- .../lib/system/poll/PollManager.class.php | 28 +++-- wcfsetup/install/files/style/ui/poll.scss | 2 +- 9 files changed, 227 insertions(+), 59 deletions(-) create mode 100644 com.woltlab.wcf/templates/__messageFormPollInline.tpl diff --git a/com.woltlab.wcf/templates/__messageFormPoll.tpl b/com.woltlab.wcf/templates/__messageFormPoll.tpl index 2a91151943..d2c32596d5 100644 --- a/com.woltlab.wcf/templates/__messageFormPoll.tpl +++ b/com.woltlab.wcf/templates/__messageFormPoll.tpl @@ -28,7 +28,7 @@
-
+
    {if $errorField == 'pollOptions'} diff --git a/com.woltlab.wcf/templates/__messageFormPollInline.tpl b/com.woltlab.wcf/templates/__messageFormPollInline.tpl new file mode 100644 index 0000000000..b3465b05dc --- /dev/null +++ b/com.woltlab.wcf/templates/__messageFormPollInline.tpl @@ -0,0 +1,73 @@ +{if $__showPoll|isset && $__showPoll} + + +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
      + {lang}wcf.poll.options.description{/lang} +
      +
      +
      +
      + +
      +
      + +
      +
      +
      +
      + +
      +
      + +
      +
      +
      +
      +
      + +
      + {if !$pollID && $__wcf->getPollManager()->canStartPublicPoll()} +
      + +
      + {/if} +
      + + {lang}wcf.poll.resultsRequireVote.description{/lang} +
      +
      + +
      +
      + + {event name='fields'} +
      +{/if} \ No newline at end of file diff --git a/com.woltlab.wcf/templates/messageFormTabsInline.tpl b/com.woltlab.wcf/templates/messageFormTabsInline.tpl index a92ac33e26..3caa6a53f8 100644 --- a/com.woltlab.wcf/templates/messageFormTabsInline.tpl +++ b/com.woltlab.wcf/templates/messageFormTabsInline.tpl @@ -1,6 +1,7 @@ {assign var=smileyCategories value=$__wcf->getSmileyCache()->getVisibleCategories()} {if !$permissionCanUseSmilies|isset}{assign var=permissionCanUseSmilies value='user.message.canUseSmilies'}{/if} {if !$wysiwygContainerID|isset}{assign var=wysiwygContainerID value='text'}{/if} +{if !$wysiwygSelector|isset}{assign var=wysiwygSelector value=$wysiwygContainerID}{/if} {capture assign='__messageFormSettingsInlineContent'}{include file='messageFormSettingsInline'}{/capture} {assign var='__messageFormSettingsInlineContent' value=$__messageFormSettingsInlineContent|trim} @@ -11,6 +12,7 @@ {if MODULE_SMILEY && $__wcf->getSession()->getPermission($permissionCanUseSmilies) && $smileyCategories|count}
    1. {lang}wcf.message.smilies{/lang}
    2. {/if} {if MODULE_ATTACHMENT && !$attachmentHandler|empty && $attachmentHandler->canUpload()}
    3. {lang}wcf.attachment.attachments{/lang}
    4. {/if} {if $__messageFormSettingsInlineContent}
    5. {lang}wcf.message.settings{/lang}
    6. {/if} + {if $__showPoll|isset && $__showPoll}
    7. {lang}wcf.poll.management{/lang}
    8. {/if} {event name='tabMenuTabs'} @@ -20,6 +22,8 @@ {if $__messageFormSettingsInlineContent}{@$__messageFormSettingsInlineContent}{/if} + {include file='__messageFormPollInline'} + {event name='tabMenuContents'} diff --git a/wcfsetup/install/files/js/WCF.Poll.js b/wcfsetup/install/files/js/WCF.Poll.js index 4df48bbff0..eed02fde8f 100644 --- a/wcfsetup/install/files/js/WCF.Poll.js +++ b/wcfsetup/install/files/js/WCF.Poll.js @@ -28,6 +28,12 @@ WCF.Poll.Management = Class.extend({ */ _count: 0, + /** + * editor element id + * @var string + */ + _editorId: '', + /** * maximum allowed number of options * @var int @@ -37,11 +43,12 @@ WCF.Poll.Management = Class.extend({ /** * Initializes the WCF.Poll.Management class. * - * @param string containerID - * @param array optionList - * @param integer maxOptions + * @param {string} containerID + * @param {Object[]} optionList + * @param {int} maxOptions + * @param {string} editorId */ - init: function(containerID, optionList, maxOptions) { + init: function(containerID, optionList, maxOptions, editorId) { this._count = 0; this._maxOptions = maxOptions || -1; this._container = $('#' + containerID).children('ol:eq(0)'); @@ -50,11 +57,19 @@ WCF.Poll.Management = Class.extend({ return; } - optionList = optionList || [ ]; + optionList = optionList || []; this._createOptionList(optionList); // bind event listener - this._container.parents('form').submit($.proxy(this._submit, this)); + if (editorId) { + this._editorId = editorId; + + WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'reset_' + editorId, this._reset.bind(this)); + WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'submit_' + editorId, this._submit.bind(this)); + } + else { + this._container.parents('form').submit($.proxy(this._submit, this)); + } // init sorting new WCF.Sortable.List(containerID, '', undefined, { @@ -152,7 +167,7 @@ WCF.Poll.Management = Class.extend({ return false; } - var $listItem = $(event.currentTarget).parents('li'); + var $listItem = $(event.currentTarget).closest('li', this._container[0]); this._createOption(undefined, undefined, $listItem); }, @@ -163,7 +178,7 @@ WCF.Poll.Management = Class.extend({ * @param object event */ _removeOption: function(event) { - $(event.currentTarget).parents('li').remove(); + $(event.currentTarget).closest('li', this._container[0]).remove(); this._count--; this._container.find('span.jsAddOption').addClass('pointer').removeClass('disabled'); @@ -175,31 +190,81 @@ WCF.Poll.Management = Class.extend({ /** * Inserts hidden input elements storing the option values. + * + * @param {(Event|Object)} event */ - _submit: function() { - var $options = [ ]; - this._container.children('li').each(function(index, listItem) { + _submit: function(event) { + var $options = []; + this._container.children('li').each(function (index, listItem) { var $listItem = $(listItem); var $optionValue = $.trim($listItem.find('input').val()); // ignore empty values if ($optionValue != '') { - $options.push({ - optionID: $listItem.data('optionID'), - optionValue: $optionValue - }); + $options.push($listItem.data('optionID') + '_' + $optionValue); } }); - // create hidden input fields - if ($options.length) { - var $formSubmit = this._container.parents('form').find('.formSubmit'); - - for (var $i = 0, $length = $options.length; $i < $length; $i++) { - var $option = $options[$i]; - $('').val($option.optionID + '_' + $option.optionValue).appendTo($formSubmit); + if (event instanceof Event) { + // create hidden input fields + if ($options.length) { + var $formSubmit = this._container.parents('form').find('.formSubmit'); + + for (var $i = 0, $length = $options.length; $i < $length; $i++) { + $('').val($options[$i]).appendTo($formSubmit); + } } } + else { + event.poll = { pollOptions: $options }; + + // get form input fields + var parentContainer = this._container.parents('.messageTabMenuContent:eq(0)'); + parentContainer.find('input').each(function(index, input) { + if (input.name) { + if (input.type !== 'checkbox' || input.checked) { + event.poll[input.name] = input.value; + } + } + }); + } + }, + + /** + * Resets the poll option form. + * + * @private + */ + _reset: function() { + // reset options + /** @type Element */ + var container = this._container[0]; + while (container.childElementCount > 1) { + container.removeChild(container.children[1]); + } + + elBySel('input', container.children[0]).value = ''; + + // reset input fields and checkboxes + var parentContainer = this._container.parents('.messageTabMenuContent:eq(0)'); + parentContainer.find('input').each(function(index, input) { + if (input.name) { + if (input.type === 'checkbox') { + input.checked = false; + } + else if (input.type === 'text') { + input.value = ''; + } + else if (input.type === 'number') { + input.value = input.min; + } + } + }); + + // reset date picker + require(['WoltLab/WCF/Date/Picker'], (function(UiDatePicker) { + UiDatePicker.clear('pollEndTime_' + this._editorId); + }).bind(this)); } }); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Date/Picker.js b/wcfsetup/install/files/js/WoltLab/WCF/Date/Picker.js index 9aebd9f9ef..87836c9e5e 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Date/Picker.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Date/Picker.js @@ -2,7 +2,7 @@ * Date picker with time support. * * @author Alexander Ebert - * @copyright 2001-2015 WoltLab GmbH + * @copyright 2001-2016 WoltLab GmbH * @license GNU Lesser General Public License * @module WoltLab/WCF/Date/Picker */ @@ -260,9 +260,9 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment /** * Renders the full picker on init. * - * @param {integer} day - * @param {integer} month - * @param {integer} year + * @param {int} day + * @param {int} month + * @param {int} year */ _renderPicker: function(day, month, year) { this._renderGrid(day, month, year); @@ -283,12 +283,12 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment /** * Updates the date grid. * - * @param {integer} day - * @param {integer} month - * @param {integer} year + * @param {int} day + * @param {int} month + * @param {int} year */ _renderGrid: function(day, month, year) { - var cell, hasDay = (day !== undefined), hasMonth = (month !== undefined); + var cell, hasDay = (day !== undefined), hasMonth = (month !== undefined), i; day = ~~day || ~~elData(_dateGrid, 'day'); month = ~~month; @@ -336,7 +336,7 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment } var selectable; - for (var i = 0; i < 35; i++) { + for (i = 0; i < 35; i++) { cell = _dateCells[i]; cell.textContent = date.getDate(); @@ -368,7 +368,7 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment } if (rebuildMonths) { - for (var i = 0; i < 12; i++) { + for (i = 0; i < 12; i++) { var currentMonth = _dateMonth.children[i]; currentMonth.disabled = (year === _minDate.getFullYear() && currentMonth.value < _minDate.getMonth()) || (year === _maxDate.getFullYear() && currentMonth.value > _maxDate.getMonth()); @@ -388,7 +388,7 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment // update active day if (day) { - for (var i = 0; i < 35; i++) { + for (i = 0; i < 35; i++) { cell = _dateCells[i]; cell.classList[(!cell.classList.contains('otherMonth') && ~~cell.textContent === day) ? 'add' : 'remove']('active'); @@ -475,8 +475,8 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment selectWrapper.appendChild(_dateMonth); monthYearContainer.appendChild(selectWrapper); - var months = '', monthNames = Language.get('__monthsShort'); - for (var i = 0; i < 12; i++) { + var i, months = '', monthNames = Language.get('__monthsShort'); + for (i = 0; i < 12; i++) { months += ''; } _dateMonth.innerHTML = months; @@ -503,7 +503,7 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment _dateGrid.appendChild(item); var span, weekdays = Language.get('__daysShort'); - for (var i = 0; i < 7; i++) { + for (i = 0; i < 7; i++) { var day = i + _firstDayOfWeek; if (day > 6) day -= 7; @@ -514,7 +514,7 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment // create date grid var callbackClick = this._click.bind(this), cell, row; - for (var i = 0; i < 5; i++) { + for (i = 0; i < 5; i++) { row = elCreate('li'); _dateGrid.appendChild(row); @@ -537,7 +537,7 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment var tmp = ''; var date = new Date(2000, 0, 1); var timeFormat = Language.get('wcf.date.timeFormat').replace(/:/, '').replace(/[isu]/g, ''); - for (var i = 0; i < 24; i++) { + for (i = 0; i < 24; i++) { date.setHours(i); tmp += '"; } @@ -551,8 +551,8 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment _dateMinute.className = 'minute'; _dateMinute.addEventListener('change', this._formatValue.bind(this)); - var tmp = ''; - for (var i = 0; i < 60; i++) { + tmp = ''; + for (i = 0; i < 60; i++) { tmp += ''; } _dateMinute.innerHTML = tmp; @@ -646,8 +646,8 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment /** * Sets the date of given element. * - * @param {(Element|string)} element input element or id - * @param {Date} date Date object + * @param {(HTMLInputElement|string)} element input element or id + * @param {Date} date Date object */ setDate: function(element, date) { element = this._getElement(element); @@ -662,7 +662,7 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment /** * Clears the date value of given element. * - * @param {(Element|string)} element input element or id + * @param {(HTMLInputElement|string)} element input element or id */ clear: function(element) { element = this._getElement(element); @@ -678,7 +678,7 @@ define(['DateUtil', 'Language', 'ObjectMap', 'Dom/ChangeListener', 'Ui/Alignment /** * Reverts the date picker into a normal input field. * - * @param {(Element|string)} element input element or id + * @param {(HTMLInputElement|string)} element input element or id */ destroy: function(element) { element = this._getElement(element); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Message/InlineEditor.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Message/InlineEditor.js index 0395356b6a..fcfa8edaab 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Message/InlineEditor.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Message/InlineEditor.js @@ -416,7 +416,7 @@ define( var id = this._getEditorId(); EventHandler.fire('com.woltlab.wcf.redactor2', 'getText_' + id, parameters.data); - EventHandler.fire('com.woltlab.wcf.messageOptionsInline', 'submit_' + id, parameters); + EventHandler.fire('com.woltlab.wcf.redactor2', 'submit_' + id, parameters); Ajax.api(this, { actionName: 'save', @@ -453,6 +453,22 @@ define( } } + // handle poll + if (typeof data.returnValues.poll === 'string') { + // find current poll + var poll = elBySel('.pollContainer', elementData.messageBody); + if (poll !== null) { + // poll contain is wrapped inside `.jsInlineEditorHideContent` + elRemove(poll.parentNode); + } + + var pollContainer = elCreate('div'); + pollContainer.className = 'jsInlineEditorHideContent'; + DomUtil.setInnerHtml(pollContainer, data.returnValues.poll); + + DomUtil.prepend(pollContainer, elementData.messageBody); + } + this._restoreMessage(); this._updateHistory(this._getHash(this._getObjectId(this._activeElement))); diff --git a/wcfsetup/install/files/lib/system/message/QuickReplyManager.class.php b/wcfsetup/install/files/lib/system/message/QuickReplyManager.class.php index acb6ec4365..bf4c965464 100644 --- a/wcfsetup/install/files/lib/system/message/QuickReplyManager.class.php +++ b/wcfsetup/install/files/lib/system/message/QuickReplyManager.class.php @@ -242,12 +242,16 @@ class QuickReplyManager extends SingletonFactory { return [ 'lastPostTime' => $message->time, + 'objectID' => $message->getObjectID(), 'template' => WCF::getTPL()->fetch($templateName, $application) ]; } else { // redirect - return ['url' => $object->getRedirectUrl($this->container, $message)]; + return [ + 'objectID' => $message->getObjectID(), + 'url' => $object->getRedirectUrl($this->container, $message) + ]; } } diff --git a/wcfsetup/install/files/lib/system/poll/PollManager.class.php b/wcfsetup/install/files/lib/system/poll/PollManager.class.php index 3117fd55df..4b884a0c1c 100644 --- a/wcfsetup/install/files/lib/system/poll/PollManager.class.php +++ b/wcfsetup/install/files/lib/system/poll/PollManager.class.php @@ -157,27 +157,33 @@ class PollManager extends SingletonFactory { /** * Reads form parameters for polls. + * + * @param array $postData optional post data to be used instead of $_POST */ - public function readFormParameters() { + public function readFormParameters(array $postData = array()) { + if (empty($postData)) { + $postData &= $_POST; + } + // reset poll data and options prior to reading form input $this->pollData = $this->pollOptions = []; // poll data - if (isset($_POST['pollEndTime'])) { - $d = \DateTime::createFromFormat('Y-m-d H:i', $_POST['pollEndTime'], WCF::getUser()->getTimeZone()); + if (isset($postData['pollEndTime'])) { + $d = \DateTime::createFromFormat('Y-m-d H:i', $postData['pollEndTime'], WCF::getUser()->getTimeZone()); $this->pollData['endTime'] = ($d !== false) ? $d->getTimestamp() : 0; } - if (isset($_POST['pollMaxVotes'])) $this->pollData['maxVotes'] = max(intval($_POST['pollMaxVotes']), 1); // force a minimum of 1 - if (isset($_POST['pollQuestion'])) $this->pollData['question'] = StringUtil::trim($_POST['pollQuestion']); + if (isset($postData['pollMaxVotes'])) $this->pollData['maxVotes'] = max(intval($postData['pollMaxVotes']), 1); // force a minimum of 1 + if (isset($postData['pollQuestion'])) $this->pollData['question'] = StringUtil::trim($postData['pollQuestion']); // boolean values - $this->pollData['isChangeable'] = (isset($_POST['pollIsChangeable'])) ? 1 : 0; - $this->pollData['resultsRequireVote'] = (isset($_POST['pollResultsRequireVote'])) ? 1 : 0; - $this->pollData['sortByVotes'] = (isset($_POST['pollSortByVotes'])) ? 1 : 0; + $this->pollData['isChangeable'] = (isset($postData['pollIsChangeable'])) ? 1 : 0; + $this->pollData['resultsRequireVote'] = (isset($postData['pollResultsRequireVote'])) ? 1 : 0; + $this->pollData['sortByVotes'] = (isset($postData['pollSortByVotes'])) ? 1 : 0; if ($this->poll === null) { - $this->pollData['isPublic'] = (isset($_POST['pollIsPublic']) && $this->canStartPublicPoll()) ? 1 : 0; + $this->pollData['isPublic'] = (isset($postData['pollIsPublic']) && $this->canStartPublicPoll()) ? 1 : 0; } else { // visibility cannot be changed after creation @@ -185,8 +191,8 @@ class PollManager extends SingletonFactory { } // poll options - if (isset($_POST['pollOptions']) && is_array($_POST['pollOptions'])) { - foreach ($_POST['pollOptions'] as $showOrder => $value) { + if (isset($postData['pollOptions']) && is_array($postData['pollOptions'])) { + foreach ($postData['pollOptions'] as $showOrder => $value) { list($optionID, $optionValue) = explode('_', $value, 2); $this->pollOptions[$showOrder] = [ 'optionID' => intval($optionID), diff --git a/wcfsetup/install/files/style/ui/poll.scss b/wcfsetup/install/files/style/ui/poll.scss index f983b196a9..f7e86b2521 100644 --- a/wcfsetup/install/files/style/ui/poll.scss +++ b/wcfsetup/install/files/style/ui/poll.scss @@ -1,5 +1,5 @@ /* poll create/edit form */ -#pollOptionContainer .pollOptionInput { +.pollOptionContainer .pollOptionInput { align-items: center; margin: 5px 0; -- 2.20.1