I have an element that contains a video player: that video player can either be Flash or HTML5 based. I want to be able to make that element fullscreen (I know, only works in webkit at the moment) and run some resizing scripts when it happens.
Here is how I do it:
this.getEl('.fullscreen').bind('click', $.proxy(function() {
this.getEl('#tpPlayer')[0].webkitRequestFullScreen();
}, this));
And the event listener:
this.getEl('#tpPlayer').bind('webkitfullscreenchange', function() {
console.log('fullscreen change');
$(this).toggleClass('tpPlayer tpPlayerFullScreen');
});
When #tpPlayer contains a <video> element, everything works fine: the element goes fullscreen, the event fires, the message is logged and the classes are toggled. However, when #tpPlayer contains a Flash <object>, the element goes fullscreen fine, but no event is fired (so the callback does not run either).
Why is this happening and how to avoid this?
Related
I run into this problem quite often when I decide to try tinkering with a 3rd party site for a browser plugin, let's say I want to make a simple auto-play plugin for a video site that doesn't have an autoplay feature. There's a UI element that I know triggers their internal function for playing the video, but I dont know how to identify that function by inspecting the element in the console.
What tricks / methods can I use to be able to trigger that function manually without the user actually clicking the element?
In Chrome dev tools I think you can add a breakpoint for when an event is fired which might allow you to find the function that the 3rd party calls or you could simulate the click event using this code from MDN:
function simulateClick() {
var event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
var cb = document.getElementById('checkbox');
var cancelled = !cb.dispatchEvent(event);
if (cancelled) {
// A handler called preventDefault.
alert("cancelled");
} else {
// None of the handlers called preventDefault.
alert("not cancelled");
}
}
For more information see MDN.
If you know that clicking a button or an element somewhere results in the video playing, often it'll be simple enough to just call .click() on that button.
With the mouse hovered over the element with the functionality, right click and Inspect at that point, and the Elements panel of the developer console should bring you to the element the mouse is over. Figure out a selector or a process to uniquely identify the element, and then .click() it, eg
document.querySelector('.video-container .play-button').click();
You also may need to wait for the video container / play button to be created in the DOM first, in which case you can use MutationObserver or a setInterval to wait for the site to be ready.
An alternative, trickier method is to, when inspecting the element, go to the Event Listeners panel, and look for listeners attached to click / mousedown (etc) events. Sometimes, these functions are callable from the global scope, in which case you can call those functions directly instead of clicking the element.
If the function isn't callable from the global scope, a hacky method to get a reference to it anyway is to monkeypatch addEventListener before the page loads, listen for when the listener you want gets attached, and then call the function passed. (But the earlier methods are much simpler and preferable when possible)
I have a script which plays/pauses a HTML5 video based on the window size. When the user enters fullscreen, the video plays. When the user exits fullscreen, the video pauses, as expected. If you enter fullscreen again on the paused video, it will call a play and then pause immediately.
Here's the play/pause script and the console logs:
// Listen for exiting fullscreen, hide video element.
$("#" + m).on("webkitfullscreenchange", function(e) {
this.className = "hide";
if($("#" + m).get(0).paused) {
v.play();
console.log('playing...')
} else {
v.pause();
console.log('pausing...')
}
Here's a CodePen demo with representative HTML and the full script.
What can I do in my logic to prevent the second pause call being made?
I found the origin of your problem.
Here is the general structure of your code :
$(document).ready(function() {
$('.cell').on('click', function() {
// some more code ...
$("#" + m).on("webkitfullscreenchange", function(e) {
// here the code for the event handler that pauses and plays the video
});
)};
)};
You can see that the code that adds the handler on the "webkitfullscreenchange" event... is inside the handler for the .cell click event !
Here what happens : every time you click on the cell, you request the fullscreen, and you add a new event handler on the "webkitfullscreenchange" event (in jQuery, on register a new event handler, it does not replace the previous one if there was one).
The first time you click, you add the handler and you request full screen mode : it emits the event, your single handler gets it and plays the video.
But the second time you click, you request full screen mode and you add a second handler. When the event is emitted, both handlers react : the first one plays the video, and the second... immediately pauses it.
So here's part of the solution : just remove the part where you register more event handlers out of the click event handler (as a rule of thumb, situations when you have to set up handlers inside other handlers are very specific, so do not do it if you don't have any specific reason).
Why part ? Because even if it solves your first problem, it does leave another one: what happens if you click, let the video finish, and then quit full screen mode? The handler will get called, verify if the video is playing, notice that it is not and start playing it... even if you just left full screen.
So here's the final solution: set up your handler so that it checks if you just went in or out of full screen mode(using document.webkitIsFullScreen), and play or pause accordingly, as per #CBroe suggestion in the comments.
$('video').on('webkitfullscreenchange', function(e) {
if(document.webkitIsFullScreen) {
this.play();
} else {
this.className = "hide";
this.pause();
}
});
I forked your CodePen and set up the full solution if you want to have a look.
I'm doing a Firefox addon to intercept wheel mouse events over an embedded iframe video of Youtube or Vimeo.
I got it working over normal YT/vimeo pages (attaching the listener to the window and then looking at event.target to identify the video), the problem is with the < iframe> tag: it doesn't intercept the "wheel" event (while for example "mouseover" works).
i.e. there is a similar HTML code in a page:
<iframe src="//player.vimeo.com/video/89055435/fallback?noscript" frameborder="0"></iframe>
This works:
iframes[i].addEventListener("mouseover", func, false);
For "wheel" I do the similar:
iframes[i].addEventListener("wheel", myFunc, false);
or
iframes[i].contentWindow.addEventListener("wheel", myFunc, false);
No result. I tried also capturing instead of bubbling: nothing.
I tried also this:
window.addEventListener("wheel", myFunc, false);
This works over every obj of the page, but nothing over the iframe itself.
I made also a setTimeout with the listener, to see if the iframe was not fully loaded: nothing changes.
http://jsfiddle.net/chtNP/121/
So, what should I do to have my wheel event when I'm over an iframe with a video inside it or how to get all wheels from the window including those over the iframe?
I had the same problem, here is my solution:
var iframe = document.querySelector('iframe');
iframe.contentDocument.addEventListener('wheel', event =>
iframe.dispatchEvent(new WheelEvent('wheel', event))
);
this will forward every wheel-event on the iframes document to the iframe element in the parent document.
Notes:
it is not possible to 'recicle' the event, it needs to be cloned
the WheelEvent constructor copies many, but not all of the original events properties
the cloned event is not isTrusted
the event forwarding is attached to the iframes document. It will only work as long as the document doesn't change. So you should run the above code once the final document is loaded
accessing the iframes document may get you in cross-domain-trouble
How can I capture a click or mousedown event on a div surrounding an iframe. I've tried attaching the function to click event on the div but since the iframe never bubbles the event up to the surrounding div the function is never called. Is there a way I can capture the event on the div and then propagate it to the iframe for default action?
If the click is in the iframe area, the iframe context handles the click event, it does not bubble up to the iframe parent. So the div will never register the click event at all if it happened in the iframe area.
Furthermore, if the iframe contains a page that does not belong to the same domain as the iframe parent, any interaction is prohibited (re. same origin policy).
When the same origin policy is met, there are a few things you can do, you could call a method in the iframe parent context:
top.parentFunction();
So in the iframe you add an event listener that delegates to the iframe parent (accessible with the top reference.
Propagating events is a lot more complicated, so I'm simply going to refer to Diego Perini's NWEvents library. I believe his event system to be one of the better ones out there and he's particular on iframe interaction.
I certainly would not start writing your own code to achieve this, this can easily be a year long project if you want to do it properly and even then will be inferior to Diego's work.
There's no "good" way to do it, but if you really need to detect a click on an Iframe, you can kind-of do it in the latest browsers.
<iframe src="http://mtw-ed.com/" id="iframe" style=""></iframe>
<script type="text/javascript">
var inIframe = false;
function checkClick() {
if (document.activeElement
&& document.activeElement === document.getElementById("iframe")) {
if (inIframe == false) {
alert("iframe click");
inIframe = true;
}
} else
inIframe = false;
}
setInterval(checkClick, 200);
</script>
This script will check every 200ms whether the user is in the Iframe. Of course, they may not have clicked on the Iframe to get there, but I'm afraid this is the best you can do without #BGerrissen's solution.
It will detect the first 'click' only, unless you click out again. It only works in really modern browsers.
You can use a library like porthole to pass messages between parent and iframe, even across domains. Using this wouldn't exactly propagate the event (you won't be able to get the event object), but you can create your own event in the form of a simple message, and then handle it in the parent as a click.
Here's their example
However, I've used Brendon's answer as it's simpler works for my current need.
If you land here because you need to track a click on a PayPal button (like me), and you have access to the JavaScript SDK, you can listen to the click by adding the onClick callback in the initialization.
Example:
paypal.Buttons({
onClick() {
// here you can track the click
}
}).render('#paypal-container');
Link to the docs: https://developer.paypal.com/sdk/js/reference/#link-oninitonclick.
I have designed a website with a menu that is initially invisible. When the user clicks on a button, the menu becomes visible. There are two ways for the user to hide the now visible menu:
Click the button that caused the menu to become visible
Click anywhere on the web page that isn't the menu
The way I have coded the second option is to tie an onclick event to the window element, and have it compare where the user clicked to the menu's position to determine if the menu should be hidden. This works great in Firefox and Safari, but it fails in Mobile Safari.
I noticed that the window onclick event only fires when I click on another element with an onclick event already assigned. If I click on an element with no event(s) assigned, the window's onclick event never fires. If I click on the button which displays the menu, it fires along with the event tied to the button.
Is it possible to assign events to the window element in Mobile Safari?
I'v been encountering this same problem. Here is what worked for me. (Note: I am working within a Modernizr and jQuery context)
First, I add a custom Modernizr class using Modernizr's addTest Plugin API to test for iOS, which will add the class appleios or no-appleios accordingly.
Because in my research the body seems to fire events on it's own agenda, I am taking a little precaution by wrapping all the document's content with an element in an iOS context. Then I add an event handler to this element.
$(".appleios body").wrapInner('<div id="appleios-helper" />');
$("#appleios-helper").bind("mouseup", function(){return;});
What was suggested earlier in this thread is using void(0). I did some quick testing, and found that void(0) as the event just wasn't causing touches on the body to be recognized. When I plugged in my own "empty" function in the form of function(){return;} things started working.
This all hinges on the fact that no events are fired in Mobile Safari unless the element explicitly has events to fire (Safari Web Content Guide.) By inserting this empty event on the wrapper, things will bubble up to the body.
If you're doing strait JavaScript with none of these libraries, the same effect could be achieved in the HTML markup
<html>
...
<body>
<div id="appleios-helper" onmouseup="function(){return;}">
...
</div>
</body>
</html>
This worked for me to hide tooltips when touching anywhere on the document's body. Your mileage may vary.
Simply adding the dummy onclick handler to the html body works for me:
<body onclick="void(0)">
Note that I am using usual live event handlers as shown below:
function liveHandler( event ) {
var target = event.target; ...}
window.addEventListener(evtype, liveHandler, true);
// evtype such as 'mousedown' or 'click'
// we use the capturing mode here (third parameter true)
This is an old question, but I struggled with the same thing today.
I found that using touchstart event works.
I solved it like this:
var isTouchDevice = 'ontouchstart' in document.documentElement;
if (isTouchDevice) {
// Do touch related stuff
$(document).on('touchstart', function (event) {
// Do stuff
});
} else {
// Do non-touch related stuff
$(document).on('click', function () {
// Do stuff
});
}
You could just add onclick="void(0);" to some <div> that covers the whole page so that no matter what, you are always clicking on an element that has an onclick event. Not a great solution, though.
I'd prefer not having the onclick event be tied to the window. Why don't you create a container <div> that has that event on it. Then handle it just like you currently are.
You can also:
$('body').css('cursor', 'pointer');
No idea what those "engineers" at Apple are doing. LOL.
This has problems though. You wouldn't want to do this on every touch device. Only touch devices that don't also have a pointing device (Laptops with Touch Screens, for example).
Source: http://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
The conclusion of the article is this:
So I don’t understand why all this is the case, but it most certainly is the case. If you’re having bubbling problems, just add an empty-function event handler anywhere between the body and the element, and you’re set to go. But it shouldn’t be necessary.