Skip to content

Commit

Permalink
feat(core): android compatible test
Browse files Browse the repository at this point in the history
  • Loading branch information
pubuzhixing8 committed Mar 16, 2023
1 parent db7c9c6 commit 9985d1d
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 80 deletions.
40 changes: 1 addition & 39 deletions demo/app/richtext/richtext.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,45 +204,7 @@ const initialValue = [
{
type: 'paragraph',
children: [
{ text: 'This is editable ' },
{ text: 'rich', bold: true },
{ text: ' text, ' },
{ text: 'much', bold: true, italic: true },
{ text: ' better than a ' },
{ text: '<textarea>', 'code-line': true },
{ text: '!' }
{ text: 'This is editabl' }
]
},
{
type: 'heading-one',
children: [{ text: 'This is h1 ' }]
},
{
type: 'heading-three',
children: [{ text: 'This is h3 ' }]
},
{
type: 'paragraph',
children: [
{
text: `Since it's rich text, you can do things like turn a selection of text `
},
{ text: 'bold', bold: true },
{
text: ', or add a semantically rendered block quote in the middle of the page, like this:'
}
]
},
{
type: 'block-quote',
children: [{ text: 'A wise quote.' }]
},
{
type: 'paragraph',
children: [{ text: 'Try it out for yourself!' }]
},
{
type: 'paragraph',
children: [{ text: '' }]
}
];
139 changes: 98 additions & 41 deletions packages/src/components/editable/editable.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
getDefaultView
} from '../../utils/dom';
import { Subject } from 'rxjs';
import { IS_FIREFOX, IS_SAFARI, IS_EDGE_LEGACY, IS_CHROME_LEGACY, IS_CHROME, HAS_BEFORE_INPUT_SUPPORT } from '../../utils/environment';
import { IS_FIREFOX, IS_SAFARI, IS_CHROME, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID } from '../../utils/environment';
import Hotkeys from '../../utils/hotkeys';
import { BeforeInputEvent, extractBeforeInputEvent } from '../../custom-event/BeforeInputEventPlugin';
import { BEFORE_INPUT_EVENTS } from '../../custom-event/before-input-polyfill';
Expand Down Expand Up @@ -226,6 +226,7 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
this.addEventListener(
'selectionchange',
event => {
console.log('selectionchange');
this.toSlateSelection();
},
window.document
Expand Down Expand Up @@ -257,7 +258,7 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
const root = AngularEditor.findDocumentOrShadowRoot(this.editor)
const domSelection = (root as Document).getSelection();

if (this.isComposing || !domSelection || !AngularEditor.isFocused(this.editor)) {
if ((this.isComposing && !IS_ANDROID) || !domSelection || !AngularEditor.isFocused(this.editor)) {
return;
}

Expand Down Expand Up @@ -341,6 +342,13 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
}

onChange() {
const ops = this.editor.operations.filter((o) => o.type !== 'set_selection');
if (ops.length > 0) {
console.log('data change: ', this.editor.operations.filter((o) => o.type !== 'set_selection'));
console.log(`data: ${JSON.stringify(this.editor.children)}`);
} else {
console.log('selection change', JSON.stringify(this.editor.selection));
}
this.forceFlush();
this.onChangeCallback(this.editor.children);
}
Expand Down Expand Up @@ -479,43 +487,49 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
}

private toSlateSelection() {
if (!this.isComposing && !this.isUpdatingSelection && !this.isDraggingInternally) {
try {
const root = AngularEditor.findDocumentOrShadowRoot(this.editor)
const { activeElement } = root;
const el = AngularEditor.toDOMNode(this.editor, this.editor);
const domSelection = (root as Document).getSelection();

if (activeElement === el) {
this.latestElement = activeElement;
IS_FOCUSED.set(this.editor, true);
} else {
IS_FOCUSED.delete(this.editor);
}

if (!domSelection) {
return Transforms.deselect(this.editor);
}

const editorElement = EDITOR_TO_ELEMENT.get(this.editor);
const hasDomSelectionInEditor = editorElement.contains(domSelection.anchorNode) && editorElement.contains(domSelection.focusNode);
if (!hasDomSelectionInEditor) {
Transforms.deselect(this.editor);
return;
}

// try to get the selection directly, because some terrible case can be normalize for normalizeDOMPoint
// for example, double-click the last cell of the table to select a non-editable DOM
const range = AngularEditor.toSlateRange(this.editor, domSelection);
if (this.editor.selection && Range.equals(range, this.editor.selection) && !hasStringTarget(domSelection)) {
// force adjust DOMSelection
this.toNativeSelection();
} else {
Transforms.select(this.editor, range);
try {
if ((!this.isComposing || IS_ANDROID) && !this.isUpdatingSelection && !this.isDraggingInternally) {
try {
console.log('toSlateSelection change');
const root = AngularEditor.findDocumentOrShadowRoot(this.editor)
const { activeElement } = root;
const el = AngularEditor.toDOMNode(this.editor, this.editor);
const domSelection = (root as Document).getSelection();

if (activeElement === el) {
this.latestElement = activeElement;
IS_FOCUSED.set(this.editor, true);
} else {
IS_FOCUSED.delete(this.editor);
}

if (!domSelection) {
return Transforms.deselect(this.editor);
}

const editorElement = EDITOR_TO_ELEMENT.get(this.editor);
const hasDomSelectionInEditor = editorElement.contains(domSelection.anchorNode) && editorElement.contains(domSelection.focusNode);
if (!hasDomSelectionInEditor) {
Transforms.deselect(this.editor);
return;
}

// try to get the selection directly, because some terrible case can be normalize for normalizeDOMPoint
// for example, double-click the last cell of the table to select a non-editable DOM
const range = AngularEditor.toSlateRange(this.editor, domSelection);
if (this.editor.selection && Range.equals(range, this.editor.selection) && !hasStringTarget(domSelection)) {
// force adjust DOMSelection
this.toNativeSelection();
} else {
console.log(`select: ${range}`);
Transforms.select(this.editor, range);
}
} catch (error) {
this.editor.onError({ code: SlateErrorCode.ToSlateSelectionError, nativeError: error })
}
} catch (error) {
this.editor.onError({ code: SlateErrorCode.ToSlateSelectionError, nativeError: error })
}
} catch (error) {
console.error(error);
}
}

Expand All @@ -531,11 +545,52 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
const editor = this.editor;
const root = AngularEditor.findDocumentOrShadowRoot(this.editor)
const { activeElement } = root;
const { selection } = editor;
const { inputType: type } = event;
const data = event.dataTransfer || event.data || undefined;
if (IS_ANDROID) {
if (type === 'insertCompositionText') {
if (data && data.toString().includes('\n')) {
const observer = new MutationObserver((mutations) => {
mutations.reverse().forEach(mutation => {
if (mutation.type === 'characterData') {
// We don't want to restore the DOM for characterData mutations
// because this interrupts the composition.
return
}

// mutation.removedNodes.forEach(node => {
// mutation.target.insertBefore(node, mutation.nextSibling)
// })

mutation.addedNodes.forEach(node => {
mutation.target.removeChild(node)
})
});
console.log('callback', mutations);
observer.disconnect();
Editor.insertBreak(editor);
});
observer.observe(this.elementRef.nativeElement, {subtree: true,
childList: true,
characterData: true,
characterDataOldValue: true});
} else {
let [nativeTargetRange] = (event as any).getTargetRanges();
if (nativeTargetRange) {
const targetRange = AngularEditor.toSlateRange(editor, nativeTargetRange);
setTimeout(() => {
Transforms.insertText(editor, data.toString(), { at: targetRange });
}, 0);
}
console.log(`handle android insert text: ${data.toString()}`);
}
return;
}
}
console.log(`beforeinput, inputType: ${type}, data: ${data}, include '\\n': ${data?.toString().includes('\n')}`);
if (!this.readonly && hasEditableTarget(editor, event.target) && !isTargetInsideVoid(editor, activeElement) && !this.isDOMEventHandled(event, this.beforeInput)) {
try {
const { selection } = editor;
const { inputType: type } = event;
const data = event.dataTransfer || event.data || undefined;
event.preventDefault();

// COMPAT: If the selection is expanded, even if the command seems like
Expand Down Expand Up @@ -721,7 +776,8 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
// aren't correct and never fire the "insertFromComposition"
// type that we need. So instead, insert whenever a composition
// ends since it will already have been committed to the DOM.
if (this.isComposing === true && !IS_SAFARI && event.data) {
if (this.isComposing === true && !IS_SAFARI && !IS_ANDROID && event.data) {
console.log('composition end event insert text');
preventInsertFromComposition(event, this.editor);
Editor.insertText(this.editor, event.data);
}
Expand Down Expand Up @@ -872,6 +928,7 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
const editor = this.editor;
const root = AngularEditor.findDocumentOrShadowRoot(this.editor)
const { activeElement } = root;
console.log(`keydown keyCode: ${event.keyCode}, key: ${event.key}`)
if (
!this.readonly &&
hasEditableTarget(editor, event.target) &&
Expand Down

0 comments on commit 9985d1d

Please sign in to comment.