Is there an equivalent to `run_at: start` in a background page? - javascript

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>.

Related

Trying to access iFrame through source URL but showing up blank [duplicate]

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('*')]);
}

How to predit in chrome extension html before it is displayed

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.

Chrome extension: must delay page load until javascript finishes

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.

How to access page variables from Chrome extension background script

With a content script you can inject a script tag into the DOM in order to access variables in the original page (as explained in this question).
I want to avoid injecting my code into every page and instead only do that when the user clicks on the extension icon.
When I tried using the same code as for the content script the values were undefined, although the script was inserted correctly.
Is this possible? Otherwise is using a content script and communicating with it the preferred solution?
Here is the code I'm using:
var scr = document.createElement("script");
scr.type="text/javascript";
scr.innerHTML = "setInterval('console.log(window.testVar)', 1000)"
document.body.appendChild(scr)
Manifest excerpt:
"permissions": [
"tabs",
"http://*/*", "https://*/*"
],
"background": {
"scripts": ["inject.js"]
},
Nope. That's not possible. You may inject a script, but it only have an access to DOM and it could make DOM manipulations. It can not read javascript variables or execute functions in the context of the current page. Your javascript code is run in a sandbox and you are restricted only to the DOM elements.
You can create a new background script with the following code:
chrome.browserAction.onClicked.addListener( function() {
chrome.tabs.executeScript( { file: 'inject.js' } );
});
Your inject.js should stay as part of the extension, but you don't need to mention it in the manifest. This way, it will be run as a content script each time you press the extension icon. You didn't include the part of the manifest where you define the browserAction, but you just need to not specify a default_popup.
You can utilize a background script to execute JavaScript within the context of the page, however, your JavaScript is executed in an isolated environment from the JavaScript that is loaded from within the page.
Consider the following:
In page.html:
<button id="myButton" onclick="console.log('Message from within the page');" />
In background script:
chrome.tabs.executeScript({
code: '$("#myButton").click(function() { console.log("Message from background script."); });'
});
Now, if you click the button within the page, you will find both log messages in the console window. The JavaScript contexts are isolated from each other, with the notable exceptions of messaging via postMessage and through the shared DOM.

Javascript in browser bar vs in content script - 'die' doesn't work

I'm trying to run a javascript command in a content script using Personalized-Web (a Chrome extension). I'm new to javascript & jquery, but I've found that entering this code:
javascript:jQuery("div.photo-container").die();
into my browser bar on a particular page achieves the desired result: it undoes a .live call performed in one of the page's javascripts.
However, if I include that same code or $("div.photo-container").die(); in a content script, it does not work. I've also attempted including this script tag in the page context:
<script type="text/javascript">
$("div.photo-container").die();
</script>
and chrome claims that $ or jQuery are not defined. However, the page's own javascripts don't include or refer to the jQuery source at any point, as far as I can tell.
So, what's the difference between the browser bar, the content script, and the in-page <script> tag? How can I use one of the 'automatic' methods (i.e., not paste it into the browser bar)?
If you inject that script tag into the page, it should work. For example:
// Runs in the context of the webpage.
var injectScript = function() {
$("div.photo-container").die();
}
// Runs in the context of the content script. We basically just append the DOM
// with the injected script and execute it so it will run.
var script = document.createElement('script');
script.appendChild(document.createTextNode('(' + injectScript + ')();'));
document.body.appendChild(script);
The above should work assuming your page has defined the $. If the $ doesn't exist, that means jQuery didn't load yet. Make sure your manifest has document_end defined as well.
...
"content_scripts": [
{
"matches": ["http://www.rim.com/*"],
"js": ["content_script.js"],
"run_at": "document_end"
}
],
...
If that doesn't work then Sometimes depending on the website, it is good to lazy load or smart load till the content (script) gets loaded because the webdesigner is asynchronously loading the scripts or content. In that case, do some research to see how jquery is being loaded. For example, do a timer with setTimeout or DOM events to figure out when it is time to run your injection. I do that many times on difficult websites such as Google+ Extensions.

Categories

Resources