我为firefox编写了一个扩展,它突出显示了网页上的所有单词(不包括给定列表中的某些单词)。
我注意到的是(除了我的扩展非常慢)一些网页被“破坏”,更具体地说,布局被破坏(特别是有重叠广告的网站或花哨的下拉菜单)。
我的代码在每个“单词”周围包含<span>
标记,或者在每个标记周围都是精确的,因为我将文本节点拆分为空格作为分隔符。
那么无论如何都可以在不破坏页面布局的情况下实现这项任务吗?
我正在迭代所有文本节点,拆分它们,并迭代每个标记。
当令牌在我的列表中时,我不突出显示它,否则我将<span>
标签包裹在它周围。
因此,任何有关如何更快地完成此任务的建议也会有所帮助。
以下是正确突出显示和未正确突出显示的网页的屏幕截图:
右: en.wikipedia.org before highlighting, en.wikipedia.org after highlighting
错误的: developer.mozilla.org before highlighting, developer.mozilla.org after highlighting
答案 0 :(得分:2)
行。研究这段代码。它搜索“是”的所有实例,并突出显示它是否未被单词字符包围。此选项卡聚焦时,将其放在便笺簿中。你会看到像“List”这样的单词和其他包含“Is”的单词没有突出显示,但是所有的“Is”都是。
我基本上为你做了一个插件。您现在可以将其作为一个名为RegEx FindBar的插件发布,并获得所有功劳....
var doc = gBrowser.contentDocument;
var ctrler = _getSelectionController(doc.defaultView);
var searchRange = doc.createRange();
searchRange.selectNodeContents(doc.documentElement);
let startPt = searchRange.cloneRange();
startPt.collapse(true);
let endPt = searchRange.cloneRange();
endPt.collapse(false);
let retRane = null;
let finder = Cc["@mozilla.org/embedcomp/rangefind;1"].createInstance().QueryInterface(Ci.nsIFind);
finder.caseSensitive = false;
var i = 0;
while (retRange = finder.Find('is', searchRange, startPt, endPt)) {
i++;
var stCont = retRange.startContainer;
var endCont = retRange.endContainer;
console.log('retRange(' + i + ') = ', retRange);
console.log('var txt = retRange.commonAncestorContainer.data',retRange.commonAncestorContainer.data);
//now test if one posiion before startOffset and one position after endOffset are WORD characters
var isOneCharBeforeStCharWordChar; //var that holds if the character before the start character is a word character
if (retRange.startOffset == 0) {
//no characters befor this characte so obviously not a word char
isOneCharBeforeStCharWordChar = false;
} else {
var oneCharBeforeStChar = stCont.data.substr(retRange.startOffset-1,1);
if (/\w/.test(oneCharBeforeStChar)) {
isOneCharBeforeStCharWordChar = true;
} else {
isOneCharBeforeStCharWordChar = false;
}
console.log('oneCharBeforeStChar',oneCharBeforeStChar);
}
var isOneCharAfterEndCharWordChar; //var that holds if the character before the start character is a word character
if (retRange.endOffset == endCont.length - 1) {
//no characters after this characte so obviously not a word char
isOneCharAfterEndCharWordChar = false;
} else {
var oneCharAferEndChar = endCont.data.substr(retRange.endOffset,1); //no need to subtract 1 from endOffset, it takes into account substr 2nd arg is length and is treated like length I THINK
if (/\w/.test(oneCharAferEndChar)) {
isOneCharAfterEndCharWordChar = true;
} else {
isOneCharAfterEndCharWordChar = false;
}
console.log('oneCharAferEndChar',oneCharAferEndChar);
}
if (isOneCharBeforeStCharWordChar == false && isOneCharAfterEndCharWordChar == false) {
//highlight it as surrounding characters are no word characters
_highlightRange(retRange, ctrler);
console.log('highlighted it as it was not surrounded by word charactes');
} else {
console.log('NOT hilte it as it was not surrounded by word charactes');
}
//break;
startPt = retRange.cloneRange();
startPt.collapse(false);
}
/*********************/
function _getEditableNode(aNode) {
while (aNode) {
if (aNode instanceof Ci.nsIDOMNSEditableElement)
return aNode.editor ? aNode : null;
aNode = aNode.parentNode;
}
return null;
}
function _highlightRange(aRange, aController) {
let node = aRange.startContainer;
let controller = aController;
let editableNode = this._getEditableNode(node);
if (editableNode)
controller = editableNode.editor.selectionController;
let findSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
findSelection.addRange(aRange);
if (editableNode) {
// Highlighting added, so cache this editor, and hook up listeners
// to ensure we deal properly with edits within the highlighting
if (!this._editors) {
this._editors = [];
this._stateListeners = [];
}
let existingIndex = this._editors.indexOf(editableNode.editor);
if (existingIndex == -1) {
let x = this._editors.length;
this._editors[x] = editableNode.editor;
this._stateListeners[x] = this._createStateListener();
this._editors[x].addEditActionListener(this);
this._editors[x].addDocumentStateListener(this._stateListeners[x]);
}
}
}
function _getSelectionController(aWindow) {
// display: none iframes don't have a selection controller, see bug 493658
if (!aWindow.innerWidth || !aWindow.innerHeight)
return null;
// Yuck. See bug 138068.
let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsISelectionDisplay)
.QueryInterface(Ci.nsISelectionController);
return controller;
}
答案 1 :(得分:1)
哦编辑我的解决方案,将使用适当的解决方案更新,我看到你想要突出显示所有单词
这是firefox在不更改文档的情况下突出显示内容的代码:Finder.jsm - _highlight function。您将需要复制此文件并将其用于整个文档,如果您需要帮助,请告诉我,我会这样做。
以下是我的解决方案,以突出显示单个词的所有匹配项:https://stackoverflow.com/a/22206366/1828637
在这里,这是你要突出整个文档的方式,我没有完成片段,但这是它的开始:Gist - HighlightTextInDocument
答案 2 :(得分:1)
这是复制粘贴答案,以突出显示文档中的所有内容。当你了解更多与我们分享的内容时,就像你可以用不同的颜色突出显示,现在它的粉红色O_O
function _getEditableNode(aNode) {
while (aNode) {
if (aNode instanceof Ci.nsIDOMNSEditableElement)
return aNode.editor ? aNode : null;
aNode = aNode.parentNode;
}
return null;
}
function _highlightRange(aRange, aController) {
let node = aRange.startContainer;
let controller = aController;
let editableNode = this._getEditableNode(node);
if (editableNode)
controller = editableNode.editor.selectionController;
let findSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
findSelection.addRange(aRange);
if (editableNode) {
// Highlighting added, so cache this editor, and hook up listeners
// to ensure we deal properly with edits within the highlighting
if (!this._editors) {
this._editors = [];
this._stateListeners = [];
}
let existingIndex = this._editors.indexOf(editableNode.editor);
if (existingIndex == -1) {
let x = this._editors.length;
this._editors[x] = editableNode.editor;
this._stateListeners[x] = this._createStateListener();
this._editors[x].addEditActionListener(this);
this._editors[x].addDocumentStateListener(this._stateListeners[x]);
}
}
}
function _getSelectionController(aWindow) {
// display: none iframes don't have a selection controller, see bug 493658
if (!aWindow.innerWidth || !aWindow.innerHeight)
return null;
// Yuck. See bug 138068.
let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsISelectionDisplay)
.QueryInterface(Ci.nsISelectionController);
return controller;
}
var doc = gBrowser.contentDocument;
var searchRange = doc.createRange();
searchRange.selectNodeContents(doc.documentElement);
_highlightRange(searchRange,_getSelectionController(gBrowser.contentWindow))
答案 3 :(得分:1)
@jervis,我无法对@Noitidart代码下的评论发表评论,因为我还没有50rep。所以我必须在这里发帖。
回复:
我现在用'gFindBar._highlightDoc(true,word)'做到了。我正在使用firefox 17,所以我不知道gFindBar是否是最先进的。 - jervis 40分钟前
但我测试了他的代码并且它有效。
不要使用gFindBar。
复制它,然后将其粘贴到Scratchpad中。
您为什么使用gFindBar._highlightDoc(true, word)
?我想你想突出文件中的所有内容吗?你从哪里得到_highlightDoc
?我在@ Noitidart的代码中没有看到任何地方。
回复yoru评论迭代所有单词并使用gFindBar._highlightDoc:
我现在用'gFindBar._highlightDoc(true,word)'做到了。我正在使用firefox 17,所以我不知道gFindBar是否是最先进的。 - jervis 39分钟前
Dude为什么这样做....我看到@Noitidart在链接主题上发布了一个单词解决方案:gBrowser.tabContainer.childNodes[0].linkedBrowser.finder.highlight(true, 'YOUR_WORD_HERE');
非常容易,一行而且不需要创建文本节点跨度或任何东西。您必须在要突出显示的每个选项卡上运行此代码。