0

我使用了一个非常旧的网站,并且数据没有以友好的方式显示。我想写一个用户脚本(javascript/jQuery)来帮助这个网站的可读性。内容看起来像(HTML 注释是我自己的,以帮助显示这一点):

<font size="3" face="Courier">
  <br>
  <!-- Begin entry 1 -->
  Name1 (Location1) - Date1:
  <br>
  Text1
  <br>
  Text1 (continued)
  <br>
  Text1 (continued)
  <br>
  <br>
  <!-- Begin entry 2 -->
  Name2 (Location2) - Date2:
  <br>
  Text2
  <br>
  Text2 (continued)
  <br>
  <br>
  Text2 (continued)
  <br>
  Text2 (continued)
  <br>
  <br>
  <!-- Begin entry 3 -->
  Name3 (Location3) - Date3:
  <br>
  Text3
  <br>
  Text3 (continued)
  <br>
  Text3 (continued)
  <br>
  <br>
  <br>
  Text3 (continued)
  <br>
  Text3 (continued)
  <!-- Below is Text3, but a user copied Entry1 here --> 
  Name1 (Location1) - Date1: <!-- text3 -->
  <br> <!-- text3 -->
  Text1 <!-- text3 -->
  <br> <!-- text3 -->
  Text1 (continued) <!-- text3 -->
  <br> <!-- text3 -->
  Text1 (continued) <!-- text3 -->
  <br>
  <br>
  <!-- Begin entry 4 -->
  Name4 ...
  ......
</font>
  • 名称示例:Bob Dole,SMITH,JOHN
  • 位置示例:via Web,INTERNAL
  • 日期示例:Jul 25, 2011 - 1317 EDT,Dec 30, 2011 - 1411 EST
  • Text1/Text2/etc 的示例:Blah blah * (test) text goes here -Thanks Here: there

如您所见,两个<br>总是在下一个“条目”(名称、位置、日期)之前出现,但由于文本是自由文本,它也可以包含各种内容,<br>包括 2 个或更多。另一个问题是文本是否还包含Name (Location) - Date从其他地方的另一个条目粘贴的内容。

因此,如果我想编写一个可以添加到谷歌浏览器的脚本,其中说添加了一个按钮,该按钮会折叠(如果已经折叠,则取消折叠)每个条目,这可能吗?我遇到的问题是,由于没有唯一元素开始或结束条目,我不知道如何开始。

一般概念是循环遍历每个“条目”(标题是名称/位置/日期)和随后的文本,直到下一个标题)并允许每个“条目”可折叠(例如 Reddit 评论是可折叠的)。

或者对于更简单的概念,如果我想用红色字体标记每个其他条目怎么办?那么所有的entry1都是黑色字体,entry2是红色字体,entry3是黑色字体,entry4是红色字体,依此类推。

4

4 回答 4

2

您必须弄清楚如何搜索 DOM 以找到所需的元素。例如,您可以按标签名称查找内容,然后检查给定标签周围的上下文以查看它是否是您要查找的内容。

如果您提供有关您要查找的确切内容的更多信息,我们可能会帮助您提供更具体的代码。

例如,document.getElementsByTagName("br")查找<br>文档中的所有标签。<br>如果您要查找的是双标签,或者您正在查找双标签之前或之后的某些特定文本,您可以检查每一个以找到双<br>标签,您也可以查找它。正如我在评论中所说,在建议更具体的代码之前,您需要更具体地了解您实际正在寻找的模式。

例如,以下是搜索<br>文档中标签后的特定文本模式的方法:

var items = document.getElementsByTagName("br");
// modify this regex to suit what you're trying to match
var re = /\w+\s\(\w+\)/;
for (var i = 0, len = items.length; i < len; i++) {
    var node = items[i];
    while ((node = node.nextSibling) && node.nodeType == 3) {
        if (re.test(node.nodeValue)) {
            // add a marker test node (just for test purposes)
            var span = document.createElement("span");
            span.className = "marker";
            span.innerHTML = "X";
            node.parentNode.insertBefore(span, node.nextSibling);
        }            
    }        
}​

您可以将正则表达式修改为您希望搜索要查找的任何内容。

你可以在这里看到一个工作演示:http: //jsfiddle.net/jfriend00/s9VMn/


好的,这里又是一个使用正则表达式猜测您正在寻找什么模式的机会。这将查找两个连续<br>的标签,后跟与模式匹配的文本。然后它将该文本包装在一个跨度中,以便可以根据偶数或奇数对其进行样式设置。

function getTextAfter(node) {
    // collect text from successive text nodes
    var txt = "";
    while ((node = node.nextSibling) && node.nodeType == 3) {
           txt += node.nodeValue;
    }
    return(txt);    
}

function wrapTextInSpan(preNode, cls) {
    // collect successive text nodes
    // into a span tag
    var node = preNode, item;
    var span = document.createElement("span");
    span.className = cls;
    node = node.nextSibling;
    while (node && node.nodeType == 3) {
        item = node;
        node = node.nextSibling;
        span.appendChild(item);
    }
    preNode.parentNode.insertBefore(span, preNode.nextSibling);
    return(span);
}

// find double br tags
var items = document.getElementsByTagName("br");
var cnt = 1;
var re = /\w+\s+\([^)]+\)\s+-\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d+,\s+\d+\d+/i;
for (var i = 0, len = items.length; i < len; i++) {
    var node = items[i];
    // collect text from successive text nodes
    var txt = "";
    while ((node = node.nextSibling) && node.nodeType == 3) {
           txt += node.nodeValue;
    }
    // if no text, check for successive BR tags
    if (txt.replace(/\n|\s/g, "") == "") {
        if (i + 1 < len && node === items[i + 1]) {
            // found a double BR tag
            // get the text after it
            txt = getTextAfter(node);
            if (re.test(txt)) {
                wrapTextInSpan(node, "marker" + (cnt % 2 ? "Odd" : "Even"));
                ++cnt;
            }
            ++i;
        }
    }
}
​

在这里工作演示:http: //jsfiddle.net/jfriend00/ewApy/


这是另一个版本,它实际上插入了展开/折叠目标并进行部分的展开/折叠。使用正确的 HTML 和像 jQuery 这样的不错的库,这可能很容易,但没有任何一个,它的代码就更多了:

function getTextAfter(node) {
    // collect text from successive text nodes
    var txt = "";
    while ((node = node.nextSibling) && node.nodeType == 3) {
           txt += node.nodeValue;
    }
    return(txt);    
}

function wrapTextInSpan(preNode, cls) {
    // collect successive text nodes
    // into a span tag
    var node = preNode, item;
    var span = document.createElement("span");
    span.className = cls;
    node = node.nextSibling;
    while (node && node.nodeType == 3) {
        item = node;
        node = node.nextSibling;
        span.appendChild(item);
    }
    preNode.parentNode.insertBefore(span, preNode.nextSibling);
    return(span);
}

function wrapBetweenInSpan(preNode, postNode, cls) {
    var node = preNode, item;
    var span = document.createElement("span");
    span.className = cls;
    node = node.nextSibling;
    if (node && node.nodeType == 1 && node.tagName == "BR") {
        preNode = node;
        node = node.nextSibling;
    }
    while (node && node != postNode) {
        item = node;
        node = node.nextSibling;
        span.appendChild(item);
    }
    preNode.parentNode.insertBefore(span, preNode.nextSibling);
    return(span);
}

function toggleClass(el, cls) {
    var str = " " + el.className + " ";
    if (str.indexOf(" " + cls + " ") >= 0) {
        str = str.replace(cls, "").replace(/\s+/, " ").replace(/^\s+|\s+%/, "");
        el.className = str;
    } else {
        el.className = el.className + " " + cls;
    }
}

function hasClass(el, cls) {
    var str = " " + el.className + " ";
    return(str.indexOf(" " + cls + " ") >= 0);    
}

function addButton(target) {
    var span = document.createElement("span");
    span.className = "expandoButton";
    span.innerHTML = "+++";
    span.onclick = function(e) {
        var expando = this;
        do {
            expando = expando.nextSibling;
        } while (expando && !hasClass(expando, "markerContents"));
        toggleClass(expando, "notshown");
    };
    target.parentNode.insertBefore(span, target.nextSibling);
}

// find double br tags
var items = document.getElementsByTagName("br");
var cnt = 1;
var spans = [];
var re = /\w+\s+\([^)]+\)\s+-\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d+,\s+\d+\d+/i;
for (var i = 0, len = items.length; i < len; i++) {
    var node = items[i];
    // collect text from successive text nodes
    var txt = "";
    while ((node = node.nextSibling) && node.nodeType == 3) {
           txt += node.nodeValue;
    }
    // if no text, check for successive BR tags
    if (txt.replace(/\n|\s/g, "") == "") {
        if (i + 1 < len && node === items[i + 1]) {
            // found a double BR tag
            // get the text after it
            txt = getTextAfter(node);
            if (re.test(txt)) {
                var span = wrapTextInSpan(node, "marker marker" + (cnt % 2 ? "Odd" : "Even"));
                spans.push(span);
                ++cnt;
            }
            ++i;
        }
    }
}

// now wrap the contents of each marker
for (i = 0, len = spans.length; i < len; i++) {
    wrapBetweenInSpan(spans[i], spans[i+1], "markerContents shown");
    addButton(spans[i]);
}
​

此版本的工作演示:http: //jsfiddle.net/jfriend00/cPbqC/

于 2012-06-04T21:16:56.980 回答
1

对于这种事情,在状态机循环中解析条目。

以下代码始终是以下问题的第一个答案:

  1. 按照问题中的指定对 HTML 进行分组。
  2. 提供点击控制来扩展/收缩分组。
  3. 折叠条目以开始 - 以获得更好的初始概述。

在 jsFiddle 上查看它的演示。

更新:

问题的 HTML 与实际的页面结构不匹配。更新了下面的脚本以解决这个问题,并将 CSS 添加到脚本代码中:

var containerNode       = document.querySelector ("p font xpre");
var contentNodes        = containerNode.childNodes;
var tempContainer       = document.createElement ("div");
var groupingContainer   = null;
var hidableDiv          = null;
var bInEntry            = false;
var bPrevNodeWasBr      = false;

for (var J = 0, numKids = contentNodes.length;  J < numKids;  ++J) {
    var node            = contentNodes[J];

    //--- Is the node an entry start?
    if (    node.nodeType === Node.TEXT_NODE
        &&  bPrevNodeWasBr
        &&  /^\s*\w.*\s\(.+?\)\s+-\s+\w.+?:\s*$/.test (node.textContent)
    ) {
        //--- End the previous grouping, if any and start a new one.
        if (bInEntry) {
            groupingContainer.appendChild (hidableDiv);
            tempContainer.appendChild (groupingContainer);
        }
        else
            bInEntry        = true;

        groupingContainer   = document.createElement ("div");
        groupingContainer.className = "groupingDiv";

        /*--- Put the entry header in a special <span> to allow for
            expand/contract functionality.
        */
        var controlSpan         = document.createElement ("span");
        controlSpan.className   = "expandCollapse";
        controlSpan.textContent = node.textContent;
        groupingContainer.appendChild (controlSpan);

        //--- Since we can't style text nodes, put everythin in this sub-wrapper.
        hidableDiv          = document.createElement ("div");
    }
    else if (bInEntry) {
        //--- Put a copy of the current node to the latest grouping container.
        hidableDiv.appendChild (node.cloneNode(false) );
    }

    if (    node.nodeType === Node.ELEMENT_NODE
        &&  node.nodeName === "BR"
    ) {
        bPrevNodeWasBr  = true;
    }
    else
        bPrevNodeWasBr  = false;
}

//--- Finish up the last entry, if any.
if (bInEntry) {
    groupingContainer.appendChild (hidableDiv);
    tempContainer.appendChild (groupingContainer);
}

/*--- If we have done any grouping, replace the original container contents
    with our collection of grouped nodes.
*/
if (numKids) {
    while (containerNode.hasChildNodes() ) {
        containerNode.removeChild (containerNode.firstChild);
    }

    while (tempContainer.hasChildNodes() ) {
        containerNode.appendChild (tempContainer.firstChild);
    }
}

//--- Initially collapse all sections and make the control spans clickable.
var entryGroups         = document.querySelectorAll ("div.groupingDiv span.expandCollapse");
for (var J = entryGroups.length - 1;  J >= 0;  --J) {
    ExpandCollapse (entryGroups[J]);

    entryGroups[J].addEventListener ("click", ExpandCollapse, false);
}


//--- Add the CSS styles that make this work well...
addStyleSheet ( "                                                   \
    div.groupingDiv {                                               \
        border:         1px solid blue;                             \
        margin:         1ex;                                        \
        padding:        1ex;                                        \
    }                                                               \
    span.expandCollapse {                                           \
        background:     lime;                                       \
        cursor:         pointer;                                    \
    }                                                               \
    div.groupingDiv     span.expandCollapse:before {                \
        content:        '-';                                        \
        background:     white;                                      \
        font-weight:    bolder;                                     \
        font-size:      150%;                                       \
        padding:        0 1ex 0 0;                                  \
    }                                                               \
    div.groupingDiv     span.expandCollapse.collapsed:before {      \
        content:        '+';                                        \
    }                                                               \
" );


//--- Functions used...
function ExpandCollapse (eventOrNode) {
    var controlSpan;
    if (typeof eventOrNode.target == 'undefined')
        controlSpan     = eventOrNode;
    else
        controlSpan     = eventOrNode.target;

    //--- Is it currently expanded or contracted?
    var bHidden;
    if (/\bcollapsed\b/.test (controlSpan.className) ) {
        bHidden         = true;
        controlSpan.className = controlSpan.className.replace (/\s*collapsed\s*/, "");
    }
    else {
        bHidden         = false;
        controlSpan.className += " collapsed";
    }

    //--- Now expand or collapse the matching group.
    var hidableDiv      = controlSpan.parentNode.children[1];
    hidableDiv.style.display    = bHidden ? "" : "none";
}


function addStyleSheet (text) {
    var D                   = document;
    var styleNode           = D.createElement ('style');
    styleNode.type          = "text/css";
    styleNode.textContent   = text;

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    //--- Don't error check here. if DOM not available, should throw error.
    targ.appendChild (styleNode);
}

如果嵌套/引用的条目要单独包装,您还需要递归。对于嵌套/引用的条目,请在回答此问题后打开一个新问题。

注意:新的示例 HTML 有多对<html>标签和 2 组条目!这可能是一个剪切和粘贴错误,但如果不是,请打开一个新问题,如果需要帮助,以便轻松模块处理多个集合。

于 2012-06-05T00:24:09.583 回答
0

有许多方法可以让您在不知道 id 的情况下选择元素,例如:

更新:我没有看到任何方法来区分<br>作为条目结束标记<br>的一行中的两个元素和作为特定条目一部分的一行中的两个元素。从您的示例中,“文本”条目可以包含名称/位置/日期行中可能存在的任何内容。因此,稍微简化它并将每个双 br 作为条目的结尾,您可以执行以下操作:

window.onload = function() {
    var fontTags = document.getElementsByTagName("font"),
        i, j = 0;

    for (i = 0; i < fontTags.length; i++)
        fontTags[i].innerHTML = '<div class="entry odd">' +
            fontTags[i].innerHTML.replace(/<br>\s*?<br>/g, function() {
            return '</div><div class="entry ' + (j++ %2===0?'even':'odd') + '">';
        }) + '</div>';
};

这假定所有字体元素都包含要处理的数据,并用于.replace()查找出现双 br 并在每个条目周围放置包装器 div。我给每个 div 一个类“条目”,然后交替使用“偶数”和“奇数”类,这样你就可以应用这样的样式:

div.odd { color : red; }

如本演示所示:http: //jsfiddle.net/C4h7s/

显然,如果您不能将类添加到样式表,您可以使用内联样式来设置颜色。

这是我能达到的最接近您的“所有其他条目为红色”的要求。在该示例中,我实际上并没有对任何东西使用“入口”类,但当时它似乎在以后可能有用,例如,在单击切换想法的这个非常笨重的实现中:http://jsfiddle。净/C4h7s/1/

(我真的没有时间或动力来整理这些演示,但至少它们应该给你一些关于一种继续进行的方法的想法。或者一种继续的方法,这取决于你认为我的代码有多愚蠢。)

于 2012-06-04T21:21:54.553 回答
0

如果需要获取<br />s 之间的文本内容:

  1. 选择<font>元素,例如.getElementsByTagName()
  2. 获取它childNodes并遍历它们:
    • 如果它的节点类型1,它将是您的 <br />元素之一 - 请检查.nodeName(否则您需要在元素子元素上展开循环)
    • 如果它的节点类型是3,它是一个文本节点。获取文本值并将其与您的内容方案匹配

然后,您应该能够从中构建更合适的 DOM。您甚至可以重用文本节点并将它们包装在适当的标签中。

于 2012-06-04T21:47:21.530 回答