0

I have to review a large number of videos on a webpage (screenshot below). The videos are partially hidden. And to view each video, I have to click the more button one by one (as shown in the image below). enter image description here

There are often 40 videos per page. Constantly scrolling and clicking the more button over and over again is tedious, and if I keep doing it I think I'll have a repetitive stress injury.

So, I thought I'd use Chrome Dev Tools' console to identify the buttons and send them clicks all in one batch process.

I am able to find the more buttons using the inspect tool in Chrome Dev Tools, like so: enter image description here

The more button's DOM-tree breadcrumb via inspect (please CLICK to enlarge, there are two image parts below):

enter image description here

enter image description here

The more button markup code looks like this:

<button class="d2l-label-text" type="button">
    <d2l-icon class="d2l-button-subtle-icon" icon="d2l-tier1:chevron-down" dir="ltr"></d2l-icon>
    <span class="d2l-button-subtle-content"><!---->more<!----></span>
    <slot></slot>
</button>

and the more button's class is d2l-label-text

I thought I'd do something like this in the console:

> let allbuttonsArray = document.getElementsByClassName("d2l-label-text");

  for (let eachbutton of allbuttonsArray) {
    eachbutton.click();
  }

However, it turns out that document.getElementsByClassName("d2l-label-text") is not grabbing anything. The length of the result array is 0.

I tried to play around with some other selectors and discovered that the console is not grabbing from the generated source/computed html, it's only grabbing tags/elements that are there in the source (the original source that can be obtained via right-click, view source).

My Question: What am I doing wrong? How do I get the console to grab the generated source/computed html more buttons?

thanks_in_advance
  • 2,603
  • 6
  • 28
  • 44

2 Answers2

2

As can be seen on the screenshots, the element is inside a ShadowRoot which means it's not accessible directly from the main document.

To find such an element you'll have to access the ShadowRoot chain recursively.
In your case there are two elements in this chain.

for (const more of document.querySelectorAll('d2l-more-less')) {
  for (const buttonSubtle of more.shadowRoot.querySelectorAll('d2l-button-subtle')) {
    const btn = buttonSubtle.shadowRoot.querySelector('button');
    if (btn) btn.dispatchEvent(new MouseEvent('click', {bubbles: true}));
  }
}

In case the shadowRoot is created by the page in 'closed' mode you'll probably have to hook Element.prototype.attachShadow in page context script.

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • Thank you for your suggestions. I tried your code directly in the console and it didn't work. So I'm going to try the `Element.prototype.attachShadow` suggestion a little later. In particular, thank you for documenting your response so beautifully (with links). I've upvoted you and if the `attachShadow` suggestion works, I'll mark it as the correct answer. – thanks_in_advance Oct 06 '19 at 17:59
  • 1
    Start by verifying the state of ShadowRoot in devtools: https://puu.sh/EpwpX/1dc0c5de86.png – wOxxOm Oct 06 '19 at 18:55
  • Thanks. Both the `shadow roots` are open, screencap here: https://imgur.com/qL0xbP1 – thanks_in_advance Oct 06 '19 at 19:47
  • 1
    Well it means the approach in this answer will work but you need to adapt it properly. For example those weren't classes, but element tag names, which I only now realized from your new screencap. Also maybe the element uses a different event listener like `mousedown`, which you can see in devtools "Event listeners" sub-panel. Anyway, I don't see how I can help further without trying the page myself. – wOxxOm Oct 06 '19 at 20:22
  • Thanks brother: this is the final code that worked: `for (const more of document.querySelectorAll('d2l-more-less')) { for (const buttonSubtle of more.shadowRoot.querySelectorAll('d2l-button-subtle')) { buttonSubtle.shadowRoot.querySelector('.d2l-label-text').click(); } }` (if you have any thoughts on why `btn.dispatchEvent(new MouseEvent('click', {bubbles: true}));}` didn't work, do share) – thanks_in_advance Oct 08 '19 at 05:45
  • 1
    It's because the event listener is attached to `.d2l-label-text`, not to `button`, apparently. – wOxxOm Oct 08 '19 at 06:06
0

Do you know if the content you are trying to get is inside an iframe within the page?

If so I believe you'd need to get the iframe first then use

theiframe.getElementsByClassName()
Pineapple Joe
  • 199
  • 10
  • The content is not in an `iframe`. Thank you for your useful suggestion. I saw some references to how `iframe` can be a cause of such behavior. – thanks_in_advance Oct 05 '19 at 19:54
  • @thanks_in_advance then I think it would help to see more of the html. A very basic test works.
    ---then in console--- var rows = document.getElementsByTagName('tr'); console.log(rows.length);
    – Pineapple Joe Oct 05 '19 at 21:56
  • Thanks for helping me with this, Pineapple. Your basic test works for me (I put that code in a new `.htm` file and ran that code and it worked. I've added the HTML DOM-tree's breadcrumbs to my original question, please have a look (they're in a couple screenshots). – thanks_in_advance Oct 06 '19 at 18:20