[Solved] Trouble accessing Shadow DOM in Tampermonkey

Discussion in 'Help & Guides' started by Vincent P, Apr 17, 2020.

  1. Vincent P

    Vincent P Active Turker

    Messages:
    642
    Ratings:
    +923
    I'm using Google Chrome and I've been trying to mess with this one HIT for ages, and I can't seem to access the Shadow DOM using methods I've seen. The part that is confusing me is I'm using a piece of script from "MTurk Submit Orange Buttons with Hotkey (`)" to troubleshoot and what is essentially the same exact use of shadowRoot works on the page in question. I'm trying to keep the post short and not messy but if anybody wants a link to the HIT interface I can share that too. These are the elements I'm trying to access (starting with crowd-image-classifier):

    [​IMG]

    And here is my code that should be navigating to the Shadow DOM:

    Code:
    var shadowCheck = document.querySelector("crowd-image-classifier");
    var shadowButton = shadowCheck.shadowRoot;
    console.log(shadowButton.innerHTML);
    But it always returns null. I can't find out any major differences between that code and:

    Code:
            document.addEventListener('keydown', function(e) {
            if (e.keyCode == 192){ // `
                let crowd =
                    document.querySelector(`crowd-button[form-action="submit"]`) ||
                    document.querySelector(`crowd-classifier`) ||
                    document.querySelector(`crowd-image-classifier`) ||
                    document.querySelector(`crowd-bounding-box`) ||
                    document.querySelector(`crowd-keypoint`) ||
                    document.querySelector(`crowd-polygon`) ||
                    document.querySelector(`crowd-instance-segmentation`) ||
                    document.querySelector(`crowd-semantic-segmentation`) ||
                    document.querySelector(`body > crowd-form`);
                if (crowd){
                    e.preventDefault();
                    crowd.shadowRoot.querySelector(`[type='submit']`).click();
                } else {
                    e.preventDefault();
                    document.querySelector(`[type='submit']`).click();
                }
            }
        });
    Which is what the MTurk Orange Button Submit script uses to navigate into similar Shadow DOMs. This works if I run it on the same page, it submits the HIT. There's other buttons I want to be able to press though, and for some reason I can't access the Shadow DOM on my own. By the way, I have no idea what I'm doing. I just started learning JQuery like two days ago. Thanks a lot to anyone who tries to help though. Don't mean to step on any toes, I'm not sure how openly you guys talk about scripting.
     
  2. AlexZ

    AlexZ Distinguished Butthat

    Messages:
    15,046
    Gender:
    Male
    Ratings:
    +45,934
    Are you sure you're including your script on the right pages? Don't forget that the HIT content itself is embedded in an iFrame.

    Try doing this:
    Code:
    // @include      https://s3.amazonaws.com/*
    // @include      https://www.mturkcontent.com/*
     
  3. Kadauchi

    Kadauchi Administrator Former MTG MotM

    Messages:
    4,367
    Ratings:
    +8,589
    It looks fine to me. My first guess would be that you're selecting the wrong crowd element to access the shadowRoot that contains the submit button. Does `crowd-button[form-action="submit"]` exist in that HIT you have pictured? I would try it without that selector or at least moving it behind `crowd-classifier` and `crowd-image-classifier`
     
    • Today I Learned Today I Learned x 1
  4. Vincent P

    Vincent P Active Turker

    Messages:
    642
    Ratings:
    +923
    Sorry if my post was confusing. Yes, `crowd-button[form-action="submit"] exists in the HIT, and it exists in the same Shadow DOM that I'm trying to access with the other piece of code. That second piece of code works fine on the page, while the first piece of code returns null, which doesn't make any sense to me. They are both referencing the same "crowd-image-classifier" block and for some reason the other person's script code is able to access the Shadow DOM and mine isn't. I can't see any major differences in the code which is why it's confusing me.
     
    Last edited: Apr 17, 2020
  5. Vincent P

    Vincent P Active Turker

    Messages:
    642
    Ratings:
    +923
    It still doesn't work, I added
    Code:
     // @include      https://s3.amazonaws.com/*
    to my script but the second piece of code I posted runs fine without it, and the selectors are referencing the same elements as my first piece of code, which is why it doesn't make sense that it's not working.
     
  6. AlexZ

    AlexZ Distinguished Butthat

    Messages:
    15,046
    Gender:
    Male
    Ratings:
    +45,934
    Can you copy this entire script (including comments on top) and try to run it on that HIT's page? Do you see HTML code in the console or does it show an error?

    Code:
    // ==UserScript==
    // @name         BigPoop
    // @namespace    http://tampermonkey.net/
    // @version      0.1
    // @description  try to take over the world!
    // @author       You
    // @include      https://www.mturkcontent.com/*
    // @include      https://s3.amazonaws.com/*
    // @grant        none
    // ==/UserScript==
    
    console.log(document.querySelector("crowd-image-classifier").shadowRoot.innerHTML);

    If you can let me know what HIT you're talking about (or just link the source code of the page), it would be much easier to help you.
     
  7. Vincent P

    Vincent P Active Turker

    Messages:
    642
    Ratings:
    +923
    Yeah, it just shows an error. Returns null when you try to access innerHTML in shadowRoot.

    Here's the HIT, I don't know why I didn't just share it right away.

    Like I said, the block of code with all of the selectors in "crowd" (the one I took from another script) works on the page and is able to retrieve elements from shadowRoot. When I basically rewrite the same exact code and try to access the elements myself it doesn't work, and I don't see anything that is allowing that block of code to work on the page while my own code doesn't work.

    EDIT: Even
    Code:
    console.log(document.querySelector("crowd-image-classifier").shadowRoot);
    On its own returns null.
     
    Last edited: Apr 17, 2020
  8. AlexZ

    AlexZ Distinguished Butthat

    Messages:
    15,046
    Gender:
    Male
    Ratings:
    +45,934
    So, in this particular case, you just have to wait a few seconds for the HIT content to completely load before you try to access "crowd-image-classifier".

    This waits 5 seconds before doing anything:

    Code:
    // ==UserScript==
    // @name         BigPoop
    // @namespace    http://tampermonkey.net/
    // @version      0.1
    // @description  try to take over the world!
    // @author       You
    // @include      https://www.mturkcontent.com/*
    // @grant        none
    // ==/UserScript==
    
    setTimeout(PrintShit, 5000);
    
    function PrintShit() {
        console.log(document.querySelector("crowd-image-classifier").shadowRoot.innerHTML);
    }
    Works on my machine.

    P.S. Also, you might wanna remove your MTurk ID from that link you posted. :p
     
    • Like Like x 2
    • Today I Learned Today I Learned x 1
  9. Vincent P

    Vincent P Active Turker

    Messages:
    642
    Ratings:
    +923
    God bless you, I'll give it a try in a second. Not surprised I dropped my ID by accident, hopefully I don't make that mistake again lol.
     
    • Like Like x 1
  10. Vincent P

    Vincent P Active Turker

    Messages:
    642
    Ratings:
    +923
    So, now I can access the innerHTML of the Shadow DOM, and I can access the div "react-mount-point", but I can't access anything past that... For instance,
    [​IMG]

    I am trying to access the elements in these divs, or even just access the divs themselves, but they all return null even after 5 seconds. Here is the code I'm using to try and figure out which elements I can access:
    Code:
            var shadowCheck = document.querySelector("crowd-image-classifier");
            var shadowBtn = shadowCheck.shadowRoot;
            var shadowDeeper = shadowBtn.querySelector("#react-mount-point");
            console.log(shadowDeeper.querySelector("#awsui").innerHTML);
    
    Starts returning null again. I can view the innerHTML of "react-mount-point" and after that get null.
     
  11. AlexZ

    AlexZ Distinguished Butthat

    Messages:
    15,046
    Gender:
    Male
    Ratings:
    +45,934
    "awsui" is a class, not an ID. If you want to select a class, you need to use a period, not #:
    Code:
    console.log(shadowDeeper.querySelector(".awsui").innerHTML);
     
    • Like Like x 1
    • LOL LOL x 1
    • Today I Learned Today I Learned x 1
  12. Vincent P

    Vincent P Active Turker

    Messages:
    642
    Ratings:
    +923
    I knew that last problem was going to be something stupid. I've got enough to go on to get back to trying to figure stuff out on my own. Thanks a lot for your help, I sincerely appreciate it.
     
    • Love Love x 2