diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/suite/mailnews/content/searchBar.js | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/suite/mailnews/content/searchBar.js')
-rw-r--r-- | comm/suite/mailnews/content/searchBar.js | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/comm/suite/mailnews/content/searchBar.js b/comm/suite/mailnews/content/searchBar.js new file mode 100644 index 0000000000..2c23b395a3 --- /dev/null +++ b/comm/suite/mailnews/content/searchBar.js @@ -0,0 +1,432 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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/. */ + +const {PluralForm} = ChromeUtils.import("resource://gre/modules/PluralForm.jsm"); + +var gSearchSession = null; +var gPreQuickSearchView = null; +var gSearchTimer = null; +var gViewSearchListener; +var gSearchBundle; +var gProgressMeter = null; +var gSearchInProgress = false; +var gClearButton = null; +var gDefaultSearchViewTerms = null; +var gQSViewIsDirty = false; +var gNumTotalMessages; +var gNumUnreadMessages; + +function SetQSStatusText(aNumHits) +{ + var statusMsg; + // if there are no hits, it means no matches were found in the search. + if (aNumHits == 0) + { + statusMsg = gSearchBundle.getString("noMatchesFound"); + } + else + { + statusMsg = PluralForm.get(aNumHits, + gSearchBundle.getString("matchesFound")); + statusMsg = statusMsg.replace("#1", aNumHits); + } + statusFeedback.showStatusString(statusMsg); +} + +// nsIMsgSearchNotify object +var gSearchNotificationListener = +{ + onSearchHit: function(header, folder) + { + gNumTotalMessages++; + if (!header.isRead) + gNumUnreadMessages++; + // XXX todo + // update status text? + }, + + onSearchDone: function(status) + { + SetQSStatusText(gDBView.QueryInterface(Ci.nsITreeView).rowCount) + statusFeedback.showProgress(0); + gProgressMeter.setAttribute("mode", "normal"); + gSearchInProgress = false; + + // ### TODO need to find out if there's quick search within a virtual folder. + if (gCurrentVirtualFolderUri && + (!gSearchInput || gSearchInput.value == "")) + { + var vFolder = MailUtils.getFolderForURI(gCurrentVirtualFolderUri, false); + var dbFolderInfo = vFolder.msgDatabase.dBFolderInfo; + dbFolderInfo.numUnreadMessages = gNumUnreadMessages; + dbFolderInfo.numMessages = gNumTotalMessages; + vFolder.updateSummaryTotals(true); // force update from db. + var msgdb = vFolder.msgDatabase; + msgdb.Commit(Ci.nsMsgDBCommitType.kLargeCommit); + // now that we have finished loading a virtual folder, + // scroll to the correct message if there is at least one. + if (vFolder.getTotalMessages(false) > 0) + ScrollToMessageAfterFolderLoad(vFolder); + } + }, + + onNewSearch: function() + { + statusFeedback.showProgress(0); + statusFeedback.showStatusString(gSearchBundle.getString("searchingMessage")); + gProgressMeter.setAttribute("mode", "undetermined"); + gSearchInProgress = true; + gNumTotalMessages = 0; + gNumUnreadMessages = 0; + } +} + +function getDocumentElements() +{ + gSearchBundle = document.getElementById("bundle_search"); + gProgressMeter = document.getElementById('statusbar-icon'); + gClearButton = document.getElementById('clearButton'); + GetSearchInput(); +} + +function addListeners() +{ + gViewSearchListener = gDBView.QueryInterface(Ci.nsIMsgSearchNotify); + gSearchSession.registerListener(gViewSearchListener); +} + +function removeListeners() +{ + gSearchSession.unregisterListener(gViewSearchListener); +} + +function removeGlobalListeners() +{ + removeListeners(); + gSearchSession.unregisterListener(gSearchNotificationListener); +} + +function initializeGlobalListeners() +{ + // Setup the javascript object as a listener on the search results + gSearchSession.registerListener(gSearchNotificationListener); +} + +function createQuickSearchView() +{ + //if not already in quick search view + if (gDBView.viewType != nsMsgViewType.eShowQuickSearchResults) + { + var treeView = gDBView.QueryInterface(Ci.nsITreeView); //clear selection + if (treeView && treeView.selection) + treeView.selection.clearSelection(); + gPreQuickSearchView = gDBView; + if (gDBView.viewType == nsMsgViewType.eShowVirtualFolderResults) + { + // remove the view as a listener on the search results + var saveViewSearchListener = gDBView.QueryInterface(Ci.nsIMsgSearchNotify); + gSearchSession.unregisterListener(saveViewSearchListener); + } + CreateDBView(gDBView.msgFolder, (gXFVirtualFolderTerms) ? nsMsgViewType.eShowVirtualFolderResults : nsMsgViewType.eShowQuickSearchResults, gDBView.viewFlags, gDBView.sortType, gDBView.sortOrder); + } +} + +function initializeSearchBar() +{ + createQuickSearchView(); + if (!gSearchSession) + { + var searchSessionContractID = "@mozilla.org/messenger/searchSession;1"; + gSearchSession = Cc[searchSessionContractID].createInstance(Ci.nsIMsgSearchSession); + initializeGlobalListeners(); + } + else + { + if (gSearchInProgress) + { + onSearchStop(); + gSearchInProgress = false; + } + removeListeners(); + } + addListeners(); +} + +function onEnterInSearchBar() +{ + if (!gSearchBundle) + getDocumentElements(); + if (gSearchInput.value == "") + { + let viewType = gDBView && gDBView.viewType; + if (viewType == nsMsgViewType.eShowQuickSearchResults || + viewType == nsMsgViewType.eShowVirtualFolderResults) + { + statusFeedback.showStatusString(""); + disableQuickSearchClearButton(); + + viewDebug ("onEnterInSearchBar gDefaultSearchViewTerms = " + gDefaultSearchViewTerms + "gVirtualFolderTerms = " + + gVirtualFolderTerms + "gXFVirtualFolderTerms = " + gXFVirtualFolderTerms + "\n"); + var addTerms = gDefaultSearchViewTerms || gVirtualFolderTerms || gXFVirtualFolderTerms; + if (addTerms) + { + viewDebug ("addTerms = " + addTerms + " count = " + addTerms.length + "\n"); + initializeSearchBar(); + onSearch(addTerms); + } + else + restorePreSearchView(); + } + else if (gPreQuickSearchView && !gDefaultSearchViewTerms)// may be a quick search from a cross-folder virtual folder + restorePreSearchView(); + + gQSViewIsDirty = false; + return; + } + + initializeSearchBar(); + + if (gClearButton) + gClearButton.setAttribute("disabled", false); //coming into search enable clear button + + ClearThreadPaneSelection(); + ClearMessagePane(); + + onSearch(null); + gQSViewIsDirty = false; +} + +function restorePreSearchView() +{ + var selectedHdr = null; + //save selection + try + { + selectedHdr = gDBView.hdrForFirstSelectedMessage; + } + catch (ex) + {} + + //we might have to sort the view coming out of quick search + var sortType = gDBView.sortType; + var sortOrder = gDBView.sortOrder; + var viewFlags = gDBView.viewFlags; + var folder = gDBView.msgFolder; + + gDBView.close(); + gDBView = null; + + if (gPreQuickSearchView) + { + gDBView = gPreQuickSearchView; + if (gDBView.viewType == nsMsgViewType.eShowVirtualFolderResults) + { + // readd the view as a listener on the search results + var saveViewSearchListener = gDBView.QueryInterface(Ci.nsIMsgSearchNotify); + if (gSearchSession) + gSearchSession.registerListener(saveViewSearchListener); + } +// dump ("view type = " + gDBView.viewType + "\n"); + + if (sortType != gDBView.sortType || sortOrder != gDBView.sortOrder) + { + gDBView.sort(sortType, sortOrder); + } + UpdateSortIndicators(sortType, sortOrder); + + gPreQuickSearchView = null; + } + else //create default view type + CreateDBView(folder, nsMsgViewType.eShowAllThreads, viewFlags, sortType, sortOrder); + + RerootThreadPane(); + + var scrolled = false; + + // now restore selection + if (selectedHdr) + { + gDBView.selectMsgByKey(selectedHdr.messageKey); + var treeView = gDBView.QueryInterface(Ci.nsITreeView); + var selectedIndex = treeView.selection.currentIndex; + if (selectedIndex >= 0) + { + // scroll + EnsureRowInThreadTreeIsVisible(selectedIndex); + scrolled = true; + } + else + ClearMessagePane(); + } + if (!scrolled) + ScrollToMessageAfterFolderLoad(null); +} + +function onSearch(aSearchTerms) +{ + viewDebug("in OnSearch, searchTerms = " + aSearchTerms + "\n"); + RerootThreadPane(); + + if (aSearchTerms) + createSearchTermsWithList(aSearchTerms); + else + createSearchTerms(); + + gDBView.searchSession = gSearchSession; + try + { + gSearchSession.search(msgWindow); + } + catch(ex) + { + dump("Search Exception\n"); + } +} + +function createSearchTermsWithList(aTermsArray) +{ + var nsMsgSearchScope = Ci.nsMsgSearchScope; + var nsMsgSearchAttrib = Ci.nsMsgSearchAttrib; + var nsMsgSearchOp = Ci.nsMsgSearchOp; + + gSearchSession.searchTerms.clear(); + gSearchSession.clearScopes(); + + var i; + var selectedFolder = GetThreadPaneFolder(); + if (gXFVirtualFolderTerms) + { + var msgDatabase = selectedFolder.msgDatabase; + if (msgDatabase) + { + var dbFolderInfo = msgDatabase.dBFolderInfo; + var srchFolderUri = dbFolderInfo.getCharProperty("searchFolderUri"); + viewDebug("createSearchTermsWithList xf vf scope = " + srchFolderUri + "\n"); + var srchFolderUriArray = srchFolderUri.split('|'); + for (i in srchFolderUriArray) + { + let realFolder = MailUtils.getFolderForURI(srchFolderUriArray[i]); + if (!realFolder.isServer) + gSearchSession.addScopeTerm(nsMsgSearchScope.offlineMail, realFolder); + } + } + } + else + { + viewDebug ("in createSearchTermsWithList, adding scope term for selected folder\n"); + gSearchSession.addScopeTerm(nsMsgSearchScope.offlineMail, selectedFolder); + } + + // Add each item in aTermsArray to the search session. + for (let term of aTermsArray) { + gSearchSession.appendTerm(term); + } +} + +function createSearchTerms() +{ + var nsMsgSearchScope = Ci.nsMsgSearchScope; + var nsMsgSearchAttrib = Ci.nsMsgSearchAttrib; + var nsMsgSearchOp = Ci.nsMsgSearchOp; + + // create an nsIMutableArray to store our search terms + var searchTermsArray = Cc["@mozilla.org/array;1"] + .createInstance(Ci.nsIMutableArray); + var selectedFolder = GetThreadPaneFolder(); + + // implement | for QS + // does this break if the user types "foo|bar" expecting to see subjects with that string? + // I claim no, since "foo|bar" will be a hit for "foo" || "bar" + // they just might get more false positives + var termList = gSearchInput.value.split("|"); + for (var i = 0; i < termList.length; i ++) + { + // if the term is empty, skip it + if (termList[i] == "") + continue; + + // create, fill, and append the subject term + var term = gSearchSession.createTerm(); + var value = term.value; + value.str = termList[i]; + term.value = value; + term.attrib = nsMsgSearchAttrib.Subject; + term.op = nsMsgSearchOp.Contains; + term.booleanAnd = false; + searchTermsArray.appendElement(term); + + // create, fill, and append the AllAddresses term + term = gSearchSession.createTerm(); + value = term.value; + value.str = termList[i]; + term.value = value; + term.attrib = nsMsgSearchAttrib.AllAddresses; + term.op = nsMsgSearchOp.Contains; + term.booleanAnd = false; + searchTermsArray.appendElement(term); + } + + // now append the default view or virtual folder criteria to the quick search + // so we don't lose any default view information + viewDebug("gDefaultSearchViewTerms = " + gDefaultSearchViewTerms + "gVirtualFolderTerms = " + gVirtualFolderTerms + + "gXFVirtualFolderTerms = " + gXFVirtualFolderTerms + "\n"); + var defaultSearchTerms = (gDefaultSearchViewTerms || gVirtualFolderTerms || gXFVirtualFolderTerms); + if (defaultSearchTerms) + { + for (let searchTerm of defaultSearchTerms) + { + searchTermsArray.appendElement(searchTerm); + } + } + + createSearchTermsWithList(searchTermsArray); + + // now that we've added the terms, clear out our input array + searchTermsArray.clear(); +} + +function onSearchStop() +{ + gSearchSession.interruptSearch(); +} + +function onClearSearch() +{ + // Use the last focused element so that focus can be restored + // if it does not exist, try and get the thread tree instead + var focusedElement = gLastFocusedElement || GetThreadTree(); + Search(""); + focusedElement.focus(); +} + +function disableQuickSearchClearButton() +{ + if (gClearButton) + gClearButton.setAttribute("disabled", true); //going out of search disable clear button +} + +function ClearQSIfNecessary() +{ + GetSearchInput(); + + if (gSearchInput.value == "") + return; + + Search(""); +} + +function Search(str) +{ + GetSearchInput(); + + if (str != gSearchInput.value) + { + gQSViewIsDirty = true; + viewDebug("in Search(), setting gQSViewIsDirty true\n"); + } + + gSearchInput.value = str; //on input does not get fired for some reason + onEnterInSearchBar(); +} |