Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get selected text from TextInput #514

Open
antwin opened this issue Apr 18, 2023 · 6 comments
Open

Get selected text from TextInput #514

antwin opened this issue Apr 18, 2023 · 6 comments

Comments

@antwin
Copy link

antwin commented Apr 18, 2023

I need to find one of several urls in a TextInput (say with a double-click) so I can open it in a browser.
I've tried

self.recTxt = gui.TextInput(single_line=False, margin='10px')
self.recTxt.ondblclick.connect(self.onDblClick)
self.recTxt.onmousemove.connect(self.onMouseMove)

def onDblClick(self,obj):
    print(obj.children['text'])

I can get all the text, but not find the particular url that was clicked on.
Or I can get the mouse position in x,y coordinates.

How do I get the text?

@dddomodossola
Copy link
Collaborator

Hello @antwin , why are you using a TextInput to do so? wouldn't it be better to use a Link widget?

@antwin
Copy link
Author

antwin commented Apr 20, 2023

Thank you for the reply - much appreciated !

The reason is that I have an editable diary/notebook entry like:

-----------------------
remi diary part 1
https://github.com/rawpython/remi
https://remi.readthedocs.io
To tablet:
    :~>adb push py/remi/rem.py 
termux script:
python storage/external-1/rem.py
exec am start --user 0 -a android.intent.action.VIEW -n org.mozilla.firefox/org.mozilla.fenix.IntentReceiverActivity  -d "http://localhost:8082" >/dev/null
--20230419--
-------------------

This combines my notes, urls and other information. I want to set it up so that when I right-click on a url it loads the browser. Much more flexible than bookmarks! But I have to be able to edit and save the entry.

I can use remi to run on android with termux - it looks like the best way of running Python on android!

However, I can't find how to incorporate clickable urls into an editable bit of html that can then be saved.

Any suggestions?

@dddomodossola
Copy link
Collaborator

Hello @antwin ,

This is an example for you ;-)

import remi.gui as gui
from remi import start, App

"""
    This TextInputAdvanced class allows to get the caret position on click event.
"""
class TextInputAdvanced(gui.TextInput):
    @gui.decorate_event_js("""
    var params={};
    params['caretPositionStart'] = -1;
    params['caretPositionEnd'] = -1;
    if (document.activeElement == this)
    {
        try{
            params['caretPositionStart'] = document.activeElement.selectionStart;
            params['caretPositionEnd'] = document.activeElement.selectionEnd;
        }catch(e){console.debug(e.message);}
    }
    remi.sendCallbackParam('%(emitter_identifier)s','%(event_name)s', params);
    """)
    def onclick(self, caretPositionStart, caretPositionEnd):
        # The onclick event returns the text selection start and end
        # If no text is selected, -1 is returned.
        caretPositionStart = int(caretPositionStart) 
        caretPositionEnd = int(caretPositionEnd)
        return (caretPositionStart, caretPositionEnd)


class MyApp(App):
    def main(self):
        # creating a container VBox type, vertical (you can use also HBox or Widget)
        main_container = gui.VBox(style={'margin': '0px auto'})

        self.lblSelectionStartCaption = gui.Label("Selection start: ", width=100)
        self.lblSelectionEndCaption = gui.Label("Selection end: ", width=100)

        self.lblSelectionStart = gui.Label("", width=100)
        self.lblSelectionEnd = gui.Label("", width=100)

        main_container.append(gui.HBox(children=[self.lblSelectionStartCaption, self.lblSelectionStart]))
        main_container.append(gui.HBox(children=[self.lblSelectionEndCaption, self.lblSelectionEnd]))

        self.txtInput = TextInputAdvanced(False, width = 150, height = 100)
        self.txtInput.set_text("This is the url https://github.com/rawpython/remi of the remi repository.")
        self.txtInput.onclick.do(self.on_text_input_click)
        main_container.append(self.txtInput)

        # returning the root widget
        return main_container

    def on_text_input_click(self, emitter, caretPositionStart, caretPositionEnd):
        """
            Since you have the caretPositionStart, you can get the text in that position
                and if it is an url, open the url
        """
        self.lblSelectionStart.set_text(str(caretPositionStart))
        self.lblSelectionEnd.set_text(str(caretPositionEnd))
        
        #splitting the text by using the spaces before and after the caret
        text = self.txtInput.get_text()
        spaceBefore = -1
        try:
            spaceBefore = text.rindex(" ", 0, caretPositionStart)
        except:
            pass

        spaceAfter = len(text)
        try:
            spaceAfter = text.index(" ", caretPositionStart)
        except:
            pass

        textPointed = text[spaceBefore+1:spaceAfter]
        print("The text below the cursor is: " + textPointed)


if __name__ == "__main__":
    # starts the webserver
    start(MyApp, address='0.0.0.0', port=0, start_browser=True)

@antwin
Copy link
Author

antwin commented Apr 27, 2023

Thank you very much! That is a very useful bit of code. I have tried modding it so that a right-click (that would normally trigger a context menu) can be used instead of a left-click, but I haven't made that work yet...

@dddomodossola
Copy link
Collaborator

dddomodossola commented Apr 29, 2023

Hello @antwin ,

Here is the working code using the right mouse button:

import remi.gui as gui
from remi import start, App

"""
    This TextInputAdvanced class allows to get the caret position on click event.
"""
class TextInputAdvanced(gui.TextInput):
    @gui.decorate_event_js("""
    var params={};
    params['caretPositionStart'] = -1;
    params['caretPositionEnd'] = -1;
    if (document.activeElement == this)
    {
        try{
            params['caretPositionStart'] = document.activeElement.selectionStart;
            params['caretPositionEnd'] = document.activeElement.selectionEnd;
        }catch(e){console.debug(e.message);}
    }
    remi.sendCallbackParam('%(emitter_identifier)s','%(event_name)s', params);
    """)
    def oncontextmenu(self, caretPositionStart, caretPositionEnd):
        # The onclick event returns the text selection start and end
        # If no text is selected, -1 is returned.
        caretPositionStart = int(caretPositionStart) 
        caretPositionEnd = int(caretPositionEnd)
        return (caretPositionStart, caretPositionEnd)


class MyApp(App):
    def main(self):
        # creating a container VBox type, vertical (you can use also HBox or Widget)
        main_container = gui.VBox(style={'margin': '0px auto'})

        self.lblSelectionStartCaption = gui.Label("Selection start: ", width=100)
        self.lblSelectionEndCaption = gui.Label("Selection end: ", width=100)

        self.lblSelectionStart = gui.Label("", width=100)
        self.lblSelectionEnd = gui.Label("", width=100)

        main_container.append(gui.HBox(children=[self.lblSelectionStartCaption, self.lblSelectionStart]))
        main_container.append(gui.HBox(children=[self.lblSelectionEndCaption, self.lblSelectionEnd]))

        self.txtInput = TextInputAdvanced(False, width = 150, height = 100)
        self.txtInput.set_text("This is the url https://github.com/rawpython/remi of the remi repository.")
        self.txtInput.oncontextmenu.do(self.on_text_input_click, js_stop_propagation=True, js_prevent_default=True)
        main_container.append(self.txtInput)

        # returning the root widget
        return main_container

    def on_text_input_click(self, emitter, caretPositionStart, caretPositionEnd):
        """
            Since you have the caretPositionStart, you can get the text in that position
                and if it is an url, open the url
        """
        self.lblSelectionStart.set_text(str(caretPositionStart))
        self.lblSelectionEnd.set_text(str(caretPositionEnd))
        
        #splitting the text by using the spaces before and after the caret
        text = self.txtInput.get_text()
        spaceBefore = -1
        try:
            spaceBefore = text.rindex(" ", 0, caretPositionStart)
        except:
            pass

        spaceAfter = len(text)
        try:
            spaceAfter = text.index(" ", caretPositionStart)
        except:
            pass

        textPointed = text[spaceBefore+1:spaceAfter]
        print("The text below the cursor is: " + textPointed)


if __name__ == "__main__":
    # starts the webserver
    start(MyApp, address='0.0.0.0', port=0, start_browser=True)

Have a nice day,
Davide

@antwin
Copy link
Author

antwin commented Apr 30, 2023

Thank you again for the code. I have tried the context menu version, and - following your example - a double-click version. These work fine on my debian desktop, but not on Android.

But the first (onclick) version works ok. I create a url which I can then click on, as below:

 def onRecTxtClick(self, emitter, caretPositionStart, caretPositionEnd):    
        ''' splitting the text by using the spaces before and after the caret 
            https://github.com/rawpython/remi/issues/514 '''
        text = self.recTxt.get_text()
        spaceBefore = -1
        try:
            spaceBefore = text.rindex(" ", 0, caretPositionStart)
        except:
            pass 
        spaceAfter = len(text)
        try:
            spaceAfter = text.index(" ", caretPositionStart)
        except:
            pass
        txt = text[spaceBefore+1:spaceAfter]
        if 'http' in txt or 'www' in txt:
            txt = txt.split('\n') # clean up if not enough spaces around, but linefeeds instead
            for line in txt:
                if 'http' in line or 'www' in line:
                    textPointed = line.strip()
                    break
  #      print("The text below the cursor is: " + textPointed)
#d            self.lbl.set_text(f'{textPointed}')
            self.lbl.set_text('')
            url = gui.Link(textPointed,textPointed, open_new_window=True) 
            self.urls.empty()
            self.urls.append(url)
        else:
            return

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants