# -*- Mode: HTML -*- # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is mozilla.org viewsource frontend. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 2003 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Blake Ross (Original Author) # Masayuki Nakano # Ben Basson # Jason Barnabe # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the LGPL or the GPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # #***** END LICENSE BLOCK ***** --> const FIND_NORMAL = 0; const FIND_TYPEAHEAD = 1; const FIND_LINKS = 2; const CHAR_CODE_SPACE = " ".charCodeAt(0); const CHAR_CODE_SLASH = "/".charCodeAt(0); const CHAR_CODE_APOSTROPHE = "'".charCodeAt(0); /* * WARNING: * Don't define global variables and functions in this file. Because this file * is included by some files. So, the global name space is not safety. * * But we need global functions for the Timer Event Handlers or for the Event * Listener Handlers. In this case, we MUST define global functions with * "findBar_" prefix. */ var gFindBar = { SELECTION_CONTROLLER: Components.interfaces.nsISelectionController, mFindEnabled: true, mFindMode: FIND_NORMAL, mFoundLink: null, mFoundEditable: null, mCurrentWindow: null, mTmpOutline: null, mTmpOutlineOffset: "0", mDrawOutline: false, mQuickFindTimeout: null, mQuickFindTimeoutLength: 0, mHighlightTimeout: null, mUseTypeAheadFind: false, mWrappedToTopStr: "", mWrappedToBottomStr: "", mNotFoundStr: "", mCaseSensitiveStr: "", mFlashFindBar: 0, mFlashFindBarCount: 6, mFlashFindBarTimeout: null, mLastHighlightString: "", mTypeAheadLinksOnly: false, mTypeAheadCaseSensitive: -1, mIsIMEComposing: false, mTextToSubURIService: null, // DOMRange used during highlighting mSearchRange: null, mStartPt: null, mEndPt: null, mTypeAheadFind: { useTAFPref: "accessibility.typeaheadfind", searchLinksPref: "accessibility.typeaheadfind.linksonly", caseSensePref: "accessibility.typeaheadfind.casesensitive", observe: function(aSubject, aTopic, aPrefName) { if (aTopic != "nsPref:changed" || (aPrefName != this.useTAFPref && aPrefName != this.searchLinksPref && aPrefName != this.caseSensePref)) return; var prefService = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); gFindBar.mUseTypeAheadFind = prefService.getBoolPref("accessibility.typeaheadfind"); gFindBar.mTypeAheadLinksOnly = prefService.getBoolPref("accessibility.typeaheadfind.linksonly"); gFindBar.mTypeAheadCaseSensitive = prefService.getIntPref("accessibility.typeaheadfind.casesensitive"); gFindBar.setCaseSensitivity(); } }, initFindBar: function () { getBrowser().addEventListener("keypress", findBar_OnBrowserKeyPress, false); getBrowser().addEventListener("mouseup", findBar_OnBrowserMouseUp, false); var prefService = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); var pbi = prefService.QueryInterface(Components.interfaces.nsIPrefBranch2); this.mQuickFindTimeoutLength = prefService.getIntPref("accessibility.typeaheadfind.timeout"); this.mFlashFindBar = prefService.getIntPref("accessibility.typeaheadfind.flashBar"); pbi.addObserver(this.mTypeAheadFind.useTAFPref, this.mTypeAheadFind, false); pbi.addObserver(this.mTypeAheadFind.searchLinksPref, this.mTypeAheadFind, false); pbi.addObserver(this.mTypeAheadFind.caseSensePref, this.mTypeAheadFind, false); this.mUseTypeAheadFind = prefService.getBoolPref("accessibility.typeaheadfind"); this.mTypeAheadLinksOnly = prefService.getBoolPref("accessibility.typeaheadfind.linksonly"); this.mTypeAheadCaseSensitive = prefService.getIntPref("accessibility.typeaheadfind.casesensitive"); var findField = document.getElementById("find-field"); findField.addEventListener("dragdrop", findBar_OnDrop, true); this.mTextToSubURIService = Components.classes["@mozilla.org/intl/texttosuburi;1"] .getService(Components.interfaces.nsITextToSubURI); }, mFindbarObserver: { onDrop: function (aEvent, aXferData, aDragSession) { var findField = document.getElementById("find-field"); findField.value = aXferData.data; gFindBar.find(aXferData.data); }, getSupportedFlavours: function () { var flavourSet = new FlavourSet(); flavourSet.appendFlavour("text/unicode"); return flavourSet; } }, uninitFindBar: function () { var prefService = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); var pbi = prefService.QueryInterface(Components.interfaces.nsIPrefBranch2); pbi.removeObserver(this.mTypeAheadFind.useTAFPref, this.mTypeAheadFind); pbi.removeObserver(this.mTypeAheadFind.searchLinksPref, this.mTypeAheadFind); pbi.removeObserver(this.mTypeAheadFind.caseSensePref, this.mTypeAheadFind); getBrowser().removeEventListener("keypress", findBar_OnBrowserKeyPress, false); getBrowser().removeEventListener("mouseup", findBar_OnBrowserMouseUp, false); }, /** * Turns highlighting on or off. * * @param aHighlight true to turn highlighting on */ toggleHighlight: function (aHighlight) { var word = document.getElementById("find-field").value; if (aHighlight) { // We have to update the status because we might still have the status // of another tab if (this.highlightDoc('yellow', 'black', word)) this.updateStatus(Components.interfaces.nsITypeAheadFind.FIND_FOUND, false); else this.updateStatus(Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND, false); } else { this.highlightDoc(null, null, null); this.mLastHighlightString = null; } }, /** * (Un)highlights each instance of the searched word in the passed window's content. * * @param highBackColor the background color for the highlight * @param highTextColor the text color for the highlight, or null to make it unhighlight * @param word the word to search for * @param win the window to search in. Passing undefined will search the current window. * @return true if the text was found */ highlightDoc: function (highBackColor, highTextColor, word, win) { if (!win) win = window.content; var textFound = false; for (var i = 0; win.frames && i < win.frames.length; i++) { if (this.highlightDoc(highBackColor, highTextColor, word, win.frames[i])) textFound = true; } var doc = win.document; if (!doc || !("body" in doc)) return textFound; var body = doc.body; var count = body.childNodes.length; this.mSearchRange = doc.createRange(); this.mStartPt = doc.createRange(); this.mEndPt = doc.createRange(); this.mSearchRange.setStart(body, 0); this.mSearchRange.setEnd(body, count); this.mStartPt.setStart(body, 0); this.mStartPt.setEnd(body, 0); this.mEndPt.setStart(body, count); this.mEndPt.setEnd(body, count); if (!highBackColor) { // Remove highlighting. We use the find API again rather than // searching for our span elements by id so that we gain access to the // anonymous content that nsIFind searches. if (!this.mLastHighlightString) return textFound; var retRange = null; var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"] .createInstance() .QueryInterface(Components.interfaces.nsIFind); while ((retRange = finder.Find(this.mLastHighlightString, this.mSearchRange, this.mStartPt, this.mEndPt))) { var startContainer = retRange.startContainer; var elem = null; try { elem = startContainer.parentNode; } catch (e) { } if (elem && elem.getAttribute("id") == "__firefox-findbar-search-id") { var child = null; var docfrag = doc.createDocumentFragment(); var next = elem.nextSibling; var parent = elem.parentNode; while ((child = elem.firstChild)) { docfrag.appendChild(child); } this.mStartPt = doc.createRange(); this.mStartPt.setStartAfter(elem); parent.removeChild(elem); parent.insertBefore(docfrag, next); parent.normalize(); } else { // Somehow we didn't highlight this instance; just skip it. this.mStartPt = doc.createRange(); this.mStartPt.setStart(retRange.endContainer, retRange.endOffset); } this.mStartPt.collapse(true); textFound = true; } return textFound; } var baseNode = doc.createElement("span"); baseNode.setAttribute("style", "background-color: " + highBackColor + "; " + "color: " + highTextColor + "; " + "display: inline; font-size: inherit;" + " padding: 0;"); baseNode.setAttribute("id", "__firefox-findbar-search-id"); return this.highlightText(word, baseNode) || textFound; }, /** * Highlights each instance of the searched word in the current range. * * @param word the word to search for * @param baseNode a node to use as a template for what will replace the * searched word * @return true if the text was found */ highlightText: function (word, baseNode) { var retRange = null; var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"] .createInstance() .QueryInterface(Components.interfaces.nsIFind); finder.caseSensitive = this.shouldBeCaseSensitive(word); var textFound = false; while((retRange = finder.Find(word, this.mSearchRange, this.mStartPt, this.mEndPt))) { // Highlight var nodeSurround = baseNode.cloneNode(true); var node = this.highlight(retRange, nodeSurround); this.mStartPt = node.ownerDocument.createRange(); this.mStartPt.setStart(node, node.childNodes.length); this.mStartPt.setEnd(node, node.childNodes.length); textFound = true; } this.mLastHighlightString = word; return textFound; }, /** * Highlights the word in the passed range. * * @param range the range that contains the word to highlight * @param node the node replace the searched word with * @return the node that replaced the searched word */ highlight: function (range, node) { var startContainer = range.startContainer; var startOffset = range.startOffset; var endOffset = range.endOffset; var docfrag = range.extractContents(); var before = startContainer.splitText(startOffset); var parent = before.parentNode; node.appendChild(docfrag); parent.insertBefore(node, before); return node; }, setCaseSensitivity: function (val) { var findToolbar = document.getElementById("FindToolbar"); if (findToolbar.hidden) return; if (!val) val = document.getElementById("find-field").value; var matchCaseCheckbox = document.getElementById("find-case-sensitive"); matchCaseCheckbox.checked = this.shouldBeCaseSensitive(val); var matchCaseText = document.getElementById("match-case-status"); matchCaseText.value = matchCaseCheckbox.checked ? this.mCaseSensitiveStr : ""; // Show the checkbox on the full Find bar in non-auto mode. Show the label // in all other cases. matchCaseCheckbox.hidden = this.mUsingMinimalUI || (this.mTypeAheadCaseSensitive != 0 && this.mTypeAheadCaseSensitive != 1); matchCaseText.hidden = !matchCaseCheckbox.hidden; var fastFind = getBrowser().fastFind; fastFind.caseSensitive = matchCaseCheckbox.checked; }, toggleCaseSensitiveCheckbox: function (aCaseSensitive) { var prefService = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); // Just set the pref; our observer will change the find bar behavior prefService.setIntPref("accessibility.typeaheadfind.casesensitive", aCaseSensitive ? 1 : 0); }, /** * Opens and displays the find bar. * * @param showMinimalUI * true if the find bar is to contain minimalist UI, false (or * undefined, as happens if no arguments are provided) if the find * bar is to display more generalized search UI * @returns bool * true if the find bar wasn't previously open, false otherwise */ openFindBar: function (showMinimalUI) { // Notify anyone else that might want to handle this event var findActivatedEvent = document.createEvent("Events"); findActivatedEvent.initEvent("find-activated", false, true); window.dispatchEvent(findActivatedEvent); if (!this.mFindEnabled) throw Components.results.NS_OK; if (!this.mNotFoundStr || !this.mWrappedToTopStr || !this.mWrappedToBottomStr || !this.mNormalFindStr || !this.mFastFindStr || !this.mCaseSensitiveStr) { var bundle = document.getElementById("bundle_findBar"); this.mNotFoundStr = bundle.getString("NotFound"); this.mWrappedToTopStr = bundle.getString("WrappedToTop"); this.mWrappedToBottomStr = bundle.getString("WrappedToBottom"); this.mNormalFindStr = bundle.getString("NormalFindLabel"); this.mFastFindStr = bundle.getString("FastFindLabel"); this.mCaseSensitiveStr = bundle.getString("CaseSensitive"); } this.updateFindUI(showMinimalUI); var findToolbar = document.getElementById("FindToolbar"); if (findToolbar.hidden) { findToolbar.hidden = false; var findField = document.getElementById("find-field"); this.setCaseSensitivity(findField.value); this.updateStatus(Components.interfaces.nsITypeAheadFind.FIND_FOUND, false); return true; } return false; }, focusFindBar: function () { var findField = document.getElementById("find-field"); findField.focus(); }, selectFindBar: function () { var findField = document.getElementById("find-field"); findField.select(); }, closeFindBar: function () { // ensure the dom is ready... setTimeout(findBar_DelayedCloseFindBar, 0); }, fireKeypressEvent: function (target, evt) { if (!target) return; var event = document.createEvent("KeyEvents"); event.initKeyEvent(evt.type, evt.canBubble, evt.cancelable, evt.view, evt.ctrlKey, evt.altKey, evt.shiftKey, evt.metaKey, evt.keyCode, evt.charCode); target.dispatchEvent(event); }, updateStatusBar: function () { var xulBrowserWindow = window.XULBrowserWindow; if (!xulBrowserWindow) return false; if (!this.mFoundLink || !this.mFoundLink.href || this.mFoundLink.href == "") { xulBrowserWindow.setOverLink(""); return true; } var docCharset = ""; var ownerDoc = this.mFoundLink.ownerDocument; if (ownerDoc) docCharset = ownerDoc.characterSet; var url = this.mTextToSubURIService.unEscapeURIForUI(docCharset, this.mFoundLink.href); xulBrowserWindow.setOverLink(url); return true; }, setFoundLink: function (foundLink) { if (this.mFoundLink == foundLink) return; if (this.mFoundLink && this.mDrawOutline) { // restore original outline this.mFoundLink.style.outline = this.mTmpOutline; this.mFoundLink.style.outlineOffset = this.mTmpOutlineOffset; } this.mDrawOutline = (foundLink && this.mFindMode != FIND_NORMAL); if (this.mDrawOutline) { // backup original outline this.mTmpOutline = foundLink.style.outline; this.mTmpOutlineOffset = foundLink.style.outlineOffset; // draw pseudo focus rect // XXX Should we change the following style for FAYT pseudo focus? // XXX Shouldn't we change default design if outline is visible already? foundLink.style.outline = "1px dotted invert"; foundLink.style.outlineOffset = "0"; } this.mFoundLink = foundLink; // We should update status bar. But we need delay. If the mouse cursor is // on the document, the status bar text is changed by mouse event that is // fired by scroll event. So, we need to change the status bar text after // mouse event. if (this.mFindMode != FIND_NORMAL) setTimeout(findBar_UpdateStatusBar, 0); }, finishFAYT: function (aKeypressEvent) { try { if (this.mFoundLink) this.mFoundLink.focus(); else if (this.mFoundEditable) { this.mFoundEditable.focus(); var fastFind = getBrowser().fastFind; fastFind.collapseSelection(); } else if (this.mCurrentWindow) this.mCurrentWindow.focus(); else return false; } catch(e) { return false; } if (aKeypressEvent) aKeypressEvent.preventDefault(); this.closeFindBar(); return true; }, delayedCloseFindBar: function () { var findField = document.getElementById("find-field"); var findToolbar = document.getElementById("FindToolbar"); var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] .getService(Components.interfaces.nsIWindowWatcher); if (window == ww.activeWindow) { var focusedElement = document.commandDispatcher.focusedElement; if (focusedElement && focusedElement.parentNode && (focusedElement.parentNode == findToolbar || focusedElement.parentNode.parentNode == findField)) { // block scrolling on focus since find already scrolls, further // scrolling is due to user action, so don't override this var suppressedScroll = document.commandDispatcher.suppressFocusScroll; document.commandDispatcher.suppressFocusScroll = true; // We MUST reset suppressFocusScroll. try { if (this.mFoundLink) this.mFoundLink.focus(); else if (this.mFoundEditable) this.mFoundEditable.focus(); else if (this.mCurrentWindow) this.mCurrentWindow.focus(); else window.content.focus(); } catch(e) { // Retry to set focus. try { window.content.focus(); } catch(e) { /* We lose focused element! */ } } document.commandDispatcher.suppressFocusScroll = suppressedScroll; } } findToolbar.hidden = true; var fastFind = getBrowser().fastFind; fastFind.setSelectionModeAndRepaint(this.SELECTION_CONTROLLER.SELECTION_ON); this.setFoundLink(null); this.mFoundEditable = null; this.mCurrentWindow = null; if (this.mQuickFindTimeout) { clearTimeout(this.mQuickFindTimeout); this.mQuickFindTimeout = null; } }, shouldFastFind: function (evt) { if (evt.ctrlKey || evt.altKey || evt.metaKey || evt.getPreventDefault()) return false; var elt = document.commandDispatcher.focusedElement; if (elt) { if (elt instanceof HTMLInputElement) { // block FAYT when an textfield element is focused var inputType = elt.type; switch (inputType) { case "text": case "password": case "file": return false; } } else if (elt instanceof HTMLTextAreaElement || elt instanceof HTMLSelectElement || elt instanceof HTMLIsIndexElement || elt instanceof HTMLObjectElement || elt instanceof HTMLEmbedElement) return false; } // disable FAYT in about:config and about:blank to prevent FAYT opening // unexpectedly - to fix bugs 264562, 267150, 269712 var url = getBrowser().currentURI.spec; if (url == "about:blank" || url == "about:config") return false; var win = document.commandDispatcher.focusedWindow; if (win && win.document.designMode == "on") return false; return true; }, shouldBeCaseSensitive: function (str) { if (this.mTypeAheadCaseSensitive == 0) return false; if (this.mTypeAheadCaseSensitive == 1) return true; return (str != str.toLowerCase()); }, onFindBarBlur: function () { var fastFind = getBrowser().fastFind; if (this.mFoundEditable) { fastFind.collapseSelection(); } else { fastFind.setSelectionModeAndRepaint(this.SELECTION_CONTROLLER.SELECTION_ON); } this.setFoundLink(null); this.mFoundEditable = null; this.mCurrentWindow = null; }, onBrowserMouseUp: function (evt) { var findToolbar = document.getElementById("FindToolbar"); if (!findToolbar.hidden && this.mFindMode != FIND_NORMAL) this.closeFindBar(); }, onBrowserKeyPress: function (evt) { // Check focused elt if (!this.shouldFastFind(evt)) return; var findField = document.getElementById("find-field"); if (this.mFindMode != FIND_NORMAL && this.mQuickFindTimeout) { if (!evt.charCode) return; this.selectFindBar(); this.focusFindBar(); this.fireKeypressEvent(findField.inputField, evt); evt.preventDefault(); return; } if (evt.charCode == CHAR_CODE_APOSTROPHE || evt.charCode == CHAR_CODE_SLASH || (this.mUseTypeAheadFind && evt.charCode && evt.charCode != CHAR_CODE_SPACE)) { var findMode = (evt.charCode == CHAR_CODE_APOSTROPHE || (this.mTypeAheadLinksOnly && evt.charCode != CHAR_CODE_SLASH)) ? FIND_LINKS : FIND_TYPEAHEAD; this.setFindMode(findMode); // Clear bar first, so that when openFindBar() calls setCaseSensitivity() // it doesn't get confused by a lingering value findField.value = ""; try { var opened = this.openFindBar(true); } catch (e) { return; } if (opened) { this.setFindCloseTimeout(); this.selectFindBar(); this.focusFindBar(); if (this.mUseTypeAheadFind && evt.charCode != CHAR_CODE_APOSTROPHE && evt.charCode != CHAR_CODE_SLASH) this.fireKeypressEvent(findField.inputField, evt); else this.updateStatus(Components.interfaces.nsITypeAheadFind.FIND_FOUND, false); evt.preventDefault(); } else { this.selectFindBar(); this.focusFindBar(); if (this.mFindMode != FIND_NORMAL) { if (evt.charCode != CHAR_CODE_APOSTROPHE && evt.charCode != CHAR_CODE_SLASH) this.fireKeypressEvent(findField.inputField, evt); else this.updateStatus(Components.interfaces.nsITypeAheadFind.FIND_FOUND, false); evt.preventDefault(); } } } }, onFindBarKeyPress: function (evt) { if (evt.keyCode == KeyEvent.DOM_VK_RETURN) { if (this.mFindMode == FIND_NORMAL) { var findString = document.getElementById("find-field"); if (!findString.value) return; #ifdef XP_MACOSX if (evt.metaKey) { #else if (evt.ctrlKey) { #endif document.getElementById("highlight").click(); return; } if (evt.shiftKey) this.findPrevious(); else this.findNext(); } else { if (this.mFoundLink) { var tmpLink = this.mFoundLink; if (this.finishFAYT(evt)) this.fireKeypressEvent(tmpLink, evt); } } } else if (evt.keyCode == KeyEvent.DOM_VK_TAB) { var shouldHandle = !evt.altKey && !evt.ctrlKey && !evt.metaKey; if (shouldHandle && this.mFindMode != FIND_NORMAL && this.finishFAYT(evt)) { if (evt.shiftKey) document.commandDispatcher.rewindFocus(); else document.commandDispatcher.advanceFocus(); } } else if (evt.keyCode == KeyEvent.DOM_VK_ESCAPE) { this.closeFindBar(); evt.preventDefault(); } else if (evt.keyCode == KeyEvent.DOM_VK_PAGE_UP) { window.top._content.scrollByPages(-1); evt.preventDefault(); } else if (evt.keyCode == KeyEvent.DOM_VK_PAGE_DOWN) { window.top._content.scrollByPages(1); evt.preventDefault(); } else if (evt.keyCode == KeyEvent.DOM_VK_UP) { window.top._content.scrollByLines(-1); evt.preventDefault(); } else if (evt.keyCode == KeyEvent.DOM_VK_DOWN) { window.top._content.scrollByLines(1); evt.preventDefault(); } }, enableFindButtons: function (aEnable) { var findNext = document.getElementById("find-next"); var findPrev = document.getElementById("find-previous"); var highlight = document.getElementById("highlight"); findNext.disabled = findPrev.disabled = highlight.disabled = !aEnable; }, /** * Determines whether minimalist or general-purpose search UI is to be * displayed when the find bar is activated. * * @param showMinimalUI * true if minimalist UI should be used, false if general-purpose UI * should be used */ updateFindUI: function (showMinimalUI) { this.mUsingMinimalUI = showMinimalUI; var findBar = document.getElementById("FindToolbar"); for (var i = 0; i < findBar.childNodes.length; i++) { var node = findBar.childNodes[i]; if (node.className == "find-fast") continue; node.hidden = showMinimalUI; } var findLabel = document.getElementById("find-label"); if (showMinimalUI) findLabel.value = this.mFastFindStr; else findLabel.value = this.mNormalFindStr; }, updateFoundLink: function (res) { var val = document.getElementById("find-field").value; if (res == Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND || !val) { this.setFoundLink(null); this.mFoundEditable = null; this.mCurrentWindow = null; } else { this.setFoundLink(getBrowser().fastFind.foundLink); this.mFoundEditable = getBrowser().fastFind.foundEditable; this.mCurrentWindow = getBrowser().fastFind.currentWindow; } }, find: function (val) { if (!val) val = document.getElementById("find-field").value; this.enableFindButtons(val); var highlightBtn = document.getElementById("highlight"); if (highlightBtn.checked) this.setHighlightTimeout(); this.setCaseSensitivity(val); var fastFind = getBrowser().fastFind; var res = fastFind.find(val, this.mFindMode == FIND_LINKS); this.updateFoundLink(res); this.updateStatus(res, true); if (this.mFindMode != FIND_NORMAL) this.setFindCloseTimeout(); }, flashFindBar: function () { var findToolbar = document.getElementById("FindToolbar"); if (this.mFlashFindBarCount-- == 0) { clearInterval(this.mFlashFindBarTimeout); findToolbar.removeAttribute("flash"); this.mFlashFindBarCount = 6; return; } findToolbar.setAttribute("flash", (this.mFlashFindBarCount % 2 == 0) ? "false" : "true"); }, onFindCmd: function () { try { this.openFindBar(); } catch (e) { } this.setFindMode(FIND_NORMAL); if (this.mFlashFindBar) { this.mFlashFindBarTimeout = setInterval(findBar_FlashFindBar, 500); var prefService = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); prefService.setIntPref("accessibility.typeaheadfind.flashBar", --this.mFlashFindBar); } this.selectFindBar(); this.focusFindBar(); }, onFindAgainCmd: function () { var findString = getBrowser().findString; if (!findString) { this.onFindCmd(); return; } var res = this.findNext(); if (res == Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND) { try { var opened = this.openFindBar(this.mUsingMinimalUI); } catch(e) { } if (opened) { this.focusFindBar(); this.selectFindBar(); if (this.mFindMode != FIND_NORMAL) this.setFindCloseTimeout(); this.updateStatus(res, true); } } }, onFindPreviousCmd: function () { var findString = getBrowser().findString; if (!findString) { this.onFindCmd(); return; } var res = this.findPrevious(); if (res == Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND) { try { var opened = this.openFindBar(this.mUsingMinimalUI); } catch (e) { } if (opened) { this.focusFindBar(); this.selectFindBar(); if (this.mFindMode != FIND_NORMAL) this.setFindCloseTimeout(); this.updateStatus(res, false); } } }, setHighlightTimeout: function () { if (this.mHighlightTimeout) clearTimeout(this.mHighlightTimeout); this.mHighlightTimeout = setTimeout(function() { gFindBar.toggleHighlight(false); gFindBar.toggleHighlight(true); }, 500); }, isFindBarVisible: function () { var findBar = document.getElementById("FindToolbar"); return !findBar.hidden; }, findNext: function () { var fastFind = getBrowser().fastFind; var res = fastFind.findNext(); this.updateFoundLink(res); this.updateStatus(res, true); if (this.mFindMode != FIND_NORMAL && this.isFindBarVisible()) this.setFindCloseTimeout(); return res; }, findPrevious: function () { var fastFind = getBrowser().fastFind; var res = fastFind.findPrevious(); this.updateFoundLink(res); this.updateStatus(res, false); if (this.mFindMode != FIND_NORMAL && this.isFindBarVisible()) this.setFindCloseTimeout(); return res; }, updateStatus: function (res, findNext) { var findBar = document.getElementById("FindToolbar"); var field = document.getElementById("find-field"); var statusIcon = document.getElementById("find-status-icon"); var statusText = document.getElementById("find-status"); switch(res) { case Components.interfaces.nsITypeAheadFind.FIND_WRAPPED: statusIcon.setAttribute("status", "wrapped"); statusText.value = findNext ? this.mWrappedToTopStr : this.mWrappedToBottomStr; break; case Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND: statusIcon.setAttribute("status", "notfound"); statusText.value = this.mNotFoundStr; field.setAttribute("status", "notfound"); break; case Components.interfaces.nsITypeAheadFind.FIND_FOUND: default: statusIcon.removeAttribute("status"); statusText.value = ""; field.removeAttribute("status"); break; } }, setFindCloseTimeout: function () { if (this.mQuickFindTimeout) clearTimeout(this.mQuickFindTimeout); // Don't close the find toolbar while IME is composing. if (this.mIsIMEComposing) { this.mQuickFindTimeout = null; return; } this.mQuickFindTimeout = setTimeout(function() { if (gFindBar.mFindMode != FIND_NORMAL) gFindBar.closeFindBar(); }, this.mQuickFindTimeoutLength); }, findBarOnDrop: function (evt) { nsDragAndDrop.drop(evt, this.mFindbarObserver); }, onFindBarCompositionStart: function (evt) { this.mIsIMEComposing = true; // Don't close the find toolbar while IME is composing. if (this.mQuickFindTimeout) { clearTimeout(this.mQuickFindTimeout); this.mQuickFindTimeout = null; } }, onFindBarCompositionEnd: function (evt) { this.mIsIMEComposing = false; if (this.mFindMode != FIND_NORMAL && this.isFindBarVisible()) this.setFindCloseTimeout(); }, setFindMode: function (mode) { this.mFindMode = mode; } }; // ================ // Event Handlers // ================ function findBar_OnDrop(aEvt) { gFindBar.findBarOnDrop(aEvt); } function findBar_OnBrowserKeyPress(aEvt) { gFindBar.onBrowserKeyPress(aEvt); } function findBar_OnBrowserMouseUp(aEvt) { gFindBar.onBrowserMouseUp(aEvt); } // ====================== // Timer Event Handlers // ====================== function findBar_DelayedCloseFindBar() { gFindBar.delayedCloseFindBar(); } function findBar_UpdateStatusBar() { gFindBar.updateStatusBar(); } function findBar_FlashFindBar() { gFindBar.flashFindBar(); }