michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: this.EXPORTED_SYMBOLS = [ michael@0: "ContentSearch", michael@0: ]; michael@0: michael@0: const { classes: Cc, interfaces: Ci, utils: Cu } = Components; michael@0: michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: const INBOUND_MESSAGE = "ContentSearch"; michael@0: const OUTBOUND_MESSAGE = INBOUND_MESSAGE; michael@0: michael@0: /** michael@0: * ContentSearch receives messages named INBOUND_MESSAGE and sends messages michael@0: * named OUTBOUND_MESSAGE. The data of each message is expected to look like michael@0: * { type, data }. type is the message's type (or subtype if you consider the michael@0: * type of the message itself to be INBOUND_MESSAGE), and data is data that is michael@0: * specific to the type. michael@0: * michael@0: * Inbound messages have the following types: michael@0: * michael@0: * GetState michael@0: * Retrieves the current search engine state. michael@0: * data: null michael@0: * ManageEngines michael@0: * Opens the search engine management window. michael@0: * data: null michael@0: * Search michael@0: * Performs a search. michael@0: * data: an object { engineName, searchString, whence } michael@0: * SetCurrentEngine michael@0: * Sets the current engine. michael@0: * data: the name of the engine michael@0: * michael@0: * Outbound messages have the following types: michael@0: * michael@0: * CurrentEngine michael@0: * Sent when the current engine changes. michael@0: * data: see _currentEngineObj michael@0: * State michael@0: * Sent in reply to GetState and when the state changes. michael@0: * data: see _currentStateObj michael@0: */ michael@0: michael@0: this.ContentSearch = { michael@0: michael@0: init: function () { michael@0: Cc["@mozilla.org/globalmessagemanager;1"]. michael@0: getService(Ci.nsIMessageListenerManager). michael@0: addMessageListener(INBOUND_MESSAGE, this); michael@0: Services.obs.addObserver(this, "browser-search-engine-modified", false); michael@0: }, michael@0: michael@0: receiveMessage: function (msg) { michael@0: let methodName = "on" + msg.data.type; michael@0: if (methodName in this) { michael@0: this[methodName](msg, msg.data.data); michael@0: } michael@0: }, michael@0: michael@0: onGetState: function (msg, data) { michael@0: this._reply(msg, "State", this._currentStateObj()); michael@0: }, michael@0: michael@0: onSearch: function (msg, data) { michael@0: let expectedDataProps = [ michael@0: "engineName", michael@0: "searchString", michael@0: "whence", michael@0: ]; michael@0: for (let prop of expectedDataProps) { michael@0: if (!(prop in data)) { michael@0: Cu.reportError("Message data missing required property: " + prop); michael@0: return; michael@0: } michael@0: } michael@0: let browserWin = msg.target.ownerDocument.defaultView; michael@0: let engine = Services.search.getEngineByName(data.engineName); michael@0: browserWin.BrowserSearch.recordSearchInHealthReport(engine, data.whence); michael@0: let submission = engine.getSubmission(data.searchString, "", data.whence); michael@0: browserWin.loadURI(submission.uri.spec, null, submission.postData); michael@0: }, michael@0: michael@0: onSetCurrentEngine: function (msg, data) { michael@0: Services.search.currentEngine = Services.search.getEngineByName(data); michael@0: }, michael@0: michael@0: onManageEngines: function (msg, data) { michael@0: let browserWin = msg.target.ownerDocument.defaultView; michael@0: browserWin.BrowserSearch.searchBar.openManager(null); michael@0: }, michael@0: michael@0: observe: function (subj, topic, data) { michael@0: switch (topic) { michael@0: case "browser-search-engine-modified": michael@0: if (data == "engine-current") { michael@0: this._broadcast("CurrentEngine", this._currentEngineObj()); michael@0: } michael@0: else if (data != "engine-default") { michael@0: // engine-default is always sent with engine-current and isn't otherwise michael@0: // relevant to content searches. michael@0: this._broadcast("State", this._currentStateObj()); michael@0: } michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: _reply: function (msg, type, data) { michael@0: msg.target.messageManager.sendAsyncMessage(...this._msgArgs(type, data)); michael@0: }, michael@0: michael@0: _broadcast: function (type, data) { michael@0: Cc["@mozilla.org/globalmessagemanager;1"]. michael@0: getService(Ci.nsIMessageListenerManager). michael@0: broadcastAsyncMessage(...this._msgArgs(type, data)); michael@0: }, michael@0: michael@0: _msgArgs: function (type, data) { michael@0: return [OUTBOUND_MESSAGE, { michael@0: type: type, michael@0: data: data, michael@0: }]; michael@0: }, michael@0: michael@0: _currentStateObj: function () { michael@0: return { michael@0: engines: Services.search.getVisibleEngines().map(engine => { michael@0: return { michael@0: name: engine.name, michael@0: iconURI: engine.getIconURLBySize(16, 16), michael@0: }; michael@0: }), michael@0: currentEngine: this._currentEngineObj(), michael@0: }; michael@0: }, michael@0: michael@0: _currentEngineObj: function () { michael@0: return { michael@0: name: Services.search.currentEngine.name, michael@0: logoURI: Services.search.currentEngine.getIconURLBySize(65, 26), michael@0: logo2xURI: Services.search.currentEngine.getIconURLBySize(130, 52), michael@0: }; michael@0: }, michael@0: };