Improved Redactor integration
authorAlexander Ebert <ebert@woltlab.com>
Sun, 30 Mar 2014 11:14:33 +0000 (13:14 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Sun, 30 Mar 2014 11:14:33 +0000 (13:14 +0200)
The biggest change was the transition to use <p> instead of <br> (disabled linebreaks mode), because attempts to style a lonely textnode (with no actual parent element except the editor container) causes a lot of issues.

Furthermore I have started to modify the HTML of Redactor's modal overlays, they (partially) mimic the appearance of WCF's overlays.

com.woltlab.wcf/templates/wysiwyg.tpl
wcfsetup/install/files/js/3rdParty/redactor/plugins/wbbcode.js
wcfsetup/install/files/js/3rdParty/redactor/plugins/wbutton.js
wcfsetup/install/files/js/3rdParty/redactor/plugins/wfontcolor.js
wcfsetup/install/files/js/3rdParty/redactor/plugins/wfontfamily.js [new file with mode: 0644]
wcfsetup/install/files/js/3rdParty/redactor/plugins/wfontsize.js [new file with mode: 0644]
wcfsetup/install/files/js/3rdParty/redactor/plugins/wmonkeypatch.js
wcfsetup/install/files/js/3rdParty/redactor/redactor.css
wcfsetup/install/files/js/3rdParty/redactor/redactor.js
wcfsetup/install/files/style/message.less

index 91903e4b0325c0e4172f1a8eefc3bb032bc2738a..384f49d3accf6574021ed8ec324a6e5fdebbc1b6 100644 (file)
@@ -19,9 +19,8 @@ $(function() {
                var $autosave = $textarea.data('autosave');
                var $config = {
                        buttons: $buttons,
-                       linebreaks: true,
                        minHeight: 200,
-                       plugins: [ 'wutil',  'wmonkeypatch', 'wbutton', 'wbbcode',  'wfontcolor' ],
+                       plugins: [ 'wutil',  'wmonkeypatch', 'wbutton', 'wbbcode',  'wfontcolor', 'wfontfamily', 'wfontsize' ],
                        wautosave: {
                                active: ($autosave) ? true : false,
                                key: ($autosave) ? $autosave : '',
@@ -39,6 +38,8 @@ $(function() {
                '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wbbcode.js',
                '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wbutton.js',
                '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wfontcolor.js',
+               '{@$__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'
                {event name='javascriptFiles'}
index 747f93df8a59e847e5af1fc313219346df0ad086..31cd080b63588e57afd676673d2e0224bd759574 100644 (file)
@@ -105,6 +105,7 @@ RedactorPlugins.wbbcode = {
         */
        toggle: function(direct) {
                if (this.opts.visual) {
+                       this._convertParagraphs();
                        this.toggleCode(direct);
                        this._convertFromHtml();
                        
@@ -137,21 +138,27 @@ RedactorPlugins.wbbcode = {
                return $string;
        },
        
+       _convertParagraphs: function() {
+               this.$editor.find('p').replaceWith(function() {
+                       var $html = $(this).html();
+                       if ($html == '<br>') {
+                               // an empty line is presented by <p><br></p> but in the textarea this equals only a single new line
+                               return $html;
+                       }
+                       
+                       return $html + '<br>';;
+               });
+               this.sync();
+       },
+       
        /**
         * Converts source contents from HTML into BBCode.
         */
        _convertFromHtml: function() {
                var html = this.$source.val();
                
-               if (html == '<br>' || html == '<p><br></p>') {
-                       return "";
-               }
-               
-               // Convert <br> to line breaks.
-               html = html.replace(/<br><\/p>/gi,"\n");
-               html = html.replace(/<br(?=[ \/>]).*?>/gi, '\r\n');
-               html = html.replace(/<p>/gi,"");
-               html = html.replace(/<\/p>/gi,"\n");
+               // drop <br>, they are pointless because the editor already adds a newline after them
+               html = html.replace(/<br>/g, '');
                html = html.replace(/&nbsp;/gi," ");
                
                // [email]
@@ -212,7 +219,9 @@ RedactorPlugins.wbbcode = {
                html = html.replace(/<span style="font-size: ?(\d+)pt;?">([\s\S]*?)<\/span>/gi, "[size=$1]$2[/size]");
                
                // [font]
-               html = html.replace(/<span style="font-family: ?(.*?);?">([\s\S]*?)<\/span>/gi, "[font='$1']$2[/font]");
+               html = html.replace(/<span style="font-family: ?(.*?);?">([\s\S]*?)<\/span>/gi, function(match, fontFamily, text) {
+                       return "[font='" + fontFamily.replace(/'/g, '') + "']" + text + "[/font]";
+               });
                
                // [align]
                html = html.replace(/<div style="text-align: ?(left|center|right|justify);? ?">([\s\S]*?)<\/div>/gi, "[align=$1]$2[/align]");
@@ -275,6 +284,13 @@ RedactorPlugins.wbbcode = {
                // Restore %20
                html = html.replace(/%20/g, ' ');
                
+               // trim leading tabs
+               var $tmp = html.split("\n");
+               for (var $i = 0, $length = $tmp.length; $i < $length; $i++) {
+                       $tmp[$i] = $tmp[$i].replace(/^\s*/, '');
+               }
+               html = $tmp.join("\n");
+               
                this.$source.val(html);
        },
        
@@ -296,9 +312,6 @@ RedactorPlugins.wbbcode = {
                        data = data.replace(/>/g, '&gt;');
                //}
                
-               // Convert line breaks to <br>.
-               data = data.replace(/(?:\r\n|\n|\r)/g, '<br>');
-               
                /*if ($pasted) {
                        $pasted = false;
                        // skip
@@ -396,6 +409,21 @@ RedactorPlugins.wbbcode = {
                // remove "javascript:"
                data = data.replace(/(javascript):/gi, '$1<span></span>:');
                
+               // unify line breaks
+               data = data.replace(/(\r|\r\n)/, "\n");
+               
+               // convert line breaks into <p></p> or empty lines to <p><br></p>
+               var $tmp = data.split("\n");
+               data = '';
+               for (var $i = 0, $length = $tmp.length; $i < $length; $i++) {
+                       var $line = $.trim($tmp[$i]);
+                       if (!$line) {
+                               $line = '<br>';
+                       }
+                       
+                       data += '<p>' + $line + '</p>';
+               }
+               
                // insert codes
                if ($.getLength($cachedCodes)) {
                        for (var $key in $cachedCodes) {
index 4f6bf590decde792632693828a689c5452b03b8d..19338cb0ff0cfbf551a6d194601d3c1df88dfd40 100644 (file)
@@ -24,14 +24,24 @@ RedactorPlugins.wbutton = {
                        this._addBBCodeButton(__REDACTOR_BUTTONS[$i]);
                }
                
+               // this list contains overrides for built-in buttons, if a button is not present
+               // Redactor's own icon will be used instead. This solves the problem of FontAwesome
+               // not providing an icon for everything we need (especially the core stuff)
                var $faIcons = {
-                       'alignment': 'align-left',
-                       'deleted': 'strikethrough',
-                       'html': 'square-o',
-                       'image': 'picture-o',
-                       'orderedlist': 'list-ol',
-                       'smiley': 'smile-o',
-                       'unorderedlist': 'list-ul'
+                       'html': 'fa-square-o',
+                       'bold': 'fa-bold',
+                       'italic': 'fa-italic',
+                       'underline': 'fa-underline',
+                       'deleted': 'fa-strikethrough',
+                       'subscript': 'fa-subscript',
+                       'superscript': 'fa-superscript',
+                       'orderedlist': 'fa-list-ol',
+                       'unorderedlist': 'fa-list-ul',
+                       'outdent': 'fa-outdent',
+                       'indent': 'fa-indent',
+                       'link': 'fa-link',
+                       'alignment': 'fa-align-left',
+                       'table': 'fa-table'
                };
                
                var $buttons = this.getOption('buttons');
@@ -47,26 +57,29 @@ RedactorPlugins.wbutton = {
                        
                        // check if button does not exist
                        var $buttonObj = this.buttonGet($button);
-                       var $className = ($faIcons[$button]) ? $faIcons[$button] : $button;
                        if ($buttonObj.length) {
-                               this.buttonAwesome($button, 'fa-' + $className);
+                               if ($faIcons[$button]) {
+                                       this.buttonAwesome($button, $faIcons[$button]);
+                               }
                        }
                        else {
-                               this._addCoreButton($button, $className, $lastButton);
+                               this._addCoreButton($button, ($faIcons[$button] ? $faIcons[$button] : null), $lastButton);
                        }
                        
                        $lastButton = $button;
                }
        },
        
-       _addCoreButton: function(buttonName, className, insertAfter) {
+       _addCoreButton: function(buttonName, faIcon, insertAfter) {
                var $button = this.buttonBuild(buttonName, {
                        title: buttonName,
                        exec: buttonName
                }, false);
                $('<li />').append($button).insertAfter(this.buttonGet(insertAfter).parent());
                
-               this.buttonAwesome(buttonName, 'fa-' + className);
+               if (faIcon !== null) {
+                       this.buttonAwesome(buttonName, faIcon);
+               }
        },
        
        /**
index fe03e2c9d87b030e945ce5318b253f0201ada2d0..f2468f12b3f26b22c739aca2a5f8b2fe6ee403c2 100644 (file)
@@ -14,9 +14,10 @@ RedactorPlugins.wfontcolor = {
        init: function() {
                this._createFontColorDropdown();
                
-               this.buttonAdd('fontcolor', this.opts.curLang.fontcolor, $.proxy(function(btnName, $button, btnObject, e) {
+               this.buttonReplace('fontcolor', 'fontcolor', this.opts.curLang.fontcolor, $.proxy(function(btnName, $button, btnObject, e) {
                        this.dropdownShow(e, btnName);
-               }, this))
+               }, this));
+               //this.buttonAwesome('fontcolor', 'fa-font');
        },
        
        /**
@@ -55,14 +56,19 @@ RedactorPlugins.wfontcolor = {
        _onColorPick: function(event) {
                event.preventDefault();
                
-               this.bufferSet();
+               //this.bufferSet();
                
-               this.$editor.focus();
-               this.inlineRemoveStyle('color');
+               //this.$editor.focus();
                
-               var $type = $(event.currentTarget).data('color');
-               if ($type !== 'none') this.inlineSetStyle('color', $type);
-               if (this.opts.air) this.$air.fadeOut(100);
-               this.sync();
+               var $color = $(event.currentTarget).data('color');
+               if ($color === 'none') {
+                       this.inlineRemoveStyle('color');
+               }
+               else {
+                       this.inlineSetStyle('color', $color);
+               }
+               
+               /*if (this.opts.air) this.$air.fadeOut(100);
+               this.sync();*/
        }
 };
\ No newline at end of file
diff --git a/wcfsetup/install/files/js/3rdParty/redactor/plugins/wfontfamily.js b/wcfsetup/install/files/js/3rdParty/redactor/plugins/wfontfamily.js
new file mode 100644 (file)
index 0000000..88a1e1c
--- /dev/null
@@ -0,0 +1,57 @@
+if (!RedactorPlugins) var RedactorPlugins = {};
+
+/**
+ * Provides a font family picker, this is actually a heavily modified version of Imperavi's 'fontfamily' plugin.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+RedactorPlugins.wfontfamily = {
+       init: function () {
+               var $fonts = {
+                       'Arial': "Arial, Helvetica, sans-serif",
+                       'Comic Sans MS': "Comic Sans MS, cursive",
+                       'Courier New': "Consolas, Courier New, Courier, monospace",
+                       'Georgia': "Georgia, serif",
+                       'Lucida Sans Unicode': "Lucida Sans Unicode, Lucida Grande, sans-serif",
+                       'Tahoma': "Tahoma, Geneva, sans-serif",
+                       'Times New Roman': "Times New Roman, Times, serif",
+                       'Trebuchet MS': "Trebuchet MS, Helvetica, sans-serif",
+                       'Verdana': "Verdana, Geneva, sans-serif"
+               };
+               
+               var $dropdown = { };
+               var $i = 0;
+               var self = this;
+               $.each($fonts, function(title, value) {
+                       $dropdown['fontFamily' + $i] = {
+                               title: title,
+                               className: 'wfontfamily-' + $i,
+                               callback: function() {
+                                       self.inlineSetStyle('font-family', value);
+                               }
+                       };
+                       
+                       $i++;
+               });
+               $dropdown['separator'] = { name: 'separator' };
+               $dropdown['remove'] = {
+                       title: 'remove font',
+                       callback: function() {
+                               this.inlineRemoveStyle('font-family');
+                       }
+               };
+               
+               this.buttonReplace('fontfamily', 'wfontfamily', 'Change font family', false, $dropdown);
+               this.buttonGet('wfontfamily').addClass('re-fontfamily');
+               
+               // modify dropdown to reflect each font family
+               $dropdown = this.$toolbar.find('.redactor_dropdown_box_wfontfamily');
+               $i = 0;
+               $.each($fonts, function(title, value) {
+                       $dropdown.children('.wfontfamily-' + $i).removeClass('wfontfamily-' + $i).css('font-family', value);
+                       $i++;
+               });
+       }
+};
\ No newline at end of file
diff --git a/wcfsetup/install/files/js/3rdParty/redactor/plugins/wfontsize.js b/wcfsetup/install/files/js/3rdParty/redactor/plugins/wfontsize.js
new file mode 100644 (file)
index 0000000..8704654
--- /dev/null
@@ -0,0 +1,50 @@
+if (!RedactorPlugins) var RedactorPlugins = {};
+
+/**
+ * Provides a font size picker, this is actually a heavily modified version of Imperavi's 'fontsize' plugin.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+RedactorPlugins.wfontsize = {
+       init: function () {
+               var $fontSizes = [ 8, 10, 12, 14, 18, 24, 36 ];
+               
+               var $dropdown = { };
+               var self = this;
+               for (var $i = 0, $length = $fontSizes.length; $i < $length; $i++) {
+                       var $fontSize = $fontSizes[$i];
+                       
+                       $dropdown['fontSize' + $i] = {
+                               title: $fontSize,
+                               className: 'wfontsize-' + $fontSize,
+                               callback: function() {
+                                       self.inlineSetStyle('font-size', $fontSize + 'pt');
+                               }
+                       };
+               }
+               
+               $dropdown['separator'] = { name: 'separator' };
+               $dropdown['remove'] = {
+                       title: 'remove font size',
+                       callback: function() {
+                               this.inlineRemoveStyle('font-size');
+                       }
+               };
+               
+               this.buttonReplace('fontsize', 'wfontsize', 'Change font size', false, $dropdown);
+               this.buttonGet('wfontsize').addClass('re-fontsize');
+               
+               // modify dropdown to reflect each font family
+               $dropdown = this.$toolbar.find('.redactor_dropdown_box_wfontsize');
+               for (var $i = 0, $length = $fontSizes.length; $i < $length; $i++) {
+                       var $fontSize = $fontSizes[$i];
+                       
+                       var $listItem = $dropdown.children('a.wfontsize-' + $fontSize).removeClass('wfontsize-' + $fontSizes).css('font-size', $fontSize + 'pt');
+                       if ($fontSize > 18) {
+                               $listItem.css('line-height', '1em');
+                       }
+               }
+       }
+};
index 431c045a10005c12c00add6f7e61581ac2373184..1c6f9374d5f9c686d887267613e4f7f616e2dfec 100644 (file)
@@ -42,6 +42,17 @@ RedactorPlugins.wmonkeypatch = {
                        
                        self.$source.height($height);
                };
+               
+               var $mpModalInit = this.modalInit;
+               this.modalInit = function(title, content, width, callback) {
+                       self.mpModalInit();
+                       
+                       $mpModalInit.call(self, title, content, width, callback);
+               };
+               
+               this.setOption('modalOpenedCallback', $.proxy(this.modalOpenedCallback, this));
+               
+               this.modalTemplatesInit();
        },
        
        /**
@@ -92,4 +103,135 @@ RedactorPlugins.wmonkeypatch = {
                        }
                }
        },
+       
+       /**
+        * Provides WCF-like overlays.
+        */
+       modalTemplatesInit: function() {
+               this.setOption('modal_image',
+                       '<fieldset>'
+                               + '<dl>'
+                                       + '<dt><label for="redactor_file_link">' + this.opts.curLang.image_web_link + '</label></dt>'
+                                       + '<dd><input type="text" name="redactor_file_link" id="redactor_file_link" class="long"  /></dd>'
+                               + '</dl>'
+                       + '</fieldset>'
+                       + '<div class="formSubmit">'
+                               + '<button id="redactor_upload_btn">' + this.opts.curLang.insert + '</button>'
+                       + '</div>'
+               );
+               
+               this.setOption('modal_table',
+                       '<fieldset>'
+                               + '<dl>'
+                                       + '<dt><label for="redactor_table_rows">' + this.opts.curLang.rows + '</label></dt>'
+                                       + '<dd><input type="number" size="5" value="2" min="0" id="redactor_table_rows" class="tiny" /></dd>'
+                               + '</dl>'
+                               + '<dl>'
+                                       + '<dt><label for="redactor_table_columns">' + this.opts.curLang.columns + '</label></dt>'
+                                       + '<dd><input type="number" size="5" value="3" min="0" id="redactor_table_columns" class="tiny" /></dd>'
+                               + '</dl>'
+                       + '</fieldset>'
+                       + '<div class="formSubmit">'
+                               + '<button id="redactor_insert_table_btn">' + this.opts.curLang.insert + '</button>'
+                       + '</div>'
+               );
+               
+               $.extend( this.opts, {
+                       modal_file: String()
+                       + '<section id="redactor-modal-file-insert">'
+                               + '<div id="redactor-progress" class="redactor-progress-inline" style="display: none;"><span></span></div>'
+                               + '<form id="redactorUploadFileForm" method="post" action="" enctype="multipart/form-data">'
+                                       + '<label>' + this.opts.curLang.filename + '</label>'
+                                       + '<input type="text" id="redactor_filename" class="redactor_input" />'
+                                       + '<div style="margin-top: 7px;">'
+                                               + '<input type="file" id="redactor_file" name="' + this.opts.fileUploadParam + '" />'
+                                       + '</div>'
+                               + '</form>'
+                       + '</section>',
+
+                       modal_image_edit: String()
+                       + '<section id="redactor-modal-image-edit">'
+                               + '<label>' + this.opts.curLang.title + '</label>'
+                               + '<input type="text" id="redactor_file_alt" class="redactor_input" />'
+                               + '<label>' + this.opts.curLang.link + '</label>'
+                               + '<input type="text" id="redactor_file_link" class="redactor_input" />'
+                               + '<label><input type="checkbox" id="redactor_link_blank"> ' + this.opts.curLang.link_new_tab + '</label>'
+                               + '<label>' + this.opts.curLang.image_position + '</label>'
+                               + '<select id="redactor_form_image_align">'
+                                       + '<option value="none">' + this.opts.curLang.none + '</option>'
+                                       + '<option value="left">' + this.opts.curLang.left + '</option>'
+                                       + '<option value="center">' + this.opts.curLang.center + '</option>'
+                                       + '<option value="right">' + this.opts.curLang.right + '</option>'
+                               + '</select>'
+                       + '</section>'
+                       + '<footer>'
+                               + '<button id="redactor_image_delete_btn" class="redactor_modal_btn redactor_modal_delete_btn">' + this.opts.curLang._delete + '</button>'
+                               + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>'
+                               + '<button id="redactorSaveBtn" class="redactor_modal_btn redactor_modal_action_btn">' + this.opts.curLang.save + '</button>'
+                       + '</footer>',
+
+                       // img
+
+                       modal_link: String()
+                       + '<section id="redactor-modal-link-insert">'
+                               + '<label>URL</label>'
+                               + '<input type="text" class="redactor_input" id="redactor_link_url" />'
+                               + '<label>' + this.opts.curLang.text + '</label>'
+                               + '<input type="text" class="redactor_input" id="redactor_link_url_text" />'
+                               + '<label><input type="checkbox" id="redactor_link_blank"> ' + this.opts.curLang.link_new_tab + '</label>'
+                       + '</section>'
+                       + '<footer>'
+                               + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>'
+                               + '<button id="redactor_insert_link_btn" class="redactor_modal_btn redactor_modal_action_btn">' + this.opts.curLang.insert + '</button>'
+                       + '</footer>',
+                       
+                       modal_video: String()
+                       + '<section id="redactor-modal-video-insert">'
+                               + '<form id="redactorInsertVideoForm">'
+                                       + '<label>' + this.opts.curLang.video_html_code + '</label>'
+                                       + '<textarea id="redactor_insert_video_area" style="width: 99%; height: 160px;"></textarea>'
+                               + '</form>'
+                       + '</section>'
+                       + '<footer>'
+                               + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>'
+                               + '<button id="redactor_insert_video_btn" class="redactor_modal_btn redactor_modal_action_btn">' + this.opts.curLang.insert + '</button>'
+                       + '</footer>'
+
+               });
+       },
+       
+       mpModalInit: function() {
+               // modal overlay
+               if (!$('#redactor_modal_overlay').length) {
+                       this.$overlay = $('<div id="redactor_modal_overlay" class="dialogOverlay" />').css({ height: '100%', zIndex: 50000 }).hide().appendTo(document.body);
+               }
+               
+               if (!$('#redactor_modal').length) {
+                       this.$modal = $('<div id="redactor_modal" class="dialogContainer" />').css({ display: 'none', zIndex: 50001 }).appendTo(document.body);
+                       $('<header class="dialogTitlebar"><span id="redactor_modal_header" class="dialogTitle" /><a id="redactor_modal_close" class="dialogCloseButton" /></header>').appendTo(this.$modal);
+                       $('<div class="dialogContent"><div id="redactor_modal_inner" /></div>').appendTo(this.$modal);
+               }
+               
+               this.$modal.children('.dialogContent').removeClass('dialogForm');
+       },
+       
+       modalOpenedCallback: function() {
+               // handle positioning of form submit controls
+               var $heightDifference = 0;
+               if (this.$modal.find('.formSubmit').length) {
+                       $heightDifference = this.$modal.find('.formSubmit').outerHeight();
+                       
+                       this.$modal.children('.dialogContent').addClass('dialogForm').css({ marginBottom: $heightDifference + 'px' });
+               }
+               else {
+                       this.$modal.children('.dialogContent').removeClass('dialogForm').css({ marginBottom: '0px' });
+               }
+               
+               // fix position
+               var $dimensions = this.$modal.getDimensions('outer');
+               this.$modal.css({
+                       marginLeft: -1 * Math.round($dimensions.width / 2) + 'px',
+                       marginTop: -1 * Math.round($dimensions.height / 2) + 'px'
+               });
+       }
 }
\ No newline at end of file
index 074abff8a674835d316a2968d30ae27b62d1c3c5..3da3de1c2cf37046f8c769757144cd83aada16c0 100644 (file)
@@ -188,6 +188,11 @@ body .redactor_box_fullscreen {
   background: none !important;
   box-shadow: none !important;
 }
+
+.redactor_editor p {
+  margin-bottom: 0 !important;
+}
+
 .redactor_editor iframe,
 .redactor_editor object,
 .redactor_editor hr {
@@ -685,7 +690,7 @@ body .redactor_air .redactor_toolbar {
 /*
        MODAL
 */
-#redactor_modal_overlay {
+/*#redactor_modal_overlay {
   position: fixed;
   top: 0;
   left: 0;
@@ -780,7 +785,7 @@ body .redactor_air .redactor_toolbar {
 }
 #redactor_modal_close:hover {
   color: #000;
-}
+}*/
 .redactor_input {
   width: 99%;
   font-size: 14px;
index 73665de1b1da7e28430ff6bd6af05e4f0d0bda50..8f1e5dd092f385444fe4681011943b85711de58a 100644 (file)
 
                        if ((range.collapsed || range.startContainer === range.endContainer) && el && !this.nodeTestBlocks(el))
                        {
+                       console.debug("1");
                                $(el)[type](attr, value);
                        }
                        else
                        {
+                       console.debug("2");
                                this.document.execCommand('fontSize', false, 4 );
 
                                var fonts = this.$editor.find('font');
index 383ad85302ded68f4125bb22993e6890e67b8c17..d127b7b4993115196de4778d9a87015955b4088a 100644 (file)
@@ -937,7 +937,7 @@ li:nth-child(2n+1) .message {
        }
        
        > li {
-               &:last-child,
+               &:last-of-type,
                &.separator {
                        border-right: 1px solid @wcfButtonBorderColor;
                }
@@ -968,7 +968,7 @@ li:nth-child(2n+1) .message {
                                }
                        }
                        
-                       &.re-icon:before {
+                       &.fa-redactor-btn:before {
                                content: "";
                        }
                }