diff --git a/browser/components/search/nsIBrowserSearchService.idl b/browser/components/search/nsIBrowserSearchService.idl index 4071e13f648..7627dcbaba3 100755 --- a/browser/components/search/nsIBrowserSearchService.idl +++ b/browser/components/search/nsIBrowserSearchService.idl @@ -162,12 +162,13 @@ interface nsISearchEngine : nsISupports }; -[scriptable, uuid(019c7025-0e26-48d0-b2a4-97cc7e0296cf)] +[scriptable, uuid(0c6164fe-580d-497f-87d3-1bf36006cb7c)] interface nsIBrowserSearchService : nsISupports { /** - * Adds a new search engine from the file at the supplied URI and optionally - * selects it as the current engine. + * Adds a new search engine from the file at the supplied URI, optionally + * asking the user for confirmation first. The confirmation dialog also + * offers the option to begin using the newly added engine right away. * * @param engineURL * The URL to the search engine's description file. @@ -181,18 +182,20 @@ interface nsIBrowserSearchService : nsISupports * icon. This value may be overridden by an icon specified in the * engine description file. * - * @param select - * A boolean value indicating whether the newly added engine should - * be selected as the current engine after it finishes loading. + * @param confirm + * A boolean value indicating whether the user should be asked for + * confirmation before this engine is added to the list. If this + * value is false, the engine will be added to the list upon successful + * load, but it will not be selected as the current engine. * * @throws NS_ERROR_FAILURE if the type is invalid, or if the description * file cannot be successfully loaded. */ void addEngine(in AString engineURL, in long type, in AString iconURL, - in boolean select); + in boolean confirm); /** - * Adds a new search engine. + * Adds a new search engine, without asking the user for confirmation. * * @param name * The search engine's name. Must be unique. Must not be null. diff --git a/browser/components/search/nsSearchService.js b/browser/components/search/nsSearchService.js index d7e54094f9f..6f94dc521a9 100755 --- a/browser/components/search/nsSearchService.js +++ b/browser/components/search/nsSearchService.js @@ -94,6 +94,7 @@ const MAX_ICON_SIZE = 10000; const DEFAULT_QUERY_CHARSET = "ISO-8859-1"; const SEARCH_BUNDLE = "chrome://browser/locale/search.properties"; +const SIDEBAR_BUNDLE = "chrome://browser/locale/sidebar/sidebar.properties"; const BRAND_BUNDLE = "chrome://branding/locale/brand.properties"; const OPENSEARCH_NS_10 = "http://a9.com/-/spec/opensearch/1.0/"; @@ -961,9 +962,14 @@ Engine.prototype = { // A URL string pointing to the engine's search form. _searchForm: null, // The URI object from which the engine was retrieved. - // This is null for local plugins, and is used for error messages, logging, - // and determining whether to start using a newly added engine right away. + // This is null for local plugins, and is used for error messages and logging. _uri: null, + // Whether to obtain user confirmation before adding the engine. This is only + // used when the engine is first added to the list. + _confirm: false, + // Whether to set this as the current engine as soon as it is loaded. This + // is only used when the engine is first added to the list. + _useNow: false, // Whether the search engine file is in the app dir. __isInAppDir: null, @@ -1052,6 +1058,41 @@ Engine.prototype = { return null; }, + _confirmAddEngine: function SRCH_SVC_confirmAddEngine() { + var sbs = Cc["@mozilla.org/intl/stringbundle;1"]. + getService(Ci.nsIStringBundleService); + var stringBundle = sbs.createBundle(SIDEBAR_BUNDLE); + var titleMessage = stringBundle.GetStringFromName("addEngineConfirmTitle"); + + // Display only the hostname portion of the URL. + var dialogMessage = + stringBundle.formatStringFromName("addEngineConfirmText", + [this._name, this._uri.host], 2); + var checkboxMessage = stringBundle.GetStringFromName("addEngineUseNowText"); + var addButtonLabel = + stringBundle.GetStringFromName("addEngineAddButtonLabel"); + + var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"]. + getService(Ci.nsIPromptService); + var buttonFlags = (ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0) + + (ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1) + + ps.BUTTON_POS_0_DEFAULT; + + var checked = {value: false}; + // confirmEx returns the index of the button that was pressed. Since "Add" + // is button 0, we want to return the negation of that value. + var confirm = !ps.confirmEx(null, + titleMessage, + dialogMessage, + buttonFlags, + addButtonLabel, + null, null, // button 1 & 2 names not used + checkboxMessage, + checked); + + return {confirmed: confirm, useNow: checked.value}; + }, + /** * Handle the successful download of an engine. Initializes the engine and * triggers parsing of the data. The engine is then flushed to disk. Notifies @@ -1111,6 +1152,19 @@ Engine.prototype = { return; } + // If requested, confirm the addition now that we have the title. + if (aEngine._confirm) { + var confirmation = aEngine._confirmAddEngine(); + LOG("_onLoad: confirm is " + confirmation.confirmed + + "; useNow is " + confirmation.useNow); + if (!confirmation.confirmed) + return; + aEngine._useNow = confirmation.useNow; + } + + // Since we're coming from a URL, we don't yet have a file. + aEngine._file = getSanitizedFile(aEngine.name); + // Write the engine to file aEngine._serializeToFile(); @@ -1235,11 +1289,6 @@ Engine.prototype = { this._type = SEARCH_TYPE_SHERLOCK; this._parseAsSherlock(); } - - // If we don't yet have a file (i.e. we instantiated an engine object from - // passed in URL), get one now - if (!this._file) - this._file = getSanitizedFile(this.name); }, /** @@ -1843,12 +1892,6 @@ Engine.prototype = { return ""; }, - // This getter is used in SearchService.observe. It is not intended to be - // used (or needed) by callers outside this file. - get uri() { - return this._uri; - }, - // The file that the plugin is loaded from is a unique identifier for it. We // use this as the identifier to store data in the sqlite database get _id() { @@ -1994,14 +2037,6 @@ SearchService.prototype = { _engines: { }, _sortedEngines: [], - // If this is set to the URI of the description of a search engine being added - // to the list (typically by calling addEngine()), that engine will be - // selected as the current engine when it finishes loading. If another - // engine is added with "start using this one now" before the first selected - // engine finishes loading, the second choice will override the first one. - // If the selected engine fails to load, this marker will be cleared. - _selectNewEngineURI: null, - _init: function() { engineMetadataService.init(); this._addObservers(); @@ -2368,22 +2403,19 @@ SearchService.prototype = { this._addEngineToStore(engine); }, - // If aSelect is true, the newly added engine will be selected as the current - // engine when it finishes loading. - addEngine: function SRCH_SVC_addEngine(aEngineURL, aType, aIconURL, aSelect) { + addEngine: function SRCH_SVC_addEngine(aEngineURL, aType, aIconURL, + aConfirm) { LOG("addEngine: Adding \"" + aEngineURL + "\"."); try { var uri = makeURI(aEngineURL); var engine = new Engine(uri, aType, false); engine._initFromURI(); - - if (aSelect) - this._selectNewEngineURI = uri; } catch (ex) { LOG("addEngine: Error adding engine:\n" + ex); throw Cr.NS_ERROR_FAILURE; } engine._setIcon(aIconURL, false); + engine._confirm = aConfirm; }, removeEngine: function SRCH_SVC_removeEngine(aEngine) { @@ -2482,14 +2514,12 @@ SearchService.prototype = { case SEARCH_ENGINE_TOPIC: if (aVerb == SEARCH_ENGINE_LOADED) { var engine = aEngine.QueryInterface(Ci.nsISearchEngine); - LOG("nsISearchEngine::observe: Done installation of " + engine.name + LOG("nsSearchService::observe: Done installation of " + engine.name + "."); this._addEngineToStore(engine.wrappedJSObject); - // Optionally start using this engine now. - if (this._selectNewEngineURI && - this._selectNewEngineURI == engine.wrappedJSObject.uri) { + if (engine.wrappedJSObject._useNow) { + LOG("nsSearchService::observe: setting current"); this.currentEngine = aEngine; - this._selectNewEngineURI = null; } } break; diff --git a/browser/components/sidebar/src/nsSidebar.js b/browser/components/sidebar/src/nsSidebar.js index a0b53c8b4f3..aeaebf43882 100644 --- a/browser/components/sidebar/src/nsSidebar.js +++ b/browser/components/sidebar/src/nsSidebar.js @@ -135,57 +135,6 @@ function (aTitle, aContentURL, aCustomizeURL, aPersist) features, dialogArgs); } -nsSidebar.prototype.confirmSearchEngine = -function (engineURL, suggestedTitle) -{ - var stringBundle = srGetStrBundle("chrome://browser/locale/sidebar/sidebar.properties"); - var titleMessage = stringBundle.GetStringFromName("addEngineConfirmTitle"); - - // With tentative title: Add "Somebody's Search" to the list... - // With no title: Add a new search engine to the list... - var engineName; - if (suggestedTitle) - engineName = stringBundle.formatStringFromName("addEngineQuotedEngineName", - [suggestedTitle], 1); - else - engineName = stringBundle.GetStringFromName("addEngineDefaultEngineName"); - - // Display only the hostname portion of the URL. - try { - var ios = Components.classes["@mozilla.org/network/io-service;1"] - .getService(Components.interfaces.nsIIOService); - var uri = ios.newURI(engineURL, null, null); - engineURL = uri.host; - } - catch (e) { - // If newURI fails, fall back to the full URL. - } - - var dialogMessage = stringBundle.formatStringFromName("addEngineConfirmText", - [engineName, engineURL], 2); - var checkboxMessage = stringBundle.GetStringFromName("addEngineUseNowText"); - var addButtonLabel = stringBundle.GetStringFromName("addEngineAddButtonLabel"); - - const ps = this.promptService; - var buttonFlags = (ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0) + - (ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1) + - ps.BUTTON_POS_0_DEFAULT; - - var checked = {value: false}; - // confirmEx returns the index of the button that was pressed. Since "Add" is - // button 0, we want to return the negation of that value. - var confirm = !this.promptService.confirmEx(null, - titleMessage, - dialogMessage, - buttonFlags, - addButtonLabel, - "", "", // button 1 & 2 names not used - checkboxMessage, - checked); - - return {confirmed: confirm, useNow: checked.value}; -} - nsSidebar.prototype.validateSearchEngine = function (engineURL, iconURL) { @@ -221,6 +170,8 @@ function (engineURL, iconURL) return true; } +// The suggestedTitle and suggestedCategory parameters are ignored, but remain +// for backward compatibility. nsSidebar.prototype.addSearchEngine = function (engineURL, iconURL, suggestedTitle, suggestedCategory) { @@ -230,10 +181,6 @@ function (engineURL, iconURL, suggestedTitle, suggestedCategory) if (!this.validateSearchEngine(engineURL, iconURL)) return; - var confirmation = this.confirmSearchEngine(engineURL, suggestedTitle); - if (!confirmation.confirmed) - return; - // OpenSearch files will likely be far more common than Sherlock files, and // have less consistent suffixes, so we assume that ".src" is a Sherlock // (text) file, and anything else is OpenSearch (XML). @@ -243,8 +190,7 @@ function (engineURL, iconURL, suggestedTitle, suggestedCategory) else dataType = Components.interfaces.nsISearchEngine.DATA_XML; - this.searchService.addEngine(engineURL, dataType, iconURL, - confirmation.useNow); + this.searchService.addEngine(engineURL, dataType, iconURL, true); } // This function exists largely to implement window.external.AddSearchProvider(), @@ -268,13 +214,8 @@ function (aDescriptionURL) if (!this.validateSearchEngine(aDescriptionURL, iconURL)) return; - var confirmation = this.confirmSearchEngine(aDescriptionURL, ""); - if (!confirmation.confirmed) - return; - const typeXML = Components.interfaces.nsISearchEngine.DATA_XML; - this.searchService.addEngine(aDescriptionURL, typeXML, iconURL, - confirmation.useNow); + this.searchService.addEngine(aDescriptionURL, typeXML, iconURL, true); } nsSidebar.prototype.addMicrosummaryGenerator =