Added support for image adding and floats
authorAlexander Ebert <ebert@woltlab.com>
Tue, 7 Jun 2016 16:01:45 +0000 (18:01 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Tue, 7 Jun 2016 16:01:53 +0000 (18:01 +0200)
com.woltlab.wcf/templates/wysiwygToolbar.tpl
wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabButton.js
wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabImage.js
wcfsetup/install/files/style/ui/redactor.scss

index ddd7aaa58270245ac21d473af99da0e4252ac518..f3f2e522300676a83792ad7b60a4d043299a9c4b 100644 (file)
@@ -11,6 +11,7 @@ buttonOptions = {
        table: { icon: 'fa-table', title: '{lang}wcf.editor.button.table{/lang}' },
        underline: { icon: 'fa-underline', title: '{lang}wcf.editor.button.underline{/lang}' },
        woltlabColor: { icon: 'fa-paint-brush', title: '{lang}wcf.editor.button.color{/lang}' },
+       woltlabImage: { icon: 'fa-picture-o', title: '{lang}wcf.editor.button.image{/lang}' },
        woltlabMedia: { icon: 'fa-file-o', title: '{lang}wcf.editor.button.media{/lang}' },
        woltlabQuote: { icon: 'fa-comment', title: '{lang}wcf.editor.button.quote{/lang}' },
        woltlabSize: { icon: 'fa-text-height', title: '{lang}wcf.editor.button.size{/lang}' }
@@ -46,11 +47,9 @@ buttons.push('alignment');
 {if $__wcf->getBBCodeHandler()->isAvailableBBCode('url')}
        buttons.push('link');
 {/if}
-{*
 {if $__wcf->getBBCodeHandler()->isAvailableBBCode('img')}
-       buttons.push('image');
+       buttons.push('woltlabImage');
 {/if}
-*}
 {if $__wcf->getBBCodeHandler()->isAvailableBBCode('table')}
        buttons.push('table');
 {/if}
index 3cf57f9c093d5dc2dabb9fb83bd003c344952976..8708e139dfdff01b9d46bf6899256b32e915b36f 100644 (file)
@@ -13,6 +13,11 @@ $.Redactor.prototype.WoltLabButton = function() {
                                        continue;
                                }
                                
+                               //noinspection JSUnresolvedVariable
+                               if (!this.opts.woltlab.buttons.hasOwnProperty(buttonName)) {
+                                       throw new Error("Missing button definition for '" + buttonName + "'.");
+                               }
+                               
                                //noinspection JSUnresolvedVariable
                                buttonData = this.opts.woltlab.buttons[buttonName];
                                
@@ -27,7 +32,7 @@ $.Redactor.prototype.WoltLabButton = function() {
                                // set icon
                                this.button.setIcon(button, '<span class="icon icon16 ' + buttonData.icon + '"></span>');
                                if (!button[0]) {
-                                       console.debug(buttonName);
+                                       throw new Error("Missing button element for '" + buttonName + "'.");
                                }
                                // set title
                                //noinspection JSUnresolvedVariable
index bf119939d851764c8c2e67db262dc03b5e298480..2f45234abe7bcb041b105e1d0cfaa54015958bc8 100644 (file)
@@ -3,22 +3,145 @@ $.Redactor.prototype.WoltLabImage = function() {
        
        return {
                init: function() {
-                       // overwrite modal templates
+                       var button = this.button.add('woltlabImage', '');
+                       this.button.addCallback(button, this.WoltLabImage.add);
+                       
+                       // add support for image source when editing
+                       // TODO: float
+                       var mpShowEdit = this.image.showEdit;
+                       this.image.showEdit = function($image) {
+                               mpShowEdit($image);
+                               
+                               elById('redactor-image-source').value = $image[0].src;
+                               
+                               var float = elById('redactor-image-float');
+                               if ($image[0].classList.contains('messageFloatObjectLeft')) float.value = 'left';
+                               else if ($image[0].classList.contains('messageFloatObjectRight')) float.value = 'right';
+                       };
+                       
+                       var mpUpdate = this.image.update;
+                       this.image.update = (function() {
+                               var sourceInput = elById('redactor-image-source');
+                               var showError = function(inputElement, message) {
+                                       $('<small class="innerError" />').text(message).insertAfter(inputElement);
+                               };
+                               
+                               // check if source is valid
+                               var source = sourceInput.value.trim();
+                               if (source === '') {
+                                       return showError(sourceInput, WCF.Language.get('wcf.global.form.error.empty'));
+                               }
+                               else if (!source.match(this.opts.regexps.url)) {
+                                       return showError(sourceInput, WCF.Language.get('wcf.editor.image.source.error.invalid'));
+                               }
+                               
+                               var image = this.observe.image[0];
+                               
+                               // update image source
+                               image.src = source;
+                               
+                               // remove old float classes
+                               image.classList.remove('messageFloatObjectLeft');
+                               image.classList.remove('messageFloatObjectRight');
+                               
+                               // set float behavior
+                               var float = elById('redactor-image-float').value;
+                               if (float === 'left' || float === 'right') {
+                                       image.classList.add('messageFloatObject' + WCF.String.ucfirst(float));
+                               }
+                               
+                               mpUpdate();
+                               
+                               // remove alt/title attribute again (not supported)
+                               image.removeAttribute('alt');
+                               image.removeAttribute('title');
+                       }).bind(this);
+                       
+                       // overwrite modal template
                        this.opts.modal['image-edit'] = '<div class="section">'
                                        + '<dl>'
-                                               + '<dt><label>' + this.lang.get('title') + '</label></dt>'
-                                               + '<dd><input type="text" id="redactor-image-title" class="long"></dd>'
+                                               + '<dt><label for="redactor-image-source">' + WCF.Language.get('wcf.editor.image.source') + '</label></dt>'
+                                               + '<dd>'
+                                                       + '<input type="text" id="redactor-image-source" class="long">'
+                                                       + '<small>' + WCF.Language.get('wcf.editor.image.source.description') + '</small>'
+                                               + '</dd>'
                                        + '</dl>'
                                        + '<dl>'
-                                               + '<dt><label>' + this.lang.get('link') + '</label></dt>'
-                                               + '<dd><input type="text" id="redactor-image-link" class="long" aria-label="' + this.lang.get('link') + '"></dd>'
+                                               + '<dt><label for="redactor-image-link">' + WCF.Language.get('wcf.editor.image.link') + '</label></dt>'
+                                               + '<dd>'
+                                                       + '<input type="text" id="redactor-image-link" class="long">'
+                                                       + '<small>' + WCF.Language.get('wcf.editor.image.link.description') + '</small>'
+                                               + '</dd>'
                                        + '</dl>'
+                                       + '<dl>'
+                                               + '<dt><label for="redactor-image-float">' + WCF.Language.get('wcf.editor.image.float') + '</label></dt>'
+                                               + '<dd>'
+                                                       + '<select id="redactor-image-float">'
+                                                               + '<option value="none">' + WCF.Language.get('wcf.global.noSelection') + '</option>'
+                                                               + '<option value="left">' + WCF.Language.get('wcf.editor.image.float.left') + '</option>'
+                                                               + '<option value="right">' + WCF.Language.get('wcf.editor.image.float.right') + '</option>'
+                                                       + '</select>'
+                                                       + '<small>' + WCF.Language.get('wcf.editor.image.float.description') + '</small>'
+                                               + '</dd>'
+                                       + '</dl>'
+                                       + '<input id="redactor-image-title" style="display: none">' /* dummy because redactor expects it to be present */
                                        + '<div class="formSubmit">'
                                                + '<button id="redactor-modal-button-action" class="buttonPrimary">Insert</button>'
                                                + '<button id="redactor-modal-button-delete" class="redactor-modal-button-offset">Delete</button>'
                                        + '</div>'
                                + '</div>';
+               },
+               
+               add: function() {
+                       this.modal.load('image-edit', WCF.Language.get('wcf.editor.image.insert'));
+                       
+                       this.modal.show();
+                       
+                       this.modal.getDeleteButton().hide();
+                       var button = this.modal.getActionButton();
+                       button[0].addEventListener(WCF_CLICK_EVENT, this.WoltLabImage.insert);
+               },
+               
+               insert: function(event) {
+                       event.preventDefault();
+                       
+                       // remove any existing error messages first
+                       this.modal.getModal().find('.innerError').remove();
+                       
+                       var sourceInput = elById('redactor-image-source');
+                       var showError = function(inputElement, message) {
+                               $('<small class="innerError" />').text(message).insertAfter(inputElement);
+                       };
+                       
+                       // check if source is valid
+                       var source = sourceInput.value.trim();
+                       if (source === '') {
+                               return showError(sourceInput, WCF.Language.get('wcf.global.form.error.empty'));
+                       }
+                       else if (!source.match(this.opts.regexps.url)) {
+                               return showError(sourceInput, WCF.Language.get('wcf.editor.image.source.error.invalid'));
+                       }
+                       
+                       // check if link is valid
+                       var linkInput = elById('redactor-image-link');
+                       var link = linkInput.value.trim();
+                       
+                       if (link !== '' && !link.match(this.opts.regexps.url)) {
+                               return showError(linkInput, WCF.Language.get('wcf.editor.image.link.error.invalid'));
+                       }
+                       
+                       var float = elById('redactor-image-float').value, className = '';
+                       if (float === 'left' || float === 'right') {
+                               className = 'messageFloatObject' + WCF.String.ucfirst(float);
+                       }
+                       
+                       var html = '<img src="' + WCF.String.escapeHTML(source) + '"' + (className ? ' class="' + className + '"' : '') + '>';
+                       if (link) {
+                               html = '<a href="' + WCF.String.escapeHTML(link) + '">' + html + '</a>'; 
+                       }
                        
+                       this.modal.close();
+                       this.insert.html(html);
                }
        };
 };
\ No newline at end of file
index 4ff264bac93f4bfba2f90b65fab137a9b5a2d856..741b8990a2930a9c72e0e856601b323918375555 100644 (file)
 .woltlab-size-18 { font-size: 18px; }
 .woltlab-size-24 { font-size: 24px; }
 .woltlab-size-36 { font-size: 36px; }
+
+/* image float */
+.messageFloatObjectLeft {
+       float: left;
+       margin: 0 20px 20px 0;
+}
+
+.messageFloatObjectRight {
+       float: right;
+       margin: 0 0 20px 20px;
+}