diff --git a/core/selection.js b/core/selection.js index 93cbd32cfb..be076cf089 100644 --- a/core/selection.js +++ b/core/selection.js @@ -4,6 +4,7 @@ import equal from 'deep-equal'; import Emitter from './emitter'; import logger from './logger'; import './shadow-selection-polyfill'; +import { ShadowSelection } from './shadow-selection-polyfill'; const debug = logger('quill:selection'); @@ -33,9 +34,13 @@ class Selection { setTimeout(this.update.bind(this, Emitter.sources.USER), 1); } }); - this.emitter.on(Emitter.events.SCROLL_BEFORE_UPDATE, () => { + this.emitter.on(Emitter.events.SCROLL_BEFORE_UPDATE, async (_, mutations) => { if (!this.hasFocus()) return; const native = this.getNativeRange(); + // when need to hack the offset on Safari, when we are dealing with the first character of a row + const hackOffset = this.rootDocument.getSelection() instanceof ShadowSelection && + mutations.some((a) => a.type === 'characterData' && a.oldValue === '') && + native.start.offset === native.end.offset; if (native == null) return; if (native.start.node === this.cursor.textNode) return; // cursor.restore() will handle this.emitter.once(Emitter.events.SCROLL_UPDATE, () => { @@ -46,9 +51,9 @@ class Selection { ) { this.setNativeRange( native.start.node, - native.start.offset, + native.start.offset + (hackOffset ? 1 : 0), native.end.node, - native.end.offset, + native.end.offset + (hackOffset ? 1 : 0), ); } this.update(Emitter.sources.SILENT); diff --git a/core/shadow-selection-polyfill.js b/core/shadow-selection-polyfill.js index 3593ee4798..a67c11eeef 100644 --- a/core/shadow-selection-polyfill.js +++ b/core/shadow-selection-polyfill.js @@ -4,7 +4,7 @@ const SUPPORTS_BEFORE_INPUT = typeof window.InputEvent.prototype.getTargetRanges const IS_FIREFOX = window.navigator.userAgent.toLowerCase().indexOf('firefox') > -1; let processing = false; -class ShadowSelection { +export class ShadowSelection { constructor() { this._ranges = []; }