From: Alexander Ebert Date: Thu, 16 Jun 2016 18:25:05 +0000 (+0200) Subject: Added proper support for code, quote and spoiler X-Git-Tag: 3.0.0_Beta_1~1412 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=442a3ea15a0bfe4003c02ee6d8572de2ea9b3dda;p=GitHub%2FWoltLab%2FWCF.git Added proper support for code, quote and spoiler --- diff --git a/com.woltlab.wcf/templates/codeMetaCode.tpl b/com.woltlab.wcf/templates/codeMetaCode.tpl new file mode 100644 index 0000000000..8fcf0abc70 --- /dev/null +++ b/com.woltlab.wcf/templates/codeMetaCode.tpl @@ -0,0 +1,33 @@ +
+
+
+
{@$highlighter->getTitle()}{if $filename}: {$filename}{/if}
+
+ +
    + {assign var='lineNumber' value=$startLineNumber} + {foreach from=$content item=line} + {if $lineNumbers[$lineNumber]|isset} +
  1. {@$line}
  2. + {else} +
  3. {@$line}
  4. + {/if} + + {assign var='lineNumber' value=$lineNumber+1} + {/foreach} +
+
+ + {if $lines > 10} + {lang}wcf.bbcode.button.showAll{/lang} + + {if !$__overlongCodeBoxSeen|isset} + {assign var='__overlongCodeBoxSeen' value=true} + + {/if} + {/if} +
diff --git a/com.woltlab.wcf/templates/spoilerMetaCode.tpl b/com.woltlab.wcf/templates/spoilerMetaCode.tpl new file mode 100644 index 0000000000..74671a2941 --- /dev/null +++ b/com.woltlab.wcf/templates/spoilerMetaCode.tpl @@ -0,0 +1,34 @@ + +
+
+ {if $buttonLabel}{$buttonLabel}{else}{lang}wcf.bbcode.spoiler.show{/lang}{/if} +
+ +
+ +
+
+ +{if !$__wcfSpoilerBBCodeJavaScript|isset} + {assign var='__wcfSpoilerBBCodeJavaScript' value=true} + +{/if} + diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Code.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Code.js index b92ec60e79..51c1f0ea48 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Code.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Code.js @@ -66,14 +66,10 @@ define(['EventHandler', 'EventKey', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Di * @protected */ _observeLoad: function() { - this._editor.events.stopDetectChanges(); - elBySelAll('pre', this._editor.$editor[0], (function(pre) { pre.addEventListener(WCF_CLICK_EVENT, this._callbackEdit); this._setTitle(pre); }).bind(this)); - - this._editor.events.startDetectChanges(); }, /** @@ -114,8 +110,6 @@ define(['EventHandler', 'EventKey', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Di _save: function(event) { event.preventDefault(); - this._editor.events.stopDetectChanges(); - var id = 'redactor-code-' + this._elementId; ['file', 'highlighter', 'line'].forEach((function (attr) { @@ -125,8 +119,6 @@ define(['EventHandler', 'EventKey', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Di this._setTitle(this._pre); this._editor.caret.after(this._pre); - this._editor.events.startDetectChanges(); - UiDialog.close(this); }, diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Quote.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Quote.js index 37e979686c..e7413b109b 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Quote.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Quote.js @@ -66,14 +66,10 @@ define(['EventHandler', 'EventKey', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Di * @protected */ _observeLoad: function() { - this._editor.events.stopDetectChanges(); - elBySelAll('blockquote', this._editor.$editor[0], (function(blockquote) { blockquote.addEventListener(WCF_CLICK_EVENT, this._callbackEdit); this._setTitle(blockquote); }).bind(this)); - - this._editor.events.startDetectChanges(); }, /** @@ -114,8 +110,6 @@ define(['EventHandler', 'EventKey', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Di _save: function(event) { event.preventDefault(); - this._editor.events.stopDetectChanges(); - var id = 'redactor-quote-' + this._elementId; ['author', 'url'].forEach((function (attr) { @@ -125,8 +119,6 @@ define(['EventHandler', 'EventKey', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Di this._setTitle(this._blockquote); this._editor.caret.after(this._blockquote); - this._editor.events.startDetectChanges(); - UiDialog.close(this); }, diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Spoiler.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Spoiler.js index 08c264863e..b598ab02bd 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Spoiler.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Redactor/Spoiler.js @@ -71,14 +71,10 @@ define(['EventHandler', 'EventKey', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Di * @protected */ _observeLoad: function() { - this._editor.events.stopDetectChanges(); - elBySelAll('woltlab-spoiler', this._editor.$editor[0], (function(spoiler) { spoiler.addEventListener(WCF_CLICK_EVENT, this._callbackEdit); this._setTitle(spoiler); }).bind(this)); - - this._editor.events.startDetectChanges(); }, /** @@ -119,15 +115,11 @@ define(['EventHandler', 'EventKey', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Di _save: function(event) { event.preventDefault(); - this._editor.events.stopDetectChanges(); - elData(this._spoiler, 'label', elById('redactor-spoiler-' + this._elementId + '-label').value); this._setTitle(this._spoiler); this._editor.caret.after(this._spoiler); - this._editor.events.startDetectChanges(); - UiDialog.close(this); }, diff --git a/wcfsetup/install/files/lib/system/bbcode/highlighter/BrainfuckHighlighter.class.php b/wcfsetup/install/files/lib/system/bbcode/highlighter/BrainfuckHighlighter.class.php deleted file mode 100644 index 69d3d1b7d0..0000000000 --- a/wcfsetup/install/files/lib/system/bbcode/highlighter/BrainfuckHighlighter.class.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @package WoltLabSuite\Core\System\Bbcode\Highlighter - */ -class BrainfuckHighlighter extends Highlighter { - /** - * @inheritDoc - */ - public function highlight($string) { - $string = preg_replace('/[^-\\+\\.,\\[\\]\\>\\<]+/', '||span class="hlComments"||\\0||/span||', $string); - $string = preg_replace('/[\\<\\>]+/', '\\0', $string); - $string = preg_replace('/[-\\+]+/', '\\0', $string); - $string = preg_replace('/[\\.,]+/', '\\0', $string); - $string = preg_replace('/[\\[\\]]+/', '\\0', $string); - - $string = str_replace(['||span class="hlComments"||', '||/span||'], ['', ''], $string); - return $string; - } -} diff --git a/wcfsetup/install/files/lib/system/html/input/filter/MessageHtmlInputFilter.class.php b/wcfsetup/install/files/lib/system/html/input/filter/MessageHtmlInputFilter.class.php index a89bf0104b..4b7596e4d0 100644 --- a/wcfsetup/install/files/lib/system/html/input/filter/MessageHtmlInputFilter.class.php +++ b/wcfsetup/install/files/lib/system/html/input/filter/MessageHtmlInputFilter.class.php @@ -31,22 +31,40 @@ class MessageHtmlInputFilter implements IHtmlInputFilter { protected function setAttributeDefinitions(\HTMLPurifier_Config $config) { // TODO: move this into own PHP classes $definition = $config->getHTMLDefinition(true); - $definition->addAttribute('blockquote', 'data-quote-title', 'Text'); - $definition->addAttribute('blockquote', 'data-quote-url', 'URI'); + // quotes + $definition->addAttribute('blockquote', 'data-author', 'Text'); + $definition->addAttribute('blockquote', 'data-url', 'URI'); + + // code + $definition->addAttribute('pre', 'data-file', 'Text'); + $definition->addAttribute('pre', 'data-line', 'Number'); + $definition->addAttribute('pre', 'data-highlighter', 'Text'); + + // color $definition->addElement('woltlab-color', 'Inline', 'Inline', '', ['class' => 'Text']); + + // size $definition->addElement('woltlab-size', 'Inline', 'Inline', '', ['class' => 'Text']); + // mention $definition->addElement('woltlab-mention', 'Inline', 'Inline', '', [ 'data-user-id' => 'Number', 'data-username' => 'Text' ]); + // spoiler + $definition->addElement('woltlab-spoiler', 'Block', 'Flow', '', [ + 'data-label' => 'Text' + ]); + + // generic metacode $definition->addElement('woltlab-metacode', 'Inline', 'Inline', '', [ 'data-attributes' => 'Text', 'data-name' => 'Text' ]); + // metacode markers $definition->addElement('woltlab-metacode-marker', 'Inline', 'Empty', '', [ 'data-attributes' => 'Text', 'data-name' => 'Text', diff --git a/wcfsetup/install/files/lib/system/html/metacode/converter/CodeMetacodeConverter.class.php b/wcfsetup/install/files/lib/system/html/metacode/converter/CodeMetacodeConverter.class.php new file mode 100644 index 0000000000..462253b64a --- /dev/null +++ b/wcfsetup/install/files/lib/system/html/metacode/converter/CodeMetacodeConverter.class.php @@ -0,0 +1,70 @@ +ownerDocument->createElement('pre'); + + $line = 1; + $highlighter = $file = ''; + + switch (count($attributes)) { + case 1: + if (is_numeric($attributes[0])) { + $line = intval($attributes[0]); + } + else if (mb_strpos($attributes[0], '.') === false) { + $highlighter = $attributes[0]; + } + else { + $file = $attributes[0]; + } + break; + + case 2: + if (is_numeric($attributes[0])) { + $line = intval($attributes[0]); + if (mb_strpos($attributes[1], '.') === false) { + $highlighter = $attributes[1]; + } + else { + $file = $attributes[1]; + } + } + else { + $highlighter = $attributes[0]; + $file = $attributes[1]; + } + break; + + default: + $highlighter = $attributes[0]; + $line = intval($attributes[1]); + $file = $attributes[2]; + break; + } + + $element->setAttribute('data-file', $file); + $element->setAttribute('data-highlighter', $highlighter); + $element->setAttribute('data-line', $line); + + $element->appendChild($fragment); + + return $element; + } + + /** + * @inheritDoc + */ + public function validateAttributes(array $attributes) { + // 0-3 attributes + return (count($attributes) <= 3); + } +} diff --git a/wcfsetup/install/files/lib/system/html/metacode/converter/SpoilerMetacodeConverter.class.php b/wcfsetup/install/files/lib/system/html/metacode/converter/SpoilerMetacodeConverter.class.php new file mode 100644 index 0000000000..89ab85c062 --- /dev/null +++ b/wcfsetup/install/files/lib/system/html/metacode/converter/SpoilerMetacodeConverter.class.php @@ -0,0 +1,28 @@ +ownerDocument->createElement('woltlab-spoiler'); + $element->setAttribute('data-label', (!empty($attributes[0])) ? StringUtil::trim($attributes[0]) : ''); + $element->appendChild($fragment); + + return $element; + } + + /** + * @inheritDoc + */ + public function validateAttributes(array $attributes) { + // 0 or 1 attribute + return (count($attributes) <= 1); + } +} diff --git a/wcfsetup/install/files/lib/system/html/node/HtmlNodeProcessor.class.php b/wcfsetup/install/files/lib/system/html/node/HtmlNodeProcessor.class.php index 261b082156..0c0e4f6668 100644 --- a/wcfsetup/install/files/lib/system/html/node/HtmlNodeProcessor.class.php +++ b/wcfsetup/install/files/lib/system/html/node/HtmlNodeProcessor.class.php @@ -21,34 +21,33 @@ class HtmlNodeProcessor implements IHtmlNodeProcessor { protected $xpath; public function load($html) { - $this->document = new \DOMDocument(); + $this->document = new \DOMDocument('1.0', 'UTF-8'); $this->xpath = null; - // convert entities as DOMDocument screws them up - $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'); - // ignore all errors when loading the HTML string, because DOMDocument does not // provide a proper way to add custom HTML elements (even though explicitly allowed // in HTML5) and the input HTML has already been sanitized by HTMLPurifier - @$this->document->loadHTML($html); + // + // we're also injecting a bogus meta tag that magically enables DOMDocument + // to handle UTF-8 properly, this avoids encoding non-ASCII characters as it + // would conflict with already existing entities when reverting them + @$this->document->loadHTML('' . $html); $this->nodeData = []; } public function getHtml() { - $html = $this->document->saveHTML(); + $html = $this->document->saveHTML($this->document->getElementsByTagName('body')->item(0)); // remove nuisance added by PHP - $html = preg_replace('~^]+>\s~', '', $html); - $html = preg_replace('~$~', '', $html); - - $html = mb_convert_encoding($html, 'UTF-8', 'HTML-ENTITIES'); + $html = preg_replace('~^~', '', $html); + $html = preg_replace('~$~', '', $html); /** @var IHtmlNode $obj */ foreach ($this->nodeData as $data) { $obj = $data['object']; $string = $obj->replaceTag($data['data']); - $html = preg_replace_callback('~(?P.*)~', function($matches) use ($string) { + $html = preg_replace_callback('~(?P[\s\S]*)~', function($matches) use ($string) { $string = str_replace('', $matches['content'], $string); return $string; diff --git a/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeBlockquote.class.php b/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeBlockquote.class.php index 611f66bca9..7aed0e40dc 100644 --- a/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeBlockquote.class.php +++ b/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeBlockquote.class.php @@ -18,19 +18,15 @@ class HtmlOutputNodeBlockquote extends AbstractHtmlNode { * @inheritDoc */ public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) { + /** @var \DOMElement $element */ foreach ($elements as $element) { - if ($element->getAttribute('class') === 'quoteBox') { - $nodeIdentifier = StringUtil::getRandomID(); - $htmlNodeProcessor->addNodeData($this, $nodeIdentifier, [ - 'title' => ($element->hasAttribute('data-quote-title')) ? $element->getAttribute('data-quote-title') : '', - 'url' => ($element->hasAttribute('data-quote-url')) ? $element->getAttribute('data-quote-url') : '' - ]); - - $htmlNodeProcessor->renameTag($element, 'wcfNode-' . $nodeIdentifier); - } - else { - $htmlNodeProcessor->unwrapContent($element); - } + $nodeIdentifier = StringUtil::getRandomID(); + $htmlNodeProcessor->addNodeData($this, $nodeIdentifier, [ + 'title' => ($element->hasAttribute('data-quote-title')) ? $element->getAttribute('data-quote-title') : '', + 'url' => ($element->hasAttribute('data-quote-url')) ? $element->getAttribute('data-quote-url') : '' + ]); + + $htmlNodeProcessor->renameTag($element, 'wcfNode-' . $nodeIdentifier); } } diff --git a/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodePre.class.php b/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodePre.class.php new file mode 100644 index 0000000000..25f74548ce --- /dev/null +++ b/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodePre.class.php @@ -0,0 +1,219 @@ +addNodeData($this, $nodeIdentifier, [ + 'content' => $element->textContent, + 'file' => ($element->hasAttribute('data-file')) ? $element->getAttribute('data-file') : '', + 'highlighter' => ($element->hasAttribute('data-highlighter')) ? $element->getAttribute('data-highlighter') : '', + 'line' => ($element->hasAttribute('data-line')) ? $element->getAttribute('data-line') : 1 + ]); + + $htmlNodeProcessor->renameTag($element, 'wcfNode-' . $nodeIdentifier); + } + } + + public function replaceTag(array $data) { + $content = preg_replace('/^\s*\n/', '', $data['content']); + $content = preg_replace('/\n\s*$/', '', $content); + + $file = $data['file']; + $highlighter = $data['highlighter']; + $line = ($data['line'] < 1) ? 1 : $data['line']; + + // fetch highlighter-classname + $className = PlainHighlighter::class; + + // no highlighting for strings over a certain size, to prevent DoS + // this serves as a safety net in case one of the regular expressions + // in a highlighter causes PCRE to exhaust resources, such as the stack + if (strlen($content) < 16384) { + if ($highlighter) { + $className = '\wcf\system\bbcode\highlighter\\'.StringUtil::firstCharToUpperCase(mb_strtolower($highlighter)).'Highlighter'; + + switch (mb_substr($className, strlen('\wcf\system\bbcode\highlighter\\'))) { + case 'ShellHighlighter': + $className = BashHighlighter::class; + break; + + case 'C++Highlighter': + $className = CHighlighter::class; + break; + + case 'JavascriptHighlighter': + $className = JsHighlighter::class; + break; + + case 'LatexHighlighter': + $className = TexHighlighter::class; + break; + } + } + else { + // try to guess highlighter + if (mb_strpos($content, 'match($content)) { + $className = BashHighlighter::class; + } + else if (mb_strpos($content, '\\documentclass') !== false) { + $className = TexHighlighter::class; + } + } + } + + if (!class_exists($className)) { + $className = PlainHighlighter::class; + } + + /** @noinspection PhpUndefinedMethodInspection */ + $highlightedContent = $this->fixMarkup(explode("\n", $className::getInstance()->highlight($content))); + + // show template + /** @noinspection PhpUndefinedMethodInspection */ + WCF::getTPL()->assign([ + 'lineNumbers' => $this->makeLineNumbers($content, $line), + 'startLineNumber' => $line, + 'content' => $highlightedContent, + 'highlighter' => $className::getInstance(), + 'filename' => $file, + 'lines' => substr_count($content, "\n") + 1 + ]); + + return WCF::getTPL()->fetch('codeMetaCode'); + } + + /** + * Returns a string with all line numbers + * + * @param string $code + * @param integer $start + * @param string $split + * @return string + */ + protected function makeLineNumbers($code, $start, $split = "\n") { + $lines = explode($split, $code); + + $lineNumbers = []; + $i = -1; + // find an unused codeID + do { + $codeID = mb_substr(StringUtil::getHash($code), 0, 6).(++$i ? '_'.$i : ''); + } + while (isset(self::$codeIDs[$codeID])); + + // mark codeID as used + self::$codeIDs[$codeID] = true; + + for ($i = $start, $j = count($lines) + $start; $i < $j; $i++) { + $lineNumbers[$i] = 'codeLine_'.$i.'_'.$codeID; + } + return $lineNumbers; + } + + /** + * Fixes markup that every line has proper number of opening and closing tags + * + * @param string[] $lines + * @return string[] + */ + protected function fixMarkup(array $lines) { + static $spanRegex = null; + static $emptyTagRegex = null; + if ($spanRegex === null) { + $spanRegex = new Regex('(?:|)'); + $emptyTagRegex = new Regex(''); + } + + $openTags = []; + foreach ($lines as &$line) { + $spanRegex->match($line, true); + // open all tags again + $line = implode('', $openTags).$line; + $matches = $spanRegex->getMatches(); + + // parse opening and closing spans + foreach ($matches[0] as $match) { + if ($match === '') array_pop($openTags); + else { + array_push($openTags, $match); + } + } + + // close all tags + $line .= str_repeat('', count($openTags)); + + // remove empty tags to avoid cluttering the output + $line = $emptyTagRegex->replace($line, ''); + } + unset($line); + + return $lines; + } +} diff --git a/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeProcessor.class.php b/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeProcessor.class.php index 26139e9123..8648ffdac5 100644 --- a/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeProcessor.class.php +++ b/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeProcessor.class.php @@ -15,5 +15,7 @@ class HtmlOutputNodeProcessor extends HtmlNodeProcessor { $this->invokeHtmlNode(new HtmlOutputNodeWoltlabMention()); $this->invokeHtmlNode(new HtmlOutputNodeWoltlabColor()); $this->invokeHtmlNode(new HtmlOutputNodeWoltlabSize()); + $this->invokeHtmlNode(new HtmlOutputNodeWoltlabSpoiler()); + $this->invokeHtmlNode(new HtmlOutputNodePre()); } } diff --git a/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeWoltlabSpoiler.class.php b/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeWoltlabSpoiler.class.php new file mode 100644 index 0000000000..921099da7e --- /dev/null +++ b/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeWoltlabSpoiler.class.php @@ -0,0 +1,38 @@ +addNodeData($this, $nodeIdentifier, [ + 'label' => ($element->hasAttribute('data-label')) ? $element->getAttribute('data-label') : '' + ]); + + $htmlNodeProcessor->renameTag($element, 'wcfNode-' . $nodeIdentifier); + } + } + + public function replaceTag(array $data) { + WCF::getTPL()->assign([ + 'buttonLabel' => $data['label'] + ]); + return WCF::getTPL()->fetch('spoilerMetaCode'); + } +} diff --git a/wcfsetup/install/files/style/bbcode/code.scss b/wcfsetup/install/files/style/bbcode/code.scss index 8672a96a4f..1660df226c 100644 --- a/wcfsetup/install/files/style/bbcode/code.scss +++ b/wcfsetup/install/files/style/bbcode/code.scss @@ -19,3 +19,131 @@ @include wcfFontHeadline; } } + +.codeBox { + background-color: $wcfContentBackground; + box-shadow: 0 0 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24); + border-radius: 2px; + margin-top: 1em; + padding: 10px; + + > div { + > ol { + margin-left: 3.4em !important; + position: relative; + + &::before { + border-right: 1px solid $wcfContentBorderInner; + bottom: 0; + content: ""; + position: absolute; + top: 0; + } + + > li { + padding-left: 5px; + } + } + } +} + +/* ############## Code Styles ############## */ + +/* -- -- -- Code Box -- -- -- */ + +.codeBox .hlQuotes { + color: red; +} + +.codeBox .hlComments, +.codeBox .hlOperators { + color: green; +} + +.codeBox .hlKeywords1 { + color: blue; +} + +.codeBox .hlKeywords2 { + color: darkred; +} + +.codeBox .hlKeywords3 { + color: darkviolet; +} + +.codeBox .hlKeywords4 { + color: darkgoldenrod; +} + +.codeBox .hlKeywords5 { + color: crimson; +} + +.codeBox .hlNumbers { + color: darkorange; +} + +/* -- -- -- Code Highlighters -- -- -- */ + +/* DIFF */ + +.diffHighlighter .hlComments { + color: darkviolet; +} + +.diffHighlighter .hlRemoved { + color: red; +} + +.diffHighlighter .hlAdded { + color: green; +} + +/* PHP */ + +.phpHighlighter .hlKeywords2 { + color: green; +} + +.phpHighlighter .hlComments { + color: darkgoldenrod; +} + +/* CSS */ + +.cssHighlighter .hlComments { + color: #236e26; +} + +.cssHighlighter .hlColors { + color: #751116; +} + +.cssHighlighter .hlNumbers, +.sqlHighlighter .hlNumbers { + color: #1906fd; +} + +.cssHighlighter .hlKeywords1 { + color: #87154f; +} + +.cssHighlighter .hlKeywords2 { + color: #994509; +} + +.cssHighlighter .hlKeywords3, +.cssHighlighter .hlKeywords4 { + color: inherit; +} + +/* SQL */ + +.sqlHighlighter .hlKeywords1 { + color: #663821; +} + +.sqlHighlighter .hlKeywords2 { + color: #871550; +} diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 4c24774321..fb95574c9c 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -1777,7 +1777,6 @@ Erlaubte Dateiendungen: {', '|implode:$attachmentHandler->getFormattedAllowedExt - diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 17d585e483..c4ad3104af 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -1784,7 +1784,6 @@ Allowed extensions: {', '|implode:$attachmentHandler->getFormattedAllowedExtensi -