The problem shows on IPad with IOS 8.0.1.
It is infinite audio, that playing on page1.html
I supposed that the sound will stop playing if I go to another page (for example page2.html), but it still have been playing.
I tried to use unload, pagehide and visibilitychange events to stop it, but all my efforts failed.
The code
<audio id="sound" loop src="audio/baby.mp3"></audio>
<script>
var player = document.getElementById("sound");
window.addEventListener("unload", function () {
player.pause();
});
if ('onpagehide' in window)
window.addEventListener("pagehide", function () {
player.pause();
});
if ('onvisibilitychange' in window)
window.addEventListener("visibilitychange", function () {
player.pause();
});
</script>
The sound stops only if I reload the page, where it was activated.
Find out!
Maybe it's bug of Safari:
Using native attribute "loop" you cannot stop audio.
So I replaced it with my own loop function, that includes page visibility check
player.addEventListener("ended", function() {
if (windowVisible)
player.play();
});
Related
I am using jquery mobile to close and open a menu in an app like this:
$('body').on('swipeleft', function(event){
if(menuOpen == true){
home.showMenu();
}
});
$('body').on('swiperight', function(event){
if(menuOpen == false){
home.showMenu();
}
});
And I have a input range (slider) in my menu like this:
<input id="changeRadiusRange" type="range" min="5" max="100" step="5" oninput="handleInputVal(value)" onchange="handleChangeVal(this.value)">
Now if I use my slider it stops after some time (I think the 30pixel for swipeleft/right to get fired and menu is closing if it is a swipeleft)
I already tried a few things regarding to this question, that results in this but didn't changed the behavior:
$('#changeRadiusRange').on('swipeleft swiperight', function(e){
e.stopPropagation();
e.preventDefault();
});
How can I force input behavior as normal not to be influenced by swipe-events?
I had the same problem today and found a less hacky solution.
var handleSwipe = function (event) {
// my swipe stuff
}
// regular event listening
$(document).on("swipeleft swiperight", handleSwipe);
// additional workaround
$(".slider").on("mousedown touchstart", function (event) {
// when starting to interact with a .slider, stop listening the event
$(document).off("swipeleft swiperight");
}).on("mouseup touchend", function (event) {
// when interaction stops, re-listen to swipe events
$(document).on("swipeleft swiperight", handleSwipe);
});
It seems that sliders never ever work properly, as long as the swipe events are used anywhere in the document. This is even the case, when there is nothing done in the event handler. Also preventDefault() and/or stopPropagation() doesn't change anything.
With this solution, I kill the previously enabled swipe events while the user interacts with a slider. When interaction is done, I re-enable swipe events. Works great for me.
This worked for me with jqm 1.4.5:
$(document).on('mousedown touchstart', 'input[type=range]',
function(e){
e.stopPropagation();
});
Currently solved it like this:
$('body').on('swipeleft', function(event){
if(event.target.id != "changeRadiusRange"){
if(menuOpen == true){
home.showMenu();
}
}
});
But then slider is stopping after the swipeleft event is called from body. does not move more to the left so I have to release the slider and slide again to the left if I need to till the swipeleft is called etc. Just workaround hope got it fixed soon
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>
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.
So only in safari on the ipad I am having an issue with the play/pause not firing inside a setTimeout. This works in all browsers and even in safari on PC and Mac, just not on ipad. If I take the setTimeout it works, but I need the setTimeout.
This is for JWPlayer 5.9.2156
jwplayer("Container").setup({
events: {
onBeforePlay: function () {
jwplayer("Container").pause('true');
if(tOut) {
clearTimeout(tOut);
tOut = null;
}
var tOut = setTimeout($.proxy(function () {
jwplayer("Container").pause("false"); //this doesnt happen
console.log("this happens");
}.bind(this), this), 1000);
},
onPause: function (e) {
//this isnt firing
console.log("OnPause fired: "+e.oldstate);
}
...
While this may not be on the same topic at first glance the accepted answer given here also applies to this situation.
HTML5 audio object doesn't play on iPad (when called from a setTimeout)
I have a web page that plays an embedded sound. If I "close" the browser on the iPad while the sound is playing, the sound does not stop. How can I make the sound stop playing when the browser is not visible?
Thought I'd let you know, since I just managed to find a solution.
Code like this, should work:
var lastSeen;
var loop = function (){
lastSeen = Date.now();
setTimeout(loop, 50);
};
loop();
var music = document.getElementById('music');
music.addEventListener('timeupdate', function (){
if(Date.now() - exports.lastSeen > 100){
this.pause();
}
}, false);