是否可以在不破坏布局的情况下突出显示网页上的所有单词?

时间:2014-03-05 16:49:48

标签: javascript html firefox dom firefox-addon

我为firefox编写了一个扩展,它突出显示了网页上的所有单词(不包括给定列表中的某些单词)。

我注意到的是(除了我的扩展非常慢)一些网页被“破坏”,更具体地说,布局被破坏(特别是有重叠广告的网站或花哨的下拉菜单)。

我的代码在每个“单词”周围包含<span>标记,或者在每个标记周围都是精确的,因为我将文本节点拆分为空格作为分隔符。

那么无论如何都可以在不破坏页面布局的情况下实现这项任务吗?

我正在迭代所有文本节点,拆分它们,并迭代每个标记。 当令牌在我的列表中时,我不突出显示它,否则我将<span>标签包裹在它周围。

因此,任何有关如何更快地完成此任务的建议也会有所帮助。

以下是正确突出显示和未正确突出显示的网页的屏幕截图:

右: en.wikipedia.org before highlightingen.wikipedia.org after highlighting

错误的: developer.mozilla.org before highlightingdeveloper.mozilla.org after highlighting

4 个答案:

答案 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');非常容易,一行而且不需要创建文本节点跨度或任何东西。您必须在要突出显示的每个选项卡上运行此代码。