Added support for attachments within the editor (e.g. quick reply)
authorAlexander Ebert <ebert@woltlab.com>
Wed, 16 Apr 2014 13:52:08 +0000 (15:52 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 16 Apr 2014 13:52:08 +0000 (15:52 +0200)
com.woltlab.wcf/templates/wysiwyg.tpl
com.woltlab.wcf/templates/wysiwygToolbar.tpl
wcfsetup/install/files/js/3rdParty/redactor/plugins/wupload.js [new file with mode: 0644]
wcfsetup/install/files/js/WCF.Message.js
wcfsetup/install/files/lib/data/IAttachmentMessageQuickReplyAction.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/message/QuickReplyManager.class.php
wcfsetup/install/files/style/message.less

index 384f49d3accf6574021ed8ec324a6e5fdebbc1b6..889da3d3283c6532b4f3a0dcc5671a4046c4f75b 100644 (file)
@@ -1,3 +1,4 @@
+{if !$wysiwygEnableUpload|isset}{assign var=wysiwygEnableUpload value=false}{/if}
 <link rel="stylesheet" type="text/css" href="{@$__wcf->getPath()}js/3rdParty/redactor/redactor.css" />
 <script data-relocate="true">
 var __REDACTOR_ICON_PATH = '{@$__wcf->getPath()}icon/';
@@ -10,6 +11,20 @@ $(function() {
        var $editorName = '{if $wysiwygSelector|isset}{$wysiwygSelector|encodeJS}{else}text{/if}';
        var $callbackIdentifier = 'Redactor_' + $editorName;
        
+       {if $wysiwygEnableUpload}
+               WCF.Language.addObject({
+                       'wcf.attachment.upload.error.invalidExtension': '{lang}wcf.attachment.upload.error.invalidExtension{/lang}',
+                       'wcf.attachment.upload.error.tooLarge': '{lang}wcf.attachment.upload.error.tooLarge{/lang}',
+                       'wcf.attachment.upload.error.reachedLimit': '{lang}wcf.attachment.upload.error.reachedLimit{/lang}',
+                       'wcf.attachment.upload.error.reachedRemainingLimit': '{lang}wcf.attachment.upload.error.reachedRemainingLimit{/lang}',
+                       'wcf.attachment.upload.error.uploadFailed': '{lang}wcf.attachment.upload.error.uploadFailed{/lang}',
+                       'wcf.global.button.upload': '{lang}wcf.global.button.upload{/lang}',
+                       'wcf.attachment.insert': '{lang}wcf.attachment.insert{/lang}',
+                       'wcf.attachment.delete.sure': '{lang}wcf.attachment.delete.sure{/lang}',
+                       'wcf.attachment.upload.limits': '{'wcf.attachment.upload.limits'|language|encodeJS}'
+               });
+       {/if}
+       
        WCF.System.Dependency.Manager.setup($callbackIdentifier, function() {
                var $textarea = $('#' + $editorName);
                var $buttons = [ ];
@@ -28,12 +43,24 @@ $(function() {
                        }
                };
                
+               {if $wysiwygEnableUpload}
+                       $config.plugins.push('wupload');
+                       $config.wattachment = {
+                               maxCount: {@$attachmentHandler->getMaxCount()},
+                               objectType: '{@$attachmentObjectType}',
+                               objectID: '{@$attachmentObjectID}',
+                               parentObjectID: '{@$attachmentParentObjectID}',
+                               tmpHash: '{$tmpHash|encodeJS}'
+                       };
+               {/if}
+               
                {event name='javascriptInit'}
                
                $textarea.redactor($config);
        });
        
        head.load([
+               '{@$__wcf->getPath()}js/WCF.Attachment{if !ENABLE_DEBUG_MODE}.min{/if}.js?v={@$__wcfVersion}',
                '{@$__wcf->getPath()}js/3rdParty/redactor/redactor.js',
                '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wbbcode.js',
                '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wbutton.js',
@@ -41,7 +68,8 @@ $(function() {
                '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wfontfamily.js',
                '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wfontsize.js',
                '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wmonkeypatch.js',
-               '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wutil.js'
+               '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wutil.js',
+               '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wupload.js'
                {event name='javascriptFiles'}
        ], function() {
                WCF.System.Dependency.Manager.invoke($callbackIdentifier);
index f86978fc728b555eab081e488613cbd6fdb6a4be..787729a2a2f85babddc3480eb4300fdd782f4317 100644 (file)
@@ -67,6 +67,10 @@ if ($buttons.length && $buttons[$buttons.length -1] != 'separator') {
        $buttons.push('table');
 {/if}
 
+{if $wysiwygEnableUpload}
+       $buttons.push('upload');
+{/if}
+
 {if MODULE_SMILEY && (!$permissionCanUseSmilies|isset || $__wcf->getSession()->getPermission($permissionCanUseSmilies)) && $defaultSmilies|isset && $defaultSmilies|count}
        $buttons.push('smiley');
 {/if}
diff --git a/wcfsetup/install/files/js/3rdParty/redactor/plugins/wupload.js b/wcfsetup/install/files/js/3rdParty/redactor/plugins/wupload.js
new file mode 100644 (file)
index 0000000..eb7b214
--- /dev/null
@@ -0,0 +1,40 @@
+if (!RedactorPlugins) var RedactorPlugins = {};
+
+/**
+ * Provides file uploads for Redactor.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+RedactorPlugins.wupload = {
+       /**
+        * attachments container object
+        * @var jQuery
+        */
+       _attachmentsContainer: null,
+       
+       /**
+        * Initializes the RedactorPlugins.wupload plugin.
+        */
+       init: function() {
+               var self = this;
+               this.buttonReplace('upload', 'upload', 'Upload', function() { self._attachmentsContainer.toggle(); });
+               this.buttonAwesome('upload', 'fa-upload');
+               
+               this._initAttachments();
+       },
+       
+       /**
+        * Initializes the attachments user interface.
+        */
+       _initAttachments: function() {
+               this._attachmentsContainer = $('<div class="redactorAttachmentContainer" />').hide().appendTo(this.$box);
+               $('<ul class="formAttachmentList clearfix" />').hide().appendTo(this._attachmentsContainer);
+               $('<dl class="wide"><dt></dt><dd><div data-max-size="{@$attachmentHandler->getMaxSize()}"></div><small>' + WCF.String.unescapeHTML(WCF.Language.get('wcf.attachment.upload.limits')) + '</small></dd></dl>').appendTo(this._attachmentsContainer);
+               
+               var $options = this.getOption('wattachment');
+               new WCF.Attachment.Upload(this._attachmentsContainer.find('> dl > dd > div'), this._attachmentsContainer.children('ul'), $options.objectType, $options.objectID, $options.tmpHash, $options.parentObjectID, $options.maxCount, this.$source.wcfIdentify());
+               new WCF.Action.Delete('wcf\\data\\attachment\\AttachmentAction', '.formAttachmentList > li');
+       }
+};
index 0a07af3083de597b3f7100d505de658687fdeff1..bec2fe99a4843e9e497dce28c0b916629b74e5c4 100644 (file)
@@ -772,7 +772,8 @@ WCF.Message.QuickReply = Class.extend({
                        },
                        lastPostTime: this._container.data('lastPostTime'),
                        pageNo: this._container.data('pageNo'),
-                       removeQuoteIDs: (this._quoteManager === null ? [ ] : this._quoteManager.getQuotesMarkedForRemoval())
+                       removeQuoteIDs: (this._quoteManager === null ? [ ] : this._quoteManager.getQuotesMarkedForRemoval()),
+                       tmpHash: this._container.data('tmpHash') || ''
                };
                if (this._container.data('anchor')) {
                        $parameters.anchor = this._container.data('anchor');
diff --git a/wcfsetup/install/files/lib/data/IAttachmentMessageQuickReplyAction.class.php b/wcfsetup/install/files/lib/data/IAttachmentMessageQuickReplyAction.class.php
new file mode 100644 (file)
index 0000000..4f30f18
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+namespace wcf\data;
+
+/**
+ * Default interface for actions implementing quick reply with attachment support.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data
+ * @category   Community Framework
+ */
+interface IAttachmentMessageQuickReplyAction extends IExtendedMessageQuickReplyAction {
+       /**
+        * Returns an attachment handler object.
+        * 
+        * @param       \wcf\data\DatabaseObject        $container
+        */
+       public function getAttachmentHandler(DatabaseObject $container);
+}
index efaf1a0b9a0be13520df6b6f8cccdb1055deebf7..165ce50fcb6503990be5086b15c1f02daed1697e 100644 (file)
@@ -12,6 +12,8 @@ use wcf\system\WCF;
 use wcf\util\ArrayUtil;
 use wcf\util\ClassUtil;
 use wcf\util\MessageUtil;
+use wcf\util\StringUtil;
+use wcf\data\IAttachmentMessageQuickReplyAction;
 
 /**
  * Manages quick replies and stored messages.
@@ -152,6 +154,9 @@ class QuickReplyManager extends SingletonFactory {
                // check for message quote ids
                $parameters['removeQuoteIDs'] = (isset($parameters['removeQuoteIDs']) && is_array($parameters['removeQuoteIDs'])) ? ArrayUtil::trim($parameters['removeQuoteIDs']) : array();
                
+               // check for tmp hash (attachments)
+               $parameters['tmpHash'] = (isset($parameters['tmpHash'])) ? StringUtil::trim($parameters['tmpHash']) : '';
+               
                EventHandler::getInstance()->fireAction($this, 'validateParameters');
        }
        
@@ -185,6 +190,11 @@ class QuickReplyManager extends SingletonFactory {
                
                $parameters['data'] = array_merge($this->additionalFields, $parameters['data']);
                
+               // attachment support
+               if (MODULE_ATTACHMENT && $object instanceof IAttachmentMessageQuickReplyAction) {
+                       $parameters['attachmentHandler'] = $object->getAttachmentHandler($this->container);
+               }
+               
                // clean up
                $this->additionalFields = array();
                
index d127b7b4993115196de4778d9a87015955b4088a..4fddf24d2d558523c737781667e988d4c883d195 100644 (file)
@@ -975,6 +975,13 @@ li:nth-child(2n+1) .message {
        }
 }
 
+.redactorAttachmentContainer {
+       background-color: rgba(255, 255, 255, 1);
+       border: 1px solid rgba(238, 238, 238, 1);
+       border-top-width: 0;
+       padding: 7px 14px 7px;
+}
+
 .redactor_dropdown_box_wsmiley > ul > li:not(:last-child) {
        margin-right: 3px !important;
 }