2

I'm trying to see if it's possible to add tabindex, along with enter key support, to some social share buttons (divs) loaded from an external library, ShareThis. The problem is I cannot seem to consistently run javascript after the buttons are actually in the DOM. I thought that according to this graph and the article it came from, I should be able to use the window.load event because it supposedly fires even after asynchronous scripts complete. I could always remove the async attribute from the script in my code, but there are scripts within the ShareThis script (a minified script that I don't think I have any control over), that have the async attribute, which is where i assume the problem is. Initially I had this:

    <script>
        function modifyShareButtons() {
            var buttons = document.getElementsByClassName('st-btn');
            for (btn of buttons) {
                btn.setAttribute('tabIndex', '0')
            }
        }
        window.addEventListener('load', (e) => modifyShareButtons());
    </script>
  <script type='text/javascript' src='//platform-api.sharethis.com/js/sharethis.js#property=12345mypropertykey12345&product=inline-share-buttons'></script>  

but this solution seems to only work - that is, call modifyShareButtons() after the buttons have actually loaded, on some browsers, and very inconsistently, suggesting that there's still a race condition.

I've tried some other solutions:

  • Attaching an onLoad attribute to the external script instead of using the window.load event. Didn't work; the handler always gets called before the buttons are in the DOM.

  • Checked if ShareThis provides some callback option or event: as far as I know, they don't.

  • They do have a "custom button" option. This would seem like the way to go, except there doesn't seem to be a way to ONLY display the custom options. Also I want them to appear as the default buttons. So I tried copy and pasting the HTML from the default buttons, adding the custom property class. This results in two identical button containers on top of each other - not acceptable. I can get rid of the default one with this style:

.st-sticky-share-buttons:not(.st-sticky-share-buttons--custom) {
    display: none !important;
}

This is admittedly extremely hacky, and if ShareThis changed their style names in the future, it would break and we'd have double buttons again, which would be very bad. But - it does mostly work. But it still leaves a problem - I don't have the share counts if I do this approach, which I need. They do provide an API for this, but it won't let me get the data because of the API server's cors policy:

Access to fetch at 'http://count-server.sharethis.com/v2.0/get_counts?url=my-url.com/' from origin 'my-url.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

What this tells me is, back to square one, basically.

This leaves me with two options that I can think of, both very undesirable:

  1. Do some sort of interval check every second until the buttons are loaded in the DOM. Unreliable, hacky, potentially opens itself up to bugs where the check never stops.
  2. Use a MutationObserver. Since ShareThis adds the buttons directly inside the body, I would need to observe the entire body, I think, which I would think is extremely costly performance-wise. This is the type of approach that I should not have to do.

Some other resources I found:

  • The accepted answer from the graph link I posted near the beginning explains that jQuery's document.ready() function checks the readyState and doesn't get called until it's complete. But like
    everything else I've tried, the buttons are still not in the DOM when this function is called.
  • OP from this question claims they added tabIndex. My question is, how on earth did they do that? They didn't say.
  • This resource is vague and doesn't include a complete solution to my problem.
  • There's a pretty lengthy drupal discussion on this, and some patches included. But it seems like there's something separate from those patches that allows Drupal to execute this patch at the correct time, and I don't know what that functionality looks like.
Aaron
  • 21
  • 1

1 Answers1

1

I would recommend using a function to create the script tag, rather than adding it to the HTML.

Doing it this way allows you to create a callback function that won't execute until the main function has completed.

<script>
    function loadSocialButtons(callback) {
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = '//platform-api.sharethis.com/js/sharethis.js#property=12345mypropertykey12345&product=inline-share-buttons';
        document.getElementsByTagName('head')[0].appendChild(script);
        callback();
    }

    function addProperties() {
        var buttons = document.getElementsByClassName('st-btn');
        for (btn of buttons) {
            btn.setAttribute('tabIndex', '0')
        }
    }

    loadSocialButtons(addProperties);
</script>

If it's helpful, you can also add a delay on the callback function by using setTimeout.

function addProperties() {
    setTimeout( function(){
        var buttons = document.getElementsByClassName('st-btn');
        for (btn of buttons) {
            btn.setAttribute('tabIndex', '0')
        }
    }, 1500 );
}
Josh
  • 3,872
  • 1
  • 12
  • 13