I want to ask is there ANY way or extension that can pre-highlight text within the iframe whenever a new window is opened containing iframe? I have tried many extension but none of them works.
I need to filter out content based on certain keywords and the content is within iframe. I can do it with CTRL+F but there are many keywords like 10-15 within each article to be found. So it makes my job very tough and time consuming. Few extensions that I have tried from chrome are multi highlighter, pearls, FF but none of them seems to work.
I also know the reason why these extension can't access content within the iframe i.e. due to cross origin policies.
But I also remember around an year ago I worked with chrome extension named 'Autofill' that could pre-select form elements whenever I opened new chrome window containing iframe.
So is there any work around?
You can set your extension permission to run content scripts in all frames as document at http://developer.chrome.com/extensions/content_scripts.html#registration by setting all_frames to true in the content scripts section of your manifest file. Adding to Google's example from that page, part of your manifest file might look like
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://www.google.com/*"],
"css": ["mystyles.css"],
"js": ["jquery.js", "myscript.js"],
"all_frames": true
}
],
...
}
You'll need to be careful since your content scripts are going to be inject into the page once for the parent page and one for each iFrame on the page. Once your content script is injected into all frames on the page you can work your magic with finding and highlighting text.
if (window === top) {
console.log('Running inside the main document', location.href);
} else {
console.log('Running inside the frame document', location.href,
[...document.querySelectorAll('*')]);
}
Related
I have an ad that displays within an iframe on a given publisher site around every 1000 loads or so. I have no control over the host site but I need a way to see the ad live as users will see it. I'm trying to figure out a javascript solution that will load the page, search for the name of my company to see if my ad loaded (the company name is the id of a div tag that loads the iframe) and then either stop there if it finds it, or reload the page if not.
I had it sort of working by running a script in the console that got the innerHTML of the document body, searched for a keyword and then reloaded the page if the keyword wasn't found.
Two problems though.
It could only find keywords outside of the iframe.
It didn't search the content of the iframe (where the actual keyword that would identify my particular ad sits) even if I set a delay or did onload.
Secondly, for every page refresh, the script would be cleared from the console.
I know this is beginner stuff but I would love any pointers to the correct way to tackle this problem.
Thanks so much for the help thus far (also, I upvoted everyone but don't think I have the necessary cred for it to show up publicly)
Here's where I got. I created a chrome plugin with the following manifest.json:
{
"manifest_version": 2,
"name": "Ad Refresh",
"version": "1.0",
"permissions": [
"activeTab",
"tabs"
],
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["jquery.min.js", "contentscript.js"],
"all_frames": true
}
]
}
I have the content-scripts running on all urls but will restrict it once I get things running properly.
For contentscript.js that gets injected and runs in each frame, I have:
setTimeout(function(){
$("[title='3rd party ad content']").attr("id", "dfp"); // "3rd party ad content" is the title of all iframes that could potentially contain my ad and is the only identifying attribute across all iframe instances. I stick an id on there so it's easier to grab with getElementById. It only gets the first instance though, need to figure out how to loop through all.
var company = document.getElementById('dfp');
if (company == null) {
console.log("no hit");
} else {
console.log(company);
}
}, 5000);
I'm not worried about reloading the page, I'm just stuck on getting access within the iframe.
I am unable to directly grab any element within the actual content of the iframe with jquery $ or getElementById etc. However, if I run getElementId on the iframe itself and console.log it, it includes all the HTML inside the iframe:
http://i.stack.imgur.com/dfuYt.png
I tried getting the innerHTML of the iframe element so that I'd have it as a string and could search for it, but all it returns is the iframe element tags, none of the inner content. I don't know if any of that makes sense but I appear to be over my head at this point.
Ok, last addition. My ad runs a script that I can see under "Sources" in inspector. So I thought "Why not run
var scripts = document.getElementsByTagName('script'); to get an array of all the scripts that were loaded on the page? Then I could just search the array to see if my script and hence my ad had loaded and we'd be golden." Unfortunately though, it doesn't include my script in the array, even when it's loaded and is visible in "Sources" and accurately includes a random Stripe script that's also loading from within an iframe. Bummer...
Use .load event of the jQuery to know whether iFrame is loaded and then read the innerHTML of the iframe body
Try this:
$('#ID_OF_THE_IFRAME').load(function() {
var iFrameContent = $('body', this.contentWindow.document).html();
console.log(iFrameContent);
});
Fiddle
JS:
var company = document.getElementById('myframe1').contentWindow.document.getElementById('company');
if (company == null) {
//reload
console.log("reload");
} else {
//continue
console.log(company);
}
It sounds like the iframe containing the ad is loaded from a different domain than the main page, is that right? That would explain why your JavaScript code running in the main page (or in the console, same thing) can't access DOM elements inside the iframe. Browser cross-domain security prevents that kind of access: the iframe is treated just like a separate browser window or tab.
If the main page and the iframe were both loaded from the same domain, then you could use contentWindow as a couple of answers have described. But that won't work across domains.
So, what can you do?
You're building a tool for your own use or the use of your colleagues - not something you need to publish on a website for the rest of the world to use, right?
This gives you a couple of other options. First, you could simply disable cross-domain browser security. In Chrome, you can do that as described here:
Disable same origin policy in Chrome
Beware: Don't do any "normal" browsing in a Chrome session running in this mode, only your special testing. But if you do run Chrome in this mode, then you'll be able to access iframe DOM elements via contentWindow and contentWindow.document as described in the other answers.
If that doesn't do the trick, or if you don't want to have to start a special Chrome session for this, another approach would be to write a Chrome extension. This would allow you to write code to access DOM elements in both the iframe and the main window using techniques like these:
access iframe content from a chrome's extension content script
Chrome extension to remove DOM elements inside iframes
Or you could write a Firefox extension if you prefer - similar capabilities are available in both.
I am writing a Chrome extension that adds a context menu item and performs an action when the user right-clicks a YouTube hyperlink.
My manifest file defines the background script as well as the javascript that is run when a link is clicked. Here are the relevant parts of my manifest.json file:
"background": {
"persistent": false,
"scripts": ["scripts/background.js"]
},
"content_scripts": [
{
"matches": ["*://*.youtube.com/*" , "*://youtube.com/*"],
"js": ["scripts/click.js"]
}
],
As you can see the background page uses the javascript file background.js and the context script uses click.js.
I am trying to debug click.js using the Chrome Developer Tools inspection utility but the problem I am running into is I can't figure out a way to get click.js to show up in the sources panel of the inspector.
If I go to the Chrome extensions page and click "Inspect views: background page" the inspector opens up but the only script shown is background.js.
If I right-click the extensions button (shown in the upper right) and select "Inspect popup" again I don't see click.js, only the javascript files that are loaded from within popup.html.
My question is, how do I debug javascript that is executed after a context menu click in Chrome? Should I "hack" it and force the script to always load click.js by adding it to the background page:
"background": {
"persistent": false,
"scripts": ["scripts/background.js", "scripts/click.js"]
},
If I did this, I could then see the script when inspecting the background page and set breakpoints, etc.
This seems like too much of a hack. There must be a more elegant way to inspect javascript files that aren't associated with the background page or any other html page (such as popup.html).
Is there a way to force the inspect window to load all javascript sources regardless of whether or not they are loaded with the page that is being inspected? Or is the inspection page limited to what is actually loaded, not the full set of scripts?
Thank you,
Clock
I have a chrome extension, with content script 1 which programmatically creates an iframe (not same domain iframe) on the current page. I want to run a content script 2 of my chrome extension inside this new iframe (e.g. when a user clicks on something inside the iframe, a message is sent to the background script).
In my manifest.json, I added in the content scripts section:
{
"matches": ["http://url_of_my_new_iframe/*"],
"css": [],
"js": ["ContentScript2.js"],
"run_at": "document_idle",
"all_frames": true
}
I thought putting the all_frames=true property would be sufficient, but when I use the extension, the ContentScript2.js is loaded in every other iframes loaded at page load, but NOT in my dynamically created iframe.
Does anybody have a solution for this?
More info:
This is the code I use in ContentScript1 to create the iframe:
var iFrame = document.createElement('iframe');
iFrame.setAttribute('id', 'some_id');
document.body.insertBefore(iFrame, some_other_dom_element);
iFrame.setAttribute('src', 'my_iframe_url_not_same_domain');
Chrome Version is 35.0.1916.114
In the following google chrome extension file why do i cannot use a jquery script inside myscript.js file,Is jquery not loaded inside myscript.js file, what changes should be done in manifest file to use jquery inside myscript.js
Manifest.json
{
"manifest_version": 2,
"name": "One-click Kittens",
"description": "This extension demonstrates a browser action with kittens.",
"version": "1.0",
"background": { "scripts": ["jquery-1.9.1.min.js","myscript.js"] },
"permissions": [
"tabs", "http://*/*"
],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
}
}
myscript.js
alert($("#extension-command-list").val()); //undefined
alert($("#extension-command-list").html()); //undefined
$(document).ready(function() {
alert("hello world"); //not seen
});
EDIT:
"background": { "scripts": ["jquery-1.9.1.min.js"] },
"content_scripts": [
{
"matches": ["https://*/*"],
"js": ["myscript.js"] or "js": ["jquery-1.9.1.min.js","myscript.js"]
}
],
The reason you are getting undefined is becaus you are not specifying a background page.
So.. the background page Chrome generates, looks just like
<html>
<head></head>
<body>
<script src="jquery-1.9.1.min.js"></script>
<script src="myscript.js"></script>
</body>
</html>
As you see there isn't any Element which can be selected, thats why your first too alert's return undefined.
Anyway, the alert("hello world") should be shown too, as the DOMContentLoaded or similar should be fired any way.
Could it be that you want to select Elements of an site you are visiting ?
If so, you should put myscript.js in an Content Script instead of a background page.
There you get access to the DOM of the site.
So the question is, what are you up to ?
If you actually want to select Elements in your background page, you have to specify one,
Looking at the background pages site shows you, its as easy as:
{
"name": "My extension",
...
"background": {
"page": "background.html"
},
...
}
Edit:
"default_popup" : "popup.html"
Refers to a Browser Actions Popup. A browser Action is used
[...] to put icons in the main Google Chrome toolbar, to the right of the address bar. In addition to its icon, a browser action can also have a tooltip, a badge, and a popup.
So
If a browser action has a popup, the popup appears when the user clicks the icon. The popup can contain any HTML contents that you like, and it's automatically sized to fit its contents.
To add a popup to your browser action, create an HTML file with the popup's contents. Specify the HTML file in the default_popup field of browser_action in the manifest, or call the setPopup method.
"background":"{...}"
A common need for extensions is to have a single long-running script to manage some task or state. Background pages to the rescue.
As the architecture overview explains, the background page is an HTML page that runs in the extension process. It exists for the lifetime of your extension, and only one instance of it at a time is active.
Also has a background script access to all parts of the Chrome Extension's Api. chrome.* if you have requested the permissions respectively
Now lets say, you want to for example extend the ContextMenu of chrome with some functionalities.
To do this, you first have create a contextMenuEntry in the background page.
And just like your background page has only one instance of it running at a time, and that for the lifetime of the extension, so should your contextMenuEntry only have one instance of it, which gets created when your extension runs and remains for the lifetime of your extension.
Now assume you want to display the currently selected text of the page you are visiting in one of you Menu Entries.
To do that, you need access to the chrome.contextMenus API Method but a contentscript is not allowed to use this.
To get this to work you need to pass a message with the selected text to the background page through e.g. chrome.extension.sendMessage
In the background page you can then update your existing contextmenuentry to display the selected text.
sry i couldn't think of a better example right now
I am writing a very simple Google Chrome extension, but have faced such a multitude of issues that it's a bit overwhelming for a project of such a miserable scale.
The extension is a very simple one: upon arrival on any page (say, google.com) the page contents is hidden and the user is faced with a question (s)he has to answer correctly... or be redirected to some other page that provides the correct answer. In other words, the user cannot access pages on the Internet unless (s)he answers the questions correctly.
To hide the page contents I decided to go for a simple overlay using the following approaches:
Approach #1
I tried appending to the current document's body a simple opaque div with position: fixed;, z-index: 2147483647; and width/height at 100%. That worked, but:
The page's CSS kept interfering with the elements inside of my div.
Flash content occasionally appeared on top of it (at least on Windows XP).
Chasing embeds all over the page and setting wmode to
"transparent" didn't help, offsetting to -10000px or setting
display:none; simply alleviated but didn't solve the problem. See also this question.
Approach #2
I tried sandboxing the GUI in an iframe that is created and injected into the page to behave exactly as the div in the above approach. It perfectly solves the issues of the first approach, but:
Apparently there's no way to access the contents of the iframe because of cross-origin policy. And that access – I need it to assign handlers to the input field where the user is typing the answer, I need to remember who's stealing the focus from my answer input field to give it back once the question is answered, etc. etc. etc.
Using Message Passing didn't work for me and I'm not even sure if I should make it work because messaging makes the entire thing overly complex and prohibits me from using the application as a simple webpage (i.e. not as an extension). Why even bother?
So... where am I wrong with my approaches? Is there a third or a fourth one that I'm not aware of?
I appreciate but don't really need code as an answer. A hint or a push to the right direction would be just as good.
P.S. I suppose that at some point somebody will ask if I have code to share. I do, but there's a bunch of it. Which part specifically would you like to see?
Approach #2
Concern #1
Apparently there's no way to access the contents of the iframe because
of cross-origin policy. And that access – I need it to assign handlers
to the input field where the user is typing the answer, I need to
remember who's stealing the focus from my answer input field to give
it back once the question is answered, etc. etc. etc
Yes you access contents of iframe(s) for matter all the code of a Web Page, no CSP etc.
Content script injecting an iframe.
I suggest this is best approach , you can inject script to dynamic generated iframes as shown here and fetch content
Sample Implementation
manifest.json
{
"name": "Iframe",
"description": "",
"version": "1",
"manifest_version": 2,
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"myscript.js"
],
"run_at": "document_end"
},
{
"matches": [
"<all_urls>"
],
"js": [
"anotherscript.js"
],
"all_frames": true
}
],
"permissions": [
"<all_urls>"
]
}
myscript.js
var iframe = document.createElement("iframe");
iframe.setAttribute("src", "https://www.facebook.com/plugins/like.php?href=http://allofrgb.blogspot.in/");
iframe.setAttribute("style", "border:none; width:150px; height:30px");
iframe.setAttribute("scrolling", "no");
iframe.setAttribute("frameborder", "0");
document.body.appendChild(iframe);
anotherscript.js
iframes = document.getElementsByTagName("iframe");
for (iframe in iframes){
console.log(iframes[iframe].src);
}
console.log("In another Script");
If you observe console logged messages you observe messages are logged twice (document log + iframe log + [any number of optional iframes in pages]*)
anotherscript.js which runs during document idle states does execute in dynamic generated iframe, how ever you can re-run content script through chrome.tabs.executeScript() any time.
Concern #2
Using Message Passing didn't work for me and I'm not even sure if I
should make it work because messaging makes the entire thing overly
complex and prohibits me from using the application as a simple
webpage (i.e. not as an extension). Why even bother?
What is you want to achieve?
Totally forgot about this question... In the end I went with approach 2 using message passing to communicate with the iframe and it works pretty fine. Here's a repo of the extension for those who are interested in reading the code: https://github.com/olegskl/invasive-kanji