Cleanup and added missing documentation
authorAlexander Ebert <ebert@woltlab.com>
Fri, 24 Jun 2016 13:32:54 +0000 (15:32 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Fri, 24 Jun 2016 13:33:08 +0000 (15:33 +0200)
32 files changed:
wcfsetup/install/files/lib/system/html/input/HtmlInputProcessor.class.php
wcfsetup/install/files/lib/system/html/input/filter/IHtmlInputFilter.class.php
wcfsetup/install/files/lib/system/html/input/filter/MessageHtmlInputFilter.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeImg.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeProcessor.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeTextParser.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeWoltlabMention.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeWoltlabMetacode.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeWoltlabMetacodeMarker.class.php
wcfsetup/install/files/lib/system/html/input/node/IHtmlInputNode.class.php
wcfsetup/install/files/lib/system/html/input/node/IHtmlInputNodeProcessor.class.php [deleted file]
wcfsetup/install/files/lib/system/html/metacode/converter/AbstractMetacodeConverter.class.php
wcfsetup/install/files/lib/system/html/metacode/converter/CodeMetacodeConverter.class.php
wcfsetup/install/files/lib/system/html/metacode/converter/ColorMetacodeConverter.class.php
wcfsetup/install/files/lib/system/html/metacode/converter/IMetacodeConverter.class.php
wcfsetup/install/files/lib/system/html/metacode/converter/QuoteMetacodeConverter.class.php
wcfsetup/install/files/lib/system/html/metacode/converter/SizeMetacodeConverter.class.php
wcfsetup/install/files/lib/system/html/metacode/converter/SpoilerMetacodeConverter.class.php
wcfsetup/install/files/lib/system/html/node/AbstractHtmlNode.class.php
wcfsetup/install/files/lib/system/html/node/AbstractHtmlNodeProcessor.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/html/node/HtmlNodeProcessor.class.php [deleted file]
wcfsetup/install/files/lib/system/html/node/IHtmlNode.class.php
wcfsetup/install/files/lib/system/html/node/IHtmlNodeProcessor.class.php
wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeBlockquote.class.php
wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodePre.class.php
wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeProcessor.class.php
wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeWoltlabColor.class.php
wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeWoltlabMention.class.php
wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeWoltlabMetacode.class.php
wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeWoltlabSize.class.php
wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeWoltlabSpoiler.class.php
wcfsetup/install/files/lib/system/html/output/node/IHtmlOutputNode.class.php

index 433f0a0b87ca1619d46d3e246a75e9489ad792a7..0a2ba2e48fb615fab0319295e72d55950b9f5c25 100644 (file)
@@ -5,14 +5,22 @@ 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;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Reads a HTML string, applies filters and parses all nodes including bbcodes.
+ * 
+ * @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\Html\Input
+ * @since       3.0
  */
 class HtmlInputProcessor {
+       /**
+        * list of embedded content grouped by type
+        * @var array
+        */
        protected $embeddedContent = [];
        
        /**
@@ -25,6 +33,12 @@ class HtmlInputProcessor {
         */
        protected $htmlInputNodeProcessor;
        
+       /**
+        * Processes input HTML by applying filters and parsing all nodes
+        * including bbcodes.
+        * 
+        * @param       string          $html           html string
+        */
        public function process($html) {
                // enforce consistent newlines
                $html = StringUtil::unifyNewlines($html);
@@ -45,14 +59,28 @@ class HtmlInputProcessor {
                // TODO
        }
        
+       /**
+        * Returns the parsed HTML ready to store.
+        * 
+        * @return      string  parsed html
+        */
        public function getHtml() {
                return $this->getHtmlInputNodeProcessor()->getHtml();
        }
        
+       /**
+        * Returns the all embedded content data.
+        *
+        * @return array
+        */
+       public function getEmbeddedContent() {
+               return $this->embeddedContent;
+       }
+       
        /**
         * @return      IHtmlInputFilter
         */
-       public function getHtmlInputFilter() {
+       protected function getHtmlInputFilter() {
                if ($this->htmlInputFilter === null) {
                        $this->htmlInputFilter = new MessageHtmlInputFilter();
                }
@@ -60,26 +88,14 @@ class HtmlInputProcessor {
                return $this->htmlInputFilter;
        }
        
-       public function setHtmlInputFilter(IHtmlInputFilter $htmlInputFilter) {
-               $this->htmlInputFilter = $htmlInputFilter;
-       }
-       
        /**
         * @return IHtmlInputNodeProcessor
         */
-       public function getHtmlInputNodeProcessor() {
+       protected function getHtmlInputNodeProcessor() {
                if ($this->htmlInputNodeProcessor === null) {
                        $this->htmlInputNodeProcessor = new HtmlInputNodeProcessor();
                }
                
                return $this->htmlInputNodeProcessor;
        }
-       
-       public function setHtmlInputNodeProcessor(IHtmlNodeProcessor $htmlInputNodeProcessor) {
-               $this->htmlInputNodeProcessor = $htmlInputNodeProcessor;
-       }
-       
-       public function getEmbeddedContent() {
-               return $this->embeddedContent;
-       }
 }
index 6cf21c496663d39c119e5afd01df3f3a9f5ff24a..461dcc5b894964bba054905f24a720e84b61e8ea 100644 (file)
@@ -2,8 +2,13 @@
 namespace wcf\system\html\input\filter;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Default interface for html input filters.
+ * 
+ * @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\Html\Input\Filter
+ * @since       3.0
  */
 interface IHtmlInputFilter {
        /**
index 4b7596e4d01bbdd3a37df3cb8d7b4597f3b3ce43..35adbfe6fb0980248205f539fdaa3809978dcd13 100644 (file)
@@ -1,9 +1,15 @@
 <?php
 namespace wcf\system\html\input\filter;
+use wcf\system\event\EventHandler;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * HTML input filter using HTMLPurifier.
+ * 
+ * @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\Html\Input\Filter
+ * @since       3.0
  */
 class MessageHtmlInputFilter implements IHtmlInputFilter {
        /**
@@ -11,6 +17,12 @@ class MessageHtmlInputFilter implements IHtmlInputFilter {
         */
        protected static $purifier;
        
+       /**
+        * Applies HTMLPurifier's filter on provided HTML.
+        * 
+        * @param       string  $html   unsafe HTML
+        * @return      string  sanitized HTML
+        */
        public function apply($html) {
                return $this->getPurifier()->purify($html);
        }
@@ -28,8 +40,12 @@ class MessageHtmlInputFilter implements IHtmlInputFilter {
                return self::$purifier;
        }
        
+       /**
+        * Sets required configuration data for HTML filter.
+        * 
+        * @param       \HTMLPurifier_Config    $config         HTMLPurifier configuration
+        */
        protected function setAttributeDefinitions(\HTMLPurifier_Config $config) {
-               // TODO: move this into own PHP classes
                $definition = $config->getHTMLDefinition(true);
                
                // quotes
@@ -73,5 +89,11 @@ class MessageHtmlInputFilter implements IHtmlInputFilter {
                
                // add data-attachment-id="" for <img>
                $definition->addAttribute('img', 'data-attachment-id', 'Number');
+               
+               $parameters = [
+                       'config' => $config,
+                       'definition' => $definition
+               ];
+               EventHandler::getInstance()->fireAction($this, 'setAttributeDefinitions', $parameters);
        }
 }
index 49d9bf1ebe0dd516ee398bca4440a7b9632c068b..12e9b64c0f3ce44b9ae74391d0e239abf6ccfc37 100644 (file)
@@ -1,22 +1,33 @@
 <?php
 namespace wcf\system\html\input\node;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\util\DOMUtil;
 use wcf\util\JSON;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Proccesses `<img>` to handle embedded attachments.
+ * 
+ * @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\Html\Input\Node
+ * @since       3.0
  */
 class HtmlInputNodeImg extends AbstractHtmlNode {
+       /**
+        * @inheritDoc
+        */
        protected $tagName = 'img';
        
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       /**
+        * @inheritDoc
+        */
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
                /** @var \DOMElement $element */
                foreach ($elements as $element) {
                        $class = $element->getAttribute('class');
-                       if ($class !== 'woltlabAttachment') {
+                       if (!preg_match('~\bwoltlabAttachment\b~', $class)) {
                                continue;
                        }
                        
@@ -25,17 +36,20 @@ class HtmlInputNodeImg extends AbstractHtmlNode {
                                continue;
                        }
                        
-                       // TODO: add alignment detection
-                       $alignment = 'none';
+                       $float = 'none';
                        $thumbnail = false;
                        
                        if (strpos($element->getAttribute('src'), 'thumbnail=1') !== false) {
                                $thumbnail = true;
                        }
                        
+                       if (preg_match('~\bmessageFloatObject(?P<float>Left|Right)\b~', $class, $matches)) {
+                               $float = ($matches['float'] === 'Left') ? 'left' : 'right';
+                       }
+                       
                        $attributes = [
                                $attachmentID,
-                               $alignment,
+                               $float,
                                $thumbnail
                        ];
                        
index e88dc7e6336069ac514895c850c877bde9eb4a3d..0d2c8e5e96ded0b7729beadddb5e9ddddabdb911 100644 (file)
@@ -1,22 +1,27 @@
 <?php
 namespace wcf\system\html\input\node;
 use wcf\system\event\EventHandler;
-use wcf\system\html\node\HtmlNodeProcessor;
-use wcf\util\DOMUtil;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Processes HTML nodes and handles bbcodes.
+ * 
+ * @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\Html\Input\Node
+ * @since       3.0
  */
-class HtmlInputNodeProcessor extends HtmlNodeProcessor implements IHtmlInputNodeProcessor {
+class HtmlInputNodeProcessor extends AbstractHtmlNodeProcessor {
+       /**
+        * list of embedded content grouped by type
+        * @var array
+        */
        protected $embeddedContent = [];
        
-       // TODO: this should include other tags
-       protected $emptyTags = ['em', 'strong', 'u'];
-       
-       // TODO: this should include other tags
-       protected $mergeTags = ['em', 'strong', 'u'];
-       
+       /**
+        * @inheritDoc
+        */
        public function process() {
                EventHandler::getInstance()->fireAction($this, 'beforeProcess');
                
@@ -29,6 +34,9 @@ class HtmlInputNodeProcessor extends HtmlNodeProcessor implements IHtmlInputNode
                $this->invokeHtmlNode(new HtmlInputNodeWoltlabMetacode());
                $this->invokeHtmlNode(new HtmlInputNodeImg());
                
+               // dynamic node handlers
+               $this->invokeNodeHandlers('wcf\system\html\input\node\HtmlInputNode', ['img', 'woltlab-metacode']);
+               
                // detect mentions, urls, emails and smileys
                $textParser = new HtmlInputNodeTextParser($this);
                $textParser->parse();
@@ -36,19 +44,24 @@ class HtmlInputNodeProcessor extends HtmlNodeProcessor implements IHtmlInputNode
                // extract embedded content
                $this->parseEmbeddedContent();
                
-               // remove empty elements and join identical siblings if appropriate
-               $this->cleanup();
-               
                EventHandler::getInstance()->fireAction($this, 'afterProcess');
        }
        
        /**
-        * @inheritDoc
+        * Returns the embedded content grouped by type.
+        * 
+        * @return      array
         */
        public function getEmbeddedContent() {
                return $this->embeddedContent;
        }
        
+       /**
+        * Add embedded content for provided type.
+        * 
+        * @param       string  $type   type name
+        * @param       array   $data   embedded content
+        */
        public function addEmbeddedContent($type, array $data) {
                if (isset($this->embeddedContent[$type])) {
                        $this->embeddedContent[$type] = array_merge($this->embeddedContent[$type], $data);
@@ -58,6 +71,9 @@ class HtmlInputNodeProcessor extends HtmlNodeProcessor implements IHtmlInputNode
                }
        }
        
+       /**
+        * Parses embedded content containedin metacode elements.
+        */
        protected function parseEmbeddedContent() {
                // handle `woltlab-metacode`
                $elements = $this->getDocument()->getElementsByTagName('woltlab-metacode');
@@ -77,47 +93,6 @@ class HtmlInputNodeProcessor extends HtmlNodeProcessor implements IHtmlInputNode
                EventHandler::getInstance()->fireAction($this, 'parseEmbeddedContent');
        }
        
-       protected function cleanup() {
-               // remove emtpy elements
-               foreach ($this->emptyTags as $emptyTag) {
-                       $elements = [];
-                       foreach ($this->getDocument()->getElementsByTagName($emptyTag) as $element) {
-                               $elements[] = $element;
-                       }
-                       
-                       /** @var \DOMElement $element */
-                       foreach ($elements as $element) {
-                               if (DOMUtil::isEmpty($element)) {
-                                       DOMUtil::removeNode($element);
-                               }
-                       }
-               }
-               
-               // find identical siblings
-               foreach ($this->mergeTags as $mergeTag) {
-                       $elements = [];
-                       foreach ($this->getDocument()->getElementsByTagName($mergeTag) as $element) {
-                               $elements[] = $element;
-                       }
-                       
-                       /** @var \DOMElement $element */
-                       foreach ($elements as $element) {
-                               $sibling = $element->nextSibling;
-                               if ($sibling === null) {
-                                       continue;
-                               }
-                               
-                               if ($sibling->nodeName === $mergeTag) {
-                                       while ($sibling->hasChildNodes()) {
-                                               $element->appendChild($sibling->childNodes[0]);
-                                       }
-                                       
-                                       DOMUtil::removeNode($sibling);
-                               }
-                       }
-               }
-       }
-       
        /**
         * Creates a new `<woltlab-metacode>` element contained in the same document
         * as the provided `$node`.
index 1488adcb6b6c2cdaa9915f37fe16235d5c3efba8..ebdf26e86801b34e105c5c5617a597977a5ac73b 100644 (file)
@@ -9,10 +9,19 @@ use wcf\system\WCF;
 use wcf\util\StringUtil;
 
 /**
- * TOOD documentation
+ * Parses all text nodes searching for links, media, mentions or smilies.
+ * 
+ * @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\Html\Input\Node
  * @since      3.0
  */
 class HtmlInputNodeTextParser {
+       /**
+        * list of markers per element that will face a replacement
+        * @var \DOMElement[][]
+        */
        protected $elementStack = [];
        
        /**
@@ -20,8 +29,16 @@ class HtmlInputNodeTextParser {
         */
        protected $htmlInputNodeProcessor;
        
+       /**
+        * list of text nodes that will face a replacement
+        * @var \DOMText[]
+        */
        protected $nodeStack = [];
        
+       /**
+        * list of smilies by smiley code
+        * @var string[]
+        */
        protected $smilies = [];
        
        /**
@@ -35,6 +52,10 @@ class HtmlInputNodeTextParser {
         */
        protected static $illegalChars = '[^\x0-\x2C\x2E\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+';
        
+       /**
+        * regex for user mentions
+        * @var string
+        */
        protected static $userRegex = "~
                \\B                                             # any non-word character, whitespace, string start is fine
                @
@@ -47,6 +68,11 @@ class HtmlInputNodeTextParser {
                )
        ~x";
        
+       /**
+        * HtmlInputNodeTextParser constructor.
+        * 
+        * @param HtmlInputNodeProcessor $htmlInputNodeProcessor
+        */
        public function __construct(HtmlInputNodeProcessor $htmlInputNodeProcessor) {
                $this->htmlInputNodeProcessor = $htmlInputNodeProcessor;
                $this->sourceBBCodes = HtmlBBCodeParser::getInstance()->getSourceBBCodes();
@@ -83,6 +109,9 @@ class HtmlInputNodeTextParser {
                }
        }
        
+       /**
+        * Parses all text nodes searching for possible replacements.
+        */
        public function parse() {
                // get all text nodes
                $nodes = [];
@@ -114,7 +143,7 @@ class HtmlInputNodeTextParser {
                
                $users = [];
                if (!empty($usernames)) {
-                       $users = $this->findUsernames($usernames);
+                       $users = $this->lookupUsernames($usernames);
                }
                
                for ($i = 0, $length = count($nodes); $i < $length; $i++) {
@@ -141,6 +170,13 @@ class HtmlInputNodeTextParser {
                }
        }
        
+       /**
+        * Detects mentions in text nodes.
+        * 
+        * @param       \DOMText        $text           text node
+        * @param       string          $value          node value
+        * @param       string[]        $usernames      list of already found usernames
+        */
        protected function detectMention(\DOMText $text, $value, array &$usernames) {
                if (mb_strpos($value, '@') === false) {
                        return;
@@ -159,7 +195,13 @@ class HtmlInputNodeTextParser {
                }
        }
        
-       protected function findUsernames(array $usernames) {
+       /**
+        * Matches the found usernames agains the user table.
+        * 
+        * @param       string[]        $usernames      list of found usernames
+        * @return      string[]        list of valid usernames
+        */
+       protected function lookupUsernames(array $usernames) {
                $exactValues = [];
                $likeValues = [];
                foreach ($usernames as $username) {
@@ -214,6 +256,14 @@ class HtmlInputNodeTextParser {
                return $users;
        }
        
+       /**
+        * Parses text nodes and searches for mentions.
+        * 
+        * @param       \DOMText        $text           text node
+        * @param       string          $value          node value
+        * @param       string[]        $users          list of usernames by user id
+        * @return      string          modified node value with replacement placeholders
+        */
        protected function parseMention(\DOMText $text, $value, array $users) {
                if (mb_strpos($value, '@') === false) {
                        return $value;
@@ -249,6 +299,13 @@ class HtmlInputNodeTextParser {
                return $value;
        }
        
+       /**
+        * Parses regular links and media links contained in text nodes.
+        * 
+        * @param       \DOMText        $text           text node
+        * @param       string          $value          node value
+        * @return      string          modified node value with replacement placeholders
+        */
        protected function parseURL(\DOMText $text, $value) {
                static $urlPattern = '';
                if ($urlPattern === '') {
@@ -288,6 +345,13 @@ class HtmlInputNodeTextParser {
                }, $value);
        }
        
+       /**
+        * Parses text nodes and replaces email addresses.
+        * 
+        * @param       \DOMText        $text           text node
+        * @param       string          $value          node value
+        * @return      string          modified node value with replacement placeholders
+        */
        protected function parseEmail(\DOMText $text, $value) {
                if (mb_strpos($this->text, '@') === false) {
                        return $value;
@@ -314,6 +378,13 @@ class HtmlInputNodeTextParser {
                }, $value);
        }
        
+       /**
+        * Parses text nodes and replaces smilies.
+        * 
+        * @param       \DOMText        $text           text node
+        * @param       string          $value          node value
+        * @return      string          modified node value with replacement placeholders
+        */
        protected function parseSmiley(\DOMText $text, $value) {
                static $smileyPattern = null;
                if ($smileyPattern === null) {
@@ -343,6 +414,12 @@ class HtmlInputNodeTextParser {
                }, $value);
        }
        
+       /**
+        * Replaces all found occurences of special text with their new value.
+        * 
+        * @param       \DOMText        $text           text node
+        * @param       \DOMElement[]   $elements       elements to be inserted
+        */
        protected function replaceMatches(\DOMText $text, array $elements) {
                $nodes = [$text];
                
@@ -373,12 +450,19 @@ class HtmlInputNodeTextParser {
                }
        }
        
+       /**
+        * Returns true if text node is inside a code element, suppresing any
+        * auto-detection of content.
+        * 
+        * @param       \DOMText        $text           text node
+        * @return      boolean         true if text node is inside a code element
+        */
        protected function hasCodeParent(\DOMText $text) {
                $parent = $text;
                /** @var \DOMElement $parent */
                while ($parent = $parent->parentNode) {
                        $nodeName = $parent->nodeName;
-                       if ($nodeName === 'code' || $nodeName === 'kbd') {
+                       if ($nodeName === 'code' || $nodeName === 'kbd' || $nodeName === 'pre') {
                                return true;
                        }
                        else if ($nodeName === 'woltlab-metacode' && in_array($parent->getAttribute('data-name'), $this->sourceBBCodes)) {
@@ -389,6 +473,13 @@ class HtmlInputNodeTextParser {
                return false;
        }
        
+       /**
+        * Returns true if text node is inside a link, preventing the link content
+        * being recognized as a link again.
+        * 
+        * @param       \DOMText        $text           text node
+        * @return      boolean         true if text node is inside a link
+        */
        protected function hasLinkParent(\DOMText $text) {
                $parent = $text;
                /** @var \DOMElement $parent */
@@ -402,6 +493,17 @@ class HtmlInputNodeTextParser {
                return false;
        }
        
+       /**
+        * Uses string markers to replace the matched text. This process prevents multiple
+        * detections being applied to the same target and enables us to delay replacement.
+        * 
+        * Immediately replacing matches would potentially cause a lot of DOM modifications
+        * and moving of nodes especially if there are multiple matches per text node.
+        * 
+        * @param       \DOMText        $text           text node
+        * @param       \DOMElement     $element        element queued for insertion
+        * @return      string          replacement marker
+        */
        public function addReplacement(\DOMText $text, \DOMElement $element) {
                $index = array_search($text, $this->nodeStack, true);
                if ($index === false) {
@@ -417,16 +519,22 @@ class HtmlInputNodeTextParser {
                return $marker;
        }
        
+       /**
+        * Returns a random string marker for replacement.
+        * 
+        * @return      string          random string marker
+        */
        public function getNewMarker() {
                return '@@@' . StringUtil::getUUID() . '@@@';
        }
        
        /**
-        * Returns the username for the given regular expression match.
-        *
-        * @param       string          $match
-        * @return      string
-        * @since       3.0
+        * Returns the username for the given regular expression match and takes care
+        * of any quotes outside the username and certain special characters, such as
+        * colons, that have been incorrectly matched.
+        * 
+        * @param       string          $match          matched username
+        * @return      string          sanitized username
         */
        public function getUsername($match) {
                // remove escaped single quotation mark
index 67f99aa3d2da83b321d8e6e5de3d56034588338f..253add68daab32ecb7ea89f482a03c90c3fda7a2 100644 (file)
@@ -1,16 +1,29 @@
 <?php
 namespace wcf\system\html\input\node;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Proccesses `<woltlab-mention>`.
+ * 
+ * @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\Html\Input\Node
+ * @since       3.0
  */
 class HtmlInputNodeWoltlabMention extends AbstractHtmlNode {
+       /**
+        * @inheritDoc
+        */
        protected $tagName = 'woltlab-mention';
        
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       /**
+        * @inheritDoc
+        */
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
+               // TODO
+               
                $userIds = [];
                
                /** @var \DOMElement $mention */
@@ -25,8 +38,4 @@ class HtmlInputNodeWoltlabMention extends AbstractHtmlNode {
                        
                }
        }
-       
-       public function replaceTag(array $data) {
-               return null;
-       }
 }
index 161680b29add894e9e1a2b78d23bb7295c17532a..23acfc86810b407b3c907fd665844b4ffe05fc6f 100644 (file)
@@ -2,12 +2,17 @@
 namespace wcf\system\html\input\node;
 use wcf\system\html\metacode\converter\IMetacodeConverter;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\util\DOMUtil;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Proccesses `<woltlab-metacode>` and converts them if appropriate.
+ *
+ * @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\Html\Input\Node
+ * @since       3.0
  */
 class HtmlInputNodeWoltlabMetacode extends AbstractHtmlNode {
        /**
@@ -23,9 +28,15 @@ class HtmlInputNodeWoltlabMetacode extends AbstractHtmlNode {
                'u' => 'u'
        ];
        
+       /**
+        * @inheritDoc
+        */
        protected $tagName = 'woltlab-metacode';
        
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       /**
+        * @inheritDoc
+        */
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
                /** @var IMetacodeConverter[] $converters */
                $converters = [];
                
@@ -78,11 +89,10 @@ class HtmlInputNodeWoltlabMetacode extends AbstractHtmlNode {
                }
        }
        
+       /**
+        * @inheritDoc
+        */
        public function replaceTag(array $data) {
                return $data['parsedTag'];
        }
-       
-       protected function getPlaceholderElement() {
-               return new \DOMElement('woltlab-placeholder');
-       }
 }
index 7e87f925ba49fa9d8bf56b9db000bd65c6e74b51..8a90cb92f8a9be43cd5d928f9efefe08cb408933 100644 (file)
@@ -2,7 +2,7 @@
 namespace wcf\system\html\input\node;
 use wcf\system\bbcode\HtmlBBCodeParser;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\util\DOMUtil;
 
 /**
@@ -44,7 +44,7 @@ class HtmlInputNodeWoltlabMetacodeMarker extends AbstractHtmlNode {
        /**
         * @inheritDoc
         */
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
                // collect pairs
                $pairs = $this->buildPairs($elements);
                
@@ -72,7 +72,7 @@ class HtmlInputNodeWoltlabMetacodeMarker extends AbstractHtmlNode {
                        while ($parent = $parent->parentNode) {
                                $nodeName = $parent->nodeName;
                                
-                               if ($nodeName === 'code' || $nodeName === 'kbd') {
+                               if ($nodeName === 'code' || $nodeName === 'kbd' || $nodeName === 'pre') {
                                        return true;
                                }
                                else if ($nodeName === 'woltlab-metacode') {
index 14a293deb7ac6ab43c457454b574bc07b0b14ca6..33d2a709ce85bc0acca775d4d28bf5a678dbf995 100644 (file)
@@ -3,7 +3,12 @@ namespace wcf\system\html\input\node;
 use wcf\system\html\node\IHtmlNode;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Default interface for html input nodes.
+ * 
+ * @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\Html\Input\Node
+ * @since       3.0
  */
 interface IHtmlInputNode extends IHtmlNode {}
diff --git a/wcfsetup/install/files/lib/system/html/input/node/IHtmlInputNodeProcessor.class.php b/wcfsetup/install/files/lib/system/html/input/node/IHtmlInputNodeProcessor.class.php
deleted file mode 100644 (file)
index 2c2f6aa..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-namespace wcf\system\html\input\node;
-use wcf\system\html\node\IHtmlNodeProcessor;
-
-/**
- * @since 3.0
- */
-interface IHtmlInputNodeProcessor extends IHtmlNodeProcessor {
-       public function getEmbeddedContent();
-       
-       public function process();
-}
index 979b264bc94aa5f4e4fa388b5435c399f7418549..43639b4621a08207527396d76074fb17fabc51ec 100644 (file)
@@ -2,8 +2,13 @@
 namespace wcf\system\html\metacode\converter;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Default implementation for metacode converters.
+ * 
+ * @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\Html\Metacode\Converter
+ * @since       3.0
  */
 abstract class AbstractMetacodeConverter implements IMetacodeConverter {
        /**
index 462253b64aefc8de1e6b796606bb039e68d65f1b..07e9c5060fc02ccfa6688588b94e2728cf5d59e3 100644 (file)
@@ -2,8 +2,13 @@
 namespace wcf\system\html\metacode\converter;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Converts code bbcode into `<pre>`.
+ * 
+ * @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\Html\Metacode\Converter
+ * @since       3.0
  */
 class CodeMetacodeConverter extends AbstractMetacodeConverter {
        /**
index d6d61fea9b69abff03252f38a5448b1723d6a864..1225d2b866a785f3019bfab9f83755011a551c11 100644 (file)
@@ -2,8 +2,13 @@
 namespace wcf\system\html\metacode\converter;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Converts color bbcode into `<woltlab-color>`.
+ * 
+ * @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\Html\Metacode\Converter
+ * @since       3.0
  */
 class ColorMetacodeConverter extends AbstractMetacodeConverter {
        /**
index d832f40cf682063d290e2023361e36fca7f0510e..499b47405ff3710bf390937c44917e8303dc43ea 100644 (file)
@@ -2,8 +2,13 @@
 namespace wcf\system\html\metacode\converter;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Default interface for metacode converters.
+ * 
+ * @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\Html\Metacode\Converter
+ * @since       3.0
  */
 interface IMetacodeConverter {
        /**
index 7318cc7b84cb654596c3bbfa74c1fcdacde84c36..0766b7b904942f15606ef665a1ff12531f10d6b4 100644 (file)
@@ -2,8 +2,13 @@
 namespace wcf\system\html\metacode\converter;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Converts quote bbcode into `<blockquote>`.
+ * 
+ * @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\Html\Metacode\Converter
+ * @since       3.0
  */
 class QuoteMetacodeConverter extends AbstractMetacodeConverter {
        /**
@@ -11,7 +16,6 @@ class QuoteMetacodeConverter extends AbstractMetacodeConverter {
         */
        public function convert(\DOMDocumentFragment $fragment, array $attributes) {
                $element = $fragment->ownerDocument->createElement('blockquote');
-               $element->setAttribute('class', 'quoteBox');
                $element->setAttribute('data-quote-title', (isset($attributes[0])) ? $attributes[0] : '');
                $element->setAttribute('data-quote-url', (isset($attributes[1])) ? $attributes[1] : '');
                $element->appendChild($fragment);
index a9aa98744aaf9493d20f4d2e50927e8ba40bda44..87fe4e90853dd317f29f271801e47c3fa9811c0c 100644 (file)
@@ -2,8 +2,13 @@
 namespace wcf\system\html\metacode\converter;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Converts size bbcode into `<woltlab-size>`.
+ * 
+ * @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\Html\Metacode\Converter
+ * @since       3.0
  */
 class SizeMetacodeConverter extends AbstractMetacodeConverter {
        protected $sizes = [8, 10, 12, 14, 18, 24, 36];
index 89ab85c0627897c84c02ec684aef566d5038c540..941b371d0bb004f866cad53dfd98cb5e240274ce 100644 (file)
@@ -3,8 +3,13 @@ namespace wcf\system\html\metacode\converter;
 use wcf\util\StringUtil;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Converts spoiler bbcode into `<woltlab-spoiler>`.
+ * 
+ * @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\Html\Metacode\Converter
+ * @since       3.0
  */
 class SpoilerMetacodeConverter extends AbstractMetacodeConverter {
        /**
index d2a37fbf61496ad3bd2f789fb07d60b0a0e1c157..cf8100d49da282399d66890ab0602c4710ff46b4 100644 (file)
@@ -2,18 +2,37 @@
 namespace wcf\system\html\node;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Default implementation for html nodes.
+ * 
+ * @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\Html\Node
+ * @since       3.0
  */
 abstract class AbstractHtmlNode implements IHtmlNode {
+       /**
+        * tag name used to identify elements consumed by this node
+        * @var string
+        */
        protected $tagName = '';
        
+       /**
+        * placeholder for inner content when performing direct html replacement
+        * @var string
+        */
        const PLACEHOLDER = '<!-- META_CODE_INNER_CONTENT -->';
        
+       /**
+        * @inheritDoc
+        */
        public function getTagName() {
                return $this->tagName;
        }
        
+       /**
+        * @inheritDoc
+        */
        public function replaceTag(array $data) {
                throw new \BadMethodCallException("Method replaceTag() is not supported by ".get_class($this));
        }
diff --git a/wcfsetup/install/files/lib/system/html/node/AbstractHtmlNodeProcessor.class.php b/wcfsetup/install/files/lib/system/html/node/AbstractHtmlNodeProcessor.class.php
new file mode 100644 (file)
index 0000000..fc4610f
--- /dev/null
@@ -0,0 +1,223 @@
+<?php
+namespace wcf\system\html\node;
+use wcf\system\exception\SystemException;
+use wcf\util\JSON;
+
+/**
+ * Default implementation for html node processors.
+ * 
+ * @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\Html\Node
+ * @since       3.0
+ */
+abstract class AbstractHtmlNodeProcessor implements IHtmlNodeProcessor {
+       /**
+        * active DOM document
+        * @var \DOMDocument
+        */
+       protected $document;
+       
+       /**
+        * storage for node replacements
+        * @var array
+        */
+       protected $nodeData = [];
+       
+       /**
+        * XPath instance
+        * @var \DOMXPath
+        */
+       protected $xpath;
+       
+       /**
+        * @inheritDOc
+        */
+       public function load($html) {
+               $this->document = new \DOMDocument('1.0', 'UTF-8');
+               $this->xpath = null;
+               
+               // 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.
+               // 
+               // 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('<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . $html);
+               
+               $this->nodeData = [];
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function getHtml() {
+               $html = $this->document->saveHTML($this->document->getElementsByTagName('body')->item(0));
+               
+               // remove nuisance added by PHP
+               $html = preg_replace('~^<body>~', '', $html);
+               $html = preg_replace('~</body>$~', '', $html);
+               
+               /** @var IHtmlNode $obj */
+               foreach ($this->nodeData as $data) {
+                       $obj = $data['object'];
+                       $string = $obj->replaceTag($data['data']);
+                       $html = preg_replace_callback('~<wcfNode-' . $data['identifier'] . '>(?P<content>[\s\S]*)</wcfNode-' . $data['identifier'] . '>~', function($matches) use ($string) {
+                               $string = str_replace('<!-- META_CODE_INNER_CONTENT -->', $matches['content'], $string);
+                               
+                               return $string;
+                       }, $html);
+                       
+               }
+               
+               return $html;
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function getDocument() {
+               return $this->document;
+       }
+       
+       /**
+        * Returns a XPath instance for the current DOM document.
+        * 
+        * @return      \DOMXPath       XPath instance
+        */
+       public function getXPath() {
+               if ($this->xpath === null) {
+                       $this->xpath = new \DOMXPath($this->getDocument());
+               }
+               
+               return $this->xpath;
+       }
+       
+       /**
+        * Renames a tag by creating a new element, moving all child nodes and
+        * eventually removing the original element.
+        * 
+        * @param       \DOMElement     $element        old element
+        * @param       string          $tagName        tag name for the new element
+        * @return      \DOMElement     newly created element
+        */
+       public function renameTag(\DOMElement $element, $tagName) {
+               $newElement = $this->document->createElement($tagName);
+               $element->parentNode->insertBefore($newElement, $element);
+               while ($element->hasChildNodes()) {
+                       $newElement->appendChild($element->firstChild);
+               }
+               
+               $element->parentNode->removeChild($element);
+               
+               return $newElement;
+       }
+       
+       /**
+        * Removes an element but preserves child nodes by moving them into
+        * its original position.
+        * 
+        * @param       \DOMElement     $element        element to be removed
+        */
+       public function unwrapContent(\DOMElement $element) {
+               while ($element->hasChildNodes()) {
+                       $element->parentNode->insertBefore($element->firstChild, $element);
+               }
+               
+               $element->parentNode->removeChild($element);
+       }
+       
+       /**
+        * Adds node replacement data.
+        * 
+        * @param       IHtmlNode       $htmlNode               node processor instance
+        * @param       string          $nodeIdentifier         replacement node identifier
+        * @param       array           $data                   replacement data
+        */
+       public function addNodeData(IHtmlNode $htmlNode, $nodeIdentifier, array $data) {
+               $this->nodeData[] = [
+                       'data' => $data,
+                       'identifier' => $nodeIdentifier,
+                       'object' => $htmlNode
+               ];
+       }
+       
+       /**
+        * Parses an attribute string.
+        * 
+        * @param       string          $attributes             base64 and JSON encoded attributes
+        * @return      array           parsed attributes
+        */
+       public function parseAttributes($attributes) {
+               if (empty($attributes)) {
+                       return [];
+               }
+               
+               $parsedAttributes = base64_decode($attributes, true);
+               if ($parsedAttributes !== false) {
+                       try {
+                               $parsedAttributes = JSON::decode($parsedAttributes);
+                       }
+                       catch (SystemException $e) {
+                               /* parse errors can occur if user provided malicious content - ignore them */
+                               $parsedAttributes = [];
+                       }
+               }
+               
+               return $parsedAttributes;
+       }
+       
+       /**
+        * Invokes a html node processor.
+        * 
+        * @param       IHtmlNode       $htmlNode       html node processor
+        */
+       protected function invokeHtmlNode(IHtmlNode $htmlNode) {
+               $tagName = $htmlNode->getTagName();
+               if (empty($tagName)) {
+                       throw new \UnexpectedValueException("Missing tag name for " . get_class($htmlNode));
+               }
+               
+               $elements = [];
+               foreach ($this->getDocument()->getElementsByTagName($tagName) as $element) {
+                       $elements[] = $element;
+               }
+               
+               if (!empty($elements)) {
+                       $htmlNode->process($elements, $this);
+               }
+       }
+       
+       /**
+        * Invokes possible html node processors based on found element tag names.
+        * 
+        * @param       string          $classNamePattern       full namespace pattern for class guessing
+        * @param       string[]        $skipTags               list of tag names that should be ignored
+        */
+       protected function invokeNodeHandlers($classNamePattern, array $skipTags = []) {
+               $skipTags = array_merge($skipTags, ['html', 'head', 'title', 'meta', 'body', 'link']);
+               
+               $tags = [];
+               /** @var \DOMElement $tag */
+               foreach ($this->getDocument()->getElementsByTagName('*') as $tag) {
+                       $tagName = $tag->nodeName;
+                       if (!isset($tags[$tagName])) $tags[$tagName] = $tagName;
+               }
+               
+               foreach ($tags as $tagName) {
+                       if (in_array($tagName, $skipTags)) {
+                               continue;
+                       }
+                       
+                       $tagName = preg_replace_callback('/-([a-z])/', function($matches) {
+                               return ucfirst($matches[1]);
+                       }, $tagName);
+                       $className = $classNamePattern . ucfirst($tagName);
+                       if (class_exists($className)) {
+                               $this->invokeHtmlNode(new $className);
+                       }
+               }
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/html/node/HtmlNodeProcessor.class.php b/wcfsetup/install/files/lib/system/html/node/HtmlNodeProcessor.class.php
deleted file mode 100644 (file)
index 0c0e4f6..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-namespace wcf\system\html\node;
-use wcf\system\exception\SystemException;
-use wcf\util\JSON;
-
-/**
- * TOOD documentation
- * @since      3.0
- */
-class HtmlNodeProcessor implements IHtmlNodeProcessor {
-       /**
-        * @var \DOMDocument
-        */
-       protected $document;
-       
-       protected $nodeData = [];
-       
-       /**
-        * @var \DOMXPath
-        */
-       protected $xpath;
-       
-       public function load($html) {
-               $this->document = new \DOMDocument('1.0', 'UTF-8');
-               $this->xpath = null;
-               
-               // 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
-               // 
-               // 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('<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . $html);
-               
-               $this->nodeData = [];
-       }
-       
-       public function getHtml() {
-               $html = $this->document->saveHTML($this->document->getElementsByTagName('body')->item(0));
-               
-               // remove nuisance added by PHP
-               $html = preg_replace('~^<body>~', '', $html);
-               $html = preg_replace('~</body>$~', '', $html);
-               
-               /** @var IHtmlNode $obj */
-               foreach ($this->nodeData as $data) {
-                       $obj = $data['object'];
-                       $string = $obj->replaceTag($data['data']);
-                       $html = preg_replace_callback('~<wcfNode-' . $data['identifier'] . '>(?P<content>[\s\S]*)</wcfNode-' . $data['identifier'] . '>~', function($matches) use ($string) {
-                               $string = str_replace('<!-- META_CODE_INNER_CONTENT -->', $matches['content'], $string);
-                               
-                               return $string;
-                       }, $html);
-                       
-               }
-               
-               return $html;
-       }
-       
-       public function getDocument() {
-               return $this->document;
-       }
-       
-       public function getXPath() {
-               if ($this->xpath === null) {
-                       $this->xpath = new \DOMXPath($this->getDocument());
-               }
-               
-               return $this->xpath;
-       }
-       
-       public function renameTag(\DOMElement $element, $tagName) {
-               $newElement = $this->document->createElement($tagName);
-               $element->parentNode->insertBefore($newElement, $element);
-               while ($element->hasChildNodes()) {
-                       $newElement->appendChild($element->firstChild);
-               }
-               
-               $element->parentNode->removeChild($element);
-               
-               return $newElement;
-       }
-       
-       public function unwrapContent(\DOMElement $element) {
-               while ($element->hasChildNodes()) {
-                       $element->parentNode->insertBefore($element->firstChild, $element);
-               }
-               
-               $element->parentNode->removeChild($element);
-       }
-       
-       public function addNodeData(IHtmlNode $htmlNode, $nodeIdentifier, array $data) {
-               $this->nodeData[] = [
-                       'data' => $data,
-                       'identifier' => $nodeIdentifier,
-                       'object' => $htmlNode
-               ];
-       }
-       
-       public function parseAttributes($attributes) {
-               if (empty($attributes)) {
-                       return [];
-               }
-               
-               $parsedAttributes = base64_decode($attributes, true);
-               if ($parsedAttributes !== false) {
-                       try {
-                               $parsedAttributes = JSON::decode($parsedAttributes);
-                       }
-                       catch (SystemException $e) {
-                               /* parse errors can occur if user provided malicious content - ignore them */
-                               $parsedAttributes = [];
-                       }
-               }
-               
-               return $parsedAttributes;
-       }
-       
-       protected function invokeHtmlNode(IHtmlNode $htmlNode) {
-               $tagName = $htmlNode->getTagName();
-               if (empty($tagName)) {
-                       throw new \UnexpectedValueException("Missing tag name for " . get_class($htmlNode));
-               }
-               
-               $elements = [];
-               foreach ($this->getDocument()->getElementsByTagName($tagName) as $element) {
-                       $elements[] = $element;
-               }
-               
-               if (!empty($elements)) {
-                       $htmlNode->process($elements, $this);
-               }
-       }
-}
index 8f81002650f030cf3586b414af740d8b69555b05..2f71694cf1902880d3c0de4d1fa15023d2fc65ef 100644 (file)
@@ -2,18 +2,34 @@
 namespace wcf\system\html\node;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Default interface for html nodes.
+ * 
+ * @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\Html\Node
+ * @since       3.0
  */
 interface IHtmlNode {
+       /**
+        * Returns the tag name of elements consumed by this node.
+        *
+        * @return      string          tag name of consumed elements
+        */
        public function getTagName();
        
        /**
-        * @param \DOMElement[] $elements
-        * @param HtmlNodeProcessor $htmlNodeProcessor
-        * @return mixed
+        * Processes the provided elements and marks them for replacement if applicable.
+        * 
+        * @param       \DOMElement[]           $elements               static list of matched elements, does not change when removing elements
+        * @param       AbstractHtmlNodeProcessor       $htmlNodeProcessor      node processor instance
         */
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor);
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor);
        
+       /**
+        * Replaces a placeholder tag with the provided data.
+        *
+        * @param       array   $data   replacement data
+        */
        public function replaceTag(array $data);
 }
index 0d428a0a350588d34ec062c933d980ca58b0a285..133b4b2fad9fef5f09b3bdc9f09c4472949fe8e6 100644 (file)
@@ -2,15 +2,38 @@
 namespace wcf\system\html\node;
 
 /**
- * @since 3.0
+ * Default interface for html node processors.
+ *
+ * @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\Html\Node
+ * @since       3.0
  */
 interface IHtmlNodeProcessor {
        /**
-        * @return      \DOMDocument
+        * Returns the currently loaded DOM document.
+        * 
+        * @return      \DOMDocument    active DOM document
         */
        public function getDocument();
        
+       /**
+        * Returns the final HTML for storage or display.
+        * 
+        * @return      string  parsed HTML
+        */
        public function getHtml();
        
+       /**
+        * Loads a HTML string for processing.
+        * 
+        * @param       string  $html   HTML string
+        */
        public function load($html);
+       
+       /**
+        * Processes the HTML and transforms it depending on the output type.
+        */
+       public function process();
 }
index 83a7744f039ffc3197179dfd0cf5a8d7cc41f9d2..d1fdea2009722a05ea4905e3b6180282dceb082d 100644 (file)
@@ -2,23 +2,31 @@
 namespace wcf\system\html\output\node;
 use wcf\system\application\ApplicationHandler;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
 use wcf\system\request\RouteHandler;
 use wcf\system\WCF;
 use wcf\util\StringUtil;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Processes quotes.
+ * 
+ * @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\Html\Output\Node
+ * @since       3.0
  */
 class HtmlOutputNodeBlockquote extends AbstractHtmlNode {
+       /**
+        * @inheritDoc
+        */
        protected $tagName = 'blockquote';
        
        /**
         * @inheritDoc
         */
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
                /** @var \DOMElement $element */
                foreach ($elements as $element) {
                        $nodeIdentifier = StringUtil::getRandomID();
@@ -31,6 +39,9 @@ class HtmlOutputNodeBlockquote extends AbstractHtmlNode {
                }
        }
        
+       /**
+        * @inheritDoc
+        */
        public function replaceTag(array $data) {
                $externalQuoteLink = (!empty($data['url'])) ? !ApplicationHandler::getInstance()->isInternalURL($data['url']) : false;
                if (!$externalQuoteLink) {
index 25f74548ce51bcdcef95c6394391538dc480796a..79184f5bb989edd235edb7d17e62e3bc26d814f9 100644 (file)
@@ -14,16 +14,24 @@ use wcf\system\bbcode\highlighter\SqlHighlighter;
 use wcf\system\bbcode\highlighter\TexHighlighter;
 use wcf\system\bbcode\highlighter\XmlHighlighter;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\system\Regex;
 use wcf\system\WCF;
 use wcf\util\StringUtil;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Processes code listings.
+ * 
+ * @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\Html\Output\Node
+ * @since       3.0
  */
 class HtmlOutputNodePre extends AbstractHtmlNode {
+       /**
+        * @inheritDoc
+        */
        protected $tagName = 'pre';
        
        /**
@@ -35,7 +43,7 @@ class HtmlOutputNodePre extends AbstractHtmlNode {
        /**
         * @inheritDoc
         */
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
                /** @var \DOMElement $element */
                foreach ($elements as $element) {
                        $nodeIdentifier = StringUtil::getRandomID();
@@ -50,6 +58,9 @@ class HtmlOutputNodePre extends AbstractHtmlNode {
                }
        }
        
+       /**
+        * @inheritDoc
+        */
        public function replaceTag(array $data) {
                $content = preg_replace('/^\s*\n/', '', $data['content']);
                $content = preg_replace('/\n\s*$/', '', $content);
index 8648ffdac52509ba61841a3de0ffc536d342354a..015203c17658f3f8431762f54c29d31555ac0b73 100644 (file)
@@ -1,21 +1,24 @@
 <?php
 namespace wcf\system\html\output\node;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Processes a HTML string and renders the final output for display.
+ * 
+ * @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\Html\Output\Node
+ * @since       3.0
  */
-class HtmlOutputNodeProcessor extends HtmlNodeProcessor {
+class HtmlOutputNodeProcessor extends AbstractHtmlNodeProcessor {
+       /**
+        * @inheritDoc
+        */
        public function process() {
                $this->invokeHtmlNode(new HtmlOutputNodeWoltlabMetacode());
                
-               // TODO: this should be dynamic to some extent
-               $this->invokeHtmlNode(new HtmlOutputNodeBlockquote());
-               $this->invokeHtmlNode(new HtmlOutputNodeWoltlabMention());
-               $this->invokeHtmlNode(new HtmlOutputNodeWoltlabColor());
-               $this->invokeHtmlNode(new HtmlOutputNodeWoltlabSize());
-               $this->invokeHtmlNode(new HtmlOutputNodeWoltlabSpoiler());
-               $this->invokeHtmlNode(new HtmlOutputNodePre());
+               // dynamic node handlers
+               $this->invokeNodeHandlers('wcf\system\html\output\node\HtmlOutputNode', ['woltlab-metacode']);
        }
 }
index 9b45a1febb0373219634348977f54ffeb1c52171..f6829e093d50a7c8a73a5a8deb21a8faae8f9259 100644 (file)
@@ -1,20 +1,28 @@
 <?php
 namespace wcf\system\html\output\node;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\util\StringUtil;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Processes text color.
+ * 
+ * @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\Html\Output\Node
+ * @since       3.0
  */
 class HtmlOutputNodeWoltlabColor extends AbstractHtmlNode {
+       /**
+        * @inheritDoc
+        */
        protected $tagName = 'woltlab-color';
        
        /**
         * @inheritDoc
         */
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
                /** @var \DOMElement $element */
                foreach ($elements as $element) {
                        // parse color
@@ -29,6 +37,9 @@ class HtmlOutputNodeWoltlabColor extends AbstractHtmlNode {
                }
        }
        
+       /**
+        * @inheritDoc
+        */
        public function replaceTag(array $data) {
                return '<span style="color: #' . $data['color'] . '">' . self::PLACEHOLDER . '</span>';
        }
index 7ecc86b4dbd4c16c982a5f43ced211527833da21..e2821b253ec900022dfd09b2eed87fe1907815be 100644 (file)
@@ -3,16 +3,24 @@ namespace wcf\system\html\output\node;
 use wcf\data\user\UserProfile;
 use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\system\WCF;
 use wcf\util\DOMUtil;
 use wcf\util\StringUtil;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Processes user mentions.
+ * 
+ * @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\Html\Output\Node
+ * @since       3.0
  */
 class HtmlOutputNodeWoltlabMention extends AbstractHtmlNode {
+       /**
+        * @inheritDoc
+        */
        protected $tagName = 'woltlab-mention';
        
        /**
@@ -23,10 +31,11 @@ class HtmlOutputNodeWoltlabMention extends AbstractHtmlNode {
        /**
         * @inheritDoc
         */
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
                $this->userProfiles = [];
                
                $userIds = [];
+               /** @var \DOMElement $element */
                foreach ($elements as $element) {
                        $userId = ($element->hasAttribute('data-user-id')) ? intval($element->getAttribute('data-user-id')) : 0;
                        $username = ($element->hasAttribute('data-username')) ? StringUtil::trim($element->getAttribute('data-username')) : '';
@@ -51,6 +60,9 @@ class HtmlOutputNodeWoltlabMention extends AbstractHtmlNode {
                }
        }
        
+       /**
+        * @inheritDoc
+        */
        public function replaceTag(array $data) {
                WCF::getTPL()->assign([
                        'username' => $data['username'],
index b2cfffe8c4bd78b50d64aa705fcf2154c6fb3033..98a2df63e183cdc41ad5a56881dc41e24bf92d9d 100644 (file)
@@ -2,20 +2,28 @@
 namespace wcf\system\html\output\node;
 use wcf\system\bbcode\HtmlBBCodeParser;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\util\StringUtil;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Processes bbcodes represented by `<woltlab-metacode>`.
+ * 
+ * @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\Html\Output\Node
+ * @since       3.0
  */
 class HtmlOutputNodeWoltlabMetacode extends AbstractHtmlNode {
+       /**
+        * @inheritDoc
+        */
        protected $tagName = 'woltlab-metacode';
        
        /**
         * @inheritDoc
         */
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
                /** @var \DOMElement $element */
                foreach ($elements as $element) {
                        $name = $element->getAttribute('data-name');
@@ -31,6 +39,9 @@ class HtmlOutputNodeWoltlabMetacode extends AbstractHtmlNode {
                }
        }
        
+       /**
+        * @inheritDoc
+        */
        public function replaceTag(array $data) {
                return HtmlBBCodeParser::getInstance()->getHtmlOutput($data['name'], $data['attributes']);
        }
index 168475c3581433b2f8fc95e0906fc2d3ddc9585d..094d96f7a570f5a6fe83685aa98fe65d9f6ba090 100644 (file)
@@ -1,20 +1,28 @@
 <?php
 namespace wcf\system\html\output\node;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\util\StringUtil;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Processes text size.
+ * 
+ * @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\Html\Output\Node
+ * @since       3.0
  */
 class HtmlOutputNodeWoltlabSize extends AbstractHtmlNode {
+       /**
+        * @inheritDoc
+        */
        protected $tagName = 'woltlab-size';
        
        /**
         * @inheritDoc
         */
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
                /** @var \DOMElement $element */
                foreach ($elements as $element) {
                        // parse color
@@ -29,6 +37,9 @@ class HtmlOutputNodeWoltlabSize extends AbstractHtmlNode {
                }
        }
        
+       /**
+        * @inheritDoc
+        */
        public function replaceTag(array $data) {
                return '<span style="font-size: ' . $data['size'] . 'px">' . self::PLACEHOLDER . '</span>';
        }
index 921099da7e25ab81e7127597af57bfd252d98baf..982172626cf3554dcc363b73cb6cd96cbcb6919a 100644 (file)
@@ -1,23 +1,29 @@
 <?php
 namespace wcf\system\html\output\node;
-use wcf\system\application\ApplicationHandler;
 use wcf\system\html\node\AbstractHtmlNode;
-use wcf\system\html\node\HtmlNodeProcessor;
-use wcf\system\request\RouteHandler;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\system\WCF;
 use wcf\util\StringUtil;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Processes spoilers.
+ * 
+ * @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\Html\Output\Node
+ * @since       3.0
  */
 class HtmlOutputNodeWoltlabSpoiler extends AbstractHtmlNode {
+       /**
+        * @inheritDoc
+        */
        protected $tagName = 'woltlab-spoiler';
        
        /**
         * @inheritDoc
         */
-       public function process(array $elements, HtmlNodeProcessor $htmlNodeProcessor) {
+       public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
                /** @var \DOMElement $element */
                foreach ($elements as $element) {
                        $nodeIdentifier = StringUtil::getRandomID();
@@ -29,6 +35,9 @@ class HtmlOutputNodeWoltlabSpoiler extends AbstractHtmlNode {
                }
        }
        
+       /**
+        * @inheritDoc
+        */
        public function replaceTag(array $data) {
                WCF::getTPL()->assign([
                        'buttonLabel' => $data['label']
index e8e34f64ab6e13bb8618670ac15cf08c366bb01e..1dd8700bdd318d0fccefc845b9b1ec8450d68dd9 100644 (file)
@@ -3,7 +3,12 @@ namespace wcf\system\html\output\node;
 use wcf\system\html\node\IHtmlNode;
 
 /**
- * TOOD documentation
- * @since      3.0
+ * Default interface for html output nodes.
+ * 
+ * @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\Html\Output\Node
+ * @since       3.0
  */
 interface IHtmlOutputNode extends IHtmlNode {}