Skip to content

Commit 053c878

Browse files
committed
Add getSelection() polyfill for Safari shadow DOM
1 parent 2186896 commit 053c878

3 files changed

Lines changed: 21 additions & 7 deletions

File tree

core/emitter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import logger from './logger';
33

44
let debug = logger('quill:events');
55

6-
const EVENTS = ['selectionchange', 'mousedown', 'mouseup', 'click'];
6+
const EVENTS = ['-shadow-selectionchange', 'mousedown', 'mouseup', 'click'];
77
const EMITTERS = [];
88
const supportsRootNode = ('getRootNode' in document);
99

core/selection.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import clone from 'clone';
33
import equal from 'deep-equal';
44
import Emitter from './emitter';
55
import logger from './logger';
6+
import * as shadow from 'shadow-selection-polyfill';
67

78
let debug = logger('quill:selection');
89

@@ -28,7 +29,7 @@ class Selection {
2829
this.lastRange = this.savedRange = new Range(0, 0);
2930
this.handleComposition();
3031
this.handleDragging();
31-
this.emitter.listenDOM('selectionchange', this.rootDocument, () => {
32+
this.emitter.listenDOM('-shadow-selectionchange', document, () => {
3233
if (!this.mouseDown) {
3334
setTimeout(this.update.bind(this, Emitter.sources.USER), 1);
3435
}
@@ -158,9 +159,21 @@ class Selection {
158159
}
159160

160161
getNativeRange() {
161-
let selection = this.rootDocument.getSelection();
162-
if (selection == null || selection.rangeCount <= 0) return null;
163-
let nativeRange = selection.getRangeAt(0);
162+
let nativeRange;
163+
164+
// in Safari and iOS we need to use shadow selection polyfill
165+
const ua = navigator.userAgent;
166+
const isSafari = /^((?!chrome|android).)*safari/i.test(ua) || /iPad|iPhone/.test(ua);
167+
const hasShadowWithNoSelection = this.rootDocument instanceof ShadowRoot && !this.rootDocument.getSelection;
168+
169+
if (hasShadowWithNoSelection && isSafari) {
170+
nativeRange = shadow.getRange();
171+
} else {
172+
let selection = this.rootDocument.getSelection();
173+
if (selection == null || selection.rangeCount <= 0) return null;
174+
nativeRange = selection.getRangeAt(0);
175+
}
176+
164177
if (nativeRange == null) return null;
165178
let range = this.normalizeNative(nativeRange);
166179
debug.info('getNativeRange', range);
@@ -269,7 +282,7 @@ class Selection {
269282
if (startNode != null && (this.root.parentNode == null || startNode.parentNode == null || endNode.parentNode == null)) {
270283
return;
271284
}
272-
let selection = this.rootDocument.getSelection();
285+
let selection = typeof this.rootDocument.getSelection === 'function' ? this.rootDocument.getSelection() : document.getSelection();
273286
if (selection == null) return;
274287
if (startNode != null) {
275288
if (!this.hasFocus()) this.root.focus();

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
"eventemitter3": "^2.0.3",
3838
"extend": "^3.0.1",
3939
"parchment": "^1.1.4",
40-
"quill-delta": "^3.6.2"
40+
"quill-delta": "^3.6.2",
41+
"shadow-selection-polyfill": "^1.0.0"
4142
},
4243
"devDependencies": {
4344
"babel-core": "^6.26.0",

0 commit comments

Comments
 (0)