forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			246 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			246 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* 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/. */
 | 
						|
 | 
						|
/* globals windowTracker */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
ChromeUtils.defineModuleGetter(this, "ExtensionPreferencesManager",
 | 
						|
                               "resource://gre/modules/ExtensionPreferencesManager.jsm");
 | 
						|
ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
 | 
						|
                               "resource://gre/modules/ExtensionSettingsStore.jsm");
 | 
						|
 | 
						|
const DEFAULT_SEARCH_STORE_TYPE = "default_search";
 | 
						|
const DEFAULT_SEARCH_SETTING_NAME = "defaultSearch";
 | 
						|
const ENGINE_ADDED_SETTING_NAME = "engineAdded";
 | 
						|
 | 
						|
// This promise is used to wait for the search service to be initialized.
 | 
						|
// None of the code in this module requests that initialization. It is assumed
 | 
						|
// that it is started at some point. If tests start to fail because this
 | 
						|
// promise never resolves, that's likely the cause.
 | 
						|
const searchInitialized = () => {
 | 
						|
  if (Services.search.isInitialized) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  return new Promise(resolve => {
 | 
						|
    const SEARCH_SERVICE_TOPIC = "browser-search-service";
 | 
						|
    Services.obs.addObserver(function observer(subject, topic, data) {
 | 
						|
      if (data != "init-complete") {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      Services.obs.removeObserver(observer, SEARCH_SERVICE_TOPIC);
 | 
						|
      resolve();
 | 
						|
    }, SEARCH_SERVICE_TOPIC);
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
this.chrome_settings_overrides = class extends ExtensionAPI {
 | 
						|
  static async processDefaultSearchSetting(action, id) {
 | 
						|
    await ExtensionSettingsStore.initialize();
 | 
						|
    let item = ExtensionSettingsStore.getSetting(DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME);
 | 
						|
    if (!item) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    if (Services.search.currentEngine.name != item.value &&
 | 
						|
        Services.search.currentEngine.name != item.initialValue) {
 | 
						|
      // The current engine is not the same as the value that the ExtensionSettingsStore has.
 | 
						|
      // This means that the user changed the engine, so we shouldn't control it anymore.
 | 
						|
      // Do nothing and remove our entry from the ExtensionSettingsStore.
 | 
						|
      ExtensionSettingsStore.removeSetting(id, DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    item = ExtensionSettingsStore[action](id, DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME);
 | 
						|
    if (item) {
 | 
						|
      try {
 | 
						|
        let engine = Services.search.getEngineByName(item.value || item.initialValue);
 | 
						|
        if (engine) {
 | 
						|
          Services.search.currentEngine = engine;
 | 
						|
        }
 | 
						|
      } catch (e) {
 | 
						|
        Cu.reportError(e);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  static async removeEngine(id) {
 | 
						|
    await ExtensionSettingsStore.initialize();
 | 
						|
    let item = await ExtensionSettingsStore.getSetting(
 | 
						|
      DEFAULT_SEARCH_STORE_TYPE, ENGINE_ADDED_SETTING_NAME, id);
 | 
						|
    if (item) {
 | 
						|
      ExtensionSettingsStore.removeSetting(
 | 
						|
        id, DEFAULT_SEARCH_STORE_TYPE, ENGINE_ADDED_SETTING_NAME);
 | 
						|
      await searchInitialized();
 | 
						|
      let engine = Services.search.getEngineByName(item.value);
 | 
						|
      try {
 | 
						|
        Services.search.removeEngine(engine);
 | 
						|
      } catch (e) {
 | 
						|
        Cu.reportError(e);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  static removeSearchSettings(id) {
 | 
						|
    this.processDefaultSearchSetting("removeSetting", id);
 | 
						|
    this.removeEngine(id);
 | 
						|
  }
 | 
						|
 | 
						|
  static onUninstall(id) {
 | 
						|
    // Note: We do not have to deal with homepage here as it is managed by
 | 
						|
    // the ExtensionPreferencesManager.
 | 
						|
    this.removeSearchSettings(id);
 | 
						|
  }
 | 
						|
 | 
						|
  static onUpdate(id, manifest) {
 | 
						|
    let haveHomepage = manifest && manifest.chrome_settings_overrides &&
 | 
						|
                       manifest.chrome_settings_overrides.homepage;
 | 
						|
    if (!haveHomepage) {
 | 
						|
      ExtensionPreferencesManager.removeSetting(id, "homepage_override");
 | 
						|
    }
 | 
						|
 | 
						|
    let haveSearchProvider = manifest && manifest.chrome_settings_overrides &&
 | 
						|
                             manifest.chrome_settings_overrides.search_provider;
 | 
						|
    if (!haveSearchProvider) {
 | 
						|
      this.removeSearchSettings(id);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  async onManifestEntry(entryName) {
 | 
						|
    let {extension} = this;
 | 
						|
    let {manifest} = extension;
 | 
						|
 | 
						|
    await ExtensionSettingsStore.initialize();
 | 
						|
    if (manifest.chrome_settings_overrides.homepage) {
 | 
						|
      ExtensionPreferencesManager.setSetting(extension.id, "homepage_override",
 | 
						|
                                             manifest.chrome_settings_overrides.homepage);
 | 
						|
    }
 | 
						|
    if (manifest.chrome_settings_overrides.search_provider) {
 | 
						|
      await searchInitialized();
 | 
						|
      extension.callOnClose({
 | 
						|
        close: () => {
 | 
						|
          if (extension.shutdownReason == "ADDON_DISABLE") {
 | 
						|
            chrome_settings_overrides.processDefaultSearchSetting("disable", extension.id);
 | 
						|
            chrome_settings_overrides.removeEngine(extension.id);
 | 
						|
          }
 | 
						|
        },
 | 
						|
      });
 | 
						|
 | 
						|
      let searchProvider = manifest.chrome_settings_overrides.search_provider;
 | 
						|
      let engineName = searchProvider.name.trim();
 | 
						|
      if (searchProvider.is_default) {
 | 
						|
        let engine = Services.search.getEngineByName(engineName);
 | 
						|
        if (engine && Services.search.getDefaultEngines().includes(engine)) {
 | 
						|
          // Needs to be called every time to handle reenabling, but
 | 
						|
          // only sets default for install or enable.
 | 
						|
          await this.setDefault(engineName);
 | 
						|
          // For built in search engines, we don't do anything further
 | 
						|
          return;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      await this.addSearchEngine(searchProvider);
 | 
						|
      if (searchProvider.is_default) {
 | 
						|
        if (extension.startupReason === "ADDON_INSTALL") {
 | 
						|
          // Don't ask if it already the current engine
 | 
						|
          let engine = Services.search.getEngineByName(engineName);
 | 
						|
          if (Services.search.currentEngine != engine) {
 | 
						|
            let allow = await new Promise(resolve => {
 | 
						|
              let subject = {
 | 
						|
                wrappedJSObject: {
 | 
						|
                  // This is a hack because we don't have the browser of
 | 
						|
                  // the actual install. This means the popup might show
 | 
						|
                  // in a different window. Will be addressed in a followup bug.
 | 
						|
                  browser: windowTracker.topWindow.gBrowser.selectedBrowser,
 | 
						|
                  name: this.extension.name,
 | 
						|
                  icon: this.extension.iconURL,
 | 
						|
                  currentEngine: Services.search.currentEngine.name,
 | 
						|
                  newEngine: engineName,
 | 
						|
                  resolve,
 | 
						|
                },
 | 
						|
              };
 | 
						|
              Services.obs.notifyObservers(subject, "webextension-defaultsearch-prompt");
 | 
						|
            });
 | 
						|
            if (!allow) {
 | 
						|
              return;
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        // Needs to be called every time to handle reenabling, but
 | 
						|
        // only sets default for install or enable.
 | 
						|
        await this.setDefault(engineName);
 | 
						|
      } else if (ExtensionSettingsStore.hasSetting(extension.id,
 | 
						|
                                                   DEFAULT_SEARCH_STORE_TYPE,
 | 
						|
                                                   DEFAULT_SEARCH_SETTING_NAME)) {
 | 
						|
        // is_default has been removed, but we still have a setting. Remove it.
 | 
						|
        chrome_settings_overrides.processDefaultSearchSetting("removeSetting", extension.id);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  async setDefault(engineName) {
 | 
						|
    let {extension} = this;
 | 
						|
    if (extension.startupReason === "ADDON_INSTALL") {
 | 
						|
      let item = await ExtensionSettingsStore.addSetting(
 | 
						|
        extension.id, DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME, engineName, () => {
 | 
						|
          return Services.search.currentEngine.name;
 | 
						|
        });
 | 
						|
      Services.search.currentEngine = Services.search.getEngineByName(item.value);
 | 
						|
    } else if (extension.startupReason === "ADDON_ENABLE") {
 | 
						|
      chrome_settings_overrides.processDefaultSearchSetting("enable", extension.id);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  async addSearchEngine(searchProvider) {
 | 
						|
    let {extension} = this;
 | 
						|
    let isCurrent = false;
 | 
						|
    let index = -1;
 | 
						|
    if (extension.startupReason === "ADDON_UPGRADE") {
 | 
						|
      let engines = Services.search.getEnginesByExtensionID(extension.id);
 | 
						|
      if (engines.length > 0) {
 | 
						|
        // There can be only one engine right now
 | 
						|
        isCurrent = Services.search.currentEngine == engines[0];
 | 
						|
        // Get position of engine and store it
 | 
						|
        index = Services.search.getEngines().indexOf(engines[0]);
 | 
						|
        Services.search.removeEngine(engines[0]);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    try {
 | 
						|
      let params = {
 | 
						|
        template: searchProvider.search_url,
 | 
						|
        iconURL: searchProvider.favicon_url,
 | 
						|
        alias: searchProvider.keyword,
 | 
						|
        extensionID: extension.id,
 | 
						|
        suggestURL: searchProvider.suggest_url,
 | 
						|
        queryCharset: "UTF-8",
 | 
						|
      };
 | 
						|
      Services.search.addEngineWithDetails(searchProvider.name.trim(), params);
 | 
						|
      await ExtensionSettingsStore.addSetting(
 | 
						|
        extension.id, DEFAULT_SEARCH_STORE_TYPE, ENGINE_ADDED_SETTING_NAME,
 | 
						|
        searchProvider.name.trim());
 | 
						|
      if (extension.startupReason === "ADDON_UPGRADE") {
 | 
						|
        let engine = Services.search.getEngineByName(searchProvider.name.trim());
 | 
						|
        if (isCurrent) {
 | 
						|
          Services.search.currentEngine = engine;
 | 
						|
        }
 | 
						|
        if (index != -1) {
 | 
						|
          Services.search.moveEngine(engine, index);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } catch (e) {
 | 
						|
      Cu.reportError(e);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
ExtensionPreferencesManager.addSetting("homepage_override", {
 | 
						|
  prefNames: [
 | 
						|
    "browser.startup.homepage",
 | 
						|
  ],
 | 
						|
  setCallback(value) {
 | 
						|
    return {
 | 
						|
      "browser.startup.homepage": value,
 | 
						|
    };
 | 
						|
  },
 | 
						|
});
 |