简体   繁体   中英

Perform custom onClick action before web app's default action in a Chrome extension

I am building a Chrome extension that will be interacting with an existing web application. I need to perform an action when the user presses a "button" on the existing application before the application's "built-in" or "default" actions (the button is actually a <div> with JS onClick events attached).

As far as I'm aware you can't force onClick handlers to be fired in any sort of order so I can't just use jQuery's .click() to add a new onClick event (b/c there is a possibility that the default action will be fired before mine).

I've been experimenting with a number of other approaches--all of which have failed me. Is what I'm trying to do even possible given Chrome's isolated worlds ?

Here are the approaches I've taken that have not worked for me:

  1. Solution: Remove all click handlers except mine, and then fire the other handlers after I complete my action
    Problem : I haven't been able to get a list of the existing click handlers
  2. Solution: Hide the default <div> button and place my button there instead. After the click event is fired on mine, show the existing button and then fire the event on the original (I'm guessing I need to show it before I can fire an event on it?)
    Problem: the button wasn't responding to the event I created.
  3. Solution: Before my action in the background at a regular interval so it is nearly guaranteed to be complete by the time the user presses the button.
    Problem: it formats text on the screen that I would rather not format until the user presses the button, it could miss some formatting based on the polling timer etc...

Note: it is entirely possible that one of these approaches should have worked but a bug prevented it from working. If this is the case, please let me know!

I'd been experimenting with this for a while, and I've found an interesting fact: Chrome gives content scripts a separate DOM to use (which, of course, is smart). The event handlers you define for any element are run AFTER the default event is. I would say there's no way around this, but I've found a nice, little, somewhat "hacky" way to do this:

var removeClickHandler = function(){
    // If you MUST use jQuery I would
    // suggest doing it in a closed scope
    // so that it doesn't interfere with anything
    // else using either 'jQuery' or '$', like this:
    /*
        (function(){
            [...Insert jQuery 1.5.5 here...]
            var target = $("#myTargetElement");
            target.unbind("click");
            target.bind("click", function(){
                alert("HAHA! What then??!! Its MY CLICK HANDLER NOW!!");
            });
        })();
    */
    // Otherwise, use plain JS...but using a closed scope is
    // still a good idea, for example, this keeps 'target' from leaking out:
    (function(){
        var target = document.getElementById("#myTargetElement");
        target.onclick = function(){
            alert("HAHA! What then??!! Its MY CLICK HANDLER NOW!!");
        };
    })();
};

window.location = "javascript: ("+removeClickHandler+")();";

Remember that Chrome instituted these security measures for a reason , so be please be VERY careful how you use this.

Lets say this element is on a site:

<div id="test" onclick="originalHandler()">test</div>

<script>
function originalHandler() {
    alert("original");
}
</script>

Then in a content script I can do:

var el = document.getElementById("test");
var oldEvent = el.onclick;
el.onclick = myHandler;

function myHandler() {
    alert("mine");

    //run original
    oldEvent();
}

Thanks for the thoughts guys. I attempted both of these solutions and they would likely have worked if it wasn't for the complexity of the web app I'm dealing with (GMail). It was difficult for me to identify what the inputs of the default click handler were (and thus how to recreate them).

Instead, I went with this solution (it isn't perfect but it gets the job done):

  1. On page load I hide the existing button and add my own instead
  2. When the user clicks my button I perform my action, then hide my button, then show the default button
  3. I listen for onFocus events on the affected fields. If the user goes back into the fields I've already processed then I undo my processing, show my button again and hide the default button
  4. Repeat steps 2-3 as needed

The end result is that the user needs to click the button twice, once to "Prepare" and once to "Send".

If anyone has any luck getting any of the other solutions to work (on the Send button in GMail) let me know and I'll update the chosen answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM