Skip to content

Commit

Permalink
feat(core): android input handing
Browse files Browse the repository at this point in the history
  • Loading branch information
pubuzhixing8 committed Mar 17, 2023
1 parent 33467e6 commit 55821dd
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/chatty-experts-provide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"slate-angular": patch
---

android input handing
8 changes: 8 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mode": "pre",
"tag": "next",
"initialVersions": {
"slate-angular": "15.0.0"
},
"changesets": []
}
18 changes: 1 addition & 17 deletions demo/app/richtext/richtext.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,24 +226,8 @@ const initialValue = [
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:'
text: `Since`
}
]
},
{
type: 'block-quote',
children: [{ text: 'A wise quote.' }]
},
{
type: 'paragraph',
children: [{ text: 'Try it out for yourself!' }]
},
{
type: 'paragraph',
children: [{ text: '' }]
}
];
47 changes: 39 additions & 8 deletions packages/src/components/editable/editable.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import {
getDefaultView
} from '../../utils/dom';
import { Subject } from 'rxjs';
import { IS_FIREFOX, IS_SAFARI, 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 All @@ -53,6 +53,7 @@ import { ViewType } from '../../types/view';
import { HistoryEditor } from 'slate-history';
import { isDecoratorRangeListEqual, check, normalize } from '../../utils';
import { SlatePlaceholder } from '../../types/feature';
import { restoreDom } from '../../utils/restore-dom';

// not correctly clipboardData on beforeinput
const forceOnDOMPaste = IS_SAFARI;
Expand Down Expand Up @@ -270,7 +271,7 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
const { activeElement } = root;
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 @@ -362,6 +363,8 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
}

onChange() {
console.log(JSON.stringify(this.editor.operations));
console.log(JSON.stringify(this.editor.children));
this.forceFlush();
this.onChangeCallback(this.editor.children);
}
Expand Down Expand Up @@ -489,7 +492,7 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
}

private toSlateSelection() {
if (!this.isComposing && !this.isUpdatingSelection && !this.isDraggingInternally) {
if ((!this.isComposing || IS_ANDROID) && !this.isUpdatingSelection && !this.isDraggingInternally) {
try {
const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
const { activeElement } = root;
Expand Down Expand Up @@ -547,16 +550,40 @@ 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')) {
restoreDom(editor, () => {
Editor.insertBreak(editor);
});
} else {
let [nativeTargetRange] = (event as any).getTargetRanges();
if (nativeTargetRange) {
const targetRange = AngularEditor.toSlateRange(editor, nativeTargetRange);
if (data) {
setTimeout(() => {
Transforms.insertText(editor, data.toString(), { at: targetRange });
}, 0);
} else {
restoreDom(editor, () => {
Transforms.delete(editor, { at: targetRange });
});
}
}
}
return;
}
}
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 All @@ -582,7 +609,11 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy, Aft
}

case 'deleteContentBackward': {
Editor.deleteBackward(editor);
if (IS_ANDROID) {
restoreDom(editor, () => {
Editor.deleteBackward(editor);
});
}
break;
}

Expand Down Expand Up @@ -745,7 +776,7 @@ 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) {
preventInsertFromComposition(event, this.editor);
Editor.insertText(this.editor, event.data);
}
Expand Down
34 changes: 34 additions & 0 deletions packages/src/utils/restore-dom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Editor } from 'slate';
import { EDITOR_TO_ELEMENT } from './weak-maps';

export function restoreDom(editor: Editor, execute: () => void) {
const editable = EDITOR_TO_ELEMENT.get(editor);
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);
console.log('removed: ', node, node.nextSibling);
});

mutation.addedNodes.forEach(node => {
mutation.target.removeChild(node);
console.log('added: ', node);
});
});
observer.disconnect();
console.log('restore dom executed');
execute();
});
observer.observe(editable, { subtree: true, childList: true, characterData: true, characterDataOldValue: true });
setTimeout(() => {
observer.disconnect();
}, 0);
}


0 comments on commit 55821dd

Please sign in to comment.