summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/unifiedtoolbar/content/items/global-search-bar.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/unifiedtoolbar/content/items/global-search-bar.mjs')
-rw-r--r--comm/mail/components/unifiedtoolbar/content/items/global-search-bar.mjs223
1 files changed, 223 insertions, 0 deletions
diff --git a/comm/mail/components/unifiedtoolbar/content/items/global-search-bar.mjs b/comm/mail/components/unifiedtoolbar/content/items/global-search-bar.mjs
new file mode 100644
index 0000000000..924955c895
--- /dev/null
+++ b/comm/mail/components/unifiedtoolbar/content/items/global-search-bar.mjs
@@ -0,0 +1,223 @@
+/* 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/. */
+
+import { SearchBar } from "chrome://messenger/content/unifiedtoolbar/search-bar.mjs";
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ GlodaIMSearcher: "resource:///modules/GlodaIMSearcher.sys.mjs",
+});
+ChromeUtils.defineModuleGetter(
+ lazy,
+ "GlodaMsgSearcher",
+ "resource:///modules/gloda/GlodaMsgSearcher.jsm"
+);
+ChromeUtils.defineModuleGetter(
+ lazy,
+ "GlodaConstants",
+ "resource:///modules/gloda/GlodaConstants.jsm"
+);
+ChromeUtils.defineModuleGetter(
+ lazy,
+ "Gloda",
+ "resource:///modules/gloda/GlodaPublic.jsm"
+);
+XPCOMUtils.defineLazyGetter(
+ lazy,
+ "glodaCompleter",
+ () =>
+ Cc["@mozilla.org/autocomplete/search;1?name=gloda"].getService(
+ Ci.nsIAutoCompleteSearch
+ ).wrappedJSObject
+);
+
+/**
+ * Unified toolbar global search bar.
+ */
+class GlobalSearchBar extends SearchBar {
+ // Fields required for the auto complete popup to work.
+
+ get popup() {
+ return document.getElementById("PopupGlodaAutocomplete");
+ }
+
+ controller = {
+ matchCount: 0,
+ searchString: "",
+ stopSearch() {
+ lazy.glodaCompleter.stopSearch();
+ },
+ handleEnter: (isAutocomplete, event) => {
+ if (!isAutocomplete) {
+ return;
+ }
+ this.#handleSearch({ detail: this.controller.searchString });
+ this.reset();
+ },
+ };
+
+ _focus() {
+ this.focus();
+ }
+
+ #searchResultListener = {
+ onSearchResult: (result, search) => {
+ this.controller.matchCount = search.matchCount;
+ if (this.controller.matchCount < 1) {
+ this.popup.closePopup();
+ return;
+ }
+ if (!this.popup.mPopupOpen) {
+ this.popup.openAutocompletePopup(
+ this,
+ this.shadowRoot.querySelector("input")
+ );
+ return;
+ }
+ this.popup.invalidate();
+ },
+ };
+
+ // Normal custom element stuff
+
+ connectedCallback() {
+ if (this.shadowRoot) {
+ return;
+ }
+ if (
+ !Services.prefs.getBoolPref(
+ "mailnews.database.global.indexer.enabled",
+ true
+ )
+ ) {
+ return;
+ }
+ // Need to call this after the shadow root test, since this will always set
+ // up a shadow root.
+ super.connectedCallback();
+ this.addEventListener("search", this.#handleSearch);
+ this.addEventListener("autocomplete", this.#handleAutocomplete);
+ // Capturing to avoid the default cursor movements inside the input.
+ this.addEventListener("keydown", this.#handleKeydown, {
+ capture: true,
+ });
+ this.addEventListener("focus", this.#handleFocus);
+ this.addEventListener("blur", this);
+ this.addEventListener("drop", this.#handleDrop, { capture: true });
+ }
+
+ handleEvent(event) {
+ switch (event.type) {
+ case "blur":
+ if (this.popup.mPopupOpen) {
+ this.popup.closePopup();
+ }
+ break;
+ }
+ }
+
+ #handleSearch = event => {
+ let tabmail = document.getElementById("tabmail");
+ let args;
+ // Build the query from the autocomplete result.
+ const selectedIndex = this.popup.selectedIndex;
+ if (selectedIndex > -1) {
+ const curResult = lazy.glodaCompleter.curResult;
+ if (curResult) {
+ const row = curResult.getObjectAt(selectedIndex);
+ if (row && !row.fullText && row.nounDef) {
+ let query = lazy.Gloda.newQuery(lazy.GlodaConstants.NOUN_MESSAGE);
+ switch (row.nounDef.name) {
+ case "tag":
+ query = query.tags(row.item);
+ break;
+ case "identity":
+ query = query.involves(row.item);
+ break;
+ }
+ query.orderBy("-date");
+ args = { query };
+ }
+ }
+ }
+ // Or just do a normal full text search.
+ if (!args) {
+ let searchString = event.detail;
+ args = {
+ searcher: new lazy.GlodaMsgSearcher(null, searchString),
+ };
+ if (Services.prefs.getBoolPref("mail.chat.enabled")) {
+ args.IMSearcher = new lazy.GlodaIMSearcher(null, searchString);
+ }
+ }
+ tabmail.openTab("glodaFacet", args);
+ this.popup.closePopup();
+ this.controller.matchCount = 0;
+ this.controller.searchString = "";
+ };
+
+ #handleAutocomplete = event => {
+ this.controller.searchString = event.detail;
+ if (!event.detail) {
+ this.popup.closePopup();
+ this.controller.matchCount = 0;
+ return;
+ }
+ lazy.glodaCompleter.startSearch(
+ this.controller.searchString,
+ "global",
+ null,
+ this.#searchResultListener
+ );
+ };
+
+ #handleKeydown = event => {
+ if (event.ctrlKey) {
+ return;
+ }
+ if (event.key == "ArrowDown") {
+ if (this.popup.selectedIndex < this.controller.matchCount - 1) {
+ ++this.popup.selectedIndex;
+ event.preventDefault();
+ return;
+ }
+ this.popup.selectedIndex = -1;
+ event.preventDefault();
+ return;
+ }
+ if (event.key == "ArrowUp") {
+ if (this.popup.selectedIndex > -1) {
+ --this.popup.selectedIndex;
+ event.preventDefault();
+ return;
+ }
+ this.popup.selectedIndex = this.controller.matchCount - 1;
+ event.preventDefault();
+ }
+ };
+
+ #handleFocus = event => {
+ if (this.controller.searchString && this.controller.matchCount >= 1) {
+ this.popup.openAutocompletePopup(
+ this,
+ this.shadowRoot.querySelector("input")
+ );
+ }
+ };
+
+ #handleDrop = event => {
+ if (event.dataTransfer.types.includes("text/x-moz-address")) {
+ const searchTerm = event.dataTransfer.getData("text/plain");
+ this.#handleSearch({ detail: searchTerm });
+ }
+ event.stopPropagation();
+ event.preventDefault();
+ };
+}
+customElements.define("global-search-bar", GlobalSearchBar);