How to add content script to iframe document programmatically - javascript

I'm writing some diagnostic tool and trying to create chrome extension for it. What I have is a page with an iframe. The iframe contains site that is laying on diffrent domain.
What I need is a communication between those two sites. What I figured out is that I can simply add an content script to each of those documents (to iframe document and my top window document) and set a communication between them by the background script and message flow.
The problem is that I don't know what is the address of the document in the iframe right now, users can put multiple diffrent pages into iframe. Because of this I cannot add content script using manifest.json file, because I do not know what to put into matches property.
I tried to use chrome.tabs.executeScript method with allFrames flag set to true. It worked fine when the iframe document was on the same domain as top window document, but when it's on diffrent domain it does not add content script to frame document.
The problem is strange, because if I know the iframe url on design time then I can add those scripts just like that from manifest file...
How can I add content script to iframe document in such situation?
I will also tell you that I have permission to every page in my manifest.json file. It lokks like this: "permissions": ["tabs", "http://*/", "https://*/"]. Additonal obstacle is that I cannot ingerate in iframe document content, it's third-party code.
Any ideas? Thanks for any help.

Following Rob W comment the problem was the timing. I was trying to inject script into iframe before it was loaded. I've used onload event on the iframe to determine the moment when the executeScript method should be called.
Now everything works fine. Thanks Rob.

Related

How to make the contents inside an iframe responsive?

I have embedded a player from a site which streams a channel using an iframe. I am able to make the iframe responsive. But the content i.e the video player inside the iframe is not adaptive to the changes in viewport. I have tried several solutions from internet but all of them make the iframe responsive but not the content inside.
Is there any way I can make the video player inside the iframe responsive?
Please note that I don't have access to the source code of the player.
Here's the link to the html file: IFrame Code (I was not able to create a working fiddle of this. So shared the file instead)
Please note that I don't have access to the source code of the player.
You are in trouble
The one major thing to know while dealing with iframe is the source of the iframe
iframe source has the same domain as the main page which renders this iframe: In this case the browser will let you put your hands on the iframe contents and manipulate it as desired. As both the main site and the iframe are unders same domain it means you are a authorized person so you can change the contents if required.
So even if you don't have access to the source code of the file there are still way's to make your contents responsive if they are in the same domain. This would require Jquery
iframe source domain is not the same as your main page which renders this iframe: In this case you cannot do much with the iframe except displaying it in your page. The browser will not allow you to change any stuff on this iframe. This is a security protocol followed in all the browsers.
what happens if at all we are given access to manipulate the contents - Eg: I can render youtube in my iframe of my website and change all the instances of the string "youtube" to my own name, thus making this entire site look like my own. Also I can manipulate the ajax calls, jquery stuff etc,etc.. and get data from the site.

Activating Zurb Foundation's Joyride in an iFrame, from Chrome Extension content script

I am building a Chrome extension that creates an iFrame inside any HTML page (i.e. any page being viewed in the browser window).
The iFrame is "injected" into the HTML page by the Chrome extension's content script. The resulting HTML looks like this:
<html>
<head>..</head>
<body>..</body>
<iframe id="myIframe">...</iframe>
</html>
After the content script adds the iFrame to the main page's DOM it goes on to populate the iframe with content by manipulating its own DOM. I use the Zurb CSS to style the iframe content.
And this all works fine.
I am now trying to add the Zurb Joyride to the content of the iframe, and it is this that I cannot get to work.
My manifest's content_scripts declaration looks like this:
"content_scripts": [{
"matches": ["*://*/*"],
"js": ["js/externalJS/jquery-2.1.4.min.js",
"js/externalJS/foundation.min.js",
"js/content_script.js"],
"run_at": "document_end"
}],
I suspect the iframe itself needs to have access to the Zurb scripts, so as well as foundation.min.js being loaded by the manifest as part of the extension, my content script also adds the relevant tags inside the iframe (by manipulating the DOM). My understanding is that the key elements within the iframe are:
tags for Zurb JS files
An object to attach the joyride to (id="testjoyride")
The joyride content itself
The initialisation call to foundation()
And so, with this in mind, I have the manifest's web_accessible_resources declaration looking like this:
"web_accessible_resources": [
"js/externalJS/jquery-2.1.4.min.js",
"js/externalJS/vendor/modernizr.js",
"js/externalJS/vendor/fastclick.js",
"js/externalJS/foundation.min.js",
"css/foundation.css",
"css/app.css"
],
And then use the content script to build up the following HTML inside the iframe:
<iframe id="myIframe">
<html>
<head>
<!-- the foundation style sheet (which works fine already) -->
<link type="text/css" rel="stylesheet" href="chrome-extension://extension_id/css/foundation.css">
<!-- the first two scripts -->
<script src="chrome-extension://extension_id/js/externalJS/vendor/modernizr.js"></script>
<script src="chrome-extension://extension_id/js/externalJS/jquery-2.1.4.min.js"></script>
</head>
<body>
<!-- a test object to attach the joyride too -->
<input type="submit" id="testjoyride">
<!-- now the rest of the iframe content -->
... content ...
<!-- the other two scripts -->
<script src="chrome-extension://extension_id/js/externalJS/vendor/fastclick.js"></script>
<script src="chrome-extension://extension_id/js/externalJS/foundation.min.js"></script>
<!-- default joyride code from foundation.zurb.com -->
<ol class="joyride-list" data-joyride="">
<li data-id="testjoyride" data-class="custom so-awesome" data-text="Next" data-prev-text="Prev">
<h4>Stop #1</h4>
</li>
<li data-button="end" data-prev-text="Prev">
<h4>Stop #3</h4>
</li>
</ol>
</body>
</html>
</iframe>
Then, finally, when all of the above content is attached to the iframe (and the iframe, of course, is attached to the parent page's DOM) I call foundation(), from the content_script.
I think I need to call it like this:
$(window.frames.myIframe.contentWindow.document).foundation('joyride', 'start');
i.e. passing in the document object of the iframe, not the parent page **
So I do all of that, and nothing happens. The joyride does not appear, nor does the HTML get transformed into the auto-generated output (as described here).
I have created a test case in a simple HTML page and it worked fine, I tried to move that test page into an iframe and the joyride stopped working. I therefore suspect, although without much confidence, that the issues lies with the iframe, not the Chrome extension.
** Note, I place this call right at the end of all the DOM manipulation. After I have added the new HTML I've created to the iframe's DOM, and after creating all my listeners etc. So I'm confident the scripts and the joyrides should be "there" by that point. However, if I stick an alert() just before the call to foundation('joyride','start'), the alert displays with an empty iframe behind it, and only after I dismiss the alert does the iframe populate. Whether that's important, or just a strange effect of the alert, I don't know.
Thanks to some helpful comments, I managed to get this working. The exact same solution got QTip2 working as well. So this is a solution for:
Third party javascript packages (specifically, JQuery, Foundation Zurb Joyride, and QTip2)...
... injected programmatically by a Chrome Extension...
... into an iFrame - that has itself been injected, by the Chrome Extension, into the user's current webpage
I will do my best to describe it below. I am self-taught and still a newbie, so my apologies for any confusing terminology or divergences from best practice.
Solution Overview
I ended up with three levels to my Chrome Extension:
A background script, controlling the extension (fairly inconsequential to this specific problem, but worth mentioning for completeness).
A content script, that receives commands from the background script and programmatically injects an iframe, the iframe HTML content, and the 3rd partly JS packages into the user's webpage.
An "iframe script", which is a custom JS script that is injected into the iframe along with the 3rd party packages. This iframe script can send/receive messages to/from the content script, whilst at the same time having access to the 3rd party JS packages - Zurb Joyride & QTips
The Manifest
Although the content script (content_script.js) controls all of the injection, it never actually runs any of the 3rd party JS packages itself. They are run by the user's webpage. Therefore my manifest's content_scripts declaration looks like this:
"content_scripts": [{
"matches": ["*://*/*"],
"js": ["js/content_script.js"],
"run_at": "document_end"
}],
Because the web page needs to access the 3rd party scripts, it must be given permission. It also needs access to our custom iframe script:
"web_accessible_resources": [
"js/iframe_script.js",
"js/externalJS/jquery-2.1.4.min.js",
"js/externalJS/jquery.qtip.min.js",
"js/externalJS/vendor/modernizr.js",
"js/externalJS/vendor/fastclick.js",
"js/externalJS/foundation.min.js",
"css/foundation.css",
"css/jquery.qtip.min.css"
],
Content Script: Inject Joyride HTML into the iframe
The content script creates an iframe element (id="myIframe") and appends it to the user's webpage. It then goes on to programatically fill it with content.
Some of that content will become the anchors for the joyride: HTML elements with their ids set to joyrideStop1, joyrideStop2, etc:
iframeContentHTML += <i class="fi-info brandSpielIcon" id="joyrideStop1"></i>
And the content script also builds up the joyride HTML, as per the Zurb docs, at the bottom of the iframe body.
joyrideHTML += '<ol class="joyride-list" data-joyride>';
joyrideHTML += ' <li data-id="joyrideStop1" data-text="Next (1 of 5)" data-prev-text="Prev" class="customJoyride">';
joyrideHTML += ' <h4>Title</h4>';
joyrideHTML += ' <p>Content</p>';
joyrideHTML += ' </li>';
...
My custom CSS class is simply:
.customJoyRide .joyride-nub {
visibility: hidden;
}
This makes the little pointy arrow on the joyride tooltip disappear. I had significant problems trying to get the joyride to display nicely inside the small iframe. Ideally I would like them to anchor to elements inside the iframe, but display as though they are part of the main page. In the end this seemed either too hard or impossible, so I just removed the nub and dodged the issue. This is a display issue, and only a problem for small iframes, so not a core part of this solution.
Content Script: Inject JS into the iframe
To get Joyride to work, we need to inject the 3rd party scripts and the custom iframe_script.js into the iframe. This is an example of the code from content_script.js for one of the 3rd party scripts:
// Inject foundation script into iframe body
var foundationScript = document.createElement('script');
foundationScript.src = chrome.extension.getURL('js/externalJS/foundation.min.js');
window.frames.myIframe.contentWindow.document.body.appendChild(foundationScript);
NB. This part of the solution corrects one of my original mistakes. The scripts do not seem to initialise if you simply append text to innerHTML like so: body.innerHTML += '<script src=".."></script>;'
So I repeat the above code for all the scripts. In the iframe head I put:
jquery.qtipmin.css
modernizr.js
jquery-2.1.4.min.js
And at the bottom of the iframe body I put:
fastclick.js
foundation.min.js
jquery.qtip.min.js
iframe_script.js.
In that order.
Iframe Script: initialise
When iframe_script.js initialises, I immediately get it to add a message listener (so the content script can communicate with it) and then send a message to the content script telling it it's ready (the content script already has its own message listener set up, the code for which is not detailed here):
(function initialise(){
// Listen for messages from the content script
window.addEventListener("message", contentScriptMessage_listener, false);
// Tell the content script we're ready to go
window.parent.postMessage({sender: 'iframe_script',
subject: 'iframeScriptHasInitialised'}, '*');
})();
NB. I struggled to make sure the iframe's listener was set up before my content_script sent its first message to the iframe. In the end this solution (waiting for a message back from the iframe) seemed to work best, although I suspect there may be a better way
Content Script: tell the iframe to activate the joyride
Now that the content script knows the iframe listeners are ready, it can tell it to activate the Zurb joyride (and/or the QTips). I do this by sending a message back to the iframe.
window.frames.myIframe.contentWindow.postMessage({
sender: 'content_script',
subject: 'pleaseActivateJoyride'}, '*');
Obviously it would be simpler to activate the joyride directly from the iframe script, without all these messages bouncing back and forth. But that's the whole point: it's the content script that knows whether or not the joyride should even be displayed, let alone all the other config details. Keeping control with the content script (and, ultimately, with the background script) makes for a much tidier implementation over all.
Iframe Script: activate Joyride
My iframe script's message handler receives the message from the content script and calls this function:
function activateJoyride(){
$(document).foundation({
joyride: {
... configuration ...
}
});
$(document).foundation('joyride', 'start');
}
NB. I have an outstanding issue here. This can sometimes run before JQuery is loaded, resulting in an error ("$ is not declared"). I have played with window.setTimeout in an effort to resolve this, and it works nearly all the time... but it's not 100%
And that's it!
There's a matching activate function for the QTips, with the appropriate content injected into the iframe earlier. Just like with the joyride, I struggled with the rendering of the Qtips inside the small iframe. QTip2 is more powerful and the docs suggest there are solutions.

jQuery selector not working on iframe contents

This part of a script works fine on a normal page:
<script>
$(function() {
$(".counter").countimator();
});
</script>
But when that same page is loaded in an iframe on a page on another domain, it doesn't work.
Is there a way to get this selector/code work when the page is loaded within an iframe? I want to give people a iframe code that they can use on their personal websites to get the content of my page on their website.
Edit
I published the basic code on http://joomlaground.com/iframe_test/
The http://joomlaground.com/iframe_test/clock.php runs standalone like it should.
Then I created a very basic iframe page iframe.php which iframe the clock.php. However then the clock.php is not counting any more.
How can I fix this?
If '.counter' element is outside of the iframe you're running the internal iframe script has no access to this element as the current document and iframe are separate documents. If you'll have any questions don't hesitate to ask below.
When you move this script in an iframe then it means you are running your script in a new window.
Now in new window you are trying to access some library function:
$(".counter").countimator();
That can only be done if you have that library included in the source of that iframe.

jQuery Copy text inside iframe to main document?

Hopefully someone here can help me with this challenge!
I have a parent page which is the checkout page for an e-commerce site. It's run on zencart and for every order placed a table row is generated through ZenCart. I've setup an EACH function which generates an iframe for an artwork uploader for each TR (order) found. The uploader works and the correct number of instances are being generated.
I wanted to avoid an iFrame, but the uploader script I purchased will not permit me to load it directly into the zencart page template, or via AJAX (tried both). There's some kind of major resource/path situation going on when doing it this way... so I've resorted to iframes.
I'm able to call JS on file-upload-complete. At that point I'm trying to capture the name of the filename that was just uploaded and place it inside the TR. The problem I'm running into are permission error when trying to access the iframe contents.
I've tried everything I've come across on this site and many others, so believe it isn't a problem with the selectors/frame selection... Firebug is telling me that I'm getting permission errors when trying to access the iframe, yet they're both on the same domain and the src is being set by a relative path....
I'm completely lost, any suggestions would be appreciated! Thanks!
www.prothings.com/store
Add items to the cart and go to checkout.....
when you want to access main window or window.document from inside an iframe you should change the context by using window.parent
For example when you want to append some text to a div, you should do something like this
window.parent.$.('#theDiv').text('the text');
There is a bug in IE when you run the code from inside the iframe and remove the iframe in between. IE can't run the code in the fly

How to grant permission to function or document element from iframe created through external .js script tag? [duplicate]

This question already has answers here:
Cross domain iframe issue
(5 answers)
Closed 6 years ago.
I am embedding a script via <script src="example.com/file.js"></script> on a domain that does not belong to me. The script outputs a iframe with its src set to a script on my site. I'm also outputting a div tag that contains the iframe (it is not rendered by the iframe but the js file). Now, I want to be able to execute a function that is loaded via the iframe to control the parent div of the iframe OR output the function along with the div tag and execute the function from the iframe. I am getting permission denied errors when attempting to do either. How can I grant permission?
You can't (and then time passes and the answer changes, see the duplicate question).
In short, you can't using the way you posted. The only thing windows (including iframe windows) can do to each other is change the URL / hash. What you can do is:
1) Make an HTML page that checks its hash for commands to run. Put this on SITEA.
2) On your regular SITEA page load SITEB in an iframe.
3) SITEB iframes doesn't have access to it's parent since it's on a seperate domain. However, it can load the page you set in step 1 through an iframe. You can also change the URL on this iframe. This SITEA iframe is allowed to talk and control SITEA parent (through something like window.top).
This may sound confusing but it works and is pretty much the only way to do it cross-browser and in IE6. I've done stuff like this to support ads that expand on the parent site.

Categories

Resources