1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
/* 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 { UrlbarUtils } from "resource:///modules/UrlbarUtils.sys.mjs";
import {
ActionsProvider,
ActionsResult,
} from "resource:///modules/ActionsProvider.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
OpenSearchEngine: "resource://gre/modules/OpenSearchEngine.sys.mjs",
loadAndParseOpenSearchEngine:
"resource://gre/modules/OpenSearchLoader.sys.mjs",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs",
});
const ENABLED_PREF = "contextualSearch.enabled";
/**
* A provider that returns an option for using the search engine provided
* by the active view if it utilizes OpenSearch.
*/
class ProviderContextualSearch extends ActionsProvider {
constructor() {
super();
this.engines = new Map();
}
get name() {
return "ActionsProviderContextualSearch";
}
isActive(queryContext) {
return (
queryContext.trimmedSearchString &&
lazy.UrlbarPrefs.get(ENABLED_PREF) &&
!queryContext.searchMode
);
}
async queryAction(queryContext, controller) {
let instance = this.queryInstance;
const hostname = URL.parse(queryContext.currentPage)?.hostname;
// This happens on about pages, which won't have associated engines
if (!hostname) {
return null;
}
let engine = await this.fetchEngine(controller);
let icon = engine?.icon || (await engine?.getIconURL?.());
let defaultEngine = lazy.UrlbarSearchUtils.getDefaultEngine();
if (
!engine ||
engine.name === defaultEngine?.name ||
instance != this.queryInstance
) {
return null;
}
return new ActionsResult({
key: "contextual-search",
l10nId: "urlbar-result-search-with",
l10nArgs: { engine: engine.name || engine.title },
icon,
});
}
async fetchEngine(controller) {
let browser = controller.browserWindow.gBrowser.selectedBrowser;
let hostname = browser?.currentURI.host;
if (this.engines.has(hostname)) {
return this.engines.get(hostname);
}
// Strip www. to allow for partial matches when looking for an engine.
const [host] = UrlbarUtils.stripPrefixAndTrim(hostname, {
stripWww: true,
});
let engines = await lazy.UrlbarSearchUtils.enginesForDomainPrefix(host, {
matchAllDomainLevels: true,
});
return engines[0] ?? browser?.engines?.[0];
}
async pickAction(queryContext, controller, element) {
// If we have an engine to add, first create a new OpenSearchEngine, then
// get and open a url to execute a search for the term in the url bar.
let engine = await this.fetchEngine(controller);
if (engine.uri) {
let engineData = await lazy.loadAndParseOpenSearchEngine(
Services.io.newURI(engine.uri)
);
engine = new lazy.OpenSearchEngine({ engineData });
engine._setIcon(engine.icon, false);
}
const [url] = UrlbarUtils.getSearchQueryUrl(
engine,
queryContext.searchString
);
element.ownerGlobal.gBrowser.fixupAndLoadURIString(url, {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
});
element.ownerGlobal.gBrowser.selectedBrowser.focus();
}
resetForTesting() {
this.engines = new Map();
}
}
export var ActionsProviderContextualSearch = new ProviderContextualSearch();
|