| Index: chrome/content/ui/filters-search.js |
| =================================================================== |
| --- a/chrome/content/ui/filters-search.js |
| +++ b/chrome/content/ui/filters-search.js |
| @@ -16,60 +16,95 @@ |
| */ |
| /** |
| * Implementation of the filter search functionality. |
| * @class |
| */ |
| var FilterSearch = |
| { |
| + lastSearchString: null, |
| + |
| /** |
| - * Initializes findbar widget. |
| + * Handles keypress events on the findbar widget. |
| */ |
| - init: function() |
| + keyPress: function(/**Event*/ event) |
| { |
| - let filters = E("filtersTree"); |
| - for (let prop in FilterSearch.fakeBrowser) |
| - filters[prop] = FilterSearch.fakeBrowser[prop]; |
| - Object.defineProperty(filters, "_lastSearchString", { |
| - get: function() |
| - { |
| - return this.finder.searchString; |
| - }, |
| - enumerable: true, |
| - configurable: true |
| - }); |
| - |
| - let findbar = E("findbar"); |
| - findbar.browser = filters; |
| - |
| - findbar.addEventListener("keypress", function(event) |
| + if (event.keyCode == KeyEvent.DOM_VK_RETURN) |
| + event.preventDefault(); |
| + else if (event.keyCode == KeyEvent.DOM_VK_ESCAPE) |
| { |
| - // Work-around for bug 490047 |
| - if (event.keyCode == KeyEvent.DOM_VK_RETURN) |
| - event.preventDefault(); |
| - }, false); |
| - |
| - // Hack to prevent "highlight all" from getting enabled |
| - findbar.toggleHighlight = function() {}; |
| + event.preventDefault(); |
| + this.close(); |
| + } |
| + else if (event.keyCode == KeyEvent.DOM_VK_UP) |
| + { |
| + event.preventDefault(); |
| + this.search(-1); |
| + } |
| + else if (event.keyCode == KeyEvent.DOM_VK_DOWN) |
| + { |
| + event.preventDefault(); |
| + this.search(1); |
| + } |
| + else if (event.keyCode == KeyEvent.DOM_VK_PAGE_UP) |
| + { |
| + event.preventDefault(); |
| + E("filtersTree").treeBoxObject.scrollByPages(-1); |
| + } |
| + else if (event.keyCode == KeyEvent.DOM_VK_PAGE_DOWN) |
| + { |
| + event.preventDefault(); |
| + E("filtersTree").treeBoxObject.scrollByPages(1); |
| + } |
| }, |
| /** |
| - * Performs a text search. |
| - * @param {String} text text to be searched |
| - * @param {Integer} direction search direction: -1 (backwards), 0 (forwards |
| - * starting with current), 1 (forwards starting with next) |
| - * @param {Boolean} caseSensitive if true, a case-sensitive search is performed |
| - * @result {Integer} one of the nsITypeAheadFind constants |
| + * Makes the find bar visible and focuses it. |
| */ |
| - search: function(text, direction, caseSensitive) |
| + open: function() |
| { |
| - function normalizeString(string) caseSensitive ? string : string.toLowerCase(); |
| + E("findbar").hidden = false; |
| + E("findbar-textbox").focus(); |
| + }, |
| - function findText(text, direction, startIndex) |
| + /** |
| + * Closes the find bar. |
| + */ |
| + close: function() |
| + { |
| + E("findbar").hidden = true; |
| + }, |
| + |
| + /** |
| + * Performs a filter search. |
| + * @param {Integer} [direction] |
| + * See @link{FilterSearch#search} |
| + * @return {String} |
| + * result status, one of "" (success), "notFound", "wrappedEnd", |
| + * "wrappedStart" |
| + */ |
| + _search: function(direction) |
| + { |
| + let text = E("findbar-textbox").value.trim(); |
| + if (!text) |
| + return ""; |
| + |
| + let caseSensitive = E("findbar-case-sensitive").checked; |
| + |
| + if (typeof direction == "undefined") |
| + direction = (text == this.lastSearchString ? 1 : 0); |
| + this.lastSearchString = text; |
| + |
| + function normalizeString(string) |
| + { |
| + return caseSensitive ? string : string.toLowerCase(); |
| + } |
| + |
| + function findText(startIndex) |
| { |
| let list = E("filtersTree"); |
| let col = list.columns.getNamedColumn("col-filter"); |
| let count = list.view.rowCount; |
| for (let i = startIndex + direction; i >= 0 && i < count; i += (direction || 1)) |
| { |
| let filter = normalizeString(list.view.getCellText(i, col)); |
| if (filter.indexOf(text) >= 0) |
| @@ -79,36 +114,36 @@ var FilterSearch = |
| } |
| } |
| return false; |
| } |
| text = normalizeString(text); |
| // First try to find the entry in the current list |
| - if (findText(text, direction, E("filtersTree").currentIndex)) |
| - return Ci.nsITypeAheadFind.FIND_FOUND; |
| + if (findText(E("filtersTree").currentIndex)) |
| + return ""; |
| // Now go through the other subscriptions |
| - let result = Ci.nsITypeAheadFind.FIND_FOUND; |
| + let result = ""; |
| let subscriptions = FilterStorage.subscriptions.slice(); |
| subscriptions.sort((s1, s2) => (s1 instanceof SpecialSubscription) - (s2 instanceof SpecialSubscription)); |
| let current = subscriptions.indexOf(FilterView.subscription); |
| direction = direction || 1; |
| for (let i = current + direction; ; i+= direction) |
| { |
| if (i < 0) |
| { |
| i = subscriptions.length - 1; |
| - result = Ci.nsITypeAheadFind.FIND_WRAPPED; |
| + result = "wrappedStart"; |
| } |
| else if (i >= subscriptions.length) |
| { |
| i = 0; |
| - result = Ci.nsITypeAheadFind.FIND_WRAPPED; |
| + result = "wrappedEnd"; |
| } |
| if (i == current) |
| break; |
| let subscription = subscriptions[i]; |
| for (let j = 0; j < subscription.filters.length; j++) |
| { |
| let filter = normalizeString(subscription.filters[j].text); |
| @@ -125,156 +160,33 @@ var FilterSearch = |
| list.ensureElementIsVisible(node); |
| list.selectItem(node); |
| if (oldFocus) |
| { |
| oldFocus.focus(); |
| Utils.runAsync(() => oldFocus.focus()); |
| } |
| - Utils.runAsync(() => findText(text, direction, direction == 1 ? -1 : subscription.filters.length)); |
| + Utils.runAsync(() => findText(direction == 1 ? -1 : subscription.filters.length)); |
| return result; |
| } |
| } |
| } |
| - return Ci.nsITypeAheadFind.FIND_NOTFOUND; |
| + return "notFound"; |
| + }, |
| + |
| + /** |
| + * Performs a filter search and displays the resulting search status. |
| + * @param {Integer} [direction] |
| + * search direction: -1 (backwards), 0 (forwards starting with current), |
| + * 1 (forwards starting with next) |
| + */ |
| + search: function(direction) |
| + { |
| + E("findbar").setAttribute("data-status", this._search(direction)); |
| } |
| }; |
| -/** |
| - * Fake browser implementation to make findbar widget happy - searches in |
| - * the filter list. |
| - */ |
| -FilterSearch.fakeBrowser = |
| +window.addEventListener("load", event => |
| { |
| - finder: |
| - { |
| - _resultListeners: [], |
| - searchString: null, |
| - caseSensitive: false, |
| - lastResult: null, |
| - |
| - _notifyResultListeners: function(result, findBackwards) |
| - { |
| - this.lastResult = result; |
| - for (let listener of this._resultListeners) |
| - { |
| - // See https://bugzilla.mozilla.org/show_bug.cgi?id=958101, starting |
| - // with Gecko 29 only one parameter is expected. |
| - try |
| - { |
| - if (listener.onFindResult.length == 1) |
| - { |
| - listener.onFindResult({searchString: this.searchString, |
| - result: result, findBackwards: findBackwards}); |
| - } |
| - else |
| - listener.onFindResult(result, findBackwards); |
| - } |
| - catch (e) |
| - { |
| - Cu.reportError(e); |
| - } |
| - } |
| - }, |
| - |
| - fastFind: function(searchString, linksOnly, drawOutline) |
| - { |
| - this.searchString = searchString; |
| - let result = FilterSearch.search(this.searchString, 0, |
| - this.caseSensitive); |
| - this._notifyResultListeners(result, false); |
| - }, |
| - |
| - findAgain: function(findBackwards, linksOnly, drawOutline) |
| - { |
| - let result = FilterSearch.search(this.searchString, |
| - findBackwards ? -1 : 1, |
| - this.caseSensitive); |
| - this._notifyResultListeners(result, findBackwards); |
| - }, |
| - |
| - addResultListener: function(listener) |
| - { |
| - if (this._resultListeners.indexOf(listener) === -1) |
| - this._resultListeners.push(listener); |
| - }, |
| - |
| - removeResultListener: function(listener) |
| - { |
| - let index = this._resultListeners.indexOf(listener); |
| - if (index !== -1) |
| - this._resultListeners.splice(index, 1); |
| - }, |
| - |
| - getInitialSelection: function() |
| - { |
| - for (let listener of this._resultListeners) |
| - listener.onCurrentSelection(null, true); |
| - }, |
| - |
| - // Irrelevant for us |
| - requestMatchesCount: function(searchString, matchLimit, linksOnly) {}, |
| - highlight: function(highlight, word) {}, |
| - enableSelection: function() {}, |
| - removeSelection: function() {}, |
| - focusContent: function() {}, |
| - keyPress: function() {} |
| - }, |
| - |
| - currentURI: Utils.makeURI("http://example.com/"), |
| - contentWindow: |
| - { |
| - focus: function() |
| - { |
| - E("filtersTree").focus(); |
| - }, |
| - scrollByLines: function(num) |
| - { |
| - E("filtersTree").boxObject.scrollByLines(num); |
| - }, |
| - scrollByPages: function(num) |
| - { |
| - E("filtersTree").boxObject.scrollByPages(num); |
| - }, |
| - }, |
| - |
| - messageManager: |
| - { |
| - _messageMap: { |
| - "Findbar:Mouseup": "mouseup", |
| - "Findbar:Keypress": "keypress" |
| - }, |
| - |
| - _messageFromEvent: function(event) |
| - { |
| - for (let message in this._messageMap) |
| - if (this._messageMap[message] == event.type) |
| - return {target: event.currentTarget, name: message, data: event}; |
| - return null; |
| - }, |
| - |
| - addMessageListener: function(message, listener) |
| - { |
| - if (!this._messageMap.hasOwnProperty(message)) |
| - return; |
| - |
| - if (!("_ABPHandler" in listener)) |
| - listener._ABPHandler = (event) => listener.receiveMessage(this._messageFromEvent(event)); |
| - |
| - E("filtersTree").addEventListener(this._messageMap[message], listener._ABPHandler, false); |
| - }, |
| - |
| - removeMessageListener: function(message, listener) |
| - { |
| - if (this._messageMap.hasOwnProperty(message) && listener._ABPHandler) |
| - E("filtersTree").removeEventListener(this._messageMap[message], listener._ABPHandler, false); |
| - }, |
| - |
| - sendAsyncMessage: function() {} |
| - } |
| -}; |
| - |
| -window.addEventListener("load", function() |
| -{ |
| - FilterSearch.init(); |
| -}, false); |
| + E("findbar").setAttribute("data-os", Services.appinfo.OS.toLowerCase()); |
| +}); |