-<div id="settings_{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if}" class="settingsContent messageTabMenuContent">
- <dl class="wide">
- {if $__wcf->getSession()->getPermission($permissionCanUseBBCodes)}
- <dt></dt>
- <dd>
- <label><input id="preParse" name="preParse" type="checkbox" value="1"{if $preParse} checked="checked"{/if} /> {lang}wcf.message.settings.preParse{/lang}</label>
- <small>{lang}wcf.message.settings.preParse.description{/lang}</small>
- </dd>
- {/if}
- {if MODULE_SMILEY && $__wcf->getSession()->getPermission($permissionCanUseSmilies)}
- <dt></dt>
- <dd>
- <label><input id="enableSmilies" name="enableSmilies" type="checkbox" value="1"{if $enableSmilies} checked="checked"{/if} /> {lang}wcf.message.settings.enableSmilies{/lang}</label>
- <small>{lang}wcf.message.settings.enableSmilies.description{/lang}</small>
- </dd>
- {/if}
- {if $__wcf->getSession()->getPermission($permissionCanUseBBCodes)}
- <dt></dt>
- <dd>
- <label><input id="enableBBCodes" name="enableBBCodes" type="checkbox" value="1"{if $enableBBCodes} checked="checked"{/if} /> {lang}wcf.message.settings.enableBBCodes{/lang}</label>
- <small>{lang}wcf.message.settings.enableBBCodes.description{/lang}</small>
- </dd>
- {/if}
- {if $__wcf->getSession()->getPermission($permissionCanUseHtml)}
- <dt></dt>
- <dd>
- <label><input id="enableHtml" name="enableHtml" type="checkbox" value="1"{if $enableHtml} checked="checked"{/if} /> {lang}wcf.message.settings.enableHtml{/lang}</label>
- <small>{lang}wcf.message.settings.enableHtml.description{/lang}</small>
- </dd>
- {/if}
- {if MODULE_USER_SIGNATURE && !$showSignatureSetting|empty && $__wcf->user->userID}
- <dt></dt>
- <dd>
- <label><input id="showSignature" name="showSignature" type="checkbox" value="1"{if $showSignature} checked="checked"{/if} /> {lang}wcf.message.settings.showSignature{/lang}</label>
- <small>{lang}wcf.message.settings.showSignature.description{/lang}</small>
- </dd>
- {/if}
-
- {event name='settings'}
- </dl>
-</div>
+{capture assign='__messageFormSettings'}
+ {hascontent}
+ <div id="settings_{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if}" class="settingsContent messageTabMenuContent">
+ <dl class="wide">
+ {content}{event name='settings'}{/content}
+ </dl>
+ </div>
+ {/hascontent}
+{/capture}
+{assign var='__messageFormSettings' value=$__messageFormSettings|trim}
+{* the settings template does not generate direct ouput anymore, but captures it content *}
+{include file='messageFormSettings'}
+
<div class="messageTabMenu" data-preselect="{if $preselectTabMenu|isset}{$preselectTabMenu}{else}true{/if}" data-wysiwyg-container-id="{if $wysiwygContainerID|isset}{$wysiwygContainerID}{else}text{/if}">
<nav class="messageTabMenuNavigation jsOnly">
<ul>
- {if MODULE_SMILEY && $__wcf->getSession()->getPermission($permissionCanUseSmilies) && $smileyCategories|count}<li data-name="smilies"><a><span class="icon icon16 fa-smile-o"></span> <span>{lang}wcf.message.smilies{/lang}</span></a></li>{/if}
+ {if MODULE_SMILEY && !$smileyCategories|empty}<li data-name="smilies"><a><span class="icon icon16 fa-smile-o"></span> <span>{lang}wcf.message.smilies{/lang}</span></a></li>{/if}
{if MODULE_ATTACHMENT && !$attachmentHandler|empty && $attachmentHandler->canUpload()}<li data-name="attachments"><a><span class="icon icon16 fa-paperclip"></span> <span>{lang}wcf.attachment.attachments{/lang}</span></a></li>{/if}
- <li data-name="settings"><a><span class="icon icon16 fa-cog"></span> <span>{lang}wcf.message.settings{/lang}</span></a></li>
+ {if $__messageFormSettings}<li data-name="settings"><a><span class="icon icon16 fa-cog"></span> <span>{lang}wcf.message.settings{/lang}</span></a></li>{/if}
{if $__showPoll|isset && $__showPoll}<li data-name="poll"><a><span class="icon icon16 fa-bar-chart"></span> <span>{lang}wcf.poll.management{/lang}</span></a></li>{/if}
{event name='tabMenuTabs'}
</ul>
</nav>
- {if MODULE_SMILEY && $__wcf->getSession()->getPermission($permissionCanUseSmilies) && $smileyCategories|count}{include file='messageFormSmilies'}{/if}
+ {if MODULE_SMILEY && !$smileyCategories|empty}{include file='messageFormSmilies'}{/if}
{if MODULE_ATTACHMENT && !$attachmentHandler|empty && $attachmentHandler->canUpload()}{include file='messageFormAttachments'}{/if}
- {include file='messageFormSettings'}
+ {if $__messageFormSettings}{@$__messageFormSettings}{/if}
{include file='__messageFormPoll'}
{event name='tabMenuContents'}
}
</style>
<script data-relocate="true">
-(function() {
- var buttons = [], buttonOptions = [];
- {include file='wysiwygToolbar'}
-
- var elementId = '{if $wysiwygSelector|isset}{$wysiwygSelector|encodeJS}{else}text{/if}';
- var callbackIdentifier = 'Redactor2_' + elementId;
-
- WCF.System.Dependency.Manager.setup(callbackIdentifier, function() {
- // TODO: Should the media stuff be here?
- {include file='mediaJavaScript'}
+require(['WoltLab/WCF/Ui/Redactor/Metacode'], function(UiRedactorMetacode) {
+ (function() {
+ var buttons = [], buttonOptions = [];
+ {include file='wysiwygToolbar'}
- var element = elById(elementId);
- var autosave = elData(element, 'autosave') || '';
- if (autosave) {
- element.removeAttribute('data-autosave');
- }
+ var elementId = '{if $wysiwygSelector|isset}{$wysiwygSelector|encodeJS}{else}text{/if}';
+ var callbackIdentifier = 'Redactor2_' + elementId;
- var config = {
- buttons: buttons,
- minHeight: 200,
- plugins: ['alignment', 'source', 'table', 'WoltLabColor', 'WoltLabDropdown', 'WoltLabEvent', 'WoltLabLink', 'WoltLabQuote', 'WoltLabSize'],
- toolbarFixed: false,
- woltlab: {
- autosave: autosave,
- buttons: buttonOptions
+ WCF.System.Dependency.Manager.setup(callbackIdentifier, function() {
+ // TODO: Should the media stuff be here?
+ {include file='mediaJavaScript'}
+
+ var element = elById(elementId);
+ UiRedactorMetacode.convert(element);
+
+ var autosave = elData(element, 'autosave') || '';
+ if (autosave) {
+ element.removeAttribute('data-autosave');
}
- };
-
- // user mentions
- if (elDataBool(element, 'support-mention')) {
- config.plugins.push('WoltLabMention');
- }
-
- // media
- {if $__wcf->session->getPermission('admin.content.cms.canUseMedia')}
- config.plugins.push('WoltLabMedia');
- {/if}
-
- // load the button plugin last to ensure all buttons have been initialized
- // already and we can safely add all icons
- config.plugins.push('WoltLabButton');
-
- $(element).redactor(config);
- });
-
- head.load([
- {* Imperavi *}
- '{@$__wcf->getPath()}js/3rdParty/redactor2/redactor.js?v={@LAST_UPDATE_TIME}',
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/alignment.js?v={@LAST_UPDATE_TIME}',
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/source.js?v={@LAST_UPDATE_TIME}',
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/table.js?v={@LAST_UPDATE_TIME}',
-
- {* WoltLab *}
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabButton.js?v={@LAST_UPDATE_TIME}',
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabColor.js?v={@LAST_UPDATE_TIME}',
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabDropdown.js?v={@LAST_UPDATE_TIME}',
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabEvent.js?v={@LAST_UPDATE_TIME}',
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabLink.js?v={@LAST_UPDATE_TIME}',
- {if $__wcf->session->getPermission('admin.content.cms.canUseMedia')}'{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabMedia.js?v={@LAST_UPDATE_TIME}',{/if}
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabMention.js?v={@LAST_UPDATE_TIME}',
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabQuote.js?v={@LAST_UPDATE_TIME}',
- '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabSize.js?v={@LAST_UPDATE_TIME}'
-
- ], function() {
- WCF.System.Dependency.Manager.invoke(callbackIdentifier);
- }
- );
-})();
+
+ var config = {
+ buttons: buttons,
+ minHeight: 200,
+ plugins: ['alignment', 'source', 'table', 'WoltLabColor', 'WoltLabDropdown', 'WoltLabEvent', 'WoltLabLink', 'WoltLabQuote', 'WoltLabSize'],
+ toolbarFixed: false,
+ woltlab: {
+ autosave: autosave,
+ buttons: buttonOptions
+ }
+ };
+
+ // user mentions
+ if (elDataBool(element, 'support-mention')) {
+ config.plugins.push('WoltLabMention');
+ }
+
+ // media
+ {if $__wcf->session->getPermission('admin.content.cms.canUseMedia')}
+ config.plugins.push('WoltLabMedia');
+ {/if}
+
+ // load the button plugin last to ensure all buttons have been initialized
+ // already and we can safely add all icons
+ config.plugins.push('WoltLabButton');
+
+ $(element).redactor(config);
+ });
+
+ head.load([
+ {* Imperavi *}
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/redactor.js?v={@LAST_UPDATE_TIME}',
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/alignment.js?v={@LAST_UPDATE_TIME}',
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/source.js?v={@LAST_UPDATE_TIME}',
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/table.js?v={@LAST_UPDATE_TIME}',
+
+ {* WoltLab *}
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabButton.js?v={@LAST_UPDATE_TIME}',
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabColor.js?v={@LAST_UPDATE_TIME}',
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabDropdown.js?v={@LAST_UPDATE_TIME}',
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabEvent.js?v={@LAST_UPDATE_TIME}',
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabLink.js?v={@LAST_UPDATE_TIME}',
+ {if $__wcf->session->getPermission('admin.content.cms.canUseMedia')}'{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabMedia.js?v={@LAST_UPDATE_TIME}',{/if}
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabMention.js?v={@LAST_UPDATE_TIME}',
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabQuote.js?v={@LAST_UPDATE_TIME}',
+ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabSize.js?v={@LAST_UPDATE_TIME}'
+
+ ], function() {
+ WCF.System.Dependency.Manager.invoke(callbackIdentifier);
+ }
+ );
+ })();
+});
</script>
{*
* @param {Element} parentEl future containing element
*/
prepend: function(el, parentEl) {
- if (parentEl.childElementCount === 0) {
+ if (parentEl.childNodes.length === 0) {
parentEl.appendChild(el);
}
else {
- parentEl.insertBefore(el, parentEl.children[0]);
+ parentEl.insertBefore(el, parentEl.childNodes[0]);
}
},
--- /dev/null
+/**
+ * Converts `<woltlab-metacode>` into the bbcode representation.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2016 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLab/WCF/Ui/Redactor/Metacode
+ */
+define(['Dom/Util'], function(DomUtil) {
+ "use strict";
+
+ /**
+ * @exports WoltLab/WCF/Ui/Redactor/Metacode
+ */
+ return {
+ /**
+ * Converts `<woltlab-metacode>` into the bbcode representation.
+ *
+ * @param {Element} element textarea element
+ */
+ convert: function(element) {
+ var div = elCreate('div');
+ div.innerHTML = element.textContent;
+
+ var attributes, metacode, metacodes = elByTag('woltlab-metacode', div), name, tagClose, tagOpen;
+ while (metacodes.length) {
+ metacode = metacodes[0];
+ name = elData(metacode, 'name');
+ attributes = elData(metacode, 'attributes');
+
+ tagOpen = this._getOpeningTag(name, attributes);
+ tagClose = this._getClosingTag(name);
+
+ if (metacode.parentNode === div) {
+ DomUtil.prepend(tagOpen, this._getFirstParagraph(metacode));
+ this._getLastParagraph(metacode).appendChild(tagClose);
+ }
+ else {
+ DomUtil.prepend(tagOpen, metacode);
+ metacode.appendChild(tagClose);
+ }
+
+ DomUtil.unwrapChildNodes(metacode);
+ }
+
+ element.textContent = div.innerHTML;
+ },
+
+ /**
+ * Returns a text node representing the opening bbcode tag.
+ *
+ * @param {string} name bbcode tag
+ * @param {string} attributes base64- and JSON-encoded attributes
+ * @returns {Text} text node containing the opening bbcode tag
+ * @protected
+ */
+ _getOpeningTag: function(name, attributes) {
+ try {
+ attributes = JSON.parse(atob(attributes));
+ }
+ catch (e) { /* invalid base64 data or invalid json */ }
+
+ if (!Array.isArray(attributes)) {
+ attributes = [];
+ }
+
+ var buffer = '[' + name;
+ if (attributes.length) {
+ buffer += '=' + attributes.join(',');
+ }
+
+ return document.createTextNode(buffer + ']');
+ },
+
+ /**
+ * Returns a text node representing the closing bbcode tag.
+ *
+ * @param {string} name bbcode tag
+ * @returns {Text} text node containing the closing bbcode tag
+ * @protected
+ */
+ _getClosingTag: function(name) {
+ return document.createTextNode('[/' + name + ']');
+ },
+
+ /**
+ * Returns the first paragraph of provided element. If there are no children or
+ * the first child is not a paragraph, a new paragraph is created and inserted
+ * as first child.
+ *
+ * @param {Element} element metacode element
+ * @returns {Element} paragraph that is the first child of provided element
+ * @protected
+ */
+ _getFirstParagraph: function (element) {
+ var firstChild, paragraph;
+
+ if (element.childElementCount === 0) {
+ paragraph = elCreate('p');
+ element.appendChild(paragraph);
+ }
+ else {
+ firstChild = element.children[0];
+
+ if (firstChild.nodeName === 'P') {
+ paragraph = firstChild;
+ }
+ else {
+ paragraph = elCreate('p');
+ element.insertBefore(paragraph, firstChild);
+ }
+ }
+
+ return paragraph;
+ },
+
+ /**
+ * Returns the last paragraph of provided element. If there are no children or
+ * the last child is not a paragraph, a new paragraph is created and inserted
+ * as last child.
+ *
+ * @param {Element} element metacode element
+ * @returns {Element} paragraph that is the last child of provided element
+ * @protected
+ */
+ _getLastParagraph: function (element) {
+ var count = element.childElementCount, lastChild, paragraph;
+
+ if (count === 0) {
+ paragraph = elCreate('p');
+ element.appendChild(paragraph);
+ }
+ else {
+ lastChild = element.children[count - 1];
+
+ if (lastChild.nodeName === 'P') {
+ paragraph = lastChild;
+ }
+ else {
+ paragraph = elCreate('p');
+ element.appendChild(paragraph);
+ }
+ }
+
+ return paragraph;
+ }
+ };
+});
<?php
namespace wcf\data;
+use wcf\system\html\input\HtmlInputProcessor;
/**
* Default interface for actions implementing quick reply.
/**
* Creates a new message object.
*
- * @return \wcf\data\DatabaseObject
+ * @return DatabaseObject
*/
public function create();
+ /**
+ * Returns the current html input processor or a new one if `$message` is not null.
+ *
+ * @param string|null $message source message
+ * @return HtmlInputProcessor
+ */
+ public function getHtmlInputProcessor($message = null);
+
/**
* Returns a message list object.
*
- * @param \wcf\data\DatabaseObject $container
- * @param integer $lastMessageTime
- * @return \wcf\data\DatabaseObjectList
+ * @param DatabaseObject $container
+ * @param integer $lastMessageTime
+ * @return DatabaseObjectList
*/
public function getMessageList(DatabaseObject $container, $lastMessageTime);
/**
* Returns page no for given container object.
*
- * @param \wcf\data\DatabaseObject $container
+ * @param DatabaseObject $container
* @return array
*/
public function getPageNo(DatabaseObject $container);
/**
* Returns the redirect url.
*
- * @param \wcf\data\DatabaseObject $container
- * @param \wcf\data\DatabaseObject $message
+ * @param DatabaseObject $container
+ * @param DatabaseObject $message
* @return string
*/
public function getRedirectUrl(DatabaseObject $container, DatabaseObject $message);
/**
* Validates the message.
*
- * @param \wcf\data\DatabaseObject $container
- * @param string $message
+ * @param DatabaseObject $container
+ * @param HtmlInputProcessor $htmlInputProcessor
*/
- public function validateMessage(DatabaseObject $container, $message);
+ public function validateMessage(DatabaseObject $container, HtmlInputProcessor $htmlInputProcessor);
/**
* Creates a new message and returns it.
/**
* Validates the container object for quick reply.
*
- * @param \wcf\data\DatabaseObject $container
+ * @param DatabaseObject $container
*/
public function validateContainer(DatabaseObject $container);
/**
* attachment handler
- * @var \wcf\system\attachment\AttachmentHandler
+ * @var AttachmentHandler
*/
- public $attachmentHandler = null;
+ public $attachmentHandler;
/**
* object id for attachments
*/
public $defaultSmilies = [];
- /**
- * enables bbcodes
- * @var boolean
- */
- public $enableBBCodes = 1;
-
- /**
- * enables html
- * @var boolean
- */
- public $enableHtml = 0;
-
/**
* enables multilingualism
* @var boolean
public $enableMultilingualism = false;
/**
- * enables smilies
- * @var boolean
+ * @var HtmlInputProcessor
*/
- public $enableSmilies = 1;
+ public $htmlInputProcessor;
/**
* content language id
* @var integer
*/
- public $languageID = null;
+ public $languageID;
/**
* maximum text length
*/
public $maxTextLength = 0;
- /**
- * pre parses the message
- * @var boolean
- */
- public $preParse = 1;
-
- /**
- * required permission to use BBCodes
- * @var boolean
- */
- public $permissionCanUseBBCodes = 'user.message.canUseBBCodes';
-
- /**
- * required permission to use HTML
- * @var boolean
- */
- public $permissionCanUseHtml = 'user.message.canUseHtml';
-
- /**
- * required permission to use smilies
- * @var boolean
- */
- public $permissionCanUseSmilies = 'user.message.canUseSmilies';
-
- /**
- * shows the signature
- * @var boolean
- */
- public $showSignature = 0;
-
- /**
- * enables the 'showSignature' setting
- * @var boolean
- */
- public $showSignatureSetting = 1;
-
/**
* list of smiley categories
* @var SmileyCategory[]
if (isset($_POST['subject'])) $this->subject = StringUtil::trim(MessageUtil::stripCrap($_POST['subject']));
if (isset($_POST['text'])) $this->text = StringUtil::trim(MessageUtil::stripCrap($_POST['text']));
- // settings
- $this->enableSmilies = $this->enableHtml = $this->enableBBCodes = $this->preParse = $this->showSignature = 0;
- if (isset($_POST['preParse'])) $this->preParse = intval($_POST['preParse']);
- if (isset($_POST['enableSmilies']) && WCF::getSession()->getPermission($this->permissionCanUseSmilies)) $this->enableSmilies = intval($_POST['enableSmilies']);
- if (isset($_POST['enableHtml']) && WCF::getSession()->getPermission($this->permissionCanUseHtml)) $this->enableHtml = intval($_POST['enableHtml']);
- if (isset($_POST['enableBBCodes']) && WCF::getSession()->getPermission($this->permissionCanUseBBCodes)) $this->enableBBCodes = intval($_POST['enableBBCodes']);
- if (isset($_POST['showSignature'])) $this->showSignature = intval($_POST['showSignature']);
-
// multilingualism
if (isset($_POST['languageID'])) $this->languageID = intval($_POST['languageID']);
}
throw new UserInputException('text', 'tooLong');
}
+ $this->htmlInputProcessor = new HtmlInputProcessor();
+ $this->htmlInputProcessor->process($this->text);
+
+ // TODO: add checks for disallowed bbcodes and stuff
+ $this->htmlInputProcessor->validate();
+
/*if ($this->enableBBCodes && $this->allowedBBCodesPermission) {
$disallowedBBCodes = BBCodeParser::getInstance()->validateBBCodes($this->text, ArrayUtil::trim(explode(',', WCF::getSession()->getPermission($this->allowedBBCodesPermission))));
if (!empty($disallowedBBCodes)) {
public function save() {
parent::save();
- $htmlInputProcessor = new HtmlInputProcessor();
- $this->text = $htmlInputProcessor->process($this->text);
+ $this->text = $this->htmlInputProcessor->getHtml();
// parse URLs
/* TODO
}
if (empty($_POST)) {
- $this->enableBBCodes = (ENABLE_BBCODES_DEFAULT_VALUE && WCF::getSession()->getPermission($this->permissionCanUseBBCodes)) ? 1 : 0;
- $this->enableHtml = (ENABLE_HTML_DEFAULT_VALUE && WCF::getSession()->getPermission($this->permissionCanUseHtml)) ? 1 : 0;
- $this->enableSmilies = (ENABLE_SMILIES_DEFAULT_VALUE && WCF::getSession()->getPermission($this->permissionCanUseSmilies)) ? 1 : 0;
- $this->preParse = PRE_PARSE_DEFAULT_VALUE;
- $this->showSignature = SHOW_SIGNATURE_DEFAULT_VALUE;
$this->languageID = WCF::getLanguage()->languageID;
}
}
}
- if ($this->enableBBCodes && $this->allowedBBCodesPermission) {
+ if ($this->allowedBBCodesPermission) {
BBCodeHandler::getInstance()->setAllowedBBCodes(explode(',', WCF::getSession()->getPermission($this->allowedBBCodesPermission)));
}
}
'attachmentParentObjectID' => $this->attachmentParentObjectID,
'availableContentLanguages' => $this->availableContentLanguages,
'defaultSmilies' => $this->defaultSmilies,
- 'enableBBCodes' => $this->enableBBCodes,
- 'enableHtml' => $this->enableHtml,
- 'enableSmilies' => $this->enableSmilies,
'languageID' => ($this->languageID ?: 0),
'maxTextLength' => $this->maxTextLength,
- 'permissionCanUseBBCodes' => $this->permissionCanUseBBCodes,
- 'permissionCanUseHtml' => $this->permissionCanUseHtml,
- 'permissionCanUseSmilies' => $this->permissionCanUseSmilies,
- 'preParse' => $this->preParse,
- 'showSignature' => $this->showSignature,
- 'showSignatureSetting' => $this->showSignatureSetting,
'smileyCategories' => $this->smileyCategories,
'subject' => $this->subject,
'text' => $this->text,
$attributes = '';
if (!empty($tag['attributes'])) {
+ // strip outer quote tags
+ $tag['attributes'] = array_map(function($attribute) {
+ if (preg_match('~^([\'"])(?P<content>.*)(\1)$~', $attribute, $matches)) {
+ return $matches['content'];
+ }
+
+ return $attribute;
+ }, $tag['attributes']);
+
// uses base64 encoding to avoid an "escape" nightmare
$attributes = ' data-attributes="' . base64_encode(JSON::encode($tag['attributes'])) . '"';
}
use wcf\system\html\input\filter\IHtmlInputFilter;
use wcf\system\html\input\filter\MessageHtmlInputFilter;
use wcf\system\html\input\node\HtmlInputNodeProcessor;
+use wcf\system\html\input\node\IHtmlInputNodeProcessor;
+use wcf\system\html\node\IHtmlNodeProcessor;
use wcf\util\StringUtil;
/**
* @since 2.2
*/
class HtmlInputProcessor {
+ protected $embeddedContent = [];
+
/**
* @var IHtmlInputFilter
*/
protected $htmlInputFilter;
/**
- * @var HtmlInputNodeProcessor
+ * @var IHtmlInputNodeProcessor
*/
protected $htmlInputNodeProcessor;
// pre-parse HTML
$this->getHtmlInputNodeProcessor()->load($html);
$this->getHtmlInputNodeProcessor()->process();
-
- return $this->getHtmlInputNodeProcessor()->getHtml();
+ $this->embeddedContent = $this->getHtmlInputNodeProcessor()->getEmbeddedContent();
}
- public function setHtmlInputFilter(IHtmlInputFilter $htmlInputFilter) {
- $this->htmlInputFilter = $htmlInputFilter;
+ public function validate() {
+ // TODO
+ }
+
+ public function getHtml() {
+ return $this->getHtmlInputNodeProcessor()->getHtml();
}
/**
- * @return IHtmlInputFilter|MessageHtmlInputFilter
+ * @return IHtmlInputFilter
*/
public function getHtmlInputFilter() {
if ($this->htmlInputFilter === null) {
return $this->htmlInputFilter;
}
- public function setHtmlInputNodeProcessor(HtmlInputNodeProcessor $htmlInputNodeProcessor) {
- $this->htmlInputNodeProcessor = $htmlInputNodeProcessor;
+ public function setHtmlInputFilter(IHtmlInputFilter $htmlInputFilter) {
+ $this->htmlInputFilter = $htmlInputFilter;
}
/**
- * @return HtmlInputNodeProcessor
+ * @return IHtmlInputNodeProcessor
*/
public function getHtmlInputNodeProcessor() {
if ($this->htmlInputNodeProcessor === null) {
return $this->htmlInputNodeProcessor;
}
+
+ public function setHtmlInputNodeProcessor(IHtmlNodeProcessor $htmlInputNodeProcessor) {
+ $this->htmlInputNodeProcessor = $htmlInputNodeProcessor;
+ }
+
+ public function getEmbeddedContent() {
+ return $this->embeddedContent;
+ }
}
<?php
namespace wcf\system\html\input\node;
+use wcf\system\event\EventHandler;
use wcf\system\html\node\HtmlNodeProcessor;
use wcf\util\DOMUtil;
* TOOD documentation
* @since 2.2
*/
-class HtmlInputNodeProcessor extends HtmlNodeProcessor {
+class HtmlInputNodeProcessor extends HtmlNodeProcessor implements IHtmlInputNodeProcessor {
+ protected $embeddedContent = [];
+
// TODO: this should include other tags
protected $emptyTags = ['em', 'strong', 'u'];
protected $mergeTags = ['em', 'strong', 'u'];
public function process() {
+ EventHandler::getInstance()->fireAction($this, 'beforeProcess');
+
+ $this->embeddedContent = [];
+
// process metacode markers first
$this->invokeHtmlNode(new HtmlInputNodeWoltlabMetacodeMarker());
// handle static converters
$this->invokeHtmlNode(new HtmlInputNodeWoltlabMetacode());
+ // extract embedded content
+ $this->parseEmbeddedContent();
+
// remove empty elements and join identical siblings if appropriate
$this->cleanup();
+
+ EventHandler::getInstance()->fireAction($this, 'afterProcess');
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getEmbeddedContent() {
+ return $this->embeddedContent;
+ }
+
+ public function addEmbeddedContent($type, array $data) {
+ $this->embeddedContent[$type] = $data;
+ }
+
+ protected function parseEmbeddedContent() {
+ // handle `woltlab-metacode`
+ $elements = $this->getDocument()->getElementsByTagName('woltlab-metacode');
+ $metacodesByName = [];
+ for ($i = 0, $length = $elements->length; $i < $length; $i++) {
+ /** @var \DOMElement $element */
+ $element = $elements->item($i);
+ $name = $element->getAttribute('data-name');
+ $attributes = $this->parseAttributes($element->getAttribute('data-attributes'));
+
+ if (!isset($metacodesByName[$name])) $metacodesByName[$name] = [];
+ $metacodesByName[$name][] = $attributes;
+ }
+
+ $this->embeddedContent = $metacodesByName;
+
+ EventHandler::getInstance()->fireAction($this, 'parseEmbeddedContent');
}
protected function cleanup() {
--- /dev/null
+<?php
+namespace wcf\system\html\input\node;
+use wcf\system\html\node\IHtmlNodeProcessor;
+
+/**
+ * @since 2.2
+ */
+interface IHtmlInputNodeProcessor extends IHtmlNodeProcessor {
+ public function getEmbeddedContent();
+
+ public function process();
+}
* TOOD documentation
* @since 2.2
*/
-class HtmlNodeProcessor {
+class HtmlNodeProcessor implements IHtmlNodeProcessor {
/**
* @var \DOMDocument
*/
--- /dev/null
+<?php
+namespace wcf\system\html\node;
+
+/**
+ * @since 2.2
+ */
+interface IHtmlNodeProcessor {
+ public function getDocument();
+
+ public function getHtml();
+
+ public function load($html);
+}
+++ /dev/null
-<?php
-namespace wcf\system\message;
-use wcf\data\DatabaseObject;
-use wcf\system\WCF;
-
-/**
- * Provides utility functions for common tasks related to inline editing and quick reply.
- *
- * @author Alexander Ebert
- * @copyright 2001-2016 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package com.woltlab.wcf
- * @subpackage system.message
- * @category Community Framework
- */
-class MessageFormSettingsHandler {
- /**
- * Computes the settings for BBCodes, Smilies and pre parsing. Optionally accepts the corresponding DatabaseObject
- * whose values will be used in case the settings did not contain the individual values (legacy support).
- *
- * @param mixed[][] $parameters
- * @param \wcf\data\DatabaseObject $object
- * @param string $permissionCanUseBBCodes
- * @param string $permissionCanUseSmilies
- * @return array
- */
- public static function getSettings(array $parameters, DatabaseObject $object = null, $permissionCanUseBBCodes = '', $permissionCanUseSmilies = '') {
- $permissionCanUseBBCodes = ($permissionCanUseBBCodes) ?: 'user.message.canUseBBCodes';
- $permissionCanUseSmilies = ($permissionCanUseSmilies) ?: 'user.message.canUseSmilies';
-
- $enableSmilies = 0;
- $enableBBCodes = 0;
- $preParse = 0;
-
- if (WCF::getSession()->getPermission($permissionCanUseSmilies)) {
- if (isset($parameters['enableSmilies'])) {
- $enableSmilies = ($parameters['enableSmilies']) ? 1 : 0;
- }
- else {
- $enableSmilies = ($object === null) ? 1 : $object->enableSmilies;
- }
- }
- else if ($object !== null) {
- $enableSmilies = ($object->enableSmilies) ? 1 : 0;
- }
-
- if (WCF::getSession()->getPermission($permissionCanUseBBCodes)) {
- if (isset($parameters['enableBBCodes'])) {
- $enableBBCodes = ($parameters['enableBBCodes']) ? 1 : 0;
- }
- else {
- $enableBBCodes = ($object === null) ? 1 : $object->enableBBCodes;
- }
-
- if (isset($parameters['preParse'])) {
- $preParse = ($parameters['preParse'] && $enableBBCodes) ? 1 : 0;
- }
- else {
- $preParse = $enableBBCodes;
- }
- }
- else if ($object !== null) {
- $enableBBCodes = $preParse = ($object->enableBBCodes) ? 1 : 0;
- }
-
- return [
- 'enableSmilies' => $enableSmilies,
- 'enableBBCodes' => $enableBBCodes,
- 'preParse' => $preParse
- ];
- }
-}
use wcf\system\exception\ParentClassException;
use wcf\system\exception\SystemException;
use wcf\system\exception\UserInputException;
+use wcf\system\html\input\HtmlInputProcessor;
use wcf\system\SingletonFactory;
use wcf\system\WCF;
use wcf\util\ArrayUtil;
}
$object->validateContainer($this->container);
+ $parameters['htmlInputProcessor'] = $object->getHtmlInputProcessor($parameters['data']['message']);
+ unset($parameters['data']['message']);
+
+ $parameters['htmlInputProcessor']->validate();
+
// validate message
- $object->validateMessage($this->container, $parameters['data']['message']);
+ $object->validateMessage($this->container, $parameters['htmlInputProcessor']);
// check for message quote ids
$parameters['removeQuoteIDs'] = (isset($parameters['removeQuoteIDs']) && is_array($parameters['removeQuoteIDs'])) ? ArrayUtil::trim($parameters['removeQuoteIDs']) : [];
unset($parameters['data']['tmpHash']);
}
- // message settings
- $parameters['data'] = array_merge($parameters['data'], MessageFormSettingsHandler::getSettings($parameters));
-
- $parameters['data']['enableHtml'] = 0;
- $parameters['data']['showSignature'] = (WCF::getUser()->userID ? WCF::getUser()->showSignature : 0);
-
EventHandler::getInstance()->fireAction($this, 'validateParameters', $parameters);
}
* Creates a new message and returns the parsed template.
*
* @param \wcf\data\IMessageQuickReplyAction $object
- * @param mixed[][] $parameters
+ * @param array $parameters
* @param string $containerActionClassName
* @param string $sortOrder
* @param string $templateName
$parameters['data']['username'] = WCF::getUser()->username;
// pre-parse message text
- if ($parameters['data']['preParse']) {
+ /*if ($parameters['data']['preParse']) {
$parameters['data']['message'] = PreParser::getInstance()->parse($parameters['data']['message'], $this->allowedBBodes);
}
- unset($parameters['data']['preParse']);
+ unset($parameters['data']['preParse']);*/
$parameters['data'] = array_merge($additionalFields, $parameters['data']);
EventHandler::getInstance()->fireAction($this, 'createdMessage', $eventParameters);
if ($message instanceof IMessage && !$message->isVisible()) {
- return [
- 'isVisible' => false
- ];
+ return ['isVisible' => false];
}
// resolve the page no
}
else {
// redirect
- return [
- 'url' => $object->getRedirectUrl($this->container, $message)
- ];
+ return ['url' => $object->getRedirectUrl($this->container, $message)];
}
}
*/
public function executeEnd(TemplateScriptingCompiler $compiler) {
$compiler->popTag('lang');
- return "<?php echo (!empty(\$this->tagStack[count(\$this->tagStack) - 1][1]['__literal']) ? wcf\system\WCF::getLanguage()->get(ob_get_clean(), \$this->tagStack[count(\$this->tagStack) - 1][1], (isset(\$this->tagStack[count(\$this->tagStack) - 1][1]['__optional']) ? \$this->tagStack[count(\$this->tagStack) - 1][1]['__optional'] : false)) : wcf\system\WCF::getLanguage()->getDynamicVariable(ob_get_clean(), \$this->tagStack[count(\$this->tagStack) - 1][1], (isset(\$this->tagStack[count(\$this->tagStack) - 1][1]['__optional']) ? \$this->tagStack[count(\$this->tagStack) - 1][1]['__optional'] : false))); array_pop(\$this->tagStack); ?>";
+ return "<?php
+ echo (
+ !empty(\$this->tagStack[count(\$this->tagStack) - 1][1]['__literal'])
+ ?
+ wcf\system\WCF::getLanguage()->get(
+ ob_get_clean(),
+ \$this->tagStack[count(\$this->tagStack) - 1][1],
+ (
+ isset(\$this->tagStack[count(\$this->tagStack) - 1][1]['__optional'])
+ ?
+ \$this->tagStack[count(\$this->tagStack) - 1][1]['__optional']
+ :
+ false
+ )
+ )
+ :
+ wcf\system\WCF::getLanguage()->getDynamicVariable(
+ ob_get_clean(),
+ \$this->tagStack[count(\$this->tagStack) - 1][1],
+ (
+ isset(\$this->tagStack[count(\$this->tagStack) - 1][1]['__optional'])
+ ?
+ \$this->tagStack[count(\$this->tagStack) - 1][1]['__optional']
+ :
+ false
+ )
+ )
+ );
+ array_pop(\$this->tagStack); ?>";
}
}
$cloneNode = self::getParentBefore($node, $ancestor);
if ($splitBefore) {
- if (self::isFirstNode($node, $cloneNode)) {
+ if ($cloneNode === null) {
+ // target node is already a direct descendant of the ancestor
+ // node, no need to split anything
+ return $node;
+ }
+ else if (self::isFirstNode($node, $cloneNode)) {
// target node is at the very start, we can safely move the
// entire parent node around
return $cloneNode;
}
}
else {
- if (self::isLastNode($node, $cloneNode)) {
+ if ($cloneNode === null) {
+ // target node is already a direct descendant of the ancestor
+ // node, no need to split anything
+ return $node;
+ }
+ else if (self::isLastNode($node, $cloneNode)) {
// target node is at the very end, we can safely move the
// entire parent node around
return $cloneNode;