In Firefox when a video tag is wrapped in an a tag, using the standard video controls when clicking on the video to pause it also re-directs. How can I make it behave like the other browsers where for example clicking on pause only pauses the video and does NOT re-direct as well. This is what I need.
Here is a simple demo: http://jsfiddle.net/me2loveit2/cSTGM/
<a href="http://www.google.com" target="_blank">
<video controls="" muted="" preload="auto" id="testid" width="500">
<source src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4"/>
<source src="http://www.w3schools.com/html/mov_bbb.ogg" type="video/ogg"/>
<source src="http://www.w3schools.com/html/mov_bbb.webm" type="video/webm"/>
<img src="http://dummyimage.com/1044x585/000/fff"/>
</video>
</a>
What you've got there is invalid markup, the HTML5 spec clearly states that
The a element may be wrapped around entire paragraphs, lists, tables, and so forth, even entire sections, so long as there is no interactive content within (e.g. buttons or other links).
and the video navigation is in fact interactive content containing buttons.
For some reason clicking the controls in Chrome does not trigger the anchor, while in Firefox it does.
This is dependant on how the browser constructs the controls with the Shadow DOM, and as the markup is invalid and there is no real standard for this, it's anyone's guess.
What you should have done is to remove the anchor and use javascript to redirect when the video is clicked, something like this
$('#testid').on('click', function() {
var win = window.open('http://www.google.com', '_blank');
win.focus();
});
That would have given you valid markup as you could just remove the wrapping anchor, but it doesn't solve the problem with not redirecting when clicking the controls either, it's exactly the same, as the controls are still inside the video and triggers the click handler in Firefox, but not in Chrome.
In webkit the controls could potentially have been targeted somehow with the -webkit-media-controls pseudo class, however Firefox doesn't seem to have any such pseudo class, so that won't work either.
What you're left with is relying on the fact that the controls seem to always be at the bottom, and they are around 30 pixels high, so you can just overlay the anchor on top of the video and leave out a little part of the bottom.
This will work in all browsers, and you'll have valid markup.
<video controls="" muted="" autoplay preload="auto" id="testid" width="500">
<!-- stuff -->
</video>
To make sure the anchor is placed correctly and has the correct size, a little javascript can be used
$('.overlay').each(function() {
var vid = $(this).prev('video');
$(this).css({
position : 'fixed',
top : vid.offset().top + 'px',
left : vid.offset().left + 'px',
width : vid.width() + 'px',
height : (vid.height() - 30) + 'px',
});
});
FIDDLE
Other than using custom controls, I am not sure it's possible to get around the control behavior in a truly elegant way, given that the video events (play, pause, etc) trigger after the click events. This is a solution that hardcodes the approximate height of the default controls. I don't like the hardcoding, but in other respects I think it is OK. It applies to all a and video elements and doesn't do any excessive iterating through elements. The setTimeout bit is a workaround for event.preventDefault() killing both the link behavior and the play/pause behavior.
$(document).on('click', 'a', function(event) {
var video = $('video:hover').first();
if (video.length && video.offset().top + video.height() - event.pageY < 35) {
var anchor = $(this);
var href = anchor.attr('href');
var target = anchor.attr('target');
anchor.attr('href', 'javascript:;');
anchor.attr('target', null);
setTimeout(function() {
anchor.attr('href', href);
anchor.attr('target', target);
}, 1);
}
});
You can accomplish this by creating custom controls for your video and wrap only the video tag with the a tag and not the controls. This gives you the option of having consistent looking controls for your video across browsers, but you have to have a good understanding of CSS to make it look good and consistent across browsers. I have included a CodePen project of what you wanted, with some custom controls. The controls don't look very good across browsers, but I think you can get the idea.
http://codepen.io/anon/pen/dtHsb
Very ugly, but the usual solutions don't works because event.stropPropagation() only work for event handlers and event.preventDefault() breaks the controls.
http://jsfiddle.net/cSTGM/28/
$('#testid').click(function() {
link = $(this).parent();
originalHref = link.attr('href');
originalTarget = link.attr('target');
link.attr('href', 'javascript:void(0)');
link.attr('target', '_self');
setTimeout(function() {
link.attr('href', originalHref);
link.attr('target', originalTarget);
}, 0);
});
We just need to prevent redirecting if it is VIDEO tag
$('#testid').click(function() {
if (event.target.tagName !=== 'VIDEO') {
//redirect
}
});
Here is the web page I'm working on: http://sebastianbiermanlytle.com/music.htm
When you click the arrows on the sides of the media players, a javascript changes the source. All of the soundcloud players are refreshing as they are supposed to, but the mixcloud plugins (under "Full 1+ Hour Sets") are not when using chrome or ie (and probably safari), but are refreshing fine in Mozilla. If you inspect the element, you can see that the src and value attributes are changing as they should when the arrows are pressed - the players are just not refreshing to show the new content.
How can I get these players to refresh?
UPDATE:
This code works:
var curSet=0;
var sets = ['<object>....</object>', '<object>...</object>',....];
function nextSet(direction){
....//update curSet value
$('#firstSet').html(sets[curSet]);
}
You're right, it doesn't work in Safari either... Unfortunately it's a known behavior: check this discussion, for example. The only way to get past it is to move manipulation on the higher level. ) You wrap your dynamic elements in <div> element, like this:
<div id="flash-container">
<object ...>
<embed...></embed>
</object>
</div>
... then completely refresh a container with the new flash object (with the required src value) each time a control fires:
$('#flash-container')
.html('<object ...><param value="new src" ...><embed ... src="new src">')
Hope this'll help. )
I have a simple page with an embedded video. Below is an example. I want to retrieve the width of the embedded video's iframe, which can vary ( for example if the video is from youtube or vimeo ). Then I can put a div next to it, with some text, and adjust the width of the latter accordingly
<html>
<head>
</head>
<body onLoad = "resizeElements()">
<iframe width="420" height="315" src="http://www.youtube.com/embed/a34QTcpnKww" frameborder="0" allowfullscreen>
</iframe>
</body>
<script language="JavaScript" type="text/javascript">
function resizeElements()
{
var iframeVideos = document.getElementsByTagName("iframe");
for ( var i = 0; i < iframeVideos.length; i++)
{
video = iframeVideos[i];
alert ( ">" + video.style.width+ "<" );
video.style.width = "112px";
video.style.height = "63px";
alert ( ">" + video.style.width+ "<" );
}
}
</script>
</html>
The page is loaded, and the first alert ( which should have the width of the iframe ) only shows "><", without the width of the video in between.
I am sure that it's not because the video object is null. The following lines resize it as expected. After the resizing, the same alert brings up the correct width.
Is there anything I can do to have the width available straight away?
I am not a big fan of libraries such as jQuery, but happy to consider in case one of them gives a straight forward solution which doesn't make it more complicated than just parsing the string inside the tag. Just in case the page needs some maintenance in the future...
Thanks!
I think that you just need to set the style attribute to match your width and height attributes:
<iframe style="width:420;height:315" width="420" height="315" src="http://www.youtube.com/embed/a34QTcpnKww" frameborder="0" allowfullscreen>
</iframe>
Because in your function, you are working with the style attribute.
DOM: element.offset*
offsetWidth and offsetHeight should help, supported even in IE6 and all modern browsers.
alert ( ">" + video.offsetWidth + "<" );
Please take a look the jsFiddle Demo.
jQuery width()/height()
If you feel ready to use jQuery, check out .width() and height(). I am not a "fan" of jQuery either, but if you're tired of working around browser inconsistencies, need advanced event handling support (instead of your current inline event handlers) and great DOM helpers, it is an amazing tool to have.
Attributes
Another way would be to simply retrieve the HTML attribute's content (being width="420"). You can do that using .getAttribute(width) or .width (which accesses the DOM property).
alert ( ">" + video.width + "<" );
alert ( ">" + video.getAttribute(width) + "<" );
I have a hidden div containing a YouTube video in an <iframe>. When the user clicks on a link, this div becomes visible, the user should then be able to play the video.
When the user closes the panel, the video should stop playback. How can I achieve this?
Code:
<!-- link to open popupVid -->
<p>Click here to see my presenting showreel, to give you an idea of my style - usually described as authoritative, affable and and engaging.</p>
<!-- popup and contents -->
<div id="popupVid" style="position:absolute;left:0px;top:87px;width:500px;background-color:#D05F27;height:auto;display:none;z-index:200;">
<iframe width="500" height="315" src="http://www.youtube.com/embed/T39hYJAwR40" frameborder="0" allowfullscreen></iframe>
<br /><br />
<a href="javascript:;" onClick="document.getElementById('popupVid').style.display='none';">
close
</a>
</div><!--end of popupVid -->
The easiest way to implement this behaviour is by calling the pauseVideo and playVideo methods, when necessary. Inspired by the result of my previous answer, I have written a pluginless function to achieve the desired behaviour.
The only adjustments:
I have added a function, toggleVideo
I have added ?enablejsapi=1 to YouTube's URL, to enable the feature
Demo: http://jsfiddle.net/ZcMkt/
Code:
<script>
function toggleVideo(state) {
// if state == 'hide', hide. Else: show video
var div = document.getElementById("popupVid");
var iframe = div.getElementsByTagName("iframe")[0].contentWindow;
div.style.display = state == 'hide' ? 'none' : '';
func = state == 'hide' ? 'pauseVideo' : 'playVideo';
iframe.postMessage('{"event":"command","func":"' + func + '","args":""}', '*');
}
</script>
<p>Click here to see my presenting showreel, to give you an idea of my style - usually described as authoritative, affable and and engaging.</p>
<!-- popup and contents -->
<div id="popupVid" style="position:absolute;left:0px;top:87px;width:500px;background-color:#D05F27;height:auto;display:none;z-index:200;">
<iframe width="500" height="315" src="http://www.youtube.com/embed/T39hYJAwR40?enablejsapi=1" frameborder="0" allowfullscreen></iframe>
<br /><br />
close
Here's a jQuery take on RobW's answer for use hiding /pausing an iframe in a modal window:
function toggleVideo(state) {
if(state == 'hide'){
$('#video-div').modal('hide');
document.getElementById('video-iframe'+id).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
}
else {
$('#video-div').modal('show');
document.getElementById('video-iframe'+id).contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
}
}
The html elements referred to are the modal div itself (#video-div) calling the show / hide methods, and the iframe (#video-iframe) which has the video url as is src="" and has the suffix enablejsapi=1? which enables programmatic control of the player (ex. .
For more on the html see RobW's answer.
Here is a simple jQuery snippet to pause all videos on the page based off of RobW's and DrewT's answers:
jQuery("iframe").each(function() {
jQuery(this)[0].contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*')
});
Hey an easy way is to simply set the src of the video to nothing, so that the video will desapear while it's hidden an then set the src back to the video you want when you click on the link that opens the video.. to do that simply set an id to the youtube iframe and call the src function using that id like this:
<script type="text/javascript">
function deleteVideo()
{
document.getElementById('VideoPlayer').src='';
}
function LoadVideo()
{
document.getElementById('VideoPlayer').src='http://www.youtube.com/embed/WHAT,EVER,YOUTUBE,VIDEO,YOU,WHANT';
}
</script>
<body>
<p onclick="LoadVideo()">LOAD VIDEO</P>
<p onclick="deleteVideo()">CLOSE</P>
<iframe id="VideoPlayer" width="853" height="480" src="http://www.youtube.com/WHAT,EVER,YOUTUBE,VIDEO,YOU,HAVE" frameborder="0" allowfullscreen></iframe>
</boby>
Since you need to set ?enablejsapi=true in the src of the iframe before you can use the playVideo / pauseVideo commands mentioned in other answers, it might be useful to add this programmatically via Javascript (especially if, eg. you want this behaviour to apply to videos embedded by other users who have just cut and paste a YouTube embed code). In that case, something like this might be useful:
function initVideos() {
// Find all video iframes on the page:
var iframes = $(".video").find("iframe");
// For each of them:
for (var i = 0; i < iframes.length; i++) {
// If "enablejsapi" is not set on the iframe's src, set it:
if (iframes[i].src.indexOf("enablejsapi") === -1) {
// ...check whether there is already a query string or not:
// (ie. whether to prefix "enablejsapi" with a "?" or an "&")
var prefix = (iframes[i].src.indexOf("?") === -1) ? "?" : "&";
iframes[i].src += prefix + "enablejsapi=true";
}
}
}
...if you call this on document.ready then all iframes in a div with a class of "video" will have enablejsapi=true added to their source, which allows the playVideo / pauseVideo commands to work on them.
(nb. this example uses jQuery for that one line that sets var iframes, but the general approach should work just as well with pure Javascript if you're not using jQuery).
I wanted to share a solution I came up with using jQuery that works if you have multiple YouTube videos embedded on a single page. In my case, I have defined a modal popup for each video as follows:
<div id="videoModalXX">
...
<button onclick="stopVideo(videoID);" type="button" class="close"></button>
...
<iframe width="90%" height="400" src="//www.youtube-nocookie.com/embed/video_id?rel=0&enablejsapi=1&version=3" frameborder="0" allowfullscreen></iframe>
...
</div>
In this case, videoModalXX represents a unique id for the video. Then, the following function stops the video:
function stopVideo(id)
{
$("#videoModal" + id + " iframe")[0].contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
}
I like this approach because it keeps the video paused where you left off in case you want to go back and continue watching later. It works well for me because it's looking for the iframe inside of the video modal with a specific id. No special YouTube element ID is required. Hopefully, someone will find this useful as well.
You can stop the video by calling the stopVideo() method on the YouTube player instance before hiding the div e.g.
player.stopVideo()
For more details see here: http://code.google.com/apis/youtube/js_api_reference.html#Playback_controls
RobW's way worked great for me. For people using jQuery here's a simplified version that I ended up using:
var iframe = $(video_player_div).find('iframe');
var src = $(iframe).attr('src');
$(iframe).attr('src', '').attr('src', src);
In this example "video_player" is a parent div containing the iframe.
just remove src of iframe
$('button.close').click(function(){
$('iframe').attr('src','');;
});
Rob W answer helped me figure out how to pause a video over iframe when a slider is hidden. Yet, I needed some modifications before I could get it to work. Here is snippet of my html:
<div class="flexslider" style="height: 330px;">
<ul class="slides">
<li class="post-64"><img src="http://localhost/.../Banner_image.jpg"></li>
<li class="post-65><img src="http://localhost/..../banner_image_2.jpg "></li>
<li class="post-67 ">
<div class="fluid-width-video-wrapper ">
<iframe frameborder="0 " allowfullscreen=" " src="//www.youtube.com/embed/video-ID?enablejsapi=1 " id="fitvid831673 "></iframe>
</div>
</li>
</ul>
</div>
Observe that this works on localhosts and also as Rob W mentioned "enablejsapi=1" was added to the end of the video URL.
Following is my JS file:
jQuery(document).ready(function($){
jQuery(".flexslider").click(function (e) {
setTimeout(checkiframe, 1000); //Checking the DOM if iframe is hidden. Timer is used to wait for 1 second before checking the DOM if its updated
});
});
function checkiframe(){
var iframe_flag =jQuery("iframe").is(":visible"); //Flagging if iFrame is Visible
console.log(iframe_flag);
var tooglePlay=0;
if (iframe_flag) { //If Visible then AutoPlaying the Video
tooglePlay=1;
setTimeout(toogleVideo, 1000); //Also using timeout here
}
if (!iframe_flag) {
tooglePlay =0;
setTimeout(toogleVideo('hide'), 1000);
}
}
function toogleVideo(state) {
var div = document.getElementsByTagName("iframe")[0].contentWindow;
func = state == 'hide' ? 'pauseVideo' : 'playVideo';
div.postMessage('{"event":"command","func":"' + func + '","args":""}', '*');
};
Also, as a simpler example, check this out on JSFiddle
This approach requires jQuery. First, select your iframe:
var yourIframe = $('iframe#yourId');
//yourId or something to select your iframe.
Now you select button play/pause of this iframe and click it
$('button.ytp-play-button.ytp-button', yourIframe).click();
I hope it will help you.
RobW's answers here and elsewhere were very helpful, but I found my needs to be much simpler. I've answered this elsewhere, but perhaps it will be useful here also.
I have a method where I form an HTML string to be loaded in a UIWebView:
NSString *urlString = [NSString stringWithFormat:#"https://www.youtube.com/embed/%#",videoID];
preparedHTML = [NSString stringWithFormat:#"<html><body style='background:none; text-align:center;'><script type='text/javascript' src='http://www.youtube.com/iframe_api'></script><script type='text/javascript'>var player; function onYouTubeIframeAPIReady(){player=new YT.Player('player')}</script><iframe id='player' class='youtube-player' type='text/html' width='%f' height='%f' src='%#?rel=0&showinfo=0&enablejsapi=1' style='text-align:center; border: 6px solid; border-radius:5px; background-color:transparent;' rel=nofollow allowfullscreen></iframe></body></html>", 628.0f, 352.0f, urlString];
You can ignore the styling stuff in the preparedHTML string. The important aspects are:
Using the API to create the "YT.player" object. At one point, I only had the video in the iFrame tag and that prevented me from referencing the "player" object later with JS.
I've seen a few examples on the web where the first script tag (the one with the iframe_api src tag) is omitted, but I definitely needed that to get this working.
Creating the "player" variable at the beginning of the API script. I have also seen some examples that have omitted that line.
Adding an id tag to the iFrame to be referenced in the API script. I almost forgot that part.
Adding "enablejsapi=1" to the end of the iFrame src tag. That hung me up for a while, as I initially had it as an attribute of the iFrame tag, which does not work/did not work for me.
When I need to pause the video, I just run this:
[webView stringByEvaluatingJavaScriptFromString:#"player.pauseVideo();"];
Hope that helps!
This is working fine to me with YT player
createPlayer(): void {
return new window['YT'].Player(this.youtube.playerId, {
height: this.youtube.playerHeight,
width: this.youtube.playerWidth,
playerVars: {
rel: 0,
showinfo: 0
}
});
}
this.youtube.player.pauseVideo();
A more concise, elegant, and secure answer: add “?enablejsapi=1” to the end of the video URL, then construct and stringify an ordinary object representing the pause command:
const YouTube_pause_video_command_JSON = JSON.stringify(Object.create(null, {
"event": {
"value": "command",
"enumerable": true
},
"func": {
"value": "pauseVideo",
"enumerable": true
}
}));
Use the Window.postMessage method to send the resulting JSON string to the embedded video document:
// |iframe_element| is defined elsewhere.
const video_URL = iframe_element.getAttributeNS(null, "src");
iframe_element.contentWindow.postMessage(YouTube_pause_video_command_JSON, video_URL);
Make sure you specify the video URL for the Window.postMessage method’s targetOrigin argument to ensure that your messages won’t be sent to any unintended recipient.
I've got a page with links to MP3s, when the link is clicked I use javascript to show a small Flash player (NiftyPlayer) under the link. When a different link is clicked, the old player is hidden and the new player is revealed.
The player auto-starts when the element is shown, and auto-stops when hidden - in Firefox.
In IE it will only auto-start and NOT auto-stop. This is what I would like to solve.
This is an example HTML with link and player
Misunderstood What You Said
<div id="player662431" class="playerhide"><embed src="http://www.example.com/shop/flash/player.swf?file=/mp3/Beat The Radar - Misunderstood What You Said.mp3&as=1" quality="high" bgcolor="#000000" width="161" height="13" name="niftyPlayer662431" align="" type="application/x-shockwave-flash" swLiveConnect="true" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>
Here is the javascript (I've got jQuery installed to let me hide all the open players on this page apart from the new one)
function toggle_visibility(id) {
$('.playerhide').hide();
var e = document.getElementById(id);
e.style.display = 'block';
}
I think what I need to do is start the player manually with javascript (rather than using the autostart as=1 function in the URL string)
There is some javascript that comes with NiftyPlayer to allow this EG
niftyplayer('niftyPlayer1').play()
there is also a stop method.
I need some help with javascript - how do I add this call to play into my toggle_visibility function (it has the same unique ID number added to the name of the player as the ID of the div that's being shown, but I don't know how to pull this ID number out of one thing and put it in another)
I also would like to be able to do
niftyplayer('niftyPlayer1').stop()
to stop the audio of the previously running player. Is it possible to store the current ID number somewhere and call it back when needed?
Thanks for the help, i'm a PHP programmer who needs some support with Javascript - I know what I want to achieve, just don't know the commands to do it!
Thanks
If you assigned each niftyplayer object a classname, f.x. ".players", then you could loop through each player, like this:
function toggle_visibility(id) {
$(".players").each(function(){
playerId = $(this).attr('id');
if(niftyplayer(playerId).getState() == 'playing') {
//Stop the currently playing player
niftyplayer(playerId).stop();
//Hide the div that was playing
$("#" + playerId).hide();
}
});
//Start the new player
niftyplayer(id).play();
$("#" + id).show();
}
So what this actually does, is it loops through all the players on the website. It checks if the status of each player is equal to "playing", if it is, then it stops it and hides the div tags. Then it starts the new player and shows that div tag.
I think this does it. Try it out.
I have a much better solution after I noticed a very nasty bug / 'feature' when using Internet Explorer in conjunction.
I had noticed that in IE the pages were taking a very long time to load when I had a lot of hidden Nifty Players, I looked closer using Fiddler and found that each instance of NiftyPlayer was preloading the MP3 in full, rather than loading on demand as with Firefox and Chrome etc.
This meant that a page with 100 items (each item having up to 4 MP3s) took several minutes to load at times with obvious data transfer implications.
My solution which is rather simpler (but maybe clunkier) than Indyber's is to just use
function toggle_visibility(id,mp3location) {
// hide all players
$(".playerarea").html('');
// show clicked player
$('#' + id).html('<embed src=\"http://www.xxx.com/shop/flash/player.swf?file=http://www.xxx.com/mp3/' + decodeURIComponent(mp3location) + '.mp3&as=1\" quality=high bgcolor=#000000 WMODE=transparent width=\"161\" height=\"13\" align=\"\" type=\"application/x-shockwave-flash\" swLiveConnect=\"true\" pluginspage=\"http://www.macromedia.com/go/getflashplayer\" class=\"playerNew\">');
}
which works fine with IE, and also solves the problem of not being able to stop the players from playing in IE