Reputation: 5768
There is a webpage that has all the HTML structure made with Javascript. Example:
<script language="JavaScript" type="text/javascript">
//<![CDATA[
function abcd()
{
document.writeln('<div id="abc">');
document.writeln('<div class="Wrapper">');
document.writeln('Test');
...
}
</script>
What I want to do is replace all instances of the word Test
with <b>Test</b>
but I'm not sure how I'm even supposed to get the elements/HTML with it made this way.
Upvotes: 0
Views: 501
Reputation: 93433
You want to wrap Test
, and the offending HTML is added by javascript. If that is so, then there are three basic approaches:
You can just wrap the target words as they appear. This is the most robust approach. See below for more detail.
You can often rewrite the offending javascript function later. For example:
// ==UserScript==
// @name YOUR_SCRIPT_NAME
// @include http://YOUR_SERVER.COM/YOUR_PATH/*
// ==/UserScript==
function abcd () {
document.writeln('<div id="abc">');
document.writeln('<div class="Wrapper">');
document.writeln('<b>Test</b>');
...
}
var D = document;
var scriptNode = D.createElement ('script');
scriptNode.type = "text/javascript";
scriptNode.textContent = abcd;
var targ = D.getElementsByTagName('head')[0] || D.body || D.documentElement;
targ.appendChild (scriptNode);
will replace the evil version of abcd ()
, hopefully before it is run.
You could try to intercept that <script>
node after it loads and before it executes (once the script has run, changing the source would have no effect).
This is possible with Firefox, see this answer for Greasemonkey code that does that. I don't recommend that approach in this case, though.
CDATA is not a factor for any of these approaches.
Use the waitForKeyElements() utility to catch the nodes of interest as they appear. There is no need to analyze the page's javascript or worry about changes to it that might break something.
Use a common-ish DOM approach to wrapping target text, without breaking HTML or trashing event listeners. In this case, it's the wrapTextWithElement
object.
jQuery makes it all easier, clearer.
Here's a complete script. You can also test it against this demo page.
// ==UserScript==
// @name YOUR_SCRIPT_NAME
// @include http://fiddle.jshell.net/gH4nV/*
// @include http://YOUR_SERVER.COM/YOUR_PATH/*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change introduced
in GM 1.0. It restores the sandbox.
*/
waitForKeyElements ("div.Wrapper", emboldenTheWordTest);
function emboldenTheWordTest (jNode) {
var testWrapper = new wrapTextWithElement ('Test', '<b>');
testWrapper.wrap (jNode);
}
function wrapTextWithElement (targText, elemToWrapWith, bCaseSensitive) {
var self = this;
var bCaseSensitive = bCaseSensitive || false;
self.targRegEx = new RegExp ("(" + targText + ")", bCaseSensitive ? "" : "i");
self.elemToWrapWith = elemToWrapWith;
self.wrap = function (node) {
$(node).contents ().each ( function () {
if (this.nodeType === Node.ELEMENT_NODE) {
self.wrap (this);
}
else if (this.nodeType === Node.TEXT_NODE) {
var ndText = this.nodeValue;
if (self.targRegEx.test (ndText) ) {
var replaceNodes = $.map (
ndText.split (self.targRegEx),
function (phrase) {
if (self.targRegEx.test (phrase) ) {
var wrapped = $(self.elemToWrapWith, {text: phrase} );
return wrapped.get ();
}
else {
if (phrase == "")
return null;
else
return document.createTextNode (phrase)
}
}
);
$(this).replaceWith (replaceNodes);
}
}
} );
};
}
Upvotes: 1