0

I have a function "snapSelectionToWord" that is supposed to be called on the onMouseUp event in a google chrome extension:

    // Initialize ability to select and grab text from browser
    function lwsSetUpTextGetter(callback) {

        console.log("lwsSetUpTextGetter()");

        //Set the onmouseup function to lwsGetText
        document.onmouseup = snapSelectionToWord(lwsGetText);
        //Handling clicking outside webpage?
        if (!document.all) document.captureEvents(Event.MOUSEUP);


    }

But instead the function snapSelectionToWord is being called immediately instead of waiting for the mouse click. What am I doing wrong here. Here's the full code...

Content Script (js)

(function () {

    // Holds text being selected in browser
    var lwsSelectedText = '';

    // Adds pop-up to current webpage
    function lwsAddContent(callback) {

        console.log("lwsAddContent()");

        // Get body tag
        var body = document.getElementsByTagName('body');

        // add invisible div
        document.body.innerHTML += '<div id="myModal" class="modal"><div class="modal-content"><span class="close">&times;</span><div id="lwsSpanishDiv"><p id="lwsSpanishTitle">Spanish</p><textarea id="lwsSpanishTextArea">Hello</textarea></div><div id="lwsEnglishDiv"><p id="lwsEnglishTitle">English</p><textarea id="lwsEnglishTextArea">Hello 2</textarea></div></div></div>';

        callback(lwsSetUpTextGetter);

    }

    // Make the pop-up visible and set up close button
    function lwsActivateContent(callback) {

        console.log("lwsActivateContent()");

        var modal = document.getElementById('myModal');

        // Get the textarea
        var txtarea = document.getElementById("myTxtArea");

        // Get the <span> element that closes the modal
        var span = document.getElementsByClassName("close")[0];

        span.onclick = function () {
            modal.style.display = "none";
        }

        callback(quickTranslate);

    }

    // Initialize ability to select and grab text from browser
    function lwsSetUpTextGetter(callback) {

        console.log("lwsSetUpTextGetter()");

        //Set the onmouseup function to lwsGetText
        document.onmouseup = snapSelectionToWord(lwsGetText);
        //Handling clicking outside webpage?
        if (!document.all) document.captureEvents(Event.MOUSEUP);


    }

    // Snaps selected text to encompass the full word
    function snapSelectionToWord(callback) {

        console.log("snapSelectionToWord()");

        var sel;

        // Check for existence of window.getSelection() and that it has a
        // modify() method. IE 9 has both selection APIs but no modify() method.
        if (window.getSelection && (sel = window.getSelection()).modify) {
            sel = window.getSelection();
            if (!sel.isCollapsed) {

                // Detect if selection is backwards
                var range = document.createRange();
                range.setStart(sel.anchorNode, sel.anchorOffset);
                range.setEnd(sel.focusNode, sel.focusOffset);
                var backwards = range.collapsed;
                range.detach();

                // modify() works on the focus of the selection
                var endNode = sel.focusNode, endOffset = sel.focusOffset;
                sel.collapse(sel.anchorNode, sel.anchorOffset);
                if (backwards) {
                    sel.modify("move", "backward", "character");
                    sel.modify("move", "forward", "word");
                    sel.extend(endNode, endOffset);
                    sel.modify("extend", "forward", "character");
                    sel.modify("extend", "backward", "word");

                } else {
                    sel.modify("move", "forward", "character");
                    sel.modify("move", "backward", "word");
                    sel.extend(endNode, endOffset);
                    sel.modify("extend", "backward", "character");
                    sel.modify("extend", "forward", "word");
                }
            }
        } else if ((sel = document.selection) && sel.type != "Control") {
            var textRange = sel.createRange();
            if (textRange.text) {
                textRange.expand("word");
                // Move the end back to not include the word's trailing space(s),
                // if necessary
                while (/\s$/.test(textRange.text)) {
                    textRange.moveEnd("character", -1);
                }
                textRange.select();
            }
        }

        console.log("before callback...");

        callback(quickTranslate);

    }

    //Gets selected text
    function lwsGetText(callback) {
        return function (e) {

            console.log("lwsGetText()");

            // Get access to spanish text area
            var spanishText = document.getElementById('lwsSpanishTextArea');

            //Get text
            lwsSelectedText = (document.all) ? document.selection.createRange().text : document.getSelection();

            //if nothing is selected, do nothing
            if (lwsSelectedText != '') {

                // test: does browser grab text correctly?
                alert(lwsSelectedText);

                // Set spanish text area content to the selected text from browser
                spanishText.value = lwsSelectedText;

                // --Error Here--
                callback();

            }
        };
    }

    function quickTranslate() {

        console.log("quickTranslate()");

        var url = "https://translate.yandex.net/api/v1.5/tr.json/translate",
        keyAPI = "trnsl.1.1.20130922T110455Z.4a9208e68c61a760.f819c1db302ba637c2bea1befa4db9f784e9fbb8";

        var englishTextArea = document.getElementById('lwsEnglishTextArea');
        var spanishTextArea = document.getElementById('lwsSpanishTextArea');

        englishTextArea.value = 'Working...';

        var xhr = new XMLHttpRequest(),
            textAPI = spanishTextArea.value,
            langAPI = 'es-en';
        data = "key=" + keyAPI + "&text=" + textAPI + "&lang=" + langAPI;
        xhr.open("POST", url, true);
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhr.send(data);
        xhr.onreadystatechange = function () {
            if (this.readyState == 4 && this.status == 200) {
                var res = this.responseText;
                var json = JSON.parse(res);
                if (json.code == 200) {
                    englishTextArea.value = json.text[0];
                }
                else {
                    englishTextArea.value = "Error Code: " + json.code;
                }
            }
        }

    }


    // When document ready
    $(document).ready(function () {

        lwsAddContent(lwsActivateContent);

    });

})();

The console looks something like this and doesn't add entries if I try clicking and selecting something:

Console Log

contentScript.js:9 lwsAddContent()
contentScript.js:24 lwsActivateContent()
contentScript.js:45 lwsSetUpTextGetter()
contentScript.js:58 snapSelectionToWord()
contentScript.js:106 before callback...

If anyone can figure out what I'm doing wrong here, that'd be great! Thanks!

TheBlindDeveloper
  • 395
  • 1
  • 4
  • 13
  • In an extension, you should *not* use the `on*` property values like `document.onmouseup` for elements you didn't add to the DOM to add event listeners. Doing so is A) bad practice, and B) has a much higher likelihood of conflicting with in-page scripts. You should use `document.adEventListener('mouseup',...`. – Makyen Aug 10 '17 at 15:45
  • It's unclear if you are really attempting to use `snapSelectionToWord` as your event handler, or if you are wanting to use the function returned by `lwsGetText`. Either way, it's not going to work. `snapSelectionToWord` does not `return` the result from `callback(quickTranslate)`, so no event handler will be assigned. However, it really appears that you are wanting `snapSelectionToWord` to be the event handler. If so, you need to not invoke it. If you are wanting to call it with additional arguments, then using `snapSelectionToWord.bind(null,lwsGetText)` is usually a good way to go. – Makyen Aug 10 '17 at 16:01
  • In neither case does either function which might be intended as your `mouseup` event handler, check which mouse button is being reported. This will result in unexpected behavior when the user is clicking any other button than the primary selection button. – Makyen Aug 10 '17 at 16:03

1 Answers1

-1
document.onmouseup = snapSelectionToWord(lwsGetText);

change to

document.onmouseup = snapSelectionToWord;

You should assign function, not the function call. Also as first argument in snapSelectionToWord you will receive event object.

Ivan
  • 876
  • 1
  • 8
  • 22
  • 1
    more like `document.onmouseup = function() { snapSelectionToWord(lwsGetText); }` to pass the right callback to snapSelectionToWord – Jaromanda X Aug 10 '17 at 07:06
  • @JaromandaX That partially works. But the callback doesn't seem to get passed through because it stops dead after finishing the function snapSelectionToWord. Ideas? – TheBlindDeveloper Aug 10 '17 at 17:22
  • Ok so I did some troubleshooting and found that it was indeed launching the function but it was throwing at the return function (e) { } So I merely deleted it and we were good to go. Thanks for your help! – TheBlindDeveloper Aug 10 '17 at 17:43