仅替换网页上的文本以创建链接

时间:2010-10-16 08:15:02

标签: javascript dom

我想修改日期形式的文档中的文字,并将其替换为在该日期将事件添加到Google日历的链接。我主要使用一个警告,它试图在已存在的链接中添加链接,其中包含日期。

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> ");

我想过在所有p标签元素的innerHTML字符串上运行替换:例如

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&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> ");
}

但这也包括孩子(例如链接标签)。我不确定如何在没有孩子的情况下为p标签元素替换innerHTML。

除了删除带有标签的所有元素(它也会破坏图像等等,所以我也应该对这些元素做同样的事情),运行替换,并重新插入标记元素,我想不出另一种方法破坏现有链接的问题(欢迎提示)。

可悲的是,我也遇到了麻烦。我可以使用正则表达式来匹配innerHTML字符串中的所有元素,但我认为使用DOM会少一些。

我尝试了以下内容,但我不知道如何解决不知道tobeReplacedNodes [i]属于哪个孩子的问题:(编辑:我可能会调用.parent或某些人来弄清楚是什么它的父母是......我会再试一次并报告它是怎么回事

tobeReplacedNodes = document.body.getElementsByTagName("a");
for(i=0;i<tobeReplacedNodes.length;i++) {
    tobeReplacedNodes[i] = document.body.replaceChild(element, tobeReplacedNodes[i]);
}

到目前为止我所拥有的是:http://code.google.com/p/calendar-event-adder/(测试分支是最新的)

感谢任何想法/建议,谢谢!

4 个答案:

答案 0 :(得分:2)

我没有在整个文档上执行RegExp,而是尝试使用DOM。

使用jQuery,我首先只选择要替换文本节点的节点。这很重要,否则你也会替换你真正想要避免的<code>或事件<script>等标签中的内容。在那些获取文本节点并提取匹配。我的例子非常保守地选择要考虑扫描哪些元素,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();
        }
    }
});

使用Node.TEXT_NODE的Afaik不是跨浏览器兼容的,如果不可用,则使用原生值3可能是必要的。我还读到String#split可能也不适用于任何地方。换句话说:需要仔细测试。

答案 1 :(得分:1)

递归地遍历DOM,跳过链接(及其子级)并仅处理nodeType"text"的节点。您应该在包含Text的所有内容中包含<p>个节点。

答案 2 :(得分:1)

此插件可以为您处理所有混乱的业务,并且不会干扰任何非文本元素。 http://benalman.com/projects/jquery-replacetext-plugin/

例如,您可以使用此单行替换#test元素中“text”一词的所有实例:

$('#test').find(':not(textarea)')
  .replaceText( /\b(text)\b/gi, '<a href="foo">$1<\/a>' );

答案 3 :(得分:0)

另一个想法:目前你首先解析整个文档(这可能需要时间)。 然后你转换文档,这可能是关键的(我作为一个用户不会很高兴看到删除一些链接)

所以我的想法是:如果你点击文档中的某个地方,你可以创建一个范围,它可以为你提供你点击的TextNode。因此,您应该能够解析TextNode的内容,看它是否与您的模式匹配,并将匹配转发给一个打开URL的函数。 这个想法的不好之处是:在用户点击它之前,你无法以某种方式标记日期。

但这只是一个想法。