toolkit/components/places/PriorityUrlProvider.jsm

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:9eb51a92cf70
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 "use strict";
6
7 this.EXPORTED_SYMBOLS = [ "PriorityUrlProvider" ];
8
9 const Ci = Components.interfaces;
10 const Cc = Components.classes;
11 const Cu = Components.utils;
12 const Cr = Components.results;
13
14 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
15 Cu.import("resource://gre/modules/Services.jsm");
16 Cu.import("resource://gre/modules/Promise.jsm");
17 Cu.import("resource://gre/modules/Task.jsm");
18
19
20 /**
21 * Provides search engines matches to the PriorityUrlProvider through the
22 * search engines definitions handled by the Search Service.
23 */
24 const SEARCH_ENGINE_TOPIC = "browser-search-engine-modified";
25
26 let SearchEnginesProvider = {
27 init: function () {
28 this._engines = new Map();
29 let deferred = Promise.defer();
30 Services.search.init(rv => {
31 if (Components.isSuccessCode(rv)) {
32 Services.search.getVisibleEngines().forEach(this._addEngine, this);
33 deferred.resolve();
34 } else {
35 deferred.reject(new Error("Unable to initialize search service."));
36 }
37 });
38 Services.obs.addObserver(this, SEARCH_ENGINE_TOPIC, true);
39 return deferred.promise;
40 },
41
42 observe: function (engine, topic, verb) {
43 let engine = engine.QueryInterface(Ci.nsISearchEngine);
44 switch (verb) {
45 case "engine-added":
46 this._addEngine(engine);
47 break;
48 case "engine-changed":
49 if (engine.hidden) {
50 this._removeEngine(engine);
51 } else {
52 this._addEngine(engine);
53 }
54 break;
55 case "engine-removed":
56 this._removeEngine(engine);
57 break;
58 }
59 },
60
61 _addEngine: function (engine) {
62 if (this._engines.has(engine.name)) {
63 return;
64 }
65 let token = engine.getResultDomain();
66 if (!token) {
67 return;
68 }
69 let match = { token: token,
70 // TODO (bug 557665): searchForm should provide an usable
71 // url with affiliate code, if available.
72 url: engine.searchForm,
73 title: engine.name,
74 iconUrl: engine.iconURI ? engine.iconURI.spec : null,
75 reason: "search" }
76 this._engines.set(engine.name, match);
77 PriorityUrlProvider.addMatch(match);
78 },
79
80 _removeEngine: function (engine) {
81 if (!this._engines.has(engine.name)) {
82 return;
83 }
84 this._engines.delete(engine.name);
85 PriorityUrlProvider.removeMatchByToken(engine.getResultDomain());
86 },
87
88 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
89 Ci.nsISupportsWeakReference])
90 }
91
92 /**
93 * The PriorityUrlProvider allows to match a given string to a list of
94 * urls that should have priority in url search components, like autocomplete.
95 * Each returned match is an object with the following properties:
96 * - token: string used to match the search term to the url
97 * - url: url string represented by the match
98 * - title: title describing the match, or an empty string if not available
99 * - iconUrl: url of the icon associated to the match, or null if not available
100 * - reason: a string describing the origin of the match, for example if it
101 * represents a search engine, it will be "search".
102 */
103 let matches = new Map();
104
105 let initialized = false;
106 function promiseInitialized() {
107 if (initialized) {
108 return Promise.resolve();
109 }
110 return Task.spawn(function* () {
111 try {
112 yield SearchEnginesProvider.init();
113 } catch (ex) {
114 Cu.reportError(ex);
115 }
116 initialized = true;
117 });
118 }
119
120 this.PriorityUrlProvider = Object.freeze({
121 addMatch: function (match) {
122 matches.set(match.token, match);
123 },
124
125 removeMatchByToken: function (token) {
126 matches.delete(token);
127 },
128
129 getMatch: function (searchToken) {
130 return Task.spawn(function* () {
131 yield promiseInitialized();
132 for (let [token, match] of matches.entries()) {
133 // Match at the beginning for now. In future an aOptions argument may
134 // allow to control the matching behavior.
135 if (token.startsWith(searchToken)) {
136 return match;
137 }
138 }
139 return null;
140 }.bind(this));
141 }
142 });

mercurial