From: Alexander Ebert Date: Fri, 9 Mar 2018 10:54:30 +0000 (+0100) Subject: Work-around for iOS Safari's missing event delegation X-Git-Tag: 3.1.1~16 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=5f4e956273777016285003e90c06396e060e49c4;p=GitHub%2FWoltLab%2FWCF.git Work-around for iOS Safari's missing event delegation --- diff --git a/wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabCaret.js b/wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabCaret.js index 693ba9bdc4..38fb43493d 100644 --- a/wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabCaret.js +++ b/wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabCaret.js @@ -1,7 +1,9 @@ $.Redactor.prototype.WoltLabCaret = function() { "use strict"; + var _iOS = false; var _isSafari = false; + var _touchstartTarget; return { init: function () { @@ -16,14 +18,32 @@ $.Redactor.prototype.WoltLabCaret = function() { mpAfter.call(this, node); }).bind(this); - var iOS = false; + var editor = this.core.editor()[0]; require(['Environment'], (function (Environment) { - iOS = (Environment.platform() === 'ios'); + _iOS = (Environment.platform() === 'ios'); + _isSafari = (Environment.browser() === 'safari'); - _isSafari = (Environment.platform() === 'desktop' && Environment.browser() === 'safari'); if (_isSafari) { - this.core.editor()[0].classList.add('jsSafariMarginClickTarget') + editor.classList.add('jsSafariMarginClickTarget'); } + + var handleEditorClick = this.WoltLabCaret._handleEditorClick.bind(this); + var handleEditorMouseUp = this.WoltLabCaret._handleEditorMouseUp.bind(this); + if (_isSafari && _iOS) { + editor.addEventListener('touchstart', function(e) { + _touchstartTarget = e.target; + }, { passive: true }); + + editor.addEventListener('touchend', (function (event) { + handleEditorClick(event); + handleEditorMouseUp(event); + }).bind(this)); + } + else { + editor.addEventListener(WCF_CLICK_EVENT, handleEditorClick); + editor.addEventListener('mouseup', handleEditorMouseUp); + } + }).bind(this)); var mpEnd = this.caret.end; @@ -41,7 +61,7 @@ $.Redactor.prototype.WoltLabCaret = function() { if (node.nodeType === Node.ELEMENT_NODE && node.lastChild && node.lastChild.nodeName === 'P') { useCustomRange = true; } - else if (iOS) { + else if (_iOS) { var editor = this.core.editor()[0]; if (node.parentNode === editor && editor.innerHTML === '


') { useCustomRange = true; @@ -82,9 +102,6 @@ $.Redactor.prototype.WoltLabCaret = function() { return returnValues; }).bind(this); - this.$editor[0].addEventListener(WCF_CLICK_EVENT, this.WoltLabCaret._handleEditorClick.bind(this)); - this.$editor[0].addEventListener('mouseup', this.WoltLabCaret._handleEditorMouseUp.bind(this)); - this.WoltLabCaret._initInternalRange(); var mpSaveInstant = this.selection.saveInstant; @@ -395,9 +412,18 @@ $.Redactor.prototype.WoltLabCaret = function() { }, _handleEditorClick: function (event) { + var clientY = event.clientY; if (!this.selection.get().isCollapsed) { - // ignore text selection - return; + if (_isSafari && _iOS && _touchstartTarget === event.target && this.utils.isBlockTag(_touchstartTarget.nodeName)) { + // Treat this as a collapsed selection instead, because the iOS Safari + // breaks event delegation and refuses to trigger click-style events + // for non-link/non-input elements. Thanks Apple. + clientY = event.changedTouches[0].clientY; + } + else { + // ignore text selection + return; + } } var block = this.selection.block(); @@ -422,7 +448,7 @@ $.Redactor.prototype.WoltLabCaret = function() { 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) { + if (clientY > event.target.getBoundingClientRect().bottom) { block = event.target; isSafariMarginHit = true; } @@ -465,11 +491,11 @@ $.Redactor.prototype.WoltLabCaret = function() { while (parent) { rect = parent.getBoundingClientRect(); - if (event.clientY < rect.top) { + if (clientY < rect.top) { insertBefore = true; block = parent; } - else if (event.clientY > rect.bottom) { + else if (clientY > rect.bottom) { insertBefore = false; block = parent; } @@ -511,7 +537,16 @@ $.Redactor.prototype.WoltLabCaret = function() { var anchorNode, sibling; var selection = window.getSelection(); - if (!selection.isCollapsed) return; + if (!selection.isCollapsed) { + if (_isSafari && _iOS && _touchstartTarget === event.target && this.utils.isBlockTag(_touchstartTarget.nodeName)) { + // Treat this as a collapsed selection instead, because the iOS Safari + // breaks event delegation and refuses to trigger click-style events + // for non-link/non-input elements. Thanks Apple. + } + else { + return; + } + } // click occured inside the editor padding if (event.target === this.$editor[0]) { diff --git a/wcfsetup/install/files/style/ui/redactor.scss b/wcfsetup/install/files/style/ui/redactor.scss index 075264fba4..8f335532bf 100644 --- a/wcfsetup/install/files/style/ui/redactor.scss +++ b/wcfsetup/install/files/style/ui/redactor.scss @@ -123,7 +123,14 @@ left: 0; position: absolute; right: 0; - transform: translateY(20px); // this is the value of `padding-bottom` + + @include screen-md-up { + transform: translateY(20px); // this is the value of `padding-bottom` + } + + @include screen-sm-down { + transform: translateY(10px); // this is the value of `padding-bottom` + } } }