I'm trying to create an extension to modify an existing site, and fix a bug in the existing javascript. A simple replace on the text contents of the document before the load would fix the bug -- specifically, hard-coded values in a tag in the header -- and my first attempt (removing the timestamps from date values) was something like this:
document.documentElement.innerHTML = document.documentElement.innerHTML.replace(/("date_of_birth": new Date\("[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4}) \d{2}:\d{2}:\d{2} GMT/g, "$1");
For example, any instance of "date_of_birth": new Date("Tue, 30 Oct 1984 00:01:00 GMT")
bees "date_of_birth": new Date("Tue, 30 Oct 1984")
The problem is that the only way I know of to access the HTML contents of the document is document.documentElement.innerHTML. Running this at document_start fails, as the DOM hasn't been loaded yet, so documentElement.innerHTML is an empty string. Running the above code after the DOM loads will be too late, as the initializing scripts have already run, and modifying the document's html at that point reloads those scripts, causing all kinds of havoc in the script-heavy page.
I cannot simply append to the documentElement before the DOM is loaded, as was the most mon suggestion when searching for a solution. This needs to modify the existing scripts before they are loaded and run.
Is there any way to access and preprocess the raw contents of the HTML document before it is loaded?
Thanks in advance.
I'm trying to create an extension to modify an existing site, and fix a bug in the existing javascript. A simple replace on the text contents of the document before the load would fix the bug -- specifically, hard-coded values in a tag in the header -- and my first attempt (removing the timestamps from date values) was something like this:
document.documentElement.innerHTML = document.documentElement.innerHTML.replace(/("date_of_birth": new Date\("[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4}) \d{2}:\d{2}:\d{2} GMT/g, "$1");
For example, any instance of "date_of_birth": new Date("Tue, 30 Oct 1984 00:01:00 GMT")
bees "date_of_birth": new Date("Tue, 30 Oct 1984")
The problem is that the only way I know of to access the HTML contents of the document is document.documentElement.innerHTML. Running this at document_start fails, as the DOM hasn't been loaded yet, so documentElement.innerHTML is an empty string. Running the above code after the DOM loads will be too late, as the initializing scripts have already run, and modifying the document's html at that point reloads those scripts, causing all kinds of havoc in the script-heavy page.
I cannot simply append to the documentElement before the DOM is loaded, as was the most mon suggestion when searching for a solution. This needs to modify the existing scripts before they are loaded and run.
Is there any way to access and preprocess the raw contents of the HTML document before it is loaded?
Thanks in advance.
Share Improve this question asked Mar 14, 2012 at 7:40 Author XAuthor X 331 silver badge3 bronze badges1 Answer
Reset to default 5There is no way to "edit" the contents of <script>
before it is executed: Once the closing </script>
tag is encountered, the contents is evaluated right away.
Instead of modifying the code itself, an indirect approach can be used: Overwrite the global Date
object, which can be done using the code below:
(function(global) {
var _Date = global.Date; /* Store original Date object */
var overwriteafterXmatches = 1; /* Overwrite after X matches*/
function date(year, month, day, hour, minute, second, millisecond) {
var tmp = /^([A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4}) \d{2}:\d{2}:\d{2} GMT$/.exec(year);
switch(arguments.length) {
case 0:
return new _Date();
case 1:
if (tmp) { /* If match */
tmp = new _Date(match[1]);
if (--overwriteAfterXmatches <= 0) {
/* Set the original Date object*/
global.Date = _Date;
}
}
return new _Date(year);
case 2:
return new _Date(year, month);
case 3:
return new _Date(year, month, day);
case 4:
return new _Date(year, month, day, hour);
case 5:
return new _Date(year, month, day, hour, minute);
case 6:
return new _Date(year, month, day, hour, minute, second);
default:
return new _Date(year, month, day, hour, minute, second, millisecond);
}
}
/* Overwrite global Date object*/
global.Date = date;
})(window);
contentscript.js
Content scripts run in an isolated environment. That means that you cannot modify global properties directly. To get the code to work in a Content script, you have to inject a <script>
tag, in this way:
var code = "\
(function(global) {\
var _Date = global.Date; /* Store original date object*/\
var overwriteafterXmatches = 1; /* Overwrite after X matches*/\
function date(year, month, day, hour, minute, second, millisecond) {\
var tmp = /^([A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4}) \d{2}:\d{2}:\d{2} GMT$/.exec(year);\
switch(arguments.length) {\
case 0:\
return new _Date();\
case 1:\
if (tmp) { /* If match */\
tmp = new _Date(match[1]);\
if (--overwriteAfterXmatches <= 0) {\
/* Set the original Date object*/\
global.Date = _Date;\
}\
}\
return new _Date(year);\
case 2:\
return new _Date(year, month);\
case 3:\
return new _Date(year, month, day);\
case 4:\
return new _Date(year, month, day, hour);\
case 5:\
return new _Date(year, month, day, hour, minute);\
case 6:\
return new _Date(year, month, day, hour, minute, second);\
default:\
return new _Date(year, month, day, hour, minute, second, millisecond);\
}\
}\
/* Overwrite global Date object*/\
global.Date = date;\
})(window);\
";
var script = document.createElement('script');
script.appendChild(document.createTextNode(code));
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);
manifest.json
Here's an example of the manifest.json
file. Replace <all_urls>
with a more specific match pattern.
{
"name": "Test",
"version": "1.0",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["contentscript.js"],
"run_at": "document_start"
}
],
"permissions": ["<all_urls>"]
}