Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: shadow dom support #1

Open
wants to merge 1 commit into
base: upstream
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/js/editor/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ export default class Editor implements EditorOptions {
* @return {Boolean}
*/
_hasFocus(): boolean {
return document.activeElement === this.element
return this.root.activeElement === this.element
}

/**
Expand Down Expand Up @@ -1347,4 +1347,18 @@ export default class Editor implements EditorOptions {
}
}
}

get root() {
const root = this.element.getRootNode();

// COMPAT: Only Chrome implements the DocumentOrShadowRoot mixin for
// ShadowRoot; other browsers still implement it on the Document
// interface. (2020/08/08)
// https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot#Properties
if (root.getSelection === undefined && this.element.ownerDocument !== null) {
return this.element.ownerDocument
}

return root
}
}
15 changes: 8 additions & 7 deletions src/js/editor/selection-change-observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,22 @@ class SelectionChangeObserver {
listeners: SelectionChangeListener[]
selection: PartialSelection

constructor() {
constructor({ editor }) {
this.started = false
this.listeners = []
this.selection = {} as PartialSelection
this.editor = editor
}

static getInstance() {
static getInstance({ editor }) {
if (!instance) {
instance = new SelectionChangeObserver()
instance = new SelectionChangeObserver({ editor })
}
return instance
}

static addListener(listener: SelectionChangeListener) {
SelectionChangeObserver.getInstance().addListener(listener)
SelectionChangeObserver.getInstance({ editor: listener.editor }).addListener(listener)
}

addListener(listener: SelectionChangeListener) {
Expand Down Expand Up @@ -74,8 +75,8 @@ class SelectionChangeObserver {
this.listeners = []
}

getSelection(): PartialSelection {
let selection = window.getSelection()!
getSelection(root = window): PartialSelection {
let selection = root.getSelection()!
let { anchorNode, focusNode, anchorOffset, focusOffset } = selection
return { anchorNode, focusNode, anchorOffset, focusOffset }
}
Expand All @@ -93,7 +94,7 @@ class SelectionChangeObserver {

update() {
let prevSelection = this.selection
let curSelection = this.getSelection()!
let curSelection = this.getSelection(this.editor.root)!
if (!this.selectionIsEqual(prevSelection, curSelection)) {
this.selection = curSelection
this.notifyListeners(curSelection, prevSelection)
Expand Down
28 changes: 25 additions & 3 deletions src/js/utils/cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { unwrap, assertNotNull, expect } from './assert'
import { isCardSection } from '../models/card'
import Section from '../models/_section'
import { Type } from '../models/types'
import Browser from './browser';

export { Position, Range }

Expand All @@ -26,7 +27,7 @@ class Cursor {
}

clearSelection() {
clearSelection()
clearSelection(this.editor.root)
}

/**
Expand Down Expand Up @@ -138,7 +139,7 @@ class Cursor {
}

get selection() {
return expect(window.getSelection(), 'expected window selection to not be null')
return expect(this.editor.root.getSelection(), 'expected editor.root selection to not be null')
}

selectedText() {
Expand Down Expand Up @@ -175,7 +176,28 @@ class Cursor {
_hasSelection() {
const element = unwrap(this.editor.element)
const { _selectionRange } = this
if (!_selectionRange || _selectionRange.collapsed) {

// COMPAT: There's a bug in chrome that always returns `true` for
// `isCollapsed` for a Selection that comes from a ShadowRoot.
// (2020/08/08)
// https://bugs.chromium.org/p/chromium/issues/detail?id=447523
let isCollapsed;
const hasShadowRoot = () => {
return !!(
window.document.activeElement && window.document.activeElement.shadowRoot
)
}
if (_selectionRange) {
if (Browser.isChrome() && hasShadowRoot()) {
isCollapsed =
_selectionRange.anchorNode === _selectionRange.focusNode &&
_selectionRange.anchorOffset === _selectionRange.focusOffset
} else {
isCollapsed = _selectionRange.isCollapsed
}
}

if (!_selectionRange || isCollapsed) {
return false
}

Expand Down
4 changes: 2 additions & 2 deletions src/js/utils/selection-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Direction } from './key'
import { isTextNode, isElementNode } from './dom-utils'
import { assertNotNull } from './assert'

export function clearSelection() {
const selection = window.getSelection()
export function clearSelection(root = window) {
const selection = root.getSelection()
selection && selection.removeAllRanges()
}

Expand Down