2014-03-05 53 views
1

我寫了一個Firefox的擴展,它突出顯示了網頁上的所有單詞(不包括給定列表中的某些單詞)。是否可以在不破壞佈局的情況下突出顯示網頁上的所有單詞?

我注意到的是(除了我的擴展速度非常慢),一些網頁被「破壞」,更具體地說佈局被破壞(特別是覆蓋廣告或花哨的下拉菜單的網站)。

我的代碼在每個「單詞」周圍標記了<span>標籤,或者精確地圍繞每個標記,因爲我將文本節點與空白分隔開作爲分隔符。

那麼是否有可能在不破壞頁面佈局的情況下實現此任務?

我遍歷所有文本節點,分割它們,並遍歷每個標記。 當令牌位於我的列表中時,我不會突出顯示它,否則我將圍繞它包裝<span>標籤。

因此,如何更快地完成這項任務可能會有所幫助。

這裏有一個正確突出和未正確突出網頁的截圖:

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

錯誤: developer.mozilla.org before highlighting, developer.mozilla.org after highlighting

+0

您必須引入無效語法或佈局不應受到影響。你有演示嗎? – isherwood

+0

除非您的正在添加邊框,邊距和/或填充,那麼佈局不應受到影響。您應該只設置背景顏色和顏色屬性。 – jeff

+0

好吧,我也這麼認爲,但這裏有一個工作示例的截圖:[en.wikipedia.org之前](http://imgur.com/FyFunmo.jpg),[en.wikipedia.org之後](http: //imgur.com/snw0K6v.jpg)下面是一些破壞版式的截圖:[developer.mozilla.org之前](http://imgur.com/glnLa4U.jpg),[developer.mozilla.org之後] (http://imgur.com/gn9mOk0.jpg)。 – jervis

回答

1

哦編輯我的解決方案時,將妥善解決更新,我看你想強調的所有單詞

這是代碼的Firefox如何凸顯的東西不改變文件:Finder.jsm - _highlight function。你將不得不復制這個文件,並將其用於整個文件,如果你需要幫助,請告訴我,我會做。

這裏是我的解決方案,突出單個單詞的所有匹配:https://stackoverflow.com/a/22206366/1828637

這裏的人,這是你將如何以突出整個文件,我沒有完成的片段,但是這是它的開始: Gist - HighlightTextInDocument

+0

我認爲迭代所有文本節點並對通過分割文本節點的.textContent生成的每個標記使用'gFindBar._highlightDoc(true,word)'會更容易。 – jervis

+0

我注意到現在這種方式無法工作,例如,如果我的列表中有'apple'這個詞(因此它被列入黑名單以突出顯示),像'a'這樣的詞會導致部分突出顯示單詞'apple' 。接下來的問題是,您必須對頁面上的單詞列表進行排序才能正確突出顯示它們,否則firefox將避免因重疊而突出顯示。 – jervis

+0

啊,這絕對是一個問題。問題在於'Ci.nsISelectionController.SELECTION_FIND',如果你把它改成'2',它就像普通的選擇一樣。找出你可以設置它在這裏看到的代碼[MXR - nsISelectionController的SourceCode](http://mxr.mozilla.org/mozilla-release/source/content/base/public/nsISelectionController.idl#30) – Noitidart

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)) 
+0

I現在用'gFindBar._highlightDoc(true,word)'做了。我使用的是Firefox 17,所以我不知道gFindBar是否是最先進的。 – jervis

1

@jervis,我不能對下@Noitidart碼您的評論評論因爲我還沒有50rep。所以我必須在這裏發帖。

回覆:

我與 'gFindBar._highlightDoc(真,字)' 現在做到了。我使用的是Firefox 17,所以我不知道gFindBar是否是最先進的。 - 真味40分鐘前

但我測試了他的代碼,並和它的作品。

請勿使用gFindBar。

將其複製並粘貼到您的便籤本中。

爲什麼使用gFindBar._highlightDoc(true, word)?我想要突出顯示文檔中的所有內容?你從哪裏得到_highlightDoc?我在@ Noitidart的代碼中看不到任何地方。

Regading上迭代夜評論所有單詞,並使用gFindBar._highlightDoc:

我與 'gFindBar._highlightDoc(真,字)' 現在做到了。我使用的是Firefox 17,所以我不知道gFindBar是否是最先進的。 - 真味39分鐘前

老兄爲什麼這樣做....我看到@Noitidart上張貼鏈接專題的每個字的解決方案:gBrowser.tabContainer.childNodes[0].linkedBrowser.finder.highlight(true, 'YOUR_WORD_HERE');,是非常容易的,一條線,沒有必要創建文本節點跨度或任何東西。您必須在每個要突出顯示的選項卡上運行此代碼。

+0

那麼,我有一個列表,列出黑名單,我不想強​​調。因此,使用查找器(我無法在DOM結構中找到並使用它給出了類型錯誤)僅僅是一種解決方法,因爲當'apple'被列入黑名單並且文檔內容中出現'a'這個詞時,'apple '部分突出顯示。我認爲,用於突出顯示的Firefox的內置函數與我的標記化操作不兼容。 – jervis

+0

哥們可以爲你做多少?做一些工作看看代碼,它可以迭代所有的範圍。因此,例如找到'a',然後遍歷返回的範圍,並且如果a被兩個非單詞字符包圍,則突出顯示它,否則不要。 – Blargh

2

好的。學習這些代碼。它搜索「is」的所有實例,並突出顯示它是否未包含單詞字符。把這個標籤放在你的便籤本中。你會看到像「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; 
    } 
+0

我不想發佈它,我想學習。也許我對特定的反饋感到不知所措,因爲前幾天我剛剛開始討論這個問題,而JS並不是我的領域。只有給定的解決方案的問題是,如果在查找欄中禁用了「全部突出顯示」,則突出顯示消失了,這對我來說沒問題,因爲我不想更改查找欄本身的行爲。 – jervis

+0

讓我們使用一些想法,我們可以找到一種方法使其與findbar高亮顯示所有內容並行工作,但如果您這樣做,那麼一定要更改插件的高亮顏色。 – Blargh

+0

夢幻般的解決方案。然而,我從MXR複製並粘貼這個,所以'createStateListener'和'_editor'的東西不能正常工作,實際上我不明白那個或nsISelectionController的東西。所以這段代碼肯定有改進的餘地。 – Noitidart

相關問題