Experimental work-around for the margin-hit detection in Safari
authorAlexander Ebert <ebert@woltlab.com>
Tue, 6 Feb 2018 15:51:14 +0000 (16:51 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Tue, 6 Feb 2018 15:51:14 +0000 (16:51 +0100)
Fixes #2533

wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabCaret.js
wcfsetup/install/files/style/ui/redactor.scss

index 95d57c2cfadabe06249122408992f7a354e404da..9934f2e8ab364644f534e3637aa061e8aae2a64e 100644 (file)
@@ -1,6 +1,8 @@
 $.Redactor.prototype.WoltLabCaret = function() {
        "use strict";
        
+       var _isSafari = false;
+       
        return {
                init: function () {
                        var mpAfter = this.caret.after;
@@ -15,9 +17,14 @@ $.Redactor.prototype.WoltLabCaret = function() {
                        }).bind(this);
                        
                        var iOS = false;
-                       require(['Environment'], function (Environment) {
+                       require(['Environment'], (function (Environment) {
                                iOS = (Environment.platform() === 'ios');
-                       });
+                               
+                               _isSafari = (Environment.platform() === 'desktop' && Environment.browser() === 'safari');
+                               if (_isSafari) {
+                                       this.core.editor()[0].classList.add('jsSafariMarginClickTarget')
+                               }
+                       }).bind(this));
                        
                        var mpEnd = this.caret.end;
                        this.caret.end = (function (node) {
@@ -309,13 +316,25 @@ $.Redactor.prototype.WoltLabCaret = function() {
                                }
                        }
                        
+                       // Safari moves the caret before triggering the `click` event, causing the
+                       // selection to appear at the first possible text node, even if it is nowhere
+                       // near the click position.
+                       var isSafariMarginHit = false;
+                       if (_isSafari && this.utils.isBlockTag(event.target.nodeName)) {
+                               // check if the click occured inside the margin at the block's bottom
+                               if (event.clientY > event.target.getBoundingClientRect().bottom) {
+                                       block = event.target;
+                                       isSafariMarginHit = true;
+                               }
+                       }
+                       
                        // get block element that received the click
                        var targetBlock = event.target;
                        while (targetBlock && !this.utils.isBlockTag(targetBlock.nodeName)) {
                                targetBlock = targetBlock.parentNode;
                        }
                        
-                       if (!targetBlock || targetBlock === block) {
+                       if (!targetBlock || (!isSafariMarginHit && targetBlock === block)) {
                                return;
                        }
                        
index dd630a1a4650c8999ddd8bf51d52df9feea76352..075264fba410cbc6b2f2c7dbe23905ef447a0269 100644 (file)
                        }
                }
        }
+       
+       /* This is a rather hacky work-around for Safari that makes the bottom margin clickable
+          in order to recognize clicks in between two block elements. See #2533 */
+       &.jsSafariMarginClickTarget {
+               pre,
+               woltlab-quote,
+               woltlab-spoiler {
+                       &::after {
+                               content: "";
+                               height: 1em; // this is the value of `margin-bottom`
+                               left: 0;
+                               position: absolute;
+                               right: 0;
+                               transform: translateY(20px); // this is the value of `padding-bottom`
+                       }
+               }
+               
+               pre::after {
+                       /* parent is `position: relative` */
+                       bottom: 0;
+               }
+       }
 }
 
 .redactor-dropdown {