From fe840a2f93b75c7949238ba9927ab1aa88bdf94b Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Thu, 21 Jun 2018 11:03:41 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Koenig=20-=20Fixed=20caption/emb?= =?UTF-8?q?ed=20inputs=20in=20Firefox=20&=20Safari?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refs https://github.com/TryGhost/Ghost/issues/9623 - disable `contenteditable` on the main editor element when an input in a card gains focus - Firefox chokes on inputs inside a `contenteditable` element - use a MutationObserver inside `{{koenig-card}}` to automatically add event handlers for focus/blur events so that each card is not required to set up handlers and enable/disable content editable manually - bump Spirit dependency - remove `user-select: none` styling from `.form-text` for text inputs - fixes captions and embed inputs in Safari and improves behaviour in Firefox - add a guard around `getSelection(0)` in the `_scrollCursorIntoView()` method to avoid Safari throwing errors --- .../addon/components/koenig-caption-input.js | 4 +- .../addon/components/koenig-card-embed.js | 1 + .../addon/components/koenig-card.js | 82 +++++++++++++++++++ .../addon/components/koenig-editor.js | 6 +- package.json | 2 +- yarn.lock | 6 +- 6 files changed, 95 insertions(+), 6 deletions(-) diff --git a/lib/koenig-editor/addon/components/koenig-caption-input.js b/lib/koenig-editor/addon/components/koenig-caption-input.js index d7f76ce072..3a440a00ad 100644 --- a/lib/koenig-editor/addon/components/koenig-caption-input.js +++ b/lib/koenig-editor/addon/components/koenig-caption-input.js @@ -16,7 +16,9 @@ export default Component.extend({ _keydownHandler: null, update() {}, - onDidInsertElement() {}, + addParagraphAfterCard() {}, + moveCursorToNextSection() {}, + moveCursorToPrevSection() {}, figCaptionClass: computed(function () { return `${kgStyle(['figcaption'])} w-100`; diff --git a/lib/koenig-editor/addon/components/koenig-card-embed.js b/lib/koenig-editor/addon/components/koenig-card-embed.js index 11aa17376b..697c846d3b 100644 --- a/lib/koenig-editor/addon/components/koenig-card-embed.js +++ b/lib/koenig-editor/addon/components/koenig-card-embed.js @@ -78,6 +78,7 @@ export default Component.extend({ } if (event.key === 'Escape') { + event.target.blur(); this.deleteCard(); } }, diff --git a/lib/koenig-editor/addon/components/koenig-card.js b/lib/koenig-editor/addon/components/koenig-card.js index ef851d8ebd..7b7e52e639 100644 --- a/lib/koenig-editor/addon/components/koenig-card.js +++ b/lib/koenig-editor/addon/components/koenig-card.js @@ -112,6 +112,11 @@ export default Component.extend({ didInsertElement() { this._super(...arguments); this._setToolbarProperties(); + this._createMutationObserver( + this.element, + run.bind(this, this._inputFocus), + run.bind(this, this._inputBlur) + ); }, willDestroyElement() { @@ -119,6 +124,14 @@ export default Component.extend({ window.removeEventListener('keydown', this._onKeydownHandler); window.removeEventListener('click', this._onClickHandler); this._removeMousemoveHandler(); + + if (this._mutationObserver) { + this._mutationObserver.disconnect(); + } + + if (this._hasDisabledContenteditable) { + this.editor.element.contentEditable = true; + } }, mouseDown(event) { @@ -280,5 +293,74 @@ export default Component.extend({ } else { run.scheduleOnce('afterRender', this, method); } + }, + + // Firefox can't handle inputs inside of a contenteditable element so we + // need to watch for any inputs being added so that we can attach focus/blur + // event handlers that can disable contenteditable on the editor element + _createMutationObserver(target, focusCallback, blurCallback) { + function addInputFocusListeners(mutation) { + function addInputFocusListener(element) { + if (!inputElements.includes(element)) { + inputElements.push(element); + element.addEventListener('focus', focusCallback, false); + element.addEventListener('blur', blurCallback, false); + } + } + + if (mutation.type === 'childList') { + Array.prototype.forEach.call( + mutation.target.querySelectorAll('input[type="text"]'), + addInputFocusListener + ); + } + } + + function removeFromElements(element) { + inputElements.splice(inputElements.indexOf(element), 1); + } + + function removeInputFocusListener(element) { + element.removeEventListener('focus', focusCallback, false); + element.removeEventListener('blur', blurCallback, false); + removeFromElements(element); + } + + function mutationObserved(mutations) { + mutations.forEach(addInputFocusListeners); + } + + function createMutationObserver(target) { + let config = { + childList: true, + subtree: true + }; + + let observer = new MutationObserver(mutationObserved); + observer.observe(target, config); // eslint-disable-line ghost/ember/no-observers + return observer; + } + + let inputElements = []; + let observer = createMutationObserver(target); + + return { + disconnect() { + if ('disconnect' in observer) { + observer.disconnect(); // eslint-disable-line ghost/ember/no-observers + inputElements.forEach(removeInputFocusListener); + } + } + }; + }, + + _inputFocus() { + this._hasDisabledContenteditable = true; + this.editor.element.contentEditable = false; + }, + + _inputBlur() { + this._hasDisabledContenteditable = false; + this.editor.element.contentEditable = true; } }); diff --git a/lib/koenig-editor/addon/components/koenig-editor.js b/lib/koenig-editor/addon/components/koenig-editor.js index 4a776e869d..ce6f6af610 100644 --- a/lib/koenig-editor/addon/components/koenig-editor.js +++ b/lib/koenig-editor/addon/components/koenig-editor.js @@ -1065,7 +1065,11 @@ export default Component.extend({ let {range} = this.editor; let selection = window.getSelection(); - let windowRange = selection && selection.getRangeAt(0); + let windowRange; + // Safari can throw an IndexSizeError from selection.getRangeAt(0) + if (selection.type !== 'None') { + windowRange = selection && selection.getRangeAt(0); + } let element = range.head && range.head.section && range.head.section.renderNode && range.head.section.renderNode.element; // prevent scroll jumps when a card is selected diff --git a/package.json b/package.json index 447ea79b6a..a0f1aad4e2 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "eslint": "4.19.1", "eslint-plugin-ghost": "0.0.25", "fs-extra": "4.0.3", - "ghost-spirit": "0.0.24", + "ghost-spirit": "0.0.25", "glob": "7.1.2", "google-caja-bower": "https://github.com/acburdine/google-caja-bower#ghost", "grunt": "1.0.3", diff --git a/yarn.lock b/yarn.lock index 9170c4189d..1231cdf177 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5182,9 +5182,9 @@ ghost-ignition@^2.7.0: prettyjson "^1.1.3" uuid "^3.0.0" -ghost-spirit@0.0.24: - version "0.0.24" - resolved "https://registry.yarnpkg.com/ghost-spirit/-/ghost-spirit-0.0.24.tgz#004ab09fcbc7b0ff3db6f769b66a5d6b892a4c90" +ghost-spirit@0.0.25: + version "0.0.25" + resolved "https://registry.yarnpkg.com/ghost-spirit/-/ghost-spirit-0.0.25.tgz#dc9ff150b18002da2b554d71620d4f7ff1b911d7" dependencies: autoprefixer "8.2.0" bluebird "^3.4.6"