// restore ampersands
html = html.replace(/@@@WCF_AMPERSAND@@@/g, '&');
+ var div = elCreate('div');
+ div.innerHTML = html;
+
// remove iframes smuggled into the HTML by the user
// they're removed on the server anyway, but keeping
// them in the wysiwyg may lead to false impressions
- var div = elCreate('div');
- div.innerHTML = html;
elBySelAll('iframe', div, elRemove);
+
+ // strip script tags
+ elBySelAll('pre', div, function (pre) {
+ if (pre.classList.contains('redactor-script-tag')) {
+ elRemove(pre);
+ }
+ });
+
html = div.innerHTML;
return html;
throwError: function(element, message) {
var error = elCreate('small');
error.className = 'innerError';
- error.textContent = message;
+ error.textContent = (message === 'empty' ? Language.get('wcf.global.form.error.empty') : message);
DomUtil.insertAfter(error, element);
},
$this->htmlInputProcessor->process($this->text, $this->messageObjectType, 0);
// check text length
+ if ($this->htmlInputProcessor->appearsToBeEmpty()) {
+ throw new UserInputException('text');
+ }
$message = $this->htmlInputProcessor->getTextContent();
if ($this->maxTextLength != 0 && mb_strlen($message) > $this->maxTextLength) {
throw new UserInputException('text', 'tooLong');
return $this->getHtmlInputNodeProcessor()->getTextContent();
}
+ /**
+ * Returns true if the message appears to be empty.
+ *
+ * @return boolean true if message appears to be empty
+ */
+ public function appearsToBeEmpty() {
+ return $this->getHtmlInputNodeProcessor()->appearsToBeEmpty();
+ }
+
/**
* Returns the all embedded content data.
*
'td' => ['text-center', 'text-justify', 'text-right']
];
+ /**
+ * list of HTML elements that are treated as empty, that means
+ * they don't generate any (indirect) output at all
+ *
+ * @var string[]
+ */
+ public static $emptyTags = [
+ // typical wrappers
+ 'div', 'p', 'span',
+
+ // headlines
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
+
+ // tables
+ 'table', 'tbody', 'thead', 'tr', 'th', 'td', 'colgroup', 'col',
+
+ // lists
+ 'ul', 'ol', 'li',
+
+ // other
+ 'a', 'kbd', 'woltlab-quote', 'woltlab-spoiler', 'pre', 'sub', 'sup'
+ ];
+
/**
* list of embedded content grouped by type
* @var array
return StringUtil::trim($this->getDocument()->getElementsByTagName('body')->item(0)->textContent);
}
+ /**
+ * Returns true if the message appears to be empty.
+ *
+ * @return boolean true if message appears to be empty
+ */
+ public function appearsToBeEmpty() {
+ if ($this->getTextContent() !== '') {
+ return false;
+ }
+
+ /** @var \DOMElement $body */
+ $body = $this->getDocument()->getElementsByTagName('body')->item(0);
+
+ /** @var \DOMElement $element */
+ foreach ($body->getElementsByTagName('*') as $element) {
+ if (!in_array($element->nodeName, self::$emptyTags)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/**
* Processes embedded content.
*/
unset($parameters['data']['message']);
$parameters['htmlInputProcessor']->validate();
+ if ($parameters['htmlInputProcessor']->appearsToBeEmpty()) {
+ throw new UserInputException('message');
+ }
// validate message
$object->validateMessage($this->container, $parameters['htmlInputProcessor']);