Added support for embedded objects
authorAlexander Ebert <ebert@woltlab.com>
Sat, 28 May 2016 17:11:27 +0000 (19:11 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 28 May 2016 17:11:27 +0000 (19:11 +0200)
com.woltlab.wcf/bbcode.xml
wcfsetup/install/files/lib/system/bbcode/AttachmentBBCode.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeImg.class.php
wcfsetup/install/files/lib/system/message/embedded/object/AbstractMessageEmbeddedObjectHandler.class.php
wcfsetup/install/files/lib/system/message/embedded/object/AttachmentMessageEmbeddedObjectHandler.class.php
wcfsetup/install/files/lib/system/message/embedded/object/IMessageEmbeddedObjectHandler.class.php
wcfsetup/install/files/lib/system/message/embedded/object/MessageEmbeddedObjectManager.class.php
wcfsetup/install/files/style/ui/message.scss

index 5927a026616301de9666f6ac53fdc258e87f1893..a74e295ffb41eaffa7aa652086a97ef3a4e016e0 100644 (file)
                                        <validationpattern>^(left|right|none)$</validationpattern>
                                </attribute>
                                <attribute name="2">
-                                       <validationpattern>^\d+$</validationpattern>
+                                       <!-- "\d+" is only matched for backward compatibility -->
+                                       <validationpattern>^(\d+|true|false)$</validationpattern>
                                </attribute>
                        </attributes>
                </bbcode>
index cc3733bb20dde9e07a3ed3d86369460b01da5aa5..cde73c7290b4197ca34a6492a0c5e47ba2e9f40f 100644 (file)
@@ -58,22 +58,28 @@ class AttachmentBBCode extends AbstractBBCode {
                        if ($attachment->showAsImage() && $attachment->canViewPreview() && $parser->getOutputType() == 'text/html') {
                                // image
                                $alignment = (isset($openingTag['attributes'][1]) ? $openingTag['attributes'][1] : '');
-                               $width = (isset($openingTag['attributes'][2]) ? $openingTag['attributes'][2] : 0);
+                               $thumbnail = (isset($openingTag['attributes'][2]) ? $openingTag['attributes'][2] : false);
                                
-                               // check if width is valid and the original is accessible by viewer
-                               if ($width > 0) {
-                                       if ($attachment->canDownload()) {
-                                               // check if width exceeds image width
-                                               if ($width > $attachment->width) {
-                                                       $width = $attachment->width;
-                                               }
+                               // backward compatibility, check if width is larger than thumbnail's width to display full version
+                               if (is_int($thumbnail)) {
+                                       if ($thumbnail == 0) {
+                                               $thumbnail = true;
                                        }
                                        else {
-                                               $width = 0;
+                                               // true if supplied width is smaller or equal to thumbnail's width
+                                               $thumbnail = ($attachment->thumbnailWidth >= $thumbnail) ? true : false;
                                        }
                                }
+                               else if ($thumbnail !== false) {
+                                       $thumbnail = true;
+                               }
+                               
+                               // check if width is valid and the original is accessible by viewer
+                               if (!$thumbnail && !$attachment->canDownload()) {
+                                       $thumbnail = false;
+                               }
                                
-                               if ($width > 0) {
+                               if (!$thumbnail) {
                                        $class = '';
                                        if ($alignment == 'left' || $alignment == 'right') {
                                                $class = 'messageFloatObject'.ucfirst($alignment);
@@ -82,7 +88,7 @@ class AttachmentBBCode extends AbstractBBCode {
                                        $source = StringUtil::encodeHTML(LinkHandler::getInstance()->getLink('Attachment', ['object' => $attachment]));
                                        $title = StringUtil::encodeHTML($attachment->filename);
                                        
-                                       $result = '<a href="' . $source . '" title="' . $title . '" class="embeddedAttachmentLink jsImageViewer' . ($class ? ' '.$class : '') . '"><img src="' . $source . '" style="width: '.$width.'px" alt="" /></a>';
+                                       $result = '<a href="' . $source . '" title="' . $title . '" class="embeddedAttachmentLink jsImageViewer' . ($class ? ' '.$class : '') . '"><img src="' . $source . '" alt="" /></a>';
                                }
                                else {
                                        $linkParameters = [
index 1d4da85b85d2739ddfb97b704eb689a284844181..f18860e8f69946a8b87de5bc4df3aebdf77b9713 100644 (file)
@@ -25,9 +25,23 @@ class HtmlInputNodeImg extends AbstractHtmlNode {
                                continue;
                        }
                        
+                       // TODO: add alignment detection
+                       $alignment = 'none';
+                       $thumbnail = false;
+                       
+                       if (strpos($element->getAttribute('src'), 'thumbnail=1') !== false) {
+                               $thumbnail = true;
+                       }
+                       
+                       $attributes = [
+                               $attachmentID,
+                               $alignment,
+                               $thumbnail
+                       ];
+                       
                        $newElement = $element->ownerDocument->createElement('woltlab-metacode');
                        $newElement->setAttribute('data-name', 'attach');
-                       $newElement->setAttribute('data-attributes', base64_encode(JSON::encode([$attachmentID])));
+                       $newElement->setAttribute('data-attributes', base64_encode(JSON::encode($attributes)));
                        DOMUtil::replaceElement($element, $newElement, false);
                }
        }
index c390ccc761d8dd72fc4da53742fde1a34f48045c..c3b9461c1b6c4e25962e8f0ee21a14a4e3c37d7b 100644 (file)
@@ -2,6 +2,7 @@
 namespace wcf\system\message\embedded\object;
 use wcf\data\object\type\ObjectType;
 use wcf\data\DatabaseObjectDecorator;
+use wcf\system\html\input\HtmlInputProcessor;
 use wcf\util\ArrayUtil;
 
 /**
@@ -24,53 +25,11 @@ abstract class AbstractMessageEmbeddedObjectHandler extends DatabaseObjectDecora
        protected static $baseClass = ObjectType::class;
        
        /**
-        * Parses given message for specific bbcode parameters.
-        * 
-        * @param       string          $message
-        * @param       string          $bbcode         bbcode name
-        * @return      array
+        * @inheritDoc
         */
-       public static function getTextParameters($message, $bbcode) {
-               if (preg_match_all('~\['.$bbcode.'\](.*?)\[/'.$bbcode.'\]~i', $message, $matches)) {
-                       $results = ArrayUtil::trim($matches[1]);
-                       $results = array_unique($results);
-                       
-                       return $results;
-               }
-               
+       public function parse(HtmlInputProcessor $htmlInputProcessor, array $embeddedData) {
+               // TODO: DEBUG ONLY, remove this method!
                return [];
        }
        
-       /**
-        * Parses given message for specific bbcode parameters.
-        * 
-        * @param       string          $message
-        * @param       string          $bbcode         bbcode name
-        * @return      array
-        */
-       public static function getFirstParameters($message, $bbcode) {
-               $pattern = '~\['.$bbcode.'=
-                               (\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'|(?:[^,\]]*))
-                               (?:,(?:\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'|[^,\]]*))*
-                       \]~ix';
-               
-               if (preg_match_all($pattern, $message, $matches)) {
-                       foreach ($matches[1] as &$value) {
-                               // remove quotes
-                               if (mb_substr($value, 0, 1) == "'" && mb_substr($value, -1) == "'") {
-                                       $value = str_replace("\'", "'", $value);
-                                       $value = str_replace("\\\\", "\\", $value);
-                               
-                                       $value = mb_substr($value, 1, -1);
-                               }
-                       }
-                       
-                       $results = ArrayUtil::trim($matches[1]);
-                       $results = array_unique($results);
-                       
-                       return $results;
-               }
-               
-               return [];
-       }
 }
index 75f4e1e29d860624516162aa6ba96e09791a594e..2fb76c42ed130aeefac1b7050ba93857e57317da 100644 (file)
@@ -2,6 +2,7 @@
 namespace wcf\system\message\embedded\object;
 use wcf\data\attachment\AttachmentList;
 use wcf\data\object\type\ObjectTypeCache;
+use wcf\system\html\input\HtmlInputProcessor;
 use wcf\util\ArrayUtil;
 
 /**
@@ -18,24 +19,30 @@ class AttachmentMessageEmbeddedObjectHandler extends AbstractMessageEmbeddedObje
        /**
         * @inheritDoc
         */
-       public function parseMessage($message) {
-               $parsedAttachmentIDs = array_unique(ArrayUtil::toIntegerArray(array_merge(self::getFirstParameters($message, 'attach'), self::getTextParameters($message, 'attach'))));
-               if (!empty($parsedAttachmentIDs)) {
-                       $attachmentIDs = [];
-                       foreach ($parsedAttachmentIDs as $parsedAttachmentID) {
-                               if ($parsedAttachmentID) $attachmentIDs[] = $parsedAttachmentID;
-                       }
+       public function parse(HtmlInputProcessor $htmlInputProcessor, array $embeddedData) {
+               if (empty($embeddedData['attach'])) {
+                       return [];
+               }
+               
+               $attachmentIDs = [];
+               for ($i = 0, $length = count($embeddedData['attach']); $i < $length; $i++) {
+                       $attributes = $embeddedData['attach'][$i];
+                       $attachmentID = (!empty($attributes[0])) ? intval($attributes[0]) : 0;
                        
-                       if (!empty($attachmentIDs)) {
-                               $attachmentList = new AttachmentList();
-                               $attachmentList->getConditionBuilder()->add("attachment.attachmentID IN (?)", [$attachmentIDs]);
-                               $attachmentList->readObjectIDs();
-                               
-                               return $attachmentList->getObjectIDs();
+                       if ($attachmentID > 0) {
+                               $attachmentIDs[] = $attachmentID;
                        }
                }
                
-               return false;
+               if (!empty($attachmentIDs)) {
+                       $attachmentList = new AttachmentList();
+                       $attachmentList->getConditionBuilder()->add("attachment.attachmentID IN (?)", [$attachmentIDs]);
+                       $attachmentList->readObjectIDs();
+                       
+                       return $attachmentList->getObjectIDs();
+               }
+               
+               return [];
        }
        
        /**
index f41d5b27f5d16064953deb8e151e313013d7ca6d..541fa7a35978901d8a4cafd2bf31789a6ef5066f 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace wcf\system\message\embedded\object;
 use wcf\data\DatabaseObject;
+use wcf\system\html\input\HtmlInputProcessor;
 
 /**
  * Default interface of embedded object handler.
@@ -14,13 +15,15 @@ use wcf\data\DatabaseObject;
  */
 interface IMessageEmbeddedObjectHandler {
        /**
-        * Parses the given message to extract embedded objects.
-        * Returns the IDs of found embedded objects.
+        * Processes embedded data and optionally accesses the current
+        * document to extract additional data. Returns the IDs of found
+        * embedded objects.
         * 
-        * @param       string          $message
-        * @return      integer[]
+        * @param       HtmlInputProcessor      $htmlInputProcessor     html input processor holding the current document
+        * @param       mixed[]                 $embeddedData           list of found embedded data with attributes
+        * @return      integer[]               ids of found embedded objects
         */
-       public function parseMessage($message);
+       public function parse(HtmlInputProcessor $htmlInputProcessor, array $embeddedData);
        
        /**
         * Loads and returns embedded objects.
index 55b6a3f96bef01f227075cea15b3e604bbf5c8be..031edb81b8b610529b1c5bf79006599c8daed778 100644 (file)
@@ -3,6 +3,7 @@ namespace wcf\system\message\embedded\object;
 use wcf\data\object\type\ObjectTypeCache;
 use wcf\system\bbcode\BBCodeParser;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\html\input\HtmlInputProcessor;
 use wcf\system\SingletonFactory;
 use wcf\system\WCF;
 
@@ -50,15 +51,12 @@ class MessageEmbeddedObjectManager extends SingletonFactory {
        /**
         * Registers the embedded objects found in given message.
         * 
-        * @param       string          $messageObjectType
-        * @param       integer         $messageID
-        * @param       string          $message
-        * @return      boolean
+        * @param       HtmlInputProcessor      $htmlInputProcessor     html input processor instance holding embedded object data
+        * @param       string                  $messageObjectType      message object type
+        * @param       integer                 $messageID              message id
+        * @return      boolean                 true if at least one embedded object was found
         */
-       public function registerObjects($messageObjectType, $messageID, $message) {
-               // remove [code] tags
-               $message = BBCodeParser::getInstance()->removeCodeTags($message);
-               
+       public function registerObjects(HtmlInputProcessor $htmlInputProcessor, $messageObjectType, $messageID) {
                // delete existing assignments
                $this->removeObjects($messageObjectType, [$messageID]);
                
@@ -73,14 +71,20 @@ class MessageEmbeddedObjectManager extends SingletonFactory {
                
                // call embedded object handlers
                WCF::getDB()->beginTransaction();
+               
+               $embeddedData = $htmlInputProcessor->getEmbeddedContent();
                $returnValue = false;
+               
+               /** @var IMessageEmbeddedObjectHandler $handler */
                foreach ($this->getEmbeddedObjectHandlers() as $handler) {
-                       $objectIDs = $handler->parseMessage($message);
+                       $objectIDs = $handler->parse($htmlInputProcessor, $embeddedData);
+                       
                        if (!empty($objectIDs)) {
-                               $returnValue = true;
                                foreach ($objectIDs as $objectID) {
                                        $statement->execute([$messageObjectTypeID, $messageID, $handler->objectTypeID, $objectID]);
                                }
+                               
+                               $returnValue = true;
                        }
                }
                WCF::getDB()->commitTransaction();
index d536e7c76bb23a1e06648d695cafe8b6869d599e..acb67d42baefeed3e8c4b1dd6994fd9715ac5b7b 100644 (file)
        
        > .messageText {
                @extend .htmlContent;
+               
+               img {
+                       max-width: 100%;
+               }
        }
 }