-1

I have an AppleScript I wrote that gets some information from a webpage (that's not mine), but the page has recently updated so that a value I need is in the shadow DOM, and not the main DOM (as shown in the Safari's Web Inspector). Before, I was using this AppleScript to retrieve the value:

set dateText to (do JavaScript "$('input#release_week').attr('value')" in doc) as string

With this being the operative JavaScript (using jQuery because the target page does):

$('input#release_week').attr('value')

Since the evaluated DOM now looks like this:

...
<input id="release_week" type="text" value="02/02/2022">
    <!-- Shadow Content (User Agent)
    <div contenteditable="plaintext-only">12/08/2021</div>
    -->
</input>
...

I'm always getting back the 02/02/2022 value, when I want the inner 12/08/2021 value instead. I've tried different variations, using the .shadowRoot property, and the >>> "shadow-piercing descending descendant combinator", neither of which worked.

What new JavaScript code can I use? The text I'm looking for is shown and selectable on the page, so I'm hopeful there has to be a way to get to it.

Update 2/3/22

This is the page I'm trying to get the date from, and this is the page element I'm trying to read the text from (at the top of the page), which doesn't match the <input>'s value after you click one of the arrows:

Date on page

Dov
  • 15,530
  • 13
  • 76
  • 177
  • We can attach shadow DOM to only [a few elements](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow) and `input` element is not one of them. If tried it throws `NotSupportedError`. Can you share reproducible code on [codesanbox](https://gerny.csb.app/shadowDom.html)? – the Hutt Feb 03 '22 at 05:33
  • @codesanbox I've added a URL and screenshot of the element I'm working with if you'd like to take a look. As mentioned, it's not a page I own. – Dov Feb 03 '22 at 18:10

3 Answers3

1

It's not related to shadow DOM. Following elements are maintaining the value:

<input id="date_release_week" type="text" name="date_release_week" class="filter-options-date date-pick dp-applied hasDatepicker" maxlength="255" autocomplete="off" value="02/02/2022">
<input id="date_begin" type="hidden" name="date_begin" class="filter-options-date-begin" maxlength="255" autocomplete="off" value="02/02/2022">
<input id="date_begin" type="hidden" name="date_begin" class="filter-options-date-begin" maxlength="255" autocomplete="off" value="02/03/2022">

In devtool console if you run one of the following you'll get the actual selected date value:

date_release_week.value
date_begin[0].value
date_begin[1].value

Also, in Jquery, use val() function to get input value:

$('input#date_release_week').change(() => {
  console.log('attr(\'val\'): ' + $('input#date_release_week').attr('value'));
  
  console.log('val(): ' + $('input#date_release_week').val());

})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
Type something and press enter.
<input type="text" id="date_release_week" name="name" required minlength="4" maxlength="8" size="10" value='add'>
the Hutt
  • 16,980
  • 2
  • 14
  • 44
-1

You can directly use the selector for div tag to get the data. Here is an example.

$(document).ready(function(){
  $('#btn').on('click', function(){
   alert($('div[contenteditable="plaintext-only"]').text());
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

<input id="release_week" type="text" value="02/02/2022">
    <!-- Shadow Content (User Agent) -->
    <div contenteditable="plaintext-only">12/08/2021</div>
</input>

<button id='btn'>GetData</button>
<label id='data'></label>
Srikant Sahu
  • 839
  • 1
  • 6
  • 16
  • I think you misunderstood - the inner `div` is shadow content, not in the regular DOM. I've updated my code snippet so it's clearer. – Dov Feb 03 '22 at 03:24
-1

So, if you can get the value of an element in the main document, you can just use $.attr() to get what you want. The same can be done if you know the shadow DOM, using $('input#release_week').closest('shadowRoot').find('div').

As for which new JavaScript to use, or where to look for help on how to use it, I'm not sure. I know there's a new module that's part of the Web Components polyfill called Element.prototype.getRootNode(), but that only works for elements in the main document -- there's no equivalent for shadow roots. So, unless something like this gets added to Web Components (I don't think it will), then you're kinda stuck with plain jQuery as far as I can tell.

My best guess would be something like this:

var root = someElementShadowRoot;
while (root) {
    if (root === document) { // your main document object
        return; // stop traversing and return element; it's not shadow DOM!
    } else { // this is a shadow DOM node tree, recurse deeper into its hierarchy
        root = root.getRootNode(); // returns a reference node / parent node / null (if at top of shadow DOM tree) -> recursive call! if statement will keep running until it finds the document and returns nothing
    }
}
return someElement; // you've reached the top of the shadow DOM tree; this is where you want to start. It may be possible that `someElement` is not actually a shadow root node, but it will be at this point (`someElement.getRootNode() === someElement`).
PJMan0300
  • 86
  • 5
  • Hi, and thanks for trying to help me figure this out. I tried the `.closest('shadowRoot')` approach, which didn't return anything. I've added a URL and screenshot of the element I'm working with if you'd like to try things out in the debugging console. – Dov Feb 03 '22 at 18:06