Can't attach mousedown event to embed element - javascript

I seem to have hit a wall with this crap and can't make sense of it. I have a page with a relatively complex SVG (it has 6 other smalled SVGs embedded into it) in it embeded inside embed tag. When I try to attach a mousedown event to it, it simply doesn't work. Here is the markup:
<body>
<embed type="image/svg+xml" src="images/cog.svg" id="cog">
</embed>
</body>
then in javascript I do
$(function(){
var cog = document.getElementById("cog");
document.addEventListener('mousedown', function(e){
console.log(e);
});
});
It doesn't work. Moreover when i attach events to document, they do not fire when I click on that embed object either!
I searched this thing for 3 hours and everywhere I look it appears as if the embed should support mousedown even without any problem. What is the problem here?
Edit:
If it's any help here is how the full markup looks like (I use Foundation framework):

If CORS aren't an issue, you can try :
document.querySelector('embed').addEventListener('load', function(){
this.getSVGDocument().addEventListener('mousedown', function(){
alert('hello')});
});
According to the specs:
3 . If the previous step determined that the content's type is
image/svg+xml, then run the following substeps:
If the embed element is not associated with a nested browsing context, associate the element with a newly created nested browsing context,[...]
Navigate the nested browsing context to the fetched resource, with replacement enabled, and with the embed element's node document's
browsing context as the source browsing context. (The src attribute of
the embed element doesn't get updated if the browsing context gets
further navigated to other locations.)
The embed element now represents its associated nested browsing context.
But I can't find anything about actually how it should handle events.
Nevertheless, it appears that when its src is set and returns something, the events are captured by the new context (whether reached or created).
See #Marius comment for a demo when no src is set, it fires the event.

I think the embed tag is sandboxed and can't be accessed from external sources. Just use the img tag.
$('#logo').click(function() {
alert('410');
});
img{
width: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>Click the SVG</h3>
<img id='logo' src="http://dev.w3.org/SVG/tools/svgweb/samples/svg-files/410.svg">

Related

I get "(variablename) is null" when trying to edit dom elements inside an iframe

I don't know jQuery and I'm trying to use only ECMAScript (ES6) and I found on W3Schools a way to edit DOM elements inside an <iframe>
My code is exactly the same:
let iframe = document.getElementById("music");
let elmnt = iframe.contentWindow.document.getElementById("player");
elmnt.play();
I have an iframe tag with id="music" and inside an audio tag with id="player". The code should play the audio source when the page is loaded, it works but I still get the error in the console and I can't interact with volume with ES6.
but I get: "TypeError: elmnt is null (sketch: line 29)"
Here's an example: https://codepen.io/mark_karrica_/pen/zgxyVL
(I'm using the p5.js library but I don't think th problem is related to that)
Your code is running before the iframe has finished loading. You can prevent this by setting up your code to run after the frame has loaded. iframe elements have a load event you can attach event handlers to.
<iframe id="myframe" src="..." onload="iframeLoaded()"></iframe>
Here, I have attached the event handler iframeLoaded to the frame's load event. You then stick your code inside that method:
function iframeLoaded() {
let iframe = document.getElementById("music");
let elmnt = iframe.contentWindow.document.getElementById("player");
elmnt.play();
}

Loading the Youtube Player API inside an iframe

I have a website with several internal (i.e. without src) iframes inside, where I want to include a Youtube player (using its API). In short, I want players inside iframes, managed by the parent page.
Problem is that the code initialization, AFAIK, is not working with iframes. For example:
var player = new YT.Player('video-player1', {});
The problem, as you might have guessed, is that you can't define the document in which that ID is contained. In jQuery, I would use something like:
$("video-player1", frames["iframe1"].document)
Is there any workaround for this? The only solution I can see is, obviously, loading the YT api in every iframe and working inside of any iframe, but that would mean refactorizing a lot of logic from my application, besides the additional cost of several loads of the Youtube JS files.
I'm sorry mate. The solution to your problem is "easy" to code/implement but painful and difficult to maintain.
Youtube API does not allow to embed a YT.Player object within an Iframe (e.g. div within an iframe), because it looks for the 'player' node within the window object and not in the iframe document.
So, a quick hotfix for this would be to save a copy of the API files and modify them to add this functionality. Obviously, from that moment on, it is your responsability to serve these files and also to update them in order the files do not get deprecated.
The solution would be (I take for granted JQuery is loaded before Youtube API):
Using the base example provided at https://developers.google.com/youtube/iframe_api_reference#Getting_Started I guess you have this
<iframe id="if"></iframe> instead of <div id="player"></div> and that later on you append the player div inside that iframe.
<body>
<iframe id="if"></iframe>
<script>
$('#if').contents().find('body').append($('<div id="player"></div>'));
// ...
So, whem defining onYoutubeAPIReady(), you must add 1 parameter to the YT.Player constructor:
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', { /* options */ }, $('#if') );
That is $('#if'), the iframe element where you want to embed the player.
iframe_api
In this file you just need to modify the src of the script it loads:
from
a.src = 'http://s.ytimg.com/yts/jsbin/www-widgetapi-vflOb0oo1.js
to a.src = './widget.js'; (widget.js is your copy of www-widgetapi-vflOb0oo1.js).
Finally on widget.js:
Here you must modify this 2 functions: function S(a,b) and function Y(a,b).
First function Y(a,b) to function Y(a,b,c) in order to get the iframe parameter. Then in its body you change S.call(this,a,new nb(b)); to S.call(this,a,new nb(b),c);
Second, function S(a,b) to function S(a,b, dom) and c = document to
c= dom === undefined ? document : dom.contents()[0].
Now you have a Youtube player inside your iframe and you are able to use it from the parent window.
I hope it is useful! ;)

DOM Events - Progress Indicator for Iframe location change

I am looking for a solution to show a progress indicator when an iframe page changes, but prior to the iframe loading completely.
There are 100's of pages on Stack Overflow going over the differences between jQuery ready(), JavaScript window.load, document.load, DOMContentReady, on('pageinit'...) and after reading the differences on all these various techniques I'm now a bit stuck on how to accomplish trapping the event within the iframe.
So far I have only succeeded in capturing when the iframe has changed once the DOM is built. I would like to be able to detect when a page is about to load so I could have some sort of indicator/spinner in my header.
This is what I have so far (capturing the iframe change on the onload):
.....
<iframe id="rssID" src="http://feeds.reuters.com/reuters/oddlyEnoughNews"
onload="blerg()" style="width: 800px; height:600px"/>
......
$(document).on('pageinit','#index', function(){
alert('pageinit'); //gets called on first load
});
$(document).on('pageinit','#rssID', function(){
alert('pageinit rssFeed'); //nothing happens.
});
function blerg() {
var myIframe = document.getElementById("rssID");
myIframe.onload = func;
};
function func() {
alert("changed");
}
http://jsfiddle.net/Gdxvs/
It would appear that pageinit is the correct path but I have no idea on how to trap that within an iframe. I would prefer not using jQuery, but I'm not sure that is possible without huge amounts of code.
One final: Do I need to use a die("pageinit");

Vimeo JavaScript API add event listener to all iframes on the page

Been messing around with Froogaloop, Vimeo's JavaScript API, and am trying to add a class to the Vimeo iFrame that is currently playing. Seems simple enough, using the API's events, but I can't seem to wrap my head around it. Here's what I've got so far:
The code below is a simplified version of their example. While it's not causing any errors in my console, I'm not getting any of the logs (and therefore not getting the classes). Am I missing something?
Thanks for your help!
var iframe = $('article.video iframe')[0],
player = $f(iframe);
player.addEvent('ready', function() {
player.addEvent('play', on);
player.addEvent('pause', off);
player.addEvent('finish', off);
});
function on(id) {
console.log('playing');
player.addClass('playing');
}
function off(id) {
console.log('not playing');
player.removeClass('playing');
}
UPDATE
The issue definitely has to do with the variables. Player tells Froogaloop which iframe to work with, iframe identifies which html object that is. So I suppose the issue is how I can identify all the iframes on the page and then feed Froogaloop the appropriate iframe when one is activated.
Yes, as I see, in the on() and off() functions Froogaloop is giving you the ID of the iframe by parameter. So, in that case you should add and remove class like this:
$('#'+id).addClass('playing');
$('#'+id).removeClass('playing');
And in your HTML you should provide an id="videoX" to every iframe tag, plus to add &player_id=videoX at the end of the url address of the src property from the iframe.

Capture click event from child frame into parent frame

Right, this is weird. I have done loads of Googling and found hundreds of articles which seem to point me in the right direction, but none seem to work.
Here's the latest incarnation of what I am trying to do:
Parent Page
<html>
<head>
<script>
$('#mainWindow').ready(function () {
$('#mainWindow').contents().find('#clickThis').live('click', function () {
alert('Click detected!');
});
});
</script>
</head>
<body>
<iframe id="mainWindow" name="mainWindow" src="myMainPage.aspx" style="border: 0; position:fixed; top:0; left:0; right:0; bottom:0; width:100%; height:100%"></iframe>
<iframe src="myOtherPage.aspx"></iframe>
</body>
</html>
Framed Page (sitting in mainWindow)
<html>
' LOADS OF STUFF INCLUDING:
<li id="clickThis">Click This</li>
</html>
So obviously what I am trying to do here is to run some code in the Parent Page when a user clicks the button in the child frame.
It needs to work live so if the page in the frame changes it is still captured by the parent (this element exists on all pages which will be loaded into the frame)
I have been able to run codes across iFrames, from parent to iFrame and from iFrame to iFrame following various other searches, but running from iFrame to parent is causing issues.
The above code does nothing, and neither do any of the other options I have tried!!
*Edit should add, all files are on the same server, the cross domain issue is not a problem
This works fine for me:
$('#myframe').contents().on('click', function () {
$('#result').text('clicked');
});​
If you want to capture the events just on a part of the content document, use .contents().find(<selector>) (<selector> being e.g. 'body') instead of just .contents()
Something to watch out for: All of your pages must exist under the same document.domain or the JavaScript calls will fail. You will see this surfaced as a security exception in your console. This happens due to same-origin policy.
Way, way way too late of an answer, but I had the same issue and the code below works in all browsers:
$('#myiframe').on('load', function () {
$(this).contents().on('click', function () {
alert('Click detected!');
})
})
It attaches onclick handler but only after iframe has been loaded. I am leaving this here for posterity and for anybody else looking for an answer to the same question.
In case you want to capture some data as well inside the iframe, this will work for you:
There is an iframe element with multiple images in it. The iframe is rendered inside of parent page. Whichever image you click inside the iframe, that image's id is sent back to the parent.
Inside iframe:
<script>
function vote(e) {
myMessage = e;
window.parent.postMessage(myMessage, "*");
return false;
}
</script>
<body><div>
<img id="Image1" src="file:///Users/abcd/Desktop/1.jpeg" width="200px" onclick="vote(this.id)">
</div></body>
Inside parent page:
</script>
function displayMessage (evt) {
var message = "You voted " + evt.data;
document.getElementById("received-message").innerHTML = message;
}
if (window.addEventListener) {
// For standards-compliant web browsers
window.addEventListener("message", displayMessage, false);
}
else {
window.attachEvent("onmessage", displayMessage);
}
</script>
<body><div id="received-message"></div></body>
This will not only capture the click but also capture the id of the element being clicked inside the iframe. Also, this does not require JQuery.
why are you using find to bind an event listener to an element that might not be there? Why not just try:
$('#mainWindow').ready(function()
{
$('#clickThis').on('click',function()
{
alert($(this).html());//or something
});
});
BTW: since your code is inside the ready callback of #mainWindow, there is no need to use $('#mainWindow') a second time, as this will scan the DOM tree a second time. Just use this or $(this), as it will reference the mainWindow element anyway.
If on doesn't work for you, don't forget to check if you have the latest version of jQuery included, too. That, too can be the reason why on isn't working.

Categories