Search code examples
javascriptgoogle-chrome-extensiondom-events

Chrome Extension add YouTube tags


I'm writing a Chrome extension that I would like to add tags to the YouTube edit page Specifically more than one. I can insert the tag text as a string with each tag delimited by a comma. For YouTube to take this comma delimited string and split it into tags correctly the tag insertion space needs to receive a keyup or change event.

I've looked at a LOT of Stack Overflow posts that talk about triggering key events, but none of the code suggested there seems to be working for me.

Unfortunately for some reason when I try to trigger the event, I get an error using the following code:

document.getElementsByClassName("video-settings-add-tag")[0].focus();
document.getElementsByClassName("video-settings-add-tag")[0].keyup();

The error states:

"Uncaught TypeError: undefined is not a function";

The focus code works so I'm definitely targeting the correct element.

It's strange because other events (that don't actually do what I need) DO work, namely focus, blur and click. YouTube has event listeners bound to the video-settings-add-tag element that I need to trigger to get it to split the string into tags.

Anyone know why this isn't working?

P.S. I also tried defining the change event to see if that would work and this code didn't throw an error but also didn't do anything:

var event = new KeyboardEvent('change');
document.getElementsByClassName("video-settings-add-tag")[0].dispatchEvent(event);
document.getElementsByClassName("video-settings-add-tag")[0].change;

Solution

  • I ran into something like this before, where objects and functions defined in scripts served with the page were not accessible to my content script, and threw similar "Uncaught TypeError: undefined is not a function" errors, but I REALLY needed to access methods and properties on the page, because I didn't want to re-implement them.

    It has to do with how Chrome sandboxes content scripts by passing them a "safe DOM." More info here

    You can get around this by setting your content script up in a way that it defines itself on the page, rather than executing in a content script context. Like so:

    // Here's where all my page-extension logic takes place:
    doTheThing = function() {
        //all my logics
    }
    
    //add logic to window. Injecting the script inline grants it
    //access to all objects on the window, including page scripts.
    var script = document.createElement('script');
    script.type = "text/javascript";
    script.textContent = '(' + doTheThing.toString() + ')();';
    document.body.appendChild(script);
    

    This approach does vastly complicate things if you need access to background scripts, but that case is still doable with a bit more work. Hope this helps!

    As far as programmatically triggering the events, I think you're confusing functions available to jQuery objects with functions available to native DOM objects. Remember, jQuery stores events that are outside the native DOM events, so if YouTube is creating jQuery events, you'll need to call the appropriate function from a jQuery object:

    $('.video-settings-add-tag')[0].keyup();
    

    If the event is registered to the native DOM object, you'll want to create an event object and dispatch it:

    var ch = document.createEvent('HTMLEvents');
    ch.initEvent('keyup', 13, true);
    document.getElementsByClassName("video-settings-add-tag")[0].dispatchEvent(ch);