-<!-- begin:parser_nonessential -->
<div class="spoilerBox jsSpoilerBox">
<header class="jsOnly">
<a class="button small jsSpoilerToggle"{if $buttonLabel} data-has-custom-label="true"{/if}>{if $buttonLabel}{$buttonLabel}{else}{lang}wcf.bbcode.spoiler.show{/lang}{/if}</a>
<div style="display: none">
<!-- META_CODE_INNER_CONTENT -->
</div>
-</div>
-
-{if !$__wcfSpoilerBBCodeJavaScript|isset}
- {assign var='__wcfSpoilerBBCodeJavaScript' value=true}
- <script data-relocate="true">
- elBySelAll('.jsSpoilerBox', null, function(spoilerBox) {
- spoilerBox.classList.remove('jsSpoilerBox');
-
- var toggleButton = elBySel('.jsSpoilerToggle', spoilerBox);
- var container = toggleButton.parentNode.nextElementSibling;
-
- toggleButton.addEventListener(WCF_CLICK_EVENT, function(event) {
- event.preventDefault();
+
+ {if !$__wcfSpoilerBBCodeJavaScript|isset}
+ {assign var='__wcfSpoilerBBCodeJavaScript' value=true}
+ <script data-relocate="true">
+ elBySelAll('.jsSpoilerBox', null, function(spoilerBox) {
+ spoilerBox.classList.remove('jsSpoilerBox');
- toggleButton.classList.toggle('active');
- window[(toggleButton.classList.contains('active') ? 'elShow' : 'elHide')](container);
+ var toggleButton = elBySel('.jsSpoilerToggle', spoilerBox);
+ var container = toggleButton.parentNode.nextElementSibling;
- if (!elDataBool(toggleButton, 'has-custom-label')) {
- toggleButton.textContent = (toggleButton.classList.contains('active')) ? '{lang}wcf.bbcode.spoiler.hide{/lang}' : '{lang}wcf.bbcode.spoiler.show{/lang}';
- }
+ toggleButton.addEventListener(WCF_CLICK_EVENT, function(event) {
+ event.preventDefault();
+
+ toggleButton.classList.toggle('active');
+ window[(toggleButton.classList.contains('active') ? 'elShow' : 'elHide')](container);
+
+ if (!elDataBool(toggleButton, 'has-custom-label')) {
+ toggleButton.textContent = (toggleButton.classList.contains('active')) ? '{lang}wcf.bbcode.spoiler.hide{/lang}' : '{lang}wcf.bbcode.spoiler.show{/lang}';
+ }
+ });
});
- });
- </script>
-{/if}
-<!-- end:parser_nonessential -->
+ </script>
+ {/if}
+</div>
this._xhr = null;
this._init(options);
- };
+ }
AjaxRequest.prototype = {
/**
* Initializes the request options.
*
- * @param {object<string, *>} options request options
+ * @param {Object} options request options
*/
_init: function(options) {
this._options = Core.extend({
* Sets a specific option.
*
* @param {string} key option name
- * @param {*} value option value
+ * @param {?} value option value
*/
setOption: function(key, value) {
this._options[key] = value;
/**
* Sets request data while honoring pinned data from setup callback.
*
- * @param {object<string, *>} data request data
+ * @param {Object} data request data
*/
setData: function(data) {
if (this._data !== null && Core.getType(data) !== 'FormData') {
* Handles a successful request.
*
* @param {XMLHttpRequest} xhr request object
- * @param {object<string, *>} options request options
+ * @param {Object} options request options
*/
_success: function(xhr, options) {
if (!options.silent) {
* a non-success status code or an entirely failed request.
*
* @param {XMLHttpRequest} xhr request object
- * @param {object<string, *>} options request options
+ * @param {Object} options request options
*/
_failure: function (xhr, options) {
if (_ignoreAllErrors) {
catch (e) {}
var showError = true;
- if (typeof options.failure === 'function') {
+ if (data !== null && typeof options.failure === 'function') {
showError = options.failure(data, xhr.responseText, xhr, options.data);
}
/**
* Finalizes a request.
*
- * @param {object<string, *>} options request options
+ * @param {Object} options request options
*/
_finalize: function(options) {
if (typeof options.finalize === 'function') {
namespace wcf\system\html\node;
use wcf\system\exception\SystemException;
use wcf\system\html\IHtmlProcessor;
+use wcf\util\DOMUtil;
use wcf\util\JSON;
/**
* Replaces an element with plain text.
*
* @param \DOMElement $element target element
- * @param string $text text used to replace target element
+ * @param string $text text used to replace target
+ * @param boolean $isBlockElement true if element is a block element
*/
- public function replaceElementWithText(\DOMElement $element, $text) {
+ public function replaceElementWithText(\DOMElement $element, $text, $isBlockElement) {
$textNode = $element->ownerDocument->createTextNode($text);
$element->parentNode->insertBefore($textNode, $element);
+
+ if ($isBlockElement) {
+ for ($i = 0; $i < 2; $i++) {
+ $br = $element->ownerDocument->createElement('br');
+ $element->parentNode->insertBefore($br, $element);
+ }
+ }
+
$element->parentNode->removeChild($element);
}
else {
$htmlNodeProcessor->replaceElementWithText(
$element,
- WCF::getLanguage()->getDynamicVariable('wcf.bbcode.quote.simplified', ['cite' => $element->getAttribute('data-author')])."\n"
+ WCF::getLanguage()->getDynamicVariable('wcf.bbcode.quote.simplified', ['cite' => $element->getAttribute('data-author')]),
+ true
);
}
break;
$nodeIdentifier = StringUtil::getRandomID();
$htmlNodeProcessor->addNodeData($this, $nodeIdentifier, [
'content' => $element->textContent,
- 'file' => ($element->hasAttribute('data-file')) ? $element->getAttribute('data-file') : '',
- 'highlighter' => ($element->hasAttribute('data-highlighter')) ? $element->getAttribute('data-highlighter') : '',
+ 'file' => $element->getAttribute('data-file'),
+ 'highlighter' => $element->getAttribute('data-highlighter'),
'line' => ($element->hasAttribute('data-line')) ? $element->getAttribute('data-line') : 1
]);
case 'text/simplified-html':
case 'text/plain':
- return WCF::getLanguage()->getDynamicVariable('wcf.bbcode.code.simplified', ['lines' => substr_count($element->nodeValue, "\n") + 1]);
+ $htmlNodeProcessor->replaceElementWithText(
+ $element,
+ WCF::getLanguage()->getDynamicVariable('wcf.bbcode.code.simplified', ['lines' => substr_count($element->nodeValue, "\n") + 1]),
+ true
+ );
break;
}
}
namespace wcf\system\html\output\node;
use wcf\system\html\node\AbstractHtmlNodeProcessor;
use wcf\system\html\node\IHtmlNode;
+use wcf\util\DOMUtil;
+use wcf\util\StringUtil;
/**
* Processes a HTML string and renders the final output for display.
// dynamic node handlers
$this->invokeNodeHandlers('wcf\system\html\output\node\HtmlOutputNode', ['woltlab-metacode']);
+
+ if ($this->outputType !== 'text/html') {
+ // convert `<p>...</p>` into `...<br><br>`
+ $paragraphs = $this->getDocument()->getElementsByTagName('p');
+ while ($paragraphs->length) {
+ $paragraph = $paragraphs->item(0);
+
+ for ($i = 0; $i < 2; $i++) {
+ $br = $this->getDocument()->createElement('br');
+ $paragraph->appendChild($br);
+ }
+
+ DOMUtil::removeNode($paragraph, true);
+ }
+
+ if ($this->outputType === 'text/plain') {
+ // remove all `\n` first
+ $nodes = [];
+ /** @var \DOMText $node */
+ foreach ($this->getXPath()->query('//text()') as $node) {
+ if (strpos($node->textContent, "\n") !== false) {
+ $nodes[] = $node;
+ }
+ }
+ foreach ($nodes as $node) {
+ $textNode = $this->getDocument()->createTextNode(preg_replace('~\r?\n~', '', $node->textContent));
+ $node->parentNode->insertBefore($textNode, $node);
+ $node->parentNode->removeChild($node);
+ }
+
+ // convert `<br>` into `\n`
+ $brs = $this->getDocument()->getElementsByTagName('br');
+ while ($brs->length) {
+ $br = $brs->item(0);
+
+ $newline = $this->getDocument()->createTextNode("\n");
+ $br->parentNode->insertBefore($newline, $br);
+ DOMUtil::removeNode($br);
+ }
+
+ // remove all other elements
+ $elements = $this->getDocument()->getElementsByTagName('*');
+ while ($elements->length) {
+ DOMUtil::removeNode($elements->item(0), true);
+ }
+ }
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getHtml() {
+ $html = parent::getHtml();
+
+ if ($this->outputType === 'text/plain') {
+ $html = StringUtil::trim($html);
+ }
+
+ return $html;
}
/**
else if ($this->outputType === 'text/plain') {
/** @var \DOMElement $element */
foreach ($elements as $element) {
- $htmlNodeProcessor->replaceElementWithText($element, '@' . $element->getAttribute('data-username'));
+ $htmlNodeProcessor->replaceElementWithText($element, '@' . $element->getAttribute('data-username'), false);
}
}
}
* @inheritDoc
*/
public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
- if ($this->outputType === 'text/html' || $this->outputType === 'text/simplified-html') {
- /** @var \DOMElement $element */
- foreach ($elements as $element) {
+ /** @var \DOMElement $element */
+ foreach ($elements as $element) {
+ if ($this->outputType === 'text/html') {
$nodeIdentifier = StringUtil::getRandomID();
$htmlNodeProcessor->addNodeData($this, $nodeIdentifier, ['label' => $element->getAttribute('data-label')]);
$htmlNodeProcessor->renameTag($element, 'wcfNode-' . $nodeIdentifier);
}
- }
- else if ($this->outputType === 'text/plain') {
- /** @var \DOMElement $element */
- foreach ($elements as $element) {
- DOMUtil::removeNode($element);
+ else if ($this->outputType === 'text/simplified-html' || $this->outputType === 'text/plain') {
+ $htmlNodeProcessor->replaceElementWithText(
+ $element,
+ WCF::getLanguage()->getDynamicVariable('wcf.bbcode.spoiler.simplified', ['label' => $element->getAttribute('data-label')]),
+ true
+ );
}
}
}
*
* @param \DOMElement $element start element
* @param string $tagName tag name to match
- * @return boolean true if there is at least one parent with the provided tag name
+ * @return boolean
*/
public static function hasParent(\DOMElement $element, $tagName) {
while ($element = $element->parentNode) {
<item name="wcf.bbcode.spoiler.hide"><![CDATA[Spoiler ausblenden]]></item>
<item name="wcf.bbcode.spoiler.show"><![CDATA[Spoiler anzeigen]]></item>
<item name="wcf.bbcode.spoiler.text"><![CDATA[(Versteckter Text)]]></item>
+ <item name="wcf.bbcode.spoiler.simplified"><![CDATA[(Versteckter Text)]]></item>
</category>
<category name="wcf.captcha">
<item name="wcf.bbcode.spoiler.hide"><![CDATA[Hide Spoiler]]></item>
<item name="wcf.bbcode.spoiler.show"><![CDATA[Display Spoiler]]></item>
<item name="wcf.bbcode.spoiler.text"><![CDATA[(Hidden Content)]]></item>
+ <item name="wcf.bbcode.spoiler.simplified"><![CDATA[(Hidden Content)]]></item>
</category>
<category name="wcf.captcha">