I would like to modify text in a document that is in the form of a date and replace it with a link to add an event on that date to Google Calendar. I mostly have this working with one caveat, it tries to add the link inside of already existing links that have dates in them.
document.body.innerHTML = document.body.innerHTML.replace(arrayDates[i], arrayDates[i] + " <a href=\"http://www.google.com/calendar/event?action=TEMPLATE&text=someevent&dates=" + dateString + "&details=&location=&trp=false&sprop=&sprop= target=\"_blank\"> <img src=\"" + chrome.extension.getURL("Config-date-16.png") + "\" title=\"Add this event to your Google Calendar\"> </a> ");
I thought of just running the replacement on the innerHTML string of all p tag elements: eg
arrayP = document.body.getElementsByTagName("p");
for(i=0;i<arrayP.length:i++) {
arrayP[i].innerHTML = arrayP[i].innerHTML.replace(arrayDates[i], arrayDates[i] + " <a href=\"http://www.google.com/calendar/event?action=TEMPLATE&text=someevent&da开发者_Python百科tes=" + dateString + "&details=&location=&trp=false&sprop=&sprop= target=\"_blank\"> <img src=\"" + chrome.extension.getURL("Config-date-16.png") + "\" title=\"Add this event to your Google Calendar\"> </a> ");
}
but this also includes the children (eg links a tag). I'm not sure of how I can only replace the innerHTML for the p tag elements without it's children.
Other than removing all elements with an a tag (it will also mangle images and such so I should do the same with those elements as well), running the replacement, and reinserting tag elements, I cannot think of another way around the issue of mangling already existing links (ideas welcome).
Sadly I'm also having trouble with this. I could use a regex to match all elements in the innerHTML string, but I think it would be less kludgey to use the DOM.
I tried the following, but I'm not sure how to get around the problem of not knowing which child tobeReplacedNodes[i] belongs to: (edit: i could probably call .parent or somesuch to figure out what it's parent is... I'll try this out again and report back how it goes)
tobeReplacedNodes = document.body.getElementsByTagName("a");
for(i=0;i<tobeReplacedNodes.length;i++) {
tobeReplacedNodes[i] = document.body.replaceChild(element, tobeReplacedNodes[i]);
}
What I have so far is here: http://code.google.com/p/calendar-event-adder/ (testing branch is most current)
Any ideas/suggestions are appreciated, thanks!
Instead of doing a RegExp on the whole document I would try working with the DOM.
Using jQuery, I first select only nodes within I want to replace text nodes. That's important because otherwise you would also replace content in tags like <code>
or event <script>
which you really want to avoid. Within those get the text nodes and extract the matches. My example is very conservative about selecting which elements to consider to scan, YMMV.
// I used this code to execute on your stackoverflow question,
// thus I choose "this" . Try it in Firebug.
var re = /(this)/gi, split;
$('div,p').contents().each( function() {
if (this.nodeType == Node.TEXT_NODE) {
if (this.nodeValue.match( re ) ) {
split = this.nodeValue.split( re );
for (var i = 0, l = split.length; i < l; i++) {
if (i % 2) {
// the re catches the match thus every
// odd index is the match
$('<a href="#destination">' + split[i] +
'</a>').insertBefore( this );
} else {
$( document.createTextNode(split[i]) ).
insertBefore( this );
}
}
$(this).remove();
}
}
});
Afaik using Node.TEXT_NODE
is not that cross browser compatible, using the native value 3
if it's not available might be necessary. I've also read that String#split may not applicable everywhere too. In other words: careful testing is required.
Walk the DOM recursively, skip over links (and their children) and process only nodes which nodeType
is "text"
. You should have a Text
node inside everything that has text, including <p>
.
This plugin handles all of the messy business for you, and doesn't interfere with any non-text elements. http://benalman.com/projects/jquery-replacetext-plugin/
For example, you can replace all instances of the word "text" in the #test element with this one-liner:
$('#test').find(':not(textarea)')
.replaceText( /\b(text)\b/gi, '<a href="foo">$1<\/a>' );
Just another idea: currently you first parse the whole document(which can take it's time). Then you transform the document, what may be critical(me as a user would'nt be glad to see some links removed)
so my idea: if you click somewhere inside a document, you can create a range, which may give you the TextNode you clicked on. So you should be able to parse the contents of the TextNode, see if it matches your pattern and forward the match to a function, which opens the URL. The bad part of this idea: you will not be able to label the Date somehow before the user has clicked on it.
But it's just an idea.
精彩评论