Last active
August 29, 2015 13:57
-
-
Save yajd/9400823 to your computer and use it in GitHub Desktop.
HighlightOnSelection inital.rev1 work
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const {classes: Cc, interfaces: Ci, utils: Cu} = Components; | |
| const self = { | |
| id: 'HilteOnSelection', | |
| suffix: '@jetpack', | |
| path: 'chrome://hiliteonselection/content/', | |
| aData: 0, | |
| }; | |
| const myServices = {}; | |
| Cu.import('resource://gre/modules/Services.jsm'); | |
| Cu.import('resource://gre/modules/XPCOMUtils.jsm'); | |
| XPCOMUtils.defineLazyGetter(myServices, 'as', function(){ return Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService) }); | |
| var addedListeners = []; | |
| function console() { | |
| return Services.appShell.hiddenDOMWindow.console; | |
| } | |
| function selectionListener(win) { | |
| this.timeout = 0; | |
| this.win = 0; | |
| this._editors = []; | |
| this._stateListeners = []; | |
| this.notifySelectionChanged = function(doc, sel, reason) | |
| { | |
| if (reason == Ci.nsISelectionListener.SELECTALL_REASON) { | |
| return; | |
| } | |
| var postTimeout = function() { | |
| //console.log('notifySelectionChanged','doc=',doc,'sel=',sel,'reason=',reason); | |
| hiliteAllSel(this.win, sel.toString(), this._editors); | |
| this.timeout = 0; | |
| } | |
| if (this.timeout === 0) { | |
| this.win = doc.defaultView; | |
| console().log('set this.win',this.win,'doc.defaultView=',doc.defaultView); | |
| this.timeout = this.win.setTimeout(postTimeout.bind(this), 1000); | |
| } else { | |
| this.win.clearTimeout(this.timeout); | |
| this.win.setTimeout(postTimeout.bind(this), 1000); | |
| } | |
| } | |
| } | |
| /* | |
| var selectionListener = { | |
| timeout: 0, | |
| timeoutWin: 0, | |
| } | |
| */ | |
| /********************************************/ | |
| //hilite all stuff | |
| function hiliteAllSel(win, text, _editors) { | |
| //win should be top level window, will make it top if the top isnt passed | |
| //should be tab windows, so no chrome windows | |
| win = win.top; | |
| //clear any present highlighting | |
| /* | |
| var DOMWin = win.QueryInterface(Ci.nsIInterfaceRequestor) | |
| .getInterface(Ci.nsIWebNavigation) | |
| .QueryInterface(Ci.nsIDocShellTreeItem) | |
| .rootTreeItem | |
| .QueryInterface(Ci.nsIInterfaceRequestor) | |
| .getInterface(Ci.nsIDOMWindow); | |
| var tab = DOMWin.gBrowser._getTabForContentWindow(win); | |
| var findbar = tab._findBar; | |
| if (findbar) { | |
| findbar.toggleHighlight(false); | |
| } | |
| */ | |
| var doc = win.document; | |
| var ctrler = _getSelectionController(win); | |
| ////unighlight alll | |
| let sel = ctrler.getSelection(Ci.nsISelectionController.SELECTION_FIND); | |
| sel.removeAllRanges(); | |
| if (_editors) { | |
| for (let x = _editors.length - 1; x >= 0; --x) { | |
| if (_editors[x].document == doc) { | |
| sel = _editors[x].selectionController.getSelection(Ci.nsISelectionController.SELECTION_FIND); | |
| sel.removeAllRanges(); | |
| // We don't need to listen to this editor any more | |
| //this._unhookListenersAtIndex(x); | |
| } | |
| } | |
| } | |
| ///end unhilite all | |
| var searchRange = doc.createRange(); | |
| if (doc.body) { | |
| searchRange.selectNodeContents(doc.body); | |
| } else { | |
| searchRange.selectNodeContents(doc.documentElement); | |
| } | |
| let startPt = searchRange.cloneRange(); | |
| startPt.collapse(true); | |
| let endPt = searchRange.cloneRange(); | |
| endPt.collapse(false); | |
| let retRange = null; | |
| let finder = Cc["@mozilla.org/embedcomp/rangefind;1"].createInstance().QueryInterface(Ci.nsIFind); | |
| finder.caseSensitive = false; | |
| //var i = 0; | |
| while (retRange = finder.Find(text, 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); | |
| _highlightRange(retRange, ctrler, _editors); | |
| //break; | |
| startPt = retRange.cloneRange(); | |
| startPt.collapse(false); | |
| } | |
| } | |
| /*stuff jacked straight from Finder.jsm*/ | |
| function _getEditableNode(aNode) { | |
| while (aNode) { | |
| if (aNode instanceof Ci.nsIDOMNSEditableElement) | |
| return aNode.editor ? aNode : null; | |
| aNode = aNode.parentNode; | |
| } | |
| return null; | |
| } | |
| function _highlightRange(aRange, aController, _editors) { | |
| let node = aRange.startContainer; | |
| let controller = aController; | |
| let editableNode = _getEditableNode(node); | |
| if (editableNode) | |
| controller = editableNode.editor.selectionController; | |
| let findSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND); | |
| findSelection.addRange(aRange); | |
| //i dont understand stateListener stuff | |
| if (editableNode) { | |
| // Highlighting added, so cache this editor, and hook up listeners | |
| // to ensure we deal properly with edits within the highlighting | |
| let existingIndex = _editors.indexOf(editableNode.editor); | |
| existingIndex = -1; | |
| if (existingIndex == -1) { | |
| let x = _editors.length; | |
| _editors[x] = editableNode.editor; | |
| //_stateListeners[x] = _createStateListener(); | |
| //_editors[x].addEditActionListener(this); | |
| //_editors[x].addDocumentStateListener(_stateListeners[x]); | |
| } | |
| } | |
| } | |
| function _getSelectionController(aWindow) { | |
| // display: none iframes don't have a selection controller, see bug 493658 | |
| if (!aWindow.innerWidth || !aWindow.innerHeight) //im guessing this is a check for if its a frame | |
| 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; | |
| } | |
| function _createStateListener() { | |
| return { | |
| //findbar: this, | |
| QueryInterface: function(aIID) { | |
| /* | |
| if (aIID.equals(Ci.nsIDocumentStateListener) || | |
| aIID.equals(Ci.nsISupports)) | |
| return this; | |
| throw Components.results.NS_ERROR_NO_INTERFACE; | |
| */ | |
| }, | |
| NotifyDocumentWillBeDestroyed: function() { | |
| //this.findbar._onEditorDestruction(this); | |
| }, | |
| // Unimplemented | |
| notifyDocumentCreated: function() {}, | |
| notifyDocumentStateChanged: function(aDirty) {} | |
| }; | |
| } | |
| //http://mxr.mozilla.org/mozilla-release/source/toolkit/modules/Finder.jsm?raw=1 | |
| /********************************************/ | |
| function addSelectionListener(win) { | |
| //win is contentWindow | |
| win = win.top; | |
| var selectionObj = win.getSelection(); | |
| if (selectionObj) { | |
| var listenerForThisWin = new selectionListener; | |
| selectionObj.QueryInterface(Ci.nsISelectionPrivate).addSelectionListener(listenerForThisWin); | |
| addedListeners.push([win, listenerForThisWin]); | |
| } else { | |
| console().warn('did not add to this window as selectionObj is null', selectionObj); | |
| } | |
| } | |
| function removeSelectionListener(win) { | |
| //win is contentWindow and should be win.top | |
| win = win.top; | |
| var selectionObj = win.getSelection(); | |
| if (selectionObj) { | |
| selectionObj.QueryInterface(Ci.nsISelectionPrivate).removeSelectionListener(selectionListener); | |
| } else { | |
| console().warn('did not add to this window as selectionObj is null', selectionObj); | |
| } | |
| } | |
| function listenPageLoad(event) { | |
| var win = event.originalTarget.defaultView; | |
| if (win.frameElement) { | |
| return; | |
| } else { | |
| addSelectionListener(win); | |
| } | |
| } | |
| /*start - windowlistener*/ | |
| var windowListener = { | |
| //DO NOT EDIT HERE | |
| onOpenWindow: function (aXULWindow) { | |
| // Wait for the window to finish loading | |
| let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); | |
| aDOMWindow.addEventListener('load', function () { | |
| aDOMWindow.removeEventListener('load', arguments.callee, false); | |
| windowListener.loadIntoWindow(aDOMWindow, aXULWindow); | |
| }, false); | |
| }, | |
| onCloseWindow: function (aXULWindow) {}, | |
| onWindowTitleChange: function (aXULWindow, aNewTitle) {}, | |
| register: function () { | |
| // Load into any existing windows | |
| let XULWindows = Services.wm.getXULWindowEnumerator(null); | |
| while (XULWindows.hasMoreElements()) { | |
| let aXULWindow = XULWindows.getNext(); | |
| let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); | |
| windowListener.loadIntoWindow(aDOMWindow, aXULWindow); | |
| } | |
| // Listen to new windows | |
| Services.wm.addListener(windowListener); | |
| }, | |
| unregister: function () { | |
| // Unload from any existing windows | |
| let XULWindows = Services.wm.getXULWindowEnumerator(null); | |
| while (XULWindows.hasMoreElements()) { | |
| let aXULWindow = XULWindows.getNext(); | |
| let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); | |
| windowListener.unloadFromWindow(aDOMWindow, aXULWindow); | |
| } | |
| //Stop listening so future added windows dont get this attached | |
| [].forEach.call(addedListeners, function(listener) { | |
| //listener[0] == win | |
| //listener[1] == new selectionListener | |
| console().log('going through addedListeners, currently on win=',listener[0]); | |
| try { | |
| var selectionObj = listener[0].getSelection(); | |
| if (selectionObj) { | |
| selectionObj.QueryInterface(Ci.nsISelectionPrivate).removeSelectionListener(listener[1]); | |
| //unhilite any hilites that were there | |
| var ctrler = _getSelectionController(listener[0]); | |
| let sel = ctrler.getSelection(Ci.nsISelectionController.SELECTION_FIND); | |
| sel.removeAllRanges(); | |
| } else { | |
| console().warn('did not REMOVE from this window as selectionObj is null', selectionObj, 'here is the listener[1]',listener[1]); | |
| } | |
| } catch(ex) { | |
| console().warn('exception while removing selectionListener=',ex); | |
| } | |
| }); | |
| Services.wm.removeListener(windowListener); | |
| }, | |
| //END - DO NOT EDIT HERE | |
| loadIntoWindow: function (aDOMWindow, aXULWindow) { | |
| if (!aDOMWindow) { | |
| return; | |
| } | |
| if (aDOMWindow.gBrowser) { | |
| aDOMWindow.gBrowser.addEventListener('DOMContentLoaded', listenPageLoad, false); | |
| if (aDOMWindow.gBrowser.tabContainer) { | |
| //has tabContainer | |
| //start - go through all tabs in this window we just added to | |
| var tabs = aDOMWindow.gBrowser.tabContainer.childNodes; | |
| for (var i = 0; i < tabs.length; i++) { | |
| //Cu.reportError('DOING tab: ' + i); | |
| var tabBrowser = tabs[i].linkedBrowser; | |
| var win = tabBrowser.contentWindow; | |
| loadIntoContentWindowAndItsFrames(win); | |
| } | |
| //end - go through all tabs in this window we just added to | |
| } else { | |
| //does not have tabContainer | |
| var win = aDOMWindow.gBrowser.contentWindow; | |
| loadIntoContentWindowAndItsFrames(win); | |
| } | |
| } else { | |
| //window does not have gBrowser | |
| } | |
| }, | |
| unloadFromWindow: function (aDOMWindow, aXULWindow) { | |
| if (!aDOMWindow) { | |
| return; | |
| } | |
| if (aDOMWindow.gBrowser) { | |
| aDOMWindow.gBrowser.removeEventListener('DOMContentLoaded', listenPageLoad, false); | |
| return; //no longer doing the bottom as dealing with constuctor now | |
| if (aDOMWindow.gBrowser.tabContainer) { | |
| //has tabContainer | |
| //start - go through all tabs in this window we just added to | |
| var tabs = aDOMWindow.gBrowser.tabContainer.childNodes; | |
| for (var i = 0; i < tabs.length; i++) { | |
| //Cu.reportError('DOING tab: ' + i); | |
| var tabBrowser = tabs[i].linkedBrowser; | |
| var win = tabBrowser.contentWindow; | |
| unloadFromContentWindowAndItsFrames(win); | |
| } | |
| //end - go through all tabs in this window we just added to | |
| } else { | |
| //does not have tabContainer | |
| var win = aDOMWindow.gBrowser.contentWindow; | |
| unloadFromContentWindowAndItsFrames(win); | |
| } | |
| } else { | |
| //window does not have gBrowser | |
| } | |
| } | |
| }; | |
| /*end - windowlistener*/ | |
| function loadIntoContentWindowAndItsFrames(win) { | |
| if (win.frameElement) { return } | |
| addSelectionListener(win); | |
| } | |
| function unloadFromContentWindowAndItsFrames(win) { | |
| if (win.frameElement) { return } | |
| removeSelectionListener(win); | |
| } | |
| function startup(aData, aReason) { | |
| //self.aData = aData; | |
| windowListener.register(); | |
| } | |
| function shutdown(aData, aReason) { | |
| if (aReason == APP_SHUTDOWN) return; | |
| windowListener.unregister(); | |
| } | |
| function install() {} | |
| function uninstall() {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="utf-8"?> | |
| <!-- This Source Code Form is subject to the terms of the Mozilla Public | |
| - License, v. 2.0. If a copy of the MPL was not distributed with this | |
| - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> | |
| <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> | |
| <Description about="urn:mozilla:install-manifest"> | |
| <em:id>HiliteOnSelection@jetpack</em:id> | |
| <em:version>initial</em:version> | |
| <em:type>2</em:type> | |
| <em:bootstrap>true</em:bootstrap> | |
| <em:unpack>false</em:unpack> | |
| <!-- Firefox --> | |
| <em:targetApplication> | |
| <Description> | |
| <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> | |
| <em:minVersion>4.0</em:minVersion> | |
| <em:maxVersion>27.0.1</em:maxVersion> | |
| </Description> | |
| </em:targetApplication> | |
| <!-- Front End MetaData --> | |
| <em:name>HiliteOnSelection</em:name> | |
| <em:description>Whatever you select is highlighted throughout the document.</em:description> | |
| <em:creator>Noitidart</em:creator> | |
| <em:contributor>Woothemes for Icon</em:contributor> | |
| </Description> | |
| </RDF> |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Rev1 = initial.rev1
install.rdf
-updated name
bootstrap.js
-removed unhighlight dependency on findbar
Rev2 = initial.rev2
bootstrap.js
-got contstructor working (turned selectionListener to constructor)
-succesfully removing addd selectionListener's on shutdown
-clearning any existing hilites on shutdown
-ohhhh my gosh finally fixed why the win was undefined in hiliteAllSel, i had to use bind!!! my first time using bind!!!
-figured out _editors!!! and hooked up so it works!
-todo: i dont understand _editor listeners yet
-fixed bug as it was always hiliting "the"