Search code examples
javascriptmicrosoft-edgeselectors-api

:scope pseudo-selector in MS Edge


Whenever I use querySelectorAll in Microsoft Edge with the :scope pseudo-selector, this error appears in the console

SCRIPT5022: SCRIPT5022: SyntaxError

I was wondering if there was an alternative to querySelectorAll, where I use this parameter: :scope > * > table. I do not want to use jQuery for this. Thanks.

EDIT:

I also wanted to add that querySelector works by itself

Okay, here is the code sample:

            function pJSON(panel) {
                var json = {tables: [], images: [], text: ""};
                var tables = Array.from(panel.querySelectorAll(":scope > * > table"));
                var images = Array.from(panel.querySelectorAll(":scope > * > img"));
                var text = panel.querySelector(":scope > textarea");
                tables.forEach(table => {
                    json["tables"].push(tJSON(table));
                });
                images.forEach(image => {
                    json["images"].push(image.outerHTML);
                });
                if (text) {
                    json["text"] = text.value;
                }
                return json;
            }

I will note again that it works in all browsers except IE and Microsoft Edge

Oh, and an example of some HTML that might be dynamically added, this is the code that was there when I called this method:

<div>
    <input type="file" multiple=""><br>
    <button>Add Table</button><br>
    <div>
        <table style="display: inline-table;">
            <tbody>
                <tr>
                    <td>
                        <input type="file" multiple=""><br>
                        <button>Add Table</button><br>
                        <textarea placeholder="Write some text"></textarea>
                    </td>
                    <td>
                        <input type="file" multiple=""><br>
                        <button>Add Table</button><br>
                        <textarea placeholder="Write some text"></textarea>
                    </td>
                    <td>
                        <button style="margin-left: 100px;">x</button>
                    </td>
                </tr>
                <tr>
                    <td>
                        <input type="file" multiple=""><br>
                        <button>Add Table</button><br>
                        <textarea placeholder="Write some text"></textarea>  
                    </td>
                    <td>
                        <input type="file" multiple=""><br>
                        <button>Add Table</button><br>
                        <textarea placeholder="Write some text"></textarea>
                    </td>
                    <td>
                        <button style="margin-left: 100px;">x</button>
                    </td>
                </tr>
            </tbody>
        </table>
        <button style="margin-left: 100px;">x</button>
    </div>
</div>

Solution

  • So what you are after is actually a polyfill for :scope.

    There is one available at https://github.com/jonathantneal/element-qsa-scope

    How it works is basically to first define a unique enough selector on the element to be matched and prepend it to the selector passed to querySelector.

    const li = document.getElementById('target');
    console.log('no :scope', li.querySelector('li>a')) // Link
    
    // workaround
    const UUID = Date.now()+'';
    li.setAttribute('data-scope-uuid', UUID);
    console.log('workedaround', li.querySelector('[data-scope-uuid="'+UUID+'"] li>a'));
    li.removeAttribute('data-scope-UUID');
    
    // where supported
    console.log(':scope', li.querySelector(':scope li>a'));
    <ul>
      <li id="target"><a>Link</a>
        <ul>
          <li><a>Sublink</a></li>
        </ul>
      </li>
    </ul>

    And to test for native support, you can simply wrap a document.querySelector(':scope') === document.documentElement in a try catch block.