I am building a chrome extension that is also supposed to remove parts of HTML.Thing is, I need to do that when I receive the html from the server BUT before it is displayed.If I use run at for document end and try to modify the HTML it'll look ugly because the page will load and then change, and I want to remove html parts and edit them before it is displayed.
For example, if my extension will need to clear the whole body tag I will need a script like that in runbefore.js:
document.body.innerHTML = "";
But when I use content scripts -
"content_scripts": [
{
"matches": ["https://www.website.com/*"],
"js": ["runbefore.js"],
"run_at": "document_end"
}
It loads the page and only then clears the whole page, and I want to clear the body tag and only then display it.If I use document_start it won't even do anything.
How do I resolve that issue ?
You can change run_at property in your manifest to document_start in your manifest.
You can get more information about this property here.
Related
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('*')]);
}
I need to run some JavaScript code before any other code is executed on the page that's being loaded.
That works fine using a content script like this:
{
"matches": ["http://*/*", "https://*/*", "file://*/*"],
"js": ["contentScript.js"],
"run_at": "document_start"
}
But now I'd like to run the content script only on certain pages which the user selects by clicking on the browser action button.
I've tried listening to chrome.tabs.onUpdated and then calling executeScript, but other code is running on the page before my content script.
Is there a way to ensure that the code injected by a background page is run before other code?
I could also add a condition inside my content script, but that would mean I need access to the current tabId and a list of all tabs where my extension is activated.
According to the documentation chrome.tabs.executeScript has several useful parameters, including runAt (by default it's document_idle, which occurs after DOMContentLoaded event), so to inject a script as soon as possible use runAt: 'document_start'.
chrome.tabs.executeScript(tabId, {
runAt: 'document_start',
code: 'console.log(document.documentElement.innerHTML);',
});
Beware the DOM tree is usually empty at this stage especially if you inject from an early executed event listener such as tabs.onUpdated or webNavigation.onCommitted. Even HEAD or BODY elements may be still absent, so you'd have to use (document.head || document.documentElement) fallback as a container for any added nodes such as <style> or <script>.
My extension reformats an ugly page that I visit often. Currently, the page first loads un-fixed, then there is a ~100ms delay, then my JS formats the html.
How do I prevent the uncorrected html from ever displaying?
My JS file is defined in the manifest as follows:
,"content_scripts": [{
"matches": ["*://*.<url goes here>.com/*"],
"js": ["js/1.js"]
}]
You need to adjust the run_at parameter.
By default, content scripts are executed after the page is fully loaded (at "document_idle").
Try adding "document_end" first and see if it improves the delay.
In the case of "document_end", the files are injected immediately after the DOM is complete, but before subresources like images and frames have loaded.
"content_scripts": [{
"matches": ["*://*.example.com/*"],
"js": ["js/1.js"],
"run_at": "document_end"
}]
This may still be too late. There's a final option, "document_start", that you can use, but beware - it executes really early, before any of the DOM is ready. There's nothing yet for you to correct.
You can wait for an element to appear and correct it immediately though, for instance.
You may also try to correct things with CSS injection. This can be safely inserted at "document_start" with no extra tricks.
P.S. Or, for example, use Gael's answer - add a CSS rule to hide the body, wait until the page is loaded (for instance, with DOMContentLoaded event), correcting it and then removing/overriding the CSS rule.
You can set run_at: "document_start" in your manifest. Add a rule to hide the page, and differ your current script in a window.onload event.
If you are visiting often this page, you could even load first your template/redesign, and then integrate the page data that you want from a cache or from the source.
I need to be able to inject a content script into an iframe that is within an action's popup.html of another extension.
Previously, before an update to this extension in question, the extension injected the iframe into the active tab. I was able to configure my manifest like this:
"content_scripts": [{
"matches": ["https://*.domain.com/*"],
"js": ["content.js"],
"all_frames": true
}],
It worked fine, the content script was injected into the iframe. Now this extension has the iframe in the action's popup.html and I can't get this to work.
Is there any way to accomplish this?
In general, you can't do this because chrome-extension: is not/no-longer a valid scheme.
However, if you can target the popup.html without using wildcards, you might be able to get to work by setting a "bad flag" in the Chrome://flags page.
Obviously, this will only work for your own personal browser.
How should I connect my pages to search and highlight text on current tab?
Currently I have:
manifest.json does defining content/backgr/event page do significant things,auto inject code etc?
popup.html essentially a shell for the search input which is used by search.js
search.js should this be in background/event/content/popup.html page?
What I still don't understand after reading:
What is a content page vs. background/event page?
I know one is constantly running vs injected, but that's as much as I got from the chrome extension manual, I still don't quite understand if the content script/page is seperate from the popup.html for example and what the difference between a script in the popup.html vs content page/script is.
What I know:
I know how to search for text on a page, and replace it or change its style etc. using JS.
I need to read up on the messaging API for Chrome Extensions.
I know I need to know how to use the messaging API, is it going to be required for page search and highlighting?
Summary:
I don't need a walk through or full answer, just a little help visualizing how Chrome extensions work, or at minimum how I should set mine up in relation to page interaction IE:
search.js content page injected >>>>> popup.html
and maybe a short bit about how injection works in chrome extensions(IE, do I only need to specify that it is content page in manifest.json to have it injected or is there more work to it)/expected behavior?
Apologies for the jumbled thoughts/question/possibly missing the things relevant to my questions while reading the manual.
I will start with making the purpose of each kind of page/script more clear.
First is the background page/script. The background script is where your extension lives. It isn't required, but in order to do most extension things, you need one. In it you can set up various event listeners and such depending on what you want it to do. It lives in its own little world and can only interact with other pages and scripts using the chrome.* apis. If you set it up as an event page it works exactly the same except that it unloads when not in use and loads back into memory when it has something to do.
Content scripts refer to injected Javascript and/or css. They are the primary tool used for interacting with web pages. They have very limited access to chrome.* apis, but they have full access to the DOM of the page they are injected into. We will come back to using them in a minute.
Now for Popup pages. Unlike the background script and content script, popups have both a HTML and JS portion. The HTML part is just like any other page, just small and as a overlay popup coming out from the icon. The script portion of it, however, can do all the things the background page does, except that it unloads whenever the popup is closed.
Now that the distinctions are more clear let's move on to what you want to do. It sounds like you want to open the popup, have the user enter text to search for in the current tab, then highlight that text on the page. Since you said that you already know how you plan on highlighting the text, I will leave that part to you.
First to set up our manifest file. For this particular action, we don't need a background script. What we do need is both the "tabs" and "activeTab" permissions. These will enable us to inject our script later. We also need to define the browser action with it's popup. Altogether it would look something like this:
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"tabs", "activeTab"
]
Now in our popup.html file, we can only have markup and css, no inline code at all. We will put it all in our js file and include it. Something like this should work:
<!DOCTYPE html>
<html>
<head>
<script src="popup.js"></script>
</head>
<body>
<input type="text" id="searchText">
<button id="searchButton">Search</button>
</body>
</html>
This is where we come back to the content script stuff. There are two ways to inject a content script, first is to define it in the manifest. This works best when you always want to inject it for a particular set of url's. Second, to use the chrome.tabs.executeScript method to inject it when we need to. That is what we will use.
window.onload = function(){
document.getElementById('searchButton').onclick = searchText;
};
function searchText(){
var search = document.getElementById('searchText').value;
if(search){
chrome.tabs.query({active:true,currentWindow:true},function(tabs){
chrome.tabs.executeScript(tabs[0].id,{file:search.js});
chrome.tabs.sendMessage(tabs[0].id,{method:'search',searchText:search});
});
}
}
With this, we have successfully injected our script and then send the search text to that script. Just make sure that the script is wrapped in a onMessage listener like this:
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
// message.searchText is the text that was captured in the popup
// Search/Highlight code goes here
});
And that pretty much sums it up. With that, you should be able to get it working. If something is still not clear let me know and I will fix it.
I think what's confusing you is the non-existant concept of a "content page". There is no such thing. What you're likely referring to is a "content script". Let me explain the three main components of an extension:
Background Page
As you said, this is the persistent aspect of a Chrome Extension. Even though it can be HTML page it is never rendered. You simply use it to run JavaScript and other content that stays persistent. The only way to "refresh" the background page is to refresh the extension in the extension manager, or to re-install the extension.
This is most useful for saving information that should remain persistent, such as authentication credentials, or counters that should build up over time. Only use the background page when absolutely necessary, though, because it consumes resources as long as the user is running your extension.
You can add a background script like to manafest file like this:
"background": {
"scripts": [
"background.js"
]
},
Or like this:
"background": {
"page": "background.html"
},
Then simply add background.js to background.html via a typical tag.
Popup
This is what you see when you click the icon on the toolbar. It's simply a popup window with some HTML. It can contain HTML, JavaScript, CSS, and whatever you would put in a normal web page.
Not all extension need a popup window, but many do. For example, your highlight extension may not need a popup if all it's doing is highlighting text on a page. However, if you need to collect a search result (which seems likely) or provide the user with some settings or other UI then a popup is a good way to go about this.
You can add a popup to the manifest file like this:
"browser_action": {
"default_popup": "popup.html"
},
Content script
As I mentioned, this is not a "page" per se -- it a script, or set of scripts. A content script is what you use to infuse JavaScript into pages the user is browser. For example, a user goes to Facebook and a content script could change the background to red. This is almost certainly what you'll need to use to highlight text on a page. Simply infuse some JavaScript and any necessarily libraries to search the page or crawl the dom, and render changes to that page.
You can inject content scripts every time a user opens any URL like this:
"content_scripts": [
{
"matches" : [
"<all_urls>"
],
"js" : [
"content.js"
]
}
],
The above injects "content.js" into "all urls".
You'll also need to add this to the permissions:
"permissions": [
"<all_urls>",
]
You can even add JQuery to the list of content scripts. The nice thing about extensions is that the content scripts are sandboxed, so the version of JQuery you inject will not collide with JQuery on pages the user visits.