<isBlockElement>1</isBlockElement>
</bbcode>
<bbcode name="quote">
- <classname>wcf\system\bbcode\QuoteBBCode</classname>
<attributes>
<attribute name="0"></attribute>
<attribute name="1"></attribute>
<isBlockElement>1</isBlockElement>
</bbcode>
<bbcode name="code">
- <classname>wcf\system\bbcode\CodeBBCode</classname>
<attributes>
<attribute name="0"></attribute>
<attribute name="1"></attribute>
<isBlockElement>1</isBlockElement>
</bbcode>
<bbcode name="img">
- <classname>wcf\system\bbcode\ImageBBCode</classname>
<attributes>
<attribute name="0">
<required>1</required>
</attributes>
</bbcode>
<bbcode name="url">
- <classname>wcf\system\bbcode\URLBBCode</classname>
<attributes>
<attribute name="0">
<required>1</required>
</attributes>
</bbcode>
<bbcode name="list">
- <classname>wcf\system\bbcode\ListBBCode</classname>
<attributes>
<attribute name="0">
<validationpattern>^(1|a|none|circle|square|disc|decimal|lower-roman|upper-roman|decimal-leading-zero|lower-greek|lower-latin|upper-latin|armenian|georgian)$</validationpattern>
</bbcode>
<bbcode name="table">
- <classname>wcf\system\bbcode\TableBBCode</classname>
<isBlockElement>1</isBlockElement>
</bbcode>
<bbcode name="tr">
<sourcecode>1</sourcecode>
</bbcode>
<bbcode name="spoiler">
- <classname>wcf\system\bbcode\SpoilerBBCode</classname>
<attributes>
<attribute name="0"></attribute>
</attributes>
+++ /dev/null
-<!-- begin:parser_nonessential -->
-<div class="spoilerBox jsSpoilerBox">
- <div class="jsOnly spoilerBoxHeader">
- <a class="button small jsSpoilerToggle"{if $buttonTitle} data-has-custom-label="true"{/if}>{if $buttonTitle}{@$buttonTitle}{else}{lang}wcf.bbcode.spoiler.show{/lang}{/if}</a>
- </div>
-
- <div class="spoilerBoxContent" style="display: none">
- {@$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();
-
- 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 -->
+++ /dev/null
-<?php
-namespace wcf\system\bbcode;
-use wcf\system\bbcode\highlighter\BashHighlighter;
-use wcf\system\bbcode\highlighter\CHighlighter;
-use wcf\system\bbcode\highlighter\DiffHighlighter;
-use wcf\system\bbcode\highlighter\HtmlHighlighter;
-use wcf\system\bbcode\highlighter\JavaHighlighter;
-use wcf\system\bbcode\highlighter\JsHighlighter;
-use wcf\system\bbcode\highlighter\PerlHighlighter;
-use wcf\system\bbcode\highlighter\PhpHighlighter;
-use wcf\system\bbcode\highlighter\PlainHighlighter;
-use wcf\system\bbcode\highlighter\PythonHighlighter;
-use wcf\system\bbcode\highlighter\SqlHighlighter;
-use wcf\system\bbcode\highlighter\TexHighlighter;
-use wcf\system\bbcode\highlighter\XmlHighlighter;
-use wcf\system\Regex;
-use wcf\system\WCF;
-use wcf\util\StringUtil;
-
-/**
- * Parses the [code] bbcode tag.
- *
- * @author Tim Duesterhus, Marcel Werk
- * @copyright 2001-2016 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Bbcode
- */
-class CodeBBCode extends AbstractBBCode {
- /**
- * code type attribute value
- * @var string
- */
- protected $codeType = '';
-
- /**
- * file name attribute value
- * @var string
- */
- protected $filename = '';
-
- /**
- * start line number attribute value
- * @var string
- */
- protected $startLineNumber = 1;
-
- /**
- * already used ids for line numbers to prevent duplicate ids in the output
- * @var string[]
- */
- private static $codeIDs = [];
-
- /**
- * @inheritDoc
- */
- public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser) {
- // encode html
- $content = self::trim($content);
-
- // get attributes
- $this->mapAttributes($openingTag);
-
- // 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 ($this->codeType) {
- $className = '\wcf\system\bbcode\highlighter\\'.StringUtil::firstCharToUpperCase(mb_strtolower($this->codeType)).'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, '<?php') !== false) {
- $className = PhpHighlighter::class;
- }
- else if (mb_strpos($content, '<html') !== false) {
- $className = HtmlHighlighter::class;
- }
- else if (mb_strpos($content, '<?xml') === 0) {
- $className = XmlHighlighter::class;
- }
- else if ( mb_strpos($content, 'SELECT') === 0
- || mb_strpos($content, 'UPDATE') === 0
- || mb_strpos($content, 'INSERT') === 0
- || mb_strpos($content, 'DELETE') === 0) {
- $className = SqlHighlighter::class;
- }
- else if (mb_strpos($content, 'import java.') !== false) {
- $className = JavaHighlighter::class;
- }
- else if ( mb_strpos($content, "---") !== false
- && mb_strpos($content, "\n+++") !== false) {
- $className = DiffHighlighter::class;
- }
- else if (mb_strpos($content, "\n#include ") !== false) {
- $className = CHighlighter::class;
- }
- else if (mb_strpos($content, '#!/usr/bin/perl') === 0) {
- $className = PerlHighlighter::class;
- }
- else if (mb_strpos($content, 'def __init__(self') !== false) {
- $className = PythonHighlighter::class;
- }
- else if (Regex::compile('^#!/bin/(ba|z)?sh')->match($content)) {
- $className = BashHighlighter::class;
- }
- else if (mb_strpos($content, '\\documentclass') !== false) {
- $className = TexHighlighter::class;
- }
- }
- }
-
- if (!class_exists($className)) {
- $className = PlainHighlighter::class;
- }
-
- if ($parser->getOutputType() == 'text/html') {
- /** @noinspection PhpUndefinedMethodInspection */
- $highlightedContent = self::fixMarkup(explode("\n", $className::getInstance()->highlight($content)));
-
- // show template
- /** @noinspection PhpUndefinedMethodInspection */
- WCF::getTPL()->assign([
- 'lineNumbers' => self::makeLineNumbers($content, $this->startLineNumber),
- 'startLineNumber' => $this->startLineNumber,
- 'content' => $highlightedContent,
- 'highlighter' => $className::getInstance(),
- 'filename' => $this->filename,
- 'lines' => substr_count($content, "\n") + 1
- ]);
- return WCF::getTPL()->fetch('codeBBCodeTag');
- }
- else if ($parser->getOutputType() == 'text/simplified-html') {
- /** @noinspection PhpUndefinedMethodInspection */
- return WCF::getLanguage()->getDynamicVariable('wcf.bbcode.code.text', [
- 'highlighterTitle' => $className::getInstance()->getTitle(),
- 'lines' => substr_count($content, "\n") + 1
- ]);
- }
- }
-
- /**
- * Maps the arguments to the property they represent.
- *
- * @param array $openingTag
- */
- protected function mapAttributes(array $openingTag) {
- // reset default values
- $this->codeType = '';
- $this->startLineNumber = 1;
- $this->filename = '';
-
- if (!isset($openingTag['attributes'])) {
- return;
- }
-
- $attributes = $openingTag['attributes'];
- switch (count($attributes)) {
- case 1:
- if (is_numeric($attributes[0])) {
- $this->startLineNumber = intval($attributes[0]);
- }
- else if (mb_strpos($attributes[0], '.') === false) {
- $this->codeType = $attributes[0];
- }
- else {
- $this->filename = $attributes[0];
- }
- break;
-
- case 2:
- if (is_numeric($attributes[0])) {
- $this->startLineNumber = intval($attributes[0]);
- if (mb_strpos($attributes[1], '.') === false) {
- $this->codeType = $attributes[1];
- }
- else {
- $this->filename = $attributes[1];
- }
- }
- else {
- $this->codeType = $attributes[0];
- $this->filename = $attributes[1];
- }
- break;
-
- default:
- $this->codeType = $attributes[0];
- $this->startLineNumber = intval($attributes[1]);
- $this->filename = $attributes[2];
- break;
- }
-
- // correct illegal line number
- if ($this->startLineNumber < 1) {
- $this->startLineNumber = 1;
- }
- }
-
- /**
- * Returns a string with all line numbers
- *
- * @param string $code
- * @param integer $start
- * @param string $split
- * @return string
- */
- protected static 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;
- }
-
- /**
- * Removes empty lines from the beginning and end of a string.
- *
- * @param string $string
- * @return string
- */
- protected static function trim($string) {
- $string = preg_replace('/^\s*\n/', '', $string);
- $string = preg_replace('/\n\s*$/', '', $string);
- return $string;
- }
-
- /**
- * Fixes markup that every line has proper number of opening and closing tags
- *
- * @param string[] $lines
- * @return string[]
- */
- public static function fixMarkup(array $lines) {
- static $spanRegex = null;
- static $emptyTagRegex = null;
- if ($spanRegex === null) {
- $spanRegex = new Regex('(?:<span(?: class="(?:[^"])*")?>|</span>)');
- $emptyTagRegex = new Regex('<span(?: class="(?:[^"])*")?></span>');
- }
-
- $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 === '</span>') array_pop($openTags);
- else {
- array_push($openTags, $match);
- }
- }
-
- // close all tags
- $line .= str_repeat('</span>', count($openTags));
-
- // remove empty tags to avoid cluttering the output
- $line = $emptyTagRegex->replace($line, '');
- }
- unset($line);
- return $lines;
- }
-}
+++ /dev/null
-<?php
-namespace wcf\system\bbcode;
-use wcf\system\request\LinkHandler;
-use wcf\util\exception\CryptoException;
-use wcf\util\CryptoUtil;
-use wcf\util\StringUtil;
-
-/**
- * Parses the [img] bbcode tag.
- *
- * @author Marcel Werk
- * @copyright 2001-2016 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Bbcode
- */
-class ImageBBCode extends AbstractBBCode {
- /**
- * @inheritDoc
- */
- public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser) {
- $src = '';
- if (isset($openingTag['attributes'][0])) {
- $src = $openingTag['attributes'][0];
- }
-
- if ($parser->getOutputType() == 'text/html') {
- $dataSource = '';
- if (MODULE_IMAGE_PROXY) {
- $dataSource = $src;
- $src = $this->getProxyLink($src);
- }
-
- $float = '';
- if (isset($openingTag['attributes'][1])) {
- $float = $openingTag['attributes'][1];
- }
-
- $style = '';
- if ($float == 'left' || $float == 'right') {
- $style = 'float: ' . $float . '; margin: ' . ($float == 'left' ? '0 15px 7px 0' : '0 0 7px 15px') . ';';
- }
-
- if (isset($openingTag['attributes'][2])) {
- $style .= 'width: ' . $openingTag['attributes'][2] . 'px;';
- }
-
- return '<img src="'.$src.'" class="jsResizeImage" alt=""'.($style ? ' style="' . $style . '"' : '').($dataSource ? ' data-source="'.StringUtil::encodeJS($dataSource).'"' : '').'>';
- }
- else if ($parser->getOutputType() == 'text/simplified-html') {
- $src = StringUtil::decodeHTML($src);
- $path = parse_url($src, PHP_URL_PATH);
- if ($path !== false) {
- return StringUtil::encodeHTML(basename($path));
- }
-
- return '';
- }
- }
-
- /**
- * Returns the link to fetch the image using the image proxy.
- *
- * @param string $link
- * @return string
- * @since 3.0
- */
- protected function getProxyLink($link) {
- try {
- $key = CryptoUtil::createSignedString($link);
-
- return LinkHandler::getInstance()->getLink('ImageProxy', [
- 'key' => $key
- ]);
- }
- catch (CryptoException $e) {
- return $link;
- }
- }
-}
+++ /dev/null
-<?php
-namespace wcf\system\bbcode;
-use wcf\util\StringUtil;
-
-/**
- * Parses the [list] bbcode tag.
- *
- * @author Marcel Werk
- * @copyright 2001-2016 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Bbcode
- */
-class ListBBCode extends AbstractBBCode {
- /**
- * @inheritDoc
- */
- public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser) {
- if (mb_strpos($content, '[*]') !== false) {
- // get list elements
- $listElements = preg_split('/\[\*\]/', StringUtil::trim($content), -1, PREG_SPLIT_NO_EMPTY);
-
- // remove empty elements
- foreach ($listElements as $key => $val) {
- $listElements[$key] = StringUtil::trim($val);
- if (empty($listElements[$key]) || $listElements[$key] == '<br />' || $listElements[$key] == '<br>') {
- unset($listElements[$key]);
- }
- }
-
- if (!empty($listElements)) {
- // get list style type
- $listType = 'disc';
- if (isset($openingTag['attributes'][0])) $listType = $openingTag['attributes'][0];
- $listType = strtolower($listType);
-
- // replace old types
- if ($listType == '1') $listType = 'decimal';
- if ($listType == 'a') $listType = 'lower-latin';
-
- if ($parser->getOutputType() == 'text/html') {
- // build list html
- $listHTML = 'ol';
- if ($listType == 'none' || $listType == 'circle' || $listType == 'square' || $listType == 'disc') {
- $listHTML = 'ul';
- }
-
- return '<'.$listHTML.' style="list-style-type: '.$listType.'" class="nativeList"><li>'.implode('</li><li>', $listElements).'</li></'.$listHTML.'>';
- }
- else if ($parser->getOutputType() == 'text/simplified-html') {
- $result = '';
-
- $i = 1;
- foreach ($listElements as $listElement) {
- switch ($listType) {
- case 'decimal':
- $result .= $i.'. ';
- break;
- default:
- $result .= '- ';
- }
-
- $result .= $listElement."\n";
- $i++;
- }
-
- return $result;
- }
- }
- }
-
- // no valid list
- // return bbcode as text
- return $openingTag['source'].$content.$closingTag['source'];
- }
-}
+++ /dev/null
-<?php
-namespace wcf\system\bbcode;
-use wcf\system\application\ApplicationHandler;
-use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
-use wcf\system\request\RouteHandler;
-use wcf\system\WCF;
-use wcf\util\StringUtil;
-
-/**
- * Parses the [quote] bbcode tag.
- *
- * @author Marcel Werk
- * @copyright 2001-2016 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Bbcode
- */
-class QuoteBBCode extends AbstractBBCode {
- /**
- * @inheritDoc
- */
- public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser) {
- if ($parser->getOutputType() == 'text/html') {
- $quoteLink = (!empty($openingTag['attributes'][1]) ? $openingTag['attributes'][1] : '');
- $externalQuoteLink = (!empty($openingTag['attributes'][1]) ? !ApplicationHandler::getInstance()->isInternalURL($openingTag['attributes'][1]) : false);
- if (!$externalQuoteLink) {
- $quoteLink = preg_replace('~^https?://~', RouteHandler::getProtocol(), $quoteLink);
- }
- $quoteAuthor = (!empty($openingTag['attributes'][0]) ? $openingTag['attributes'][0] : '');
- $quoteAuthorObject = null;
- if ($quoteAuthor && !$externalQuoteLink) {
- $quoteAuthorLC = mb_strtolower(StringUtil::decodeHTML($quoteAuthor));
- foreach (MessageEmbeddedObjectManager::getInstance()->getObjects('com.woltlab.wcf.quote') as $user) {
- if (mb_strtolower($user->username) == $quoteAuthorLC) {
- $quoteAuthorObject = $user;
- break;
- }
- }
- }
-
- WCF::getTPL()->assign([
- 'content' => $content,
- 'quoteLink' => $quoteLink,
- 'quoteAuthor' => $quoteAuthor,
- 'quoteAuthorObject' => $quoteAuthorObject,
- 'isExternalQuoteLink' => $externalQuoteLink
- ]);
- return WCF::getTPL()->fetch('quoteBBCodeTag');
- }
- else if ($parser->getOutputType() == 'text/simplified-html') {
- return WCF::getLanguage()->getDynamicVariable('wcf.bbcode.quote.text', ['content' => $content, 'cite' => !empty($openingTag['attributes'][0]) ? $openingTag['attributes'][0] : ''])."\n";
- }
- }
-}
+++ /dev/null
-<?php
-namespace wcf\system\bbcode;
-use wcf\system\WCF;
-
-/**
- * Parses the [spoiler] bbcode tag.
- *
- * @author Marcel Werk
- * @copyright 2001-2016 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Bbcode
- */
-class SpoilerBBCode extends AbstractBBCode {
- /**
- * @inheritDoc
- */
- public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser) {
- if ($parser->getOutputType() == 'text/html') {
- WCF::getTPL()->assign([
- 'content' => $content,
- 'buttonTitle' => !empty($openingTag['attributes'][0]) ? $openingTag['attributes'][0] : ''
- ]);
- return WCF::getTPL()->fetch('spoilerBBCodeTag');
- }
- if ($parser->getOutputType() == 'text/simplified-html') {
- return WCF::getLanguage()->get('wcf.bbcode.spoiler.text');
- }
- }
-}
+++ /dev/null
-<?php
-namespace wcf\system\bbcode;
-
-/**
- * Parses the [table] bbcode tag.
- *
- * @author Alexander Ebert
- * @copyright 2001-2016 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Bbcode
- */
-class TableBBCode extends AbstractBBCode {
- /**
- * @inheritDoc
- */
- public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser) {
- // fake output
- return '[table]' . $content . '[/table]';
- }
-}
+++ /dev/null
-<?php
-namespace wcf\system\bbcode;
-use wcf\util\StringUtil;
-
-/**
- * Parses the [url] bbcode tag.
- *
- * @author Marcel Werk
- * @copyright 2001-2016 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Bbcode
- */
-class URLBBCode extends AbstractBBCode {
- /**
- * @inheritDoc
- */
- public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser) {
- $url = '';
- if (isset($openingTag['attributes'][0])) {
- $url = $openingTag['attributes'][0];
- }
-
- $noTitle = ($content == $url);
- $url = StringUtil::decodeHTML($url);
-
- // add protocol if necessary
- if (!preg_match("/[a-z]:\/\//si", $url)) $url = 'http://'.$url;
-
- return StringUtil::getAnchorTag($url, (!$noTitle ? $content : ''), false);
- }
-}