Home » Android » webview – Can't delete image in contenteditable div on Android

webview – Can't delete image in contenteditable div on Android

Posted by: admin May 14, 2020 Leave a comment

Questions:

I am building a rich text editor in android. To do so, I am using a webView with a contentEditable div.

To add styles, I invoke JavaScript. This all works fine, except when I invoke JavaScript to insert either an image or a horizontal rule. When I use JavaScript to insert these things, if I then try to press the back button to delete either the image or the horizontal rule, it doesn’t work.

Oddly enough, if I first enter any other character, and then insert the image or horizontal rule, I can delete the image/horizontal rule just fine, but cannot delete the character I entered immediately before the image/horizontal rule.

I’ve tried printing out the HTML in every state, checking the selection/range, etc, and can’t seem to find anything that’s different about the state that might explain why I can’t delete the image, etc.

How to&Answers:

Android: Backspace in WebView/BaseInputConnection

Subclass Webview and override the method as shown by this guy’s question.

On some phones, only the guy’s question will satisfy the requirements. The link’s answer will complete the code for compatibility with other phones. Though, you subclass a InputConnectionWrapper. not inputconnection. and then return that wrapper within your custom webview.

Just a FYI, this link has a much more detailed explanation of the situation, however I tried quickly implementing their ideas and it didn’t work. Maybe too complicated for my purposes. The reason I tried their solution instead of what I mentioned above is because the solution I mentioned above causes the voice-to-text function to not work correctly.
Android – cannot capture backspace/delete press in soft. keyboard

Answer:

I have implemented a richTextEditor using WebView and JavaScript.

I had no problem in inserting/deleting image that I have added to
content editable html page. Code that I have used for inserting image is

String exeSucess = "document.execCommand('insertHtml', false,'<img src=\""
        + selectedImagePath + "\" height=auto width=200 ></img>');";
   //Then code for executing this javascript.

Thanks.

Answer:

<div contenteditable="true"></div>

I use this to do a rich editor in a webview

Then override method TapInputConnection in Webview

@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
    return new TapInputConnection(super.onCreateInputConnection(outAttrs));
}



class TapInputConnection implements InputConnection {

    private InputConnection mConnection;


    public TapInputConnection(InputConnection conn){
        this.mConnection = conn;
    }

    @Override
    public CharSequence getTextBeforeCursor(int n, int flags) {
        return mConnection.getTextBeforeCursor(n, flags);
    }

    @Override
    public CharSequence getTextAfterCursor(int n, int flags) {
        return mConnection.getTextAfterCursor(n, flags);
    }

    @Override
    public CharSequence getSelectedText(int flags) {
        return mConnection.getSelectedText(flags);
    }

    @Override
    public int getCursorCapsMode(int reqModes) {
        return mConnection.getCursorCapsMode(reqModes);
    }

    @Override
    public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
        return mConnection.getExtractedText(request, flags);
    }

    @Override
    public boolean deleteSurroundingText(int beforeLength, int afterLength) {
        return mConnection.deleteSurroundingText(beforeLength, afterLength);
    }

    @Override
    public boolean setComposingText(CharSequence text, int newCursorPosition) {
        return mConnection.setComposingText(text, newCursorPosition);
    }

    @Override
    public boolean setComposingRegion(int start, int end) {
        return mConnection.setComposingRegion(start, end);
    }

    @Override
    public boolean finishComposingText() {
        return mConnection.finishComposingText();
    }

    @Override
    public boolean commitText(CharSequence text, int newCursorPosition) {
        return mConnection.commitText(text, newCursorPosition );
    }

    @Override
    public boolean commitCompletion(CompletionInfo text) {
        return mConnection.commitCompletion(text);
    }

    @Override
    public boolean commitCorrection(CorrectionInfo correctionInfo) {
        return mConnection.commitCorrection(correctionInfo);
    }

    @Override
    public boolean setSelection(int start, int end) {
        return mConnection.setSelection(start, end);
    }

    @Override
    public boolean performEditorAction(int editorAction) {
        return mConnection.performEditorAction(editorAction);
    }

    @Override
    public boolean performContextMenuAction(int id) {
        return mConnection.performContextMenuAction(id);
    }

    @Override
    public boolean beginBatchEdit() {
        return mConnection.beginBatchEdit();
    }

    @Override
    public boolean endBatchEdit() {
        return mConnection.endBatchEdit();
    }

    @Override
    public boolean sendKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
            if (event.getAction() == KeyEvent.ACTION_UP) {
                delete();
            }
            return true;
        }
        return mConnection.sendKeyEvent(event);
    }

    @Override
    public boolean clearMetaKeyStates(int states) {
        return false;
    }

    @Override
    public boolean reportFullscreenMode(boolean enabled) {
        return mConnection.reportFullscreenMode(enabled);
    }

    @Override
    public boolean performPrivateCommand(String action, Bundle data) {
        return mConnection.performPrivateCommand(action, data);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public boolean requestCursorUpdates(int cursorUpdateMode) {
        return mConnection.requestCursorUpdates(cursorUpdateMode);
    }
}

You have realized that I override sendKeyEvent and I deal with Delete Key by myself

This is the delete() function;

public void delete(){
  loadurl("javascript:document.execCommand('delete', false, null);");
}