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") becomes "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 common 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.
There 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.jsContent 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.jsonHere'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>"]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With