How do I keep standard 'select all' and 'copy' menu items in the WebView text selection menu?
Asked Answered
N

1

11

I need to extend android WebView's text selection menu with my custom commands. So far I have managed to implement my custom webview text selection menu the following way:

public class CustomActionWebView extends WebView {

    static String TAG = "CustomActionWebView";

    ActionMode mActionMode;

    int mMenuID;
    Activity mParentAct;

    ActionSelectListener mActionSelectListener;
    ButtonClickListener mButtonClick;

    public CustomActionWebView(Context context) {
        super(context);
    }

    public CustomActionWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomActionWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setActionMenu(int mActionMenu, Activity ParentAct) {

        setWebViewClient(new CustomWebViewClient());
        this.mMenuID = mActionMenu;
        mParentAct = ParentAct;
    }

    private ActionMode resolveActionMode(ActionMode actionMode) {
        if (actionMode != null) {
            final Menu menu = actionMode.getMenu();
            mActionMode = actionMode;
            menu.clear();

            mParentAct.getMenuInflater().inflate(mMenuID, menu);

            for (int i = 0; i < menu.size(); i++) {
                MenuItem mi = menu.getItem(i);

                mi.setOnMenuItemClickListener(item -> {
                    int id=item.getItemId();
                    if(id == R.id.cab_select_all)
                    {
                        String js = "var el =document.getElementsByTagName(\"BODY\")[0]; el.setSelectionRange(0, el.value.length); alert(el.value);)";
                        evaluateJavascript("javascript:" + js, null);
                    }
                    else getSelectedData( item.getItemId());
                    releaseAction();
                    return true;
                });

            }

        }
        mActionMode = actionMode;
        return actionMode;
    }

    @Override
    public ActionMode startActionMode(ActionMode.Callback callback) {
        ActionMode actionMode = super.startActionMode(callback);
        return resolveActionMode(actionMode);
    }

    @Override
    public ActionMode startActionMode(ActionMode.Callback callback, int type) {
        ActionMode actionMode = super.startActionMode(callback, type);
        return resolveActionMode(actionMode);
    }

    private void releaseAction() {
        if (mActionMode != null) {
            mActionMode.finish();
            mActionMode = null;
        }
    }

    private void getSelectedData(int menuID) {


        String js2 = "(function getSelectedText() {" +
                "var txt;" +
                "var parentID;" +
                "var test;" +
                "var menuID = " + menuID + ";" +
                "if (window.getSelection) {" +
                "txt = window.getSelection().toString();" +
                "parentID = window.getSelection().baseNode.parentNode.id;"+
                "test = '1st';"+
                "} else if (window.document.getSelection) {" +
                "txt = window.document.getSelection().toString();" +
                "parentID = window.document.getSelection().baseNode.parentNode.id;"+
                "test = '2nd';"+
                "} else if (window.document.selection) {" +
                "txt = window.document.selection.createRange().text;" +
                "parentID = window.document.selection.baseNode.parentNode.id;"+
                "test = '3rd';"+
                "}" +
                "JSInterface.callback(txt, menuID, parentID);" +
                "})()";


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            evaluateJavascript("javascript:" + js2, null);
        } else {
            loadUrl("javascript:" + js2);
        }
    }

    public void linkJSInterface() {
        addJavascriptInterface(new ActionSelectInterface(this), "JSInterface");
        addJavascriptInterface(new ButtonClickInterface(this), "ButtonClick");
    }

    public void setActionSelectListener(ActionSelectListener actionSelectListener) {
        this.mActionSelectListener = actionSelectListener;
    }

    public void setVerseToolbarClickListener(ButtonClickListener mButtonClick) {
        this.mButtonClick = mButtonClick;
    }

    public void dismissAction() {
        releaseAction();
    }


    private class ActionSelectInterface {

        CustomActionWebView mContext;

        ActionSelectInterface(CustomActionWebView c) {
            mContext = c;
        }

        @JavascriptInterface
        public void callback(final String value, final int menuID, final String parentDivID) {
            if (mActionSelectListener != null) {
                mActionSelectListener.onTextSelectionMenuClick(menuID, value, parentDivID);
            }
        }

        @JavascriptInterface
        public void hl_click(long row_id) {
            if (mActionSelectListener != null) {
                mActionSelectListener.onHighlightClick(row_id);
            }
        }
    }

    private class ButtonClickInterface {

        CustomActionWebView mContext;

        ButtonClickInterface(CustomActionWebView c) {
            mContext = c;
        }

        @JavascriptInterface
        public void call(final String id) {
            if (mButtonClick != null) {
                mButtonClick.onClick(id);
            }
        }
    }


    private class CustomWebViewClient extends WebViewClient {

        private boolean mLastLoadFailed = false;

        @Override
        public void onPageFinished(WebView webView, String url) {
            super.onPageFinished(webView, url);
            if (!mLastLoadFailed) {
                CustomActionWebView customActionWebView = (CustomActionWebView) webView;
                customActionWebView.linkJSInterface();

            }
        }

        @Override
        public void onPageStarted(WebView webView, String url, Bitmap favicon) {
            super.onPageStarted(webView, url, favicon);
        }

        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            super.onReceivedError(view, request, error);
            mLastLoadFailed = true;
        }
    }


}

However this implementation results in the absence of the standard webview "COPY" and "SELECT ALL" menu items. I could implement my own COPY menu item, however I don't know how to have equivalent of the standard "SELECT ALL" menu item or to implement my own custom webview menu in such a way so that it preserves the standard ones. Can anyone please suggest how can I have "SELECT ALL" menu item working?

Nydianye answered 27/6, 2019 at 10:11 Comment(1)
I think you just need to remove menu.clear() to keep the default items in the menu and instead remove the specific item you want to remove like mentioned in the answer by Ibrahim Ali using: menu.removeItem(android.R.id.cut);Caffeine
D
2

I definitely don't encourage you to create a new selection menu while you need to use a functionalities in old one.

The key: You Just need to modify the current one

Yes we can edit the current selection menu by adding new selection tab or remove old selection tab.

The code explain that:

@Override
public ActionMode startActionMode(ActionMode.Callback callback, int type) {
    // Get the original action menu
    ActionMode modifiedMode = super.startActionMode(callback, type);

    // Obtain the menu reference
    Menu menu = modifiedMode.getMenu();

    // add new selection with click listener
    menu.add("test").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem menuItem) {
            Toast.makeText(getContext(),"مرحباً", Toast.LENGTH_LONG).show();
            return true;
        }
    });

    // remove the 'cut' selection from menu
    menu.removeItem(android.R.id.cut);

    return modifiedMode;
}
Duckling answered 23/7, 2019 at 9:44 Comment(5)
this answer does not say how to implement "select all" command in webviewNydianye
@Nydianye you question title is: How do I keep standard 'select all' and 'copy' menu items in the WebView text selection menu? not how implement it. so I suggest to edit your question title so.Duckling
but your answer does not say how to preserve standard select all command eitherNydianye
@Nydianye If you tried my answer you will find it work as intended, you can modify on system selection menu, adding new selection tab or removing one.Duckling
we can achieve selectAll or copy by document.execCommand('selectAll') or document.execCommand('copy')Schlosser

© 2022 - 2024 — McMap. All rights reserved.