From 9c0a929283ed1af175d2cdf6ac65cd4d0d9c0492 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Thu, 28 Jul 2016 11:04:29 +0200 Subject: [PATCH] Overhauled message preview --- .../templates/messageFormPreviewButton.tpl | 14 +++- wcfsetup/install/files/js/WCF.Message.js | 65 +++++++++++-------- .../files/js/WoltLab/WCF/Ui/Message/Reply.js | 11 ++-- .../bbcode/MessagePreviewAction.class.php | 61 +++++------------ .../html/output/HtmlOutputProcessor.class.php | 4 -- .../MessageEmbeddedObjectManager.class.php | 28 ++++++++ 6 files changed, 102 insertions(+), 81 deletions(-) diff --git a/com.woltlab.wcf/templates/messageFormPreviewButton.tpl b/com.woltlab.wcf/templates/messageFormPreviewButton.tpl index cd1bc984a4..d9c7eadd82 100644 --- a/com.woltlab.wcf/templates/messageFormPreviewButton.tpl +++ b/com.woltlab.wcf/templates/messageFormPreviewButton.tpl @@ -1,4 +1,9 @@ - +{if !$previewMessageFieldID|isset}{assign var=previewMessageFieldID value='text'}{/if} +{if !$previewButtonID|isset}{assign var=previewButtonID value='buttonMessagePreview'}{/if} +{if !$previewMessageObjectType|isset}{assign var=previewMessageObjectType value=''}{/if} +{if !$previewMessageObjectID|isset}{assign var=previewMessageObjectID value=0}{/if} + + \ No newline at end of file diff --git a/wcfsetup/install/files/js/WCF.Message.js b/wcfsetup/install/files/js/WCF.Message.js index 76777380cb..c225b6f09f 100644 --- a/wcfsetup/install/files/js/WCF.Message.js +++ b/wcfsetup/install/files/js/WCF.Message.js @@ -388,14 +388,7 @@ WCF.Message.Preview = Class.extend({ * @return string */ _getMessage: function() { - if (!$.browser.redactor) { - return $.trim(this._textarea.val()); - } - else if (this._textarea.data('redactor')) { - return this._textarea.redactor('wutil.getText'); - } - - return null; + return this._textarea.redactor('code.get'); }, /** @@ -456,33 +449,39 @@ WCF.Message.Preview = Class.extend({ * @see WCF.Message.Preview */ WCF.Message.DefaultPreview = WCF.Message.Preview.extend({ - _attachmentObjectType: null, - _attachmentObjectID: null, - _tmpHash: null, + _dialog: null, + _options: {}, /** * @see WCF.Message.Preview.init() */ - init: function(attachmentObjectType, attachmentObjectID, tmpHash) { - this._super('wcf\\data\\bbcode\\MessagePreviewAction', 'text', 'previewButton'); + init: function(options) { + if (arguments.length > 1 && typeof options === 'string') { + throw new Error("Outdated API call, please update your implementation."); + } + + this._options = $.extend({ + disallowedBBCodesPermission: 'user.message.disallowedBBCodes', + messageFieldID: '', + previewButtonID: '', + messageObjectType: '', + messageObjectID: 0 + }, options); - this._attachmentObjectType = attachmentObjectType || null; - this._attachmentObjectID = attachmentObjectID || null; - this._tmpHash = tmpHash || null; + if (!this._options.messageObjectType) { + throw new Error("Field 'messageObjectType' cannot be empty."); + } + + this._super('wcf\\data\\bbcode\\MessagePreviewAction', this._options.messageFieldID, this._options.previewButtonID); }, /** * @see WCF.Message.Preview._handleResponse() */ _handleResponse: function(data) { - var $preview = $('#previewContainer'); - if (!$preview.length) { - $preview = $('

' + WCF.Language.get('wcf.global.preview') + '

').prependTo($('#messageContainer')).wcfFadeIn(); - } - - $preview.find('div:eq(0)').html(data.returnValues.message); - - new WCF.Effect.Scroll().scrollTo($preview); + require(['WoltLab/WCF/Ui/Dialog'], (function(UiDialog) { + UiDialog.open(this, '
' + data.returnValues.message + '
'); + }).bind(this)); }, /** @@ -491,13 +490,23 @@ WCF.Message.DefaultPreview = WCF.Message.Preview.extend({ _getParameters: function(message) { var $parameters = this._super(message); - if (this._attachmentObjectType != null) { - $parameters.attachmentObjectType = this._attachmentObjectType; - $parameters.attachmentObjectID = this._attachmentObjectID; - $parameters.tmpHash = this._tmpHash; + for (var key in this._options) { + if (this._options.hasOwnProperty(key) && key !== 'messageFieldID' && key !== 'previewButtonID') { + $parameters[key] = this._options[key]; + } } return $parameters; + }, + + _dialogSetup: function() { + return { + id: 'messagePreview', + options: { + title: WCF.Language.get('wcf.global.preview') + }, + source: null + } } }); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Message/Reply.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Message/Reply.js index 72cae533a0..06f98c6d2f 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Message/Reply.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Message/Reply.js @@ -6,7 +6,7 @@ * @license GNU Lesser General Public License * @module WoltLab/WCF/Ui/Message/Reply */ -define(['Ajax', 'Core', 'EventHandler', 'Language', 'Dom/ChangeListener', 'Dom/Util', 'Dom/Traverse', 'Ui/Dialog', 'Ui/Notification', '../Scroll', 'EventKey', 'User', 'WoltLab/WCF/Controller/Captcha'], +define(['Ajax', 'Core', 'EventHandler', 'Language', 'Dom/ChangeListener', 'Dom/Util', 'Dom/Traverse', 'Ui/Dialog', 'Ui/Notification', 'WoltLab/WCF/Ui/Scroll', 'EventKey', 'User', 'WoltLab/WCF/Controller/Captcha'], function(Ajax, Core, EventHandler, Language, DomChangeListener, DomUtil, DomTraverse, UiDialog, UiNotification, UiScroll, EventKey, User, ControllerCaptcha) { "use strict"; @@ -54,8 +54,6 @@ define(['Ajax', 'Core', 'EventHandler', 'Language', 'Dom/ChangeListener', 'Dom/U }).bind(this)); }).bind(this)); } - - // TODO: add event listener for submit through keyboard in Redactor }, /** @@ -74,7 +72,7 @@ define(['Ajax', 'Core', 'EventHandler', 'Language', 'Dom/ChangeListener', 'Dom/U if (usernameInput.value === '') { var error = DomTraverse.nextByClass(usernameInput, 'innerError'); if (!error) { - var error = elCreate('small'); + error = elCreate('small'); error.className = 'innerError'; error.innerText = Language.get('wcf.global.form.error.empty'); @@ -94,6 +92,7 @@ define(['Ajax', 'Core', 'EventHandler', 'Language', 'Dom/ChangeListener', 'Dom/U } }; + //noinspection JSCheckFunctionSignatures var captchaId = elData(event.currentTarget, 'captcha-id'); if (ControllerCaptcha.has(captchaId)) { parameters = Core.extend(parameters, ControllerCaptcha.getData(captchaId)); @@ -306,6 +305,10 @@ define(['Ajax', 'Core', 'EventHandler', 'Language', 'Dom/ChangeListener', 'Dom/U } }, + /** + * @param {{returnValues:{guestDialog:string,guestDialogID:string}}} data + * @protected + */ _ajaxSuccess: function(data) { if (!User.userId && !data.returnValues.guestDialogID) { throw new Error("Missing 'guestDialogID' return value for guest."); diff --git a/wcfsetup/install/files/lib/data/bbcode/MessagePreviewAction.class.php b/wcfsetup/install/files/lib/data/bbcode/MessagePreviewAction.class.php index 6e0ba8551b..191cd1aa83 100644 --- a/wcfsetup/install/files/lib/data/bbcode/MessagePreviewAction.class.php +++ b/wcfsetup/install/files/lib/data/bbcode/MessagePreviewAction.class.php @@ -1,17 +1,17 @@ * @package WoltLabSuite\Core\Data\Message @@ -26,13 +26,9 @@ class MessagePreviewAction extends BBCodeAction { * Validates parameters for message preview. */ public function validateGetMessagePreview() { - if (!isset($this->parameters['data']['message'])) { - throw new UserInputException('message'); - } - - if (!isset($this->parameters['options'])) { - throw new UserInputException('options'); - } + $this->readString('message', false, 'data'); + $this->readString('messageObjectType'); + $this->readInteger('messageObjectID', true); } /** @@ -42,22 +38,14 @@ class MessagePreviewAction extends BBCodeAction { * @throws UserInputException */ public function getMessagePreview() { - // get options - $enableBBCodes = (isset($this->parameters['options']['enableBBCodes'])) ? 1 : 0; - $enableHtml = (isset($this->parameters['options']['enableHtml'])) ? 1 : 0; - $enableSmilies = (isset($this->parameters['options']['enableSmilies'])) ? 1 : 0; - $preParse = (isset($this->parameters['options']['preParse'])) ? 1 : 0; - - $allowedBBCodesPermission = (isset($this->parameters['allowedBBCodesPermission'])) ? $this->parameters['allowedBBCodesPermission'] : 'user.message.allowedBBCodes'; - - // validate permissions for options - if ($enableBBCodes && !WCF::getSession()->getPermission('user.message.canUseBBCodes')) $enableBBCodes = 0; - if ($enableHtml && !WCF::getSession()->getPermission('user.message.canUseHtml')) $enableHtml = 0; - if ($enableSmilies && !WCF::getSession()->getPermission('user.message.canUseSmilies')) $enableSmilies = 0; + $htmlInputProcessor = new HtmlInputProcessor(); + $htmlInputProcessor->process($this->parameters['data']['message'], $this->parameters['messageObjectType'], $this->parameters['messageObjectID']); // check if disallowed bbcode are used - if ($enableBBCodes && $allowedBBCodesPermission) { - $disallowedBBCodes = MessageParser::getInstance()->validateBBCodes($this->parameters['data']['message'], ArrayUtil::trim(explode(',', WCF::getSession()->getPermission($allowedBBCodesPermission)))); + $disallowedBBCodesPermission = (isset($this->parameters['disallowedBBCodesPermission'])) ? $this->parameters['disallowedBBCodesPermission'] : 'user.message.disallowedBBCodes'; + if ($disallowedBBCodesPermission) { + BBCodeHandler::getInstance()->setDisallowedBBCodes(ArrayUtil::trim(explode(',', WCF::getSession()->getPermission($disallowedBBCodesPermission)))); + $disallowedBBCodes = $htmlInputProcessor->validate(); if (!empty($disallowedBBCodes)) { throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.disallowedBBCodes', [ 'disallowedBBCodes' => $disallowedBBCodes @@ -65,27 +53,14 @@ class MessagePreviewAction extends BBCodeAction { } } - // get message - $message = StringUtil::trim($this->parameters['data']['message']); - - // get embedded objects - MessageEmbeddedObjectManager::getInstance()->parseTemporaryMessage($message); - - // parse URLs - if ($preParse && $enableBBCodes) { - if ($allowedBBCodesPermission) { - $message = PreParser::getInstance()->parse($message, ArrayUtil::trim(explode(',', WCF::getSession()->getPermission($allowedBBCodesPermission)))); - } - else { - $message = PreParser::getInstance()->parse($message); - } - } + MessageEmbeddedObjectManager::getInstance()->registerTemporaryMessage($htmlInputProcessor); - // parse message - $preview = MessageParser::getInstance()->parse($message, $enableSmilies, $enableHtml, $enableBBCodes, false); + $htmlOutputProcessor = new HtmlOutputProcessor(); + $htmlOutputProcessor->process($htmlInputProcessor->getHtml(), $this->parameters['messageObjectType'], $this->parameters['messageObjectID']); return [ - 'message' => $preview + 'message' => $htmlOutputProcessor->getHtml(), + 'raw' => $htmlInputProcessor->getHtml() ]; } } diff --git a/wcfsetup/install/files/lib/system/html/output/HtmlOutputProcessor.class.php b/wcfsetup/install/files/lib/system/html/output/HtmlOutputProcessor.class.php index 78e1598d16..6e28572b9f 100644 --- a/wcfsetup/install/files/lib/system/html/output/HtmlOutputProcessor.class.php +++ b/wcfsetup/install/files/lib/system/html/output/HtmlOutputProcessor.class.php @@ -67,10 +67,6 @@ class HtmlOutputProcessor extends AbstractHtmlProcessor { * @throws \InvalidArgumentException */ public function setContext($objectType, $objectID) { - if (!$objectID) { - throw new \InvalidArgumentException("Output processor requires a valid objectID."); - } - parent::setContext($objectType, $objectID); MessageEmbeddedObjectManager::getInstance()->setActiveMessage($objectType, $objectID); diff --git a/wcfsetup/install/files/lib/system/message/embedded/object/MessageEmbeddedObjectManager.class.php b/wcfsetup/install/files/lib/system/message/embedded/object/MessageEmbeddedObjectManager.class.php index f17d4ef64c..c00c57bb7e 100644 --- a/wcfsetup/install/files/lib/system/message/embedded/object/MessageEmbeddedObjectManager.class.php +++ b/wcfsetup/install/files/lib/system/message/embedded/object/MessageEmbeddedObjectManager.class.php @@ -272,6 +272,34 @@ class MessageEmbeddedObjectManager extends SingletonFactory { } } + /** + * Temporarily registers a message, the parsed data will not be stored. + * + * @param HtmlInputProcessor $htmlInputProcessor html input processor + */ + public function registerTemporaryMessage(HtmlInputProcessor $htmlInputProcessor) { + $context = $htmlInputProcessor->getContext(); + + // set active message information + $this->activeMessageObjectTypeID = $context['objectTypeID']; + $this->activeMessageID = $context['objectID']; + + $embeddedData = $htmlInputProcessor->getEmbeddedContent(); + + /** @var IMessageEmbeddedObjectHandler $handler */ + foreach ($this->getEmbeddedObjectHandlers() as $handler) { + $objectIDs = $handler->parse($htmlInputProcessor, $embeddedData); + + if (!empty($objectIDs)) { + // save assignments + $this->messageEmbeddedObjects[$this->activeMessageObjectTypeID][$this->activeMessageID][$handler->objectTypeID] = $objectIDs; + + // loads objects + $this->embeddedObjects[$handler->objectTypeID] = $handler->loadObjects($objectIDs); + } + } + } + /** * @return ISimpleMessageEmbeddedObjectHandler[]; */ -- 2.20.1