Detect facebook like button and twitter share button's onload? - twitter

The 3rd party buttons usually take quite a bit of time to load and having them flash in suddenly is a bit jarring to the aesthetics of the page.
I decided to hide the enclosing div and then fade it in when the buttons load. Is there a clean way to bind an onload event to the buttons?

Here is an example with facebook sdk:
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = '//connect.facebook.net/en_US/all.js#xfbml=1';
js.onload = function(){
FB.Event.subscribe('xfbml.render',
function(response) {
doSomething();
});
};
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
Look at the facebook sdk for event handling:
Facebook Event Handling
After the SDK is loaded, you can acces the FB object.
Or read this article: Asynchronously loading twitter, google, facebook and linked-in buttons and widgets + Ajax bonus

Related

How can I trigger a YouTube video to play in browser on iOS by clicking on a play button instead of the embed?

On my site, I want to have users watch an embedded YouTube video without leaving the page, but I don't want to have the not so stylistic YouTube embed visible prior to clicking.
This is entirely doable on desktop, as you can use the YouTube JavaScript API to trigger the embed to play, but on iOS, programmatic triggering of the player to play is blocked. So how can I do this on iOS?
When thinking about this problem, I thought that one alternative route would be to have a layer that's opaque and styled, but you could click through it. This would mean the user thinks they're clicking a pretty button, when actually they're just clicking the embed to play.
Turns out there's a way of doing this, using the fancy (unofficial) CSS pointer-events property! Setting this to none means that clicks don't register, and instead punch straight through the element to whatever is behind it. In this case, the YouTube embed iframe. Support is iOS 6+.
Here's a JSFiddle of it working.
Note this is for iOS (and maybe Android) - it utilises the behaviour in which the video will automatically go full screen when it starts playing. If you watch this on desktop, the overlay remains.. overlaid.
There's some more polishing to be done with this to get it schmick:
Handling the initial click and altering the UI so they know immediately the video is kicking off. Perhaps hide the overlay, fade it, or change it to simply signify "Loading... "
On finish, resetting the video by recreating the iframe
You could do some tricky stuff with this technique, e.g. having a small player iframe overlaid by a small button. Still going to go fullscreen, so it'll work fine.
But regardless, there you go - proof of concept of playing a YouTube video on iOS without the user knowing they clicked on an embed.
iOS allows to call HTMLMediaElement.play function only from dispatched (triggered) by an user event (for example, from a "click" event handler).
Thus the code like this will work in iOS (because the player.playVideo is called from the dispatched by an user "click" event):
<div class="video">
Play
<iframe width="560" height="315" src="https://www.youtube.com/embed/pqLVAeoRavo?enablejsapi=1" frameborder="0" allowfullscreen allow="autoplay"></iframe>
</div>
<script>
(function() {
var player;
window.onYouTubeIframeAPIReady = function() {
new YT.Player(document.querySelector('.video iframe'), {
events: {
onReady: function(e) {
player = e.target
}
}
})
}
document.querySelector('.video .play').addEventListener('click', function(e) {
e.preventDefault()
player.playVideo()
})
})()
</script>
<script src="https://www.youtube.com/iframe_api"></script>
And the code like this will work in iOS too (because the initial call (the playMyVideo()) is still in the "click" event):
<div class="video">
Play
<iframe width="560" height="315" src="https://www.youtube.com/embed/pqLVAeoRavo?enablejsapi=1" frameborder="0" allowfullscreen allow="autoplay"></iframe>
</div>
<script>
(function() {
var playMyVideo;
window.onYouTubeIframeAPIReady = function() {
new YT.Player(document.querySelector('.video iframe'), {
events: {
onReady: function(e) {
playMyVideo = function() {
var player = e.target
player.playVideo()
}
}
}
})
}
document.querySelector('.video .play').addEventListener('click', function(e) {
e.preventDefault()
playMyVideo()
})
})()
</script>
<script src="https://www.youtube.com/iframe_api"></script>
But the code like this will not work in iOS (because the player.playVideo is called from the https://www.youtube.com/iframe_api script and not from the "click" event; i.e. only the window.onYouTubeIframeAPIReady function declaration is presented in the "click" event and window.onYouTubeIframeAPIReady is called from the https://www.youtube.com/iframe_api script):
<div class="video">
Play
<iframe width="560" height="315" src="https://www.youtube.com/embed/pqLVAeoRavo?enablejsapi=1" frameborder="0" allowfullscreen allow="autoplay"></iframe>
</div>
<script>
(function() {
document.querySelector('.video .play').addEventListener('click', function(e) {
e.preventDefault()
window.onYouTubeIframeAPIReady = function() {
new YT.Player(document.querySelector('.video iframe'), {
events: {
onReady: function(e) {
var player = e.target
player.playVideo()
}
}
})
}
var tag = document.createElement('script')
tag.src = 'https://www.youtube.com/iframe_api'
var firstScriptTag = document.getElementsByTagName('script')[0]
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag)
})
})()
</script>

Stop the back history, juste close panel [duplicate]

I have a jQuery mobile panel which slides in from the side, it works great.
But lets say you have a login page, that redirects to a main page with a panel. Now if the user opens the panel, and then clicks the back button, he expects the panel to close. But instead the browser navigates back to the login page.
I´ve tried adding something to the url:
window.location.hash = "panelOpen";
But that just messes up the jQuery mobile history state pattern. I´ve also tried to listen to the navigate event, and prevent it if a panel is open:
$(window).on('navigate', function (e, hans) {
var panels = $('[data-role="panel"].ui-panel-open');
if (panels&&panels.length>0) {
e.preventDefault();
e.stopPropagation();
$('#' + panels[0].id).panel('close');
return false;
}
});
This kind of works, except that the url is changed, and I cannot grab the event that changes the url. Furthermore, it also messes up the jQuery mobile history pattern.
So how does people achieve this expected 'app-like' behaviour with a jQuery mobile panel; open panel > history back > close panel. And thats it.
Thanks alot!
Updated
Instead of retrieving current URL from jQuery Mobile's history, It is safer to retrieve it from hashchange event event.originalEvent.newURL and then pass it to popstate event to be replaceState() with that URL.
Instead of listening to navigate, listen to popstate which fires before. The trick here is manipulate both browser's history and jQuery Mobile's history by replaceState() and reload same page without transition.
var newUrl;
$(window).on("hashchange", function (e) {
/* retrieve URL */
newUrl = e.originalEvent.newURL;
}).on("popstate", function (e) {
var direction = e.historyState.direction == "back" ? true : false,
activePanel = $(".ui-panel-open").length > 0 ? true : false,
url = newUrl,
title = document.title;
if (direction && activePanel) {
$(".ui-panel-open").panel("close");
$(".ui-header .ui-btn-active").removeClass("ui-btn-active");
/* reload same page to maintain jQM's history */
$.mobile.pageContainer.pagecontainer("change", url, {
allowSamePageTransition: true
});
/* replace state to maintain browsers history */
window.history.replaceState({}, title, url);
/* prevent navigating into history */
return false;
}
});
This part is meant to maintain same transition used previously as transition is set to none when reloading same page.
$(document).on("pagebeforechange", function (e, data) {
if (data.options && data.options.allowSamePageTransition) {
data.options.transition = "none";
} else {
data.options.transition = $.mobile.defaultPageTransition;
}
});
Demo - Code
I am a little bit late on the party, but i had recently the same requirements and i would like to share how i did it. So, i extended the requirement in the original question to Panels, Popups and Pages:
...an expected 'app-like' behaviour, history back > close
whaterver is open. And thats it.
In .on("panelopen"), .on("popupafteropen") and .on("pagecontainershow") i simply add another entry to the window history, by using the HTML5 API (https://developer.mozilla.org/en-US/docs/Web/API/History_API) (I believe there is no need to use the JQM navigate browser quirks for that):
window.history.pushState({}, window.document.title, window.location.href);
After that, i'm using more or less Omar's function to intercept the popstate event:
$(window).on("popstate", function (e) {
var pageId = $(":mobile-pagecontainer").pagecontainer("getActivePage").prop("id");
var pageOpen = (pageId != "page-home");
var panelOpen = $(".ui-panel-open").length > 0;
var popupOpen = $(".ui-popup-active").length > 0;
if(pageOpen) {
$.mobile.pageContainer.pagecontainer("change", "#page-home", {reverse: true});
return false;
}
if(panelOpen) {
$(".ui-panel-open").panel("close");
return false;
}
if(popupOpen) {
$(".ui-popup-active .ui-popup").popup("close")
return false;
}
});
As you see, the is just only one level to the home-page, but this can be easily extended by using JQM history implementation to get the previous page:
var activeId = $.mobile.navigate.history.activeIndex;
var jqmHistory = $.mobile.navigate.history.stack; // array of pages
and use pagecontainer to change to the active entry - 1.
As last note, this works well also by completely disabling the built-in JQM Ajax navigation system:
/* Completely disable navigation for mobile app */
$.mobile.ajaxEnabled = false;
$.mobile.loadingMessage = false;
$.mobile.pushStateEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.changePage.defaults.changeHash = false;
$.mobile.popup.prototype.options.history = false;
(Tested in Browser, on real Android and iOS devices)

onStateChange does not fire the second time

There seems to be a lot of discussion around onStateChange event not firing but I cannot seem to find the answer my specific problem. In my case, I can connect fine with the API and load the video. The API ready event fires, followed by onPlayerReady and then onStateChange. When I closer the viewer (iFrame in which the video is embedded) and open it up again, the API ready event fires, followed by the onPlayerReady however the onStateChange does not fire when the video starts playing...
I have to refresh the browser and load the script again for the same or a different video to work which obviously in my case is not an acceptable solution.
I have also tried manually adding the listener but unfortunately I have the opposite issue with that, as multiple events are then fired as there is no way to remove that listener on closing the viewer.
I should also add that the behaviour is the same in Chrome and Firefox (latest versions)
Your help in this matter will be really appreciated.
Thanks,
Okay so I dug into the code a little bit more and minimized it to the exact problem. It's an issue with the iFrame set url call. Jeff, I modified your example on JSfiddle (http://jsfiddle.net/jeffposnick/yhWsG/3/) as follows:
HTML Code:
<div id="DIVTAG">
<iframe class="gwt-Frame" id="player" width="640" height="360" src="https://www.youtube.com/embed/M7lc1UVf-VE?wmode=transparent&enablejsapi=1&modestbranding=1&rel=0&showinfo=0&fs=0;autoplay=1"></iframe>
</div>
<button onclick="hide()">Hide Player</button>
<button onclick="show()">Show Player</button>
JavaScript Code:
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
events: {
'onReady': onReady,
'onStateChange': onPlayerStateChange
}
});
}
function onReady() {
alert("player ready");
}
// The API will call this function when the video player state changes.
function onPlayerStateChange(event) {
alert("player state changed");
}
function hide() {
player.stopVideo();
document.getElementById("player").style.display="none";
}
function show() {
document.getElementById("player").style.display="block";
document.getElementById("player").src="https://www.youtube.com/embed/M7lc1UVf-VE?wmode=transparent&enablejsapi=1&modestbranding=1&rel=0&showinfo=0&fs=0;autoplay=1";
}
You can choose to ignore the "hide player" button and just click on "show player" once the video loads and you will see that the stateChange events will not fire once the player is loaded the second time.
I am simply setting the source of the iframe on which the onReady event is fired both times but the onStateChange is not. Hope this helps to suggest a fix.
That's not how you load a new video into an existing player. You should be calling player.loadVideoById('VIDEOID') instead of trying to change the src attribute of the existing iframe.
And as mentioned, please don't hide the player by setting display: none. You can move the player offscreen (negative x/y position) if needed.

Are YouTube view counts incremented when using the iframe Player?

We are embedding a youtube player into our page. Easy implementation of code and html5 support driven us to use the youtube iframe player.
Problem is that view count does not work with the api. No video does not autoplay and we are playing the video with youtube's default play button.
When I revert back to a AS3 player view count seems to work.
Is it a bug in the iframe api?
Anyone come across a solve?
Thanks!!!
Views that originate as a result of clicking on one of the native player UI elements (either the play button in the control bar or on the static player image) will normally count towards incrementing the views for a video. There are obviously other signals that could come into play, but all things being equal, there's no reason why using an <iframe> embed vs. an ActionScript 3 embed should prevent views from being counted.
If you have a specific example of your implementation that you want to pass along, I can take a look and see if you're doing anything unorthodox.
we have created a simple test html file with a video using the YouTube iFrame API, as the idea is to have the videoplayer fall back to the HTML5 videoplayer on mobile devices. However views are not being counted on click to play video:
http://www.youtube.com/watch?v=-LHUt9FGgys
In the body of the html we have the following:
<div id="player"></div>
<script>
var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: '-LHUt9FGgys',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(event) {
//event.target.playVideo();
}
var done = false;
function onPlayerStateChange(event) {
// if (event.data == YT.PlayerState.PLAYING && !done) {
// setTimeout(stopVideo, 6000);
// done = true;
// }
}
function stopVideo() {
player.stopVideo();
}
</script>
It would be interesting to see if you or someone else has a solution for this. Thanks!

How to make jQuery Mobile not manipulate the hash when displaying a dialog

I have a jQuery Mobile + backbone site. To play nice with backbone, I've also disabled routing like so:
$(document).bind("mobileinit", function () {
$.mobile.ajaxEnabled = false;
$.mobile.linkBindingEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.pushStateEnabled = false; });
I'd like to display a dialog via js in my jQM + backbone site:
$.mobile.changePage("#dialog",
{
transition: 'pop',
role: 'dialog',
changeHash:false
});
The problem is, this fires a hash change event. My page router picks this up and routes to an incorrect page, away from the dialog.
Why does a simple changePage with a dialog ignore the changeHash parameter? Anyone else run into this?
I know it's quite an old thread - but the problem is the following:
By: $.mobile.hashListeningEnabled = false; you are disabling the jqm routing facility and so jqm does not listen on hash changes but the backbone router does. What you need to do is to define an event in your corresponding backbone view where the dialog shall be opened - would be something like:
var YourView = Backbone.View.extend({
[...]
events: {
"click #myDialog: "openMyDialog"
},
openMyDialog:function() {
[Call your Dialog/Popup here]
}
})

Resources