Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Twitter Embedded Timeline Callback

I've been doing a lot of research into Twitter's Embedded Timelines. I've been trying to figure out if it is possible to know when the timeline is finished loading and displays on the page. This issue has been requested, but has yet to be implemented. I have come to a dead end an am hoping someone is able to help me find the solution. Here is what I have found so far:

The code to add an Embedded Timeline:

<a class="twitter-timeline" href="https://twitter.com/twitterapi" data-widget-id="YOUR-    WIDGET-ID-HERE">Tweets by @twitterapi</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>

What happens when the script is run:

  1. The script replaces the <a> tag with an <iframe> element.

  2. The contents of the iframe are ready, but the avatar image and the 'follow @username' button are not done downloading. The iframe's height attribute is set to 0 so that you don't see the content without the images.

  3. The avatar image is downloaded, but the 'follow @username' button is still downloading. Content is still not visible.

  4. The 'follow @username' button is finished downloading. The iframe's height attribute is set to match the height of the contents of the iframe. The timeline is now visible.

Now, I've tried everything I can think of to figure out when the timeline is visible (without using settimeout/interval). The goal is to have a non-polling event/function/callback. Here is what I have tried so far without success:

  • Setting event listeners on the iframe (such as onload, DOMContentLoaded, DOMFrameContentLoaded, etc) to know when the content has finished loading. This doens't work becuase the iframe has no src attribute. After going through the uglified code (I was unable to find an uncompressed version), my guess is that it is using writes to add the content to the body of the iframe.
  • Setting event listeners to know when the height attribute changes on the iframe. Theoretically, this event should fire three times: first when the content loads, second when the height is set to 0, and third when the height is set to show the fully loaded timeline. However, I was only able to get the event to fire for the first two cases and never for the third (the one I actually wanted). I used DOMSubtreeModified, onreadystatechange, and onpropertychange, but only DOMSubtreeModified worked for firing the event.
  • Setting event listeners on the cotents of the iframe. Because JavaScript can reach inside of the iframe from Twitter, it is possible to grab any element inside the iframe (such as document or window). However, adding onload, DOMContentLoaded, or DOMFrameContentLoaded event listeners on the window or document of the iframe still does not fire those events.
  • Setting event listeners on the 'follow @username' button. The button is actually an iframe that does have a src attribute. By setting an onload event, it will get fired when it is loaded. However, the onload event will always fire twice. The first time when it has finished downloading and the second when it has finished processing. Immediatly after the second trigger, the timeline will be shown. To implement this is quite the hack though (I guess everything is) since you must wait for the contents of the iframe to load, reach inside and get the 'follow @username' iframe, set an onload event on it, then wait for the second event to fire.
  • Using the twttr.widgets.createTimeline() function, which has an optional parameter for a callback. However, the callback is called when the content is ready (step 2), but not when the iframe is visible (step 4).

There's probably a few more combinations I forgot at this point. I know there exists a github gist that uses the Twitter widget.js, but adds callbacks to it. I was unable to get this to work.

Sorry for the log question, but I hope someone is able to help. Thanks.

like image 529
Steven Lambert Avatar asked Jul 22 '13 22:07

Steven Lambert


People also ask

What is embedded timeline?

An Embedded Timeline lets site visitors scroll through past, present, and future events. These events can be marked with text, images, or both. Embedded timeline styles "vertical by month" and "vertical by year" show a continuous vertical timeline as opposed to the existing scrollable horizontal timeline.

Can you see someone's Twitter timeline?

The media timeline on your profile displays the photos, videos, and GIFs you've uploaded with your Tweets. You can also visit other people's profiles to view their media timelines.

What is Twitter embedded?

Embedded Tweets bring your pick of content from Twitter into your website articles. An embedded Tweet includes photos, video and cards media created for display on Twitter, and can even stream live video from Periscope.


2 Answers

I'm gonna post my solution here even if it's been 1month just in case someones finds this post again, what I had to do was to poll until the iframe had a width > 1 as an indicator for callback

if ($('.twitter-timeline').length) {
    //Timeline exists is it rendered ?
    interval_timeline = false;
    interval_timeline = setInterval(function(){
        console.log($('.twitter-timeline').width());
        if ($('.twitter-timeline').hasClass('twitter-timeline-rendered')) {
            if ($('.twitter-timeline').width() > 10) {
                //Callback
                clearInterval(interval_timeline);
                DoWhatEverYouNeedHere();
            }     
        }
    },200);
}
like image 62
Elyx0 Avatar answered Sep 22 '22 04:09

Elyx0


You could try using the Javascript factory instead of attribute binding. The createTimeline method returns a promise so you can chain your post load activities there. See the twitter documentation: https://dev.twitter.com/web/embedded-timelines/parameters

twttr.widgets.createTimeline(
    "YOUR-WIDGET-ID-HERE",
    document.getElementById("container"),
    {
        height: 400,
        chrome: "nofooter",
        linkColor: "#820bbb",
        borderColor: "#a80000"
    }
)
.then(function(){
      DoSomething();
});
like image 36
crispybits Avatar answered Sep 22 '22 04:09

crispybits