我使用的网站非常旧,数据不会以友好的方式显示。我想写一个用户脚本(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
Blah blah * (test) text goes here -Thanks Here: there
如您所见,两个<br>
总是出现在下一个“条目”(名称,位置,日期)之前,但由于文本是自由文本,因此它还可以包含各种<br>
,包括2个或更多。另一个问题是,如果文本还包含Name (Location) - Date
粘贴在别处的其他条目。
因此,如果我想编写一个可以添加到谷歌浏览器的脚本,它说添加了一个可以折叠的按钮(或者如果已经折叠,则会折叠)每个条目,这可能吗?我遇到的问题是,由于没有唯一的元素开始或结束条目,我不知道如何开始这个。
一般的概念是遍历每个“条目”(标题是名称/位置/日期)和后面的文本直到下一个标题)并允许每个“条目”可折叠(例如Reddit注释是可折叠的)。
或者对于一个更简单的概念,如果我想用红色字体标记每个其他条目怎么办?那么所有的entry1都是黑色字体,entry2是红色字体,entry3是黑色字体,entry4是红色字体,依此类推。
答案 0 :(得分: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/
答案 1 :(得分:1)
对于这种事情,在状态机循环中解析条目。
以下代码始终是第一个答案:
问题的HTML与the actual page structure不匹配。更新了下面的脚本以解释该问题,并将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组条目!这可能是剪切和粘贴错误,但如果不是,请打开一个新问题,如果easy mod需要帮助来处理多个集合。
答案 2 :(得分:0)
有许多方法可让您在不知道ID的情况下选择元素,例如:
更新:我没有看到任何方法来区分行中的两个<br>
元素作为入口结束标记和行中的两个<br>
元素只是其中的一部分一个特定的条目。在您的示例中,“text”条目可以包含可能位于名称/位置/日期行中的任何内容。因此,稍微简化它并将每个 double-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.net/C4h7s/1/ < / p>
(我没有时间或动力来整理这些演示,但至少他们应该给你一些关于一种方法的想法。或者单向不继续进行,取决于你认为我的代码是多么愚蠢。)
答案 3 :(得分:0)
如果您需要在<br />
s:
<font>
元素,例如.getElementsByTagName()
childNodes
并循环遍历它们:
然后你应该能够从中构建一个更合适的DOM。您甚至可以重用文本节点,只需将它们包装在适当的标签中即可。