Skip to content

Commit fedf8be

Browse files
committed
Active element handling updated to work in shadow DOM.
1 parent 3c1d883 commit fedf8be

File tree

15 files changed

+41
-17
lines changed

15 files changed

+41
-17
lines changed

packages/ckeditor5-ckbox/src/ckboxcommand.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ export default class CKBoxCommand extends Command {
202202
}
203203

204204
// TODO ShadowRoot
205+
// - can we append it to the body collection?
206+
// - does CKBox support Shadow DOM?
205207
this._wrapper = createElement( document, 'div', { class: 'ck ckbox-wrapper' } );
206208
document.body.appendChild( this._wrapper );
207209

packages/ckeditor5-ckbox/src/ckboximageedit/ckboximageeditcommand.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ export default class CKBoxImageEditCommand extends Command {
109109
}
110110

111111
// TODO ShadowRoot
112+
// - can we append it to the body collection?
113+
// - does CKBox support Shadow DOM?
112114
const wrapper = createElement( document, 'div', { class: 'ck ckbox-wrapper' } );
113115

114116
this._wrapper = wrapper;

packages/ckeditor5-clipboard/src/dragdrop.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,8 @@ export default class DragDrop extends Plugin {
670670
} );
671671

672672
// TODO ShadowRoot
673+
// - can we append it to the body collection?
674+
// - is the preview generated correctly in the Shadow DOM
673675
global.document.body.appendChild( this._previewContainer );
674676
} else if ( this._previewContainer.firstElementChild ) {
675677
this._previewContainer.removeChild( this._previewContainer.firstElementChild );

packages/ckeditor5-clipboard/src/dragdropblocktoolbar.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ export default class DragDropBlockToolbar extends Plugin {
6868
const element = blockToolbar.buttonView.element!;
6969

7070
this._domEmitter.listenTo( element, 'dragstart', ( evt, data ) => this._handleBlockDragStart( data ) );
71+
7172
// TODO ShadowRoot
73+
// - those events will propagate across the shadow DOM boundary (bubbles and composed flags set)
7274
this._domEmitter.listenTo( global.document, 'dragover', ( evt, data ) => this._handleBlockDragging( data ) );
7375
this._domEmitter.listenTo( global.document, 'drop', ( evt, data ) => this._handleBlockDragging( data ) );
7476
this._domEmitter.listenTo( global.document, 'dragend', () => this._handleBlockDragEnd(), { useCapture: true } );
@@ -133,7 +135,10 @@ export default class DragDropBlockToolbar extends Plugin {
133135

134136
let target = document.elementFromPoint( clientX, clientY );
135137

136-
// TODO ShadowRoot - this is a workaround, works this way only in open shadow root
138+
// TODO ShadowRoot
139+
// - this is a workaround, works this way only in open shadow root
140+
// - we should use map of known shadow roots and not depend on the shadowRoot property (it's there only for open mode)
141+
// - the ShadowRoot#elementFromPoint() is non-standard but available in all browsers.
137142
if ( target && target.shadowRoot && target.shadowRoot.elementFromPoint ) {
138143
target = target.shadowRoot.elementFromPoint( clientX, clientY );
139144
}

packages/ckeditor5-clipboard/src/dragdroptarget.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,8 @@ function findScrollableElement( domNode: HTMLElement ): HTMLElement {
521521
let domElement: HTMLElement = domNode;
522522

523523
do {
524+
// TODO ShadowRoot
525+
// - use helper for easier parent element access
524526
domElement = domElement.parentNode instanceof ShadowRoot ?
525527
domElement.parentNode.host as HTMLElement :
526528
domElement.parentElement!;

packages/ckeditor5-engine/src/view/domconverter.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,8 @@ export default class DomConverter {
10911091
public focus( viewEditable: EditableElement ): void {
10921092
const domEditable = this.mapViewToDom( viewEditable );
10931093

1094-
if ( domEditable && domEditable.ownerDocument.activeElement !== domEditable ) {
1094+
// TODO ShadowRoot
1095+
if ( domEditable && domEditable.getRootNode().activeElement !== domEditable ) {
10951096
// Save the scrollX and scrollY positions before the focus.
10961097
const { scrollX, scrollY } = global.window;
10971098
const scrollPositions: Array<[ number, number ]> = [];
@@ -1850,7 +1851,7 @@ function forEachDomElementAncestor( element: DomElement, callback: ( node: DomEl
18501851

18511852
while ( node ) {
18521853
callback( node );
1853-
node = node.parentElement;
1854+
node = node.parentElement; // TODO ShadowRoot
18541855
}
18551856
}
18561857

packages/ckeditor5-engine/src/view/observer/selectionobserver.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ export default class SelectionObserver extends Observer {
115115
* @inheritDoc
116116
*/
117117
public override observe( domElement: HTMLElement ): void {
118-
const domDocument = domElement.ownerDocument;
119-
120118
const startDocumentIsSelecting = () => {
121119
this.document.isSelecting = true;
122120

@@ -131,7 +129,7 @@ export default class SelectionObserver extends Observer {
131129

132130
// Make sure that model selection is up-to-date at the end of selecting process.
133131
// Sometimes `selectionchange` events could arrive after the `mouseup` event and that selection could be already outdated.
134-
this._handleSelectionChange( domDocument );
132+
this._handleSelectionChange( domElement );
135133

136134
this.document.isSelecting = false;
137135

@@ -147,16 +145,19 @@ export default class SelectionObserver extends Observer {
147145
this.listenTo( domElement, 'keydown', endDocumentIsSelecting, { priority: 'highest', useCapture: true } );
148146
this.listenTo( domElement, 'keyup', endDocumentIsSelecting, { priority: 'highest', useCapture: true } );
149147

148+
const domDocument = domElement.ownerDocument;
149+
150150
// Add document-wide listeners only once. This method could be called for multiple editing roots.
151-
// TODO ShadowRoot
152151
if ( this._documents.has( domDocument ) ) {
153152
return;
154153
}
155154

156155
// This listener is using capture mode to make sure that selection is upcasted before any other
157156
// handler would like to check it and update (for example table multi cell selection).
157+
// TODO ShadowRoot - this event will propagate across the shadow DOM boundary (bubbles and composed flags set)
158158
this.listenTo( domDocument, 'mouseup', endDocumentIsSelecting, { priority: 'highest', useCapture: true } );
159159

160+
// TODO ShadowRoot - this event is always fired from the document, even inside a Shadow DOM.
160161
this.listenTo( domDocument, 'selectionchange', ( evt, domEvent ) => {
161162
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
162163
// @if CK_DEBUG_TYPING // _debouncedLine();
@@ -182,6 +183,7 @@ export default class SelectionObserver extends Observer {
182183
return;
183184
}
184185

186+
// TODO ShadowRoot - this will not work if separate roots are in separate shadow DOMs
185187
this._handleSelectionChange( domElement );
186188

187189
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
@@ -207,7 +209,8 @@ export default class SelectionObserver extends Observer {
207209
// @if CK_DEBUG_TYPING // );
208210
// @if CK_DEBUG_TYPING // }
209211

210-
this._handleSelectionChange( domDocument );
212+
// TODO ShadowRoot - this will not work if separate roots are in separate shadow DOMs
213+
this._handleSelectionChange( domElement );
211214

212215
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
213216
// @if CK_DEBUG_TYPING // console.groupEnd();
@@ -248,14 +251,14 @@ export default class SelectionObserver extends Observer {
248251
* a selection changes and fires {@link module:engine/view/document~Document#event:selectionChange} event on every change
249252
* and {@link module:engine/view/document~Document#event:selectionChangeDone} when a selection stop changing.
250253
*
251-
* @param domDocument DOM document.
254+
* @param domElement DOM element.
252255
*/
253-
private _handleSelectionChange( domDocument: Document ) {
256+
private _handleSelectionChange( domElement: HTMLElement ) {
254257
if ( !this.isEnabled ) {
255258
return;
256259
}
257260

258-
const domSelection = getSelection( domDocument )!;
261+
const domSelection = getSelection( domElement )!;
259262

260263
if ( this.checkShouldIgnoreEventFromTarget( domSelection.anchorNode! ) ) {
261264
return;

packages/ckeditor5-engine/src/view/renderer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,7 @@ export default class Renderer extends /* #__PURE__ */ ObservableMixin() {
10951095
const domSelection = doc.getSelection()!;
10961096

10971097
if ( domSelection.rangeCount ) {
1098+
// TODO ShadowRoot - the activeElement of the closest ShadowRoot?
10981099
const activeDomElement = doc.activeElement!;
10991100
const viewElement = this.domConverter.mapDomToView( activeDomElement as DomElement );
11001101

packages/ckeditor5-ui/src/bindings/clickoutsidehandler.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ export default function clickOutsideHandler(
4242

4343
// Check if `composedPath` is `undefined` in case the browser does not support native shadow DOM.
4444
// Can be removed when all supported browsers support native shadow DOM.
45-
// TODO ShadowRoot This won't work for closed shadow root.
46-
// We probably should listen to all shadow roots we know of and have access to.
45+
// TODO ShadowRoot
46+
// - This won't work for closed shadow root.
47+
// - We probably should listen to all shadow roots we know of and have access to.
4748
const path = typeof domEvt.composedPath == 'function' ? domEvt.composedPath() : [];
4849

4950
const contextElementsList = typeof contextElements == 'function' ? contextElements() : contextElements;

packages/ckeditor5-ui/src/dropdown/menu/dropdownmenunestedmenuview.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,6 @@ export default class DropdownMenuNestedMenuView extends View implements Focusabl
303303
keystrokes.listenTo( panelView.element! );
304304
panelView.pin( {
305305
positions: this._panelPositions,
306-
// TODO ShadowRoot
307306
limiter: global.document.body,
308307
element: panelView.element!,
309308
target: buttonView.element!,

packages/ckeditor5-ui/src/dropdown/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -606,8 +606,8 @@ function focusDropdownButtonOnClose( dropdownView: DropdownView ) {
606606
// If the dropdown was closed, move the focus back to the button (#12125).
607607
// Don't touch the focus, if it moved somewhere else (e.g. moved to the editing root on #execute) (#12178).
608608
// Note: Don't use the state of the DropdownView#focusTracker here. It fires #blur with the timeout.
609-
// TODO ShadowRoot
610-
if ( elements.some( element => element.contains( global.document.activeElement ) ) ) {
609+
// TODO ShadowRoot - the activeElement is valid for the closest ShadowRoot
610+
if ( elements.some( element => element.getRootNode().activeElement && element.contains( element.getRootNode().activeElement ) ) ) {
611611
dropdownView.buttonView.focus();
612612
}
613613
} );

packages/ckeditor5-ui/src/panel/balloon/balloonpanelview.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,11 @@ export default class BalloonPanelView extends View {
399399
}
400400

401401
let targetElement = getDomElement( options.target );
402-
// TODO ShadowRoot
403402
const limiterElement = options.limiter ? getDomElement( options.limiter ) : global.document.body;
404403

404+
// TODO ShadowRoot
405+
// - we need to listen to the scroll event on every ShadowRoot
406+
// (it is not composed and does not propagate to parent DOM)
405407
// Then we need to listen on scroll event of eny element in the document.
406408
this.listenTo( global.document, 'scroll', ( evt, domEvt ) => {
407409
const scrollTarget = domEvt.target as Element;

packages/ckeditor5-ui/src/tooltipmanager.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ export default class TooltipManager extends /* #__PURE__ */ DomEmitterMixin() {
192192
this._pinTooltipDebounced = debounce( this._pinTooltip, 600 );
193193
this._unpinTooltipDebounced = debounce( this._unpinTooltip, 400 );
194194

195+
// TODO ShadowRoot - make sure those events propagate to parent shadow DOM
195196
this.listenTo( global.document, 'keydown', this._onKeyDown.bind( this ), { useCapture: true } );
196197

197198
this.listenTo( global.document, 'focus', this._onEnterOrFocus.bind( this ), { useCapture: true } );

packages/ckeditor5-utils/src/dom/findclosestscrollableancestor.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ import global from './global.js';
1717
*/
1818
export default function findClosestScrollableAncestor( domElement: HTMLElement ): HTMLElement | null {
1919
let element = domElement.parentElement;
20+
2021
if ( !element ) {
2122
return null;
2223
}
2324

25+
// TODO: ShadowRoot
2426
while ( element.tagName != 'BODY' ) {
2527
const overflow = element.style.overflowY || global.window.getComputedStyle( element ).overflowY;
2628

packages/ckeditor5-widget/src/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ export function calculateResizeHostAncestorWidth( domResizeHost: HTMLElement ):
483483
let checkedElement = domResizeHostParent!;
484484

485485
while ( isNaN( parentWidth ) ) {
486+
// TODO ShadowRoot
486487
checkedElement = checkedElement.parentElement!;
487488

488489
if ( ++currentLevel > ancestorLevelLimit ) {

0 commit comments

Comments
 (0)