toolkit/components/search/nsSearchSuggestions.js

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 const SEARCH_RESPONSE_SUGGESTION_JSON = "application/x-suggestions+json";
michael@0 6
michael@0 7 const BROWSER_SUGGEST_PREF = "browser.search.suggest.enabled";
michael@0 8 const XPCOM_SHUTDOWN_TOPIC = "xpcom-shutdown";
michael@0 9 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
michael@0 10
michael@0 11 const Cc = Components.classes;
michael@0 12 const Ci = Components.interfaces;
michael@0 13 const Cr = Components.results;
michael@0 14 const Cu = Components.utils;
michael@0 15
michael@0 16 const HTTP_OK = 200;
michael@0 17 const HTTP_INTERNAL_SERVER_ERROR = 500;
michael@0 18 const HTTP_BAD_GATEWAY = 502;
michael@0 19 const HTTP_SERVICE_UNAVAILABLE = 503;
michael@0 20
michael@0 21 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 22 Cu.import("resource://gre/modules/nsFormAutoCompleteResult.jsm");
michael@0 23 Cu.import("resource://gre/modules/Services.jsm");
michael@0 24
michael@0 25 /**
michael@0 26 * SuggestAutoComplete is a base class that implements nsIAutoCompleteSearch
michael@0 27 * and can collect results for a given search by using the search URL supplied
michael@0 28 * by the subclass. We do it this way since the AutoCompleteController in
michael@0 29 * Mozilla requires a unique XPCOM Service for every search provider, even if
michael@0 30 * the logic for two providers is identical.
michael@0 31 * @constructor
michael@0 32 */
michael@0 33 function SuggestAutoComplete() {
michael@0 34 this._init();
michael@0 35 }
michael@0 36 SuggestAutoComplete.prototype = {
michael@0 37
michael@0 38 _init: function() {
michael@0 39 this._addObservers();
michael@0 40 this._suggestEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF);
michael@0 41 },
michael@0 42
michael@0 43 get _suggestionLabel() {
michael@0 44 delete this._suggestionLabel;
michael@0 45 let bundle = Services.strings.createBundle("chrome://global/locale/search/search.properties");
michael@0 46 return this._suggestionLabel = bundle.GetStringFromName("suggestion_label");
michael@0 47 },
michael@0 48
michael@0 49 /**
michael@0 50 * Search suggestions will be shown if this._suggestEnabled is true.
michael@0 51 */
michael@0 52 _suggestEnabled: null,
michael@0 53
michael@0 54 /*************************************************************************
michael@0 55 * Server request backoff implementation fields below
michael@0 56 * These allow us to throttle requests if the server is getting hammered.
michael@0 57 **************************************************************************/
michael@0 58
michael@0 59 /**
michael@0 60 * This is an array that contains the timestamps (in unixtime) of
michael@0 61 * the last few backoff-triggering errors.
michael@0 62 */
michael@0 63 _serverErrorLog: [],
michael@0 64
michael@0 65 /**
michael@0 66 * If we receive this number of backoff errors within the amount of time
michael@0 67 * specified by _serverErrorPeriod, then we initiate backoff.
michael@0 68 */
michael@0 69 _maxErrorsBeforeBackoff: 3,
michael@0 70
michael@0 71 /**
michael@0 72 * If we receive enough consecutive errors (where "enough" is defined by
michael@0 73 * _maxErrorsBeforeBackoff above) within this time period,
michael@0 74 * we trigger the backoff behavior.
michael@0 75 */
michael@0 76 _serverErrorPeriod: 600000, // 10 minutes in milliseconds
michael@0 77
michael@0 78 /**
michael@0 79 * If we get another backoff error immediately after timeout, we increase the
michael@0 80 * backoff to (2 x old period) + this value.
michael@0 81 */
michael@0 82 _serverErrorTimeoutIncrement: 600000, // 10 minutes in milliseconds
michael@0 83
michael@0 84 /**
michael@0 85 * The current amount of time to wait before trying a server request
michael@0 86 * after receiving a backoff error.
michael@0 87 */
michael@0 88 _serverErrorTimeout: 0,
michael@0 89
michael@0 90 /**
michael@0 91 * Time (in unixtime) after which we're allowed to try requesting again.
michael@0 92 */
michael@0 93 _nextRequestTime: 0,
michael@0 94
michael@0 95 /**
michael@0 96 * The last engine we requested against (so that we can tell if the
michael@0 97 * user switched engines).
michael@0 98 */
michael@0 99 _serverErrorEngine: null,
michael@0 100
michael@0 101 /**
michael@0 102 * The XMLHttpRequest object.
michael@0 103 * @private
michael@0 104 */
michael@0 105 _request: null,
michael@0 106
michael@0 107 /**
michael@0 108 * The object implementing nsIAutoCompleteObserver that we notify when
michael@0 109 * we have found results
michael@0 110 * @private
michael@0 111 */
michael@0 112 _listener: null,
michael@0 113
michael@0 114 /**
michael@0 115 * If this is true, we'll integrate form history results with the
michael@0 116 * suggest results.
michael@0 117 */
michael@0 118 _includeFormHistory: true,
michael@0 119
michael@0 120 /**
michael@0 121 * True if a request for remote suggestions was sent. This is used to
michael@0 122 * differentiate between the "_request is null because the request has
michael@0 123 * already returned a result" and "_request is null because no request was
michael@0 124 * sent" cases.
michael@0 125 */
michael@0 126 _sentSuggestRequest: false,
michael@0 127
michael@0 128 /**
michael@0 129 * This is the callback for the suggest timeout timer.
michael@0 130 */
michael@0 131 notify: function SAC_notify(timer) {
michael@0 132 // FIXME: bug 387341
michael@0 133 // Need to break the cycle between us and the timer.
michael@0 134 this._formHistoryTimer = null;
michael@0 135
michael@0 136 // If this._listener is null, we've already sent out suggest results, so
michael@0 137 // nothing left to do here.
michael@0 138 if (!this._listener)
michael@0 139 return;
michael@0 140
michael@0 141 // Otherwise, the XMLHTTPRequest for suggest results is taking too long,
michael@0 142 // so send out the form history results and cancel the request.
michael@0 143 this._listener.onSearchResult(this, this._formHistoryResult);
michael@0 144 this._reset();
michael@0 145 },
michael@0 146
michael@0 147 /**
michael@0 148 * This determines how long (in ms) we should wait before giving up on
michael@0 149 * the suggestions and just showing local form history results.
michael@0 150 */
michael@0 151 _suggestionTimeout: 500,
michael@0 152
michael@0 153 /**
michael@0 154 * This is the callback for that the form history service uses to
michael@0 155 * send us results.
michael@0 156 */
michael@0 157 onSearchResult: function SAC_onSearchResult(search, result) {
michael@0 158 this._formHistoryResult = result;
michael@0 159
michael@0 160 if (this._request) {
michael@0 161 // We still have a pending request, wait a bit to give it a chance to
michael@0 162 // finish.
michael@0 163 this._formHistoryTimer = Cc["@mozilla.org/timer;1"].
michael@0 164 createInstance(Ci.nsITimer);
michael@0 165 this._formHistoryTimer.initWithCallback(this, this._suggestionTimeout,
michael@0 166 Ci.nsITimer.TYPE_ONE_SHOT);
michael@0 167 } else if (!this._sentSuggestRequest) {
michael@0 168 // We didn't send a request, so just send back the form history results.
michael@0 169 this._listener.onSearchResult(this, this._formHistoryResult);
michael@0 170 this._reset();
michael@0 171 }
michael@0 172 },
michael@0 173
michael@0 174 /**
michael@0 175 * This is the URI that the last suggest request was sent to.
michael@0 176 */
michael@0 177 _suggestURI: null,
michael@0 178
michael@0 179 /**
michael@0 180 * Autocomplete results from the form history service get stored here.
michael@0 181 */
michael@0 182 _formHistoryResult: null,
michael@0 183
michael@0 184 /**
michael@0 185 * This holds the suggest server timeout timer, if applicable.
michael@0 186 */
michael@0 187 _formHistoryTimer: null,
michael@0 188
michael@0 189 /**
michael@0 190 * Maximum number of history items displayed. This is capped at 7
michael@0 191 * because the primary consumer (Firefox search bar) displays 10 rows
michael@0 192 * by default, and so we want to leave some space for suggestions
michael@0 193 * to be visible.
michael@0 194 */
michael@0 195 _historyLimit: 7,
michael@0 196
michael@0 197 /**
michael@0 198 * This clears all the per-request state.
michael@0 199 */
michael@0 200 _reset: function SAC_reset() {
michael@0 201 // Don't let go of our listener and form history result if the timer is
michael@0 202 // still pending, the timer will call _reset() when it fires.
michael@0 203 if (!this._formHistoryTimer) {
michael@0 204 this._listener = null;
michael@0 205 this._formHistoryResult = null;
michael@0 206 }
michael@0 207 this._request = null;
michael@0 208 },
michael@0 209
michael@0 210 /**
michael@0 211 * This sends an autocompletion request to the form history service,
michael@0 212 * which will call onSearchResults with the results of the query.
michael@0 213 */
michael@0 214 _startHistorySearch: function SAC_SHSearch(searchString, searchParam) {
michael@0 215 var formHistory =
michael@0 216 Cc["@mozilla.org/autocomplete/search;1?name=form-history"].
michael@0 217 createInstance(Ci.nsIAutoCompleteSearch);
michael@0 218 formHistory.startSearch(searchString, searchParam, this._formHistoryResult, this);
michael@0 219 },
michael@0 220
michael@0 221 /**
michael@0 222 * Makes a note of the fact that we've received a backoff-triggering
michael@0 223 * response, so that we can adjust the backoff behavior appropriately.
michael@0 224 */
michael@0 225 _noteServerError: function SAC__noteServeError() {
michael@0 226 var currentTime = Date.now();
michael@0 227
michael@0 228 this._serverErrorLog.push(currentTime);
michael@0 229 if (this._serverErrorLog.length > this._maxErrorsBeforeBackoff)
michael@0 230 this._serverErrorLog.shift();
michael@0 231
michael@0 232 if ((this._serverErrorLog.length == this._maxErrorsBeforeBackoff) &&
michael@0 233 ((currentTime - this._serverErrorLog[0]) < this._serverErrorPeriod)) {
michael@0 234 // increase timeout, and then don't request until timeout is over
michael@0 235 this._serverErrorTimeout = (this._serverErrorTimeout * 2) +
michael@0 236 this._serverErrorTimeoutIncrement;
michael@0 237 this._nextRequestTime = currentTime + this._serverErrorTimeout;
michael@0 238 }
michael@0 239 },
michael@0 240
michael@0 241 /**
michael@0 242 * Resets the backoff behavior; called when we get a successful response.
michael@0 243 */
michael@0 244 _clearServerErrors: function SAC__clearServerErrors() {
michael@0 245 this._serverErrorLog = [];
michael@0 246 this._serverErrorTimeout = 0;
michael@0 247 this._nextRequestTime = 0;
michael@0 248 },
michael@0 249
michael@0 250 /**
michael@0 251 * This checks whether we should send a server request (i.e. we're not
michael@0 252 * in a error-triggered backoff period.
michael@0 253 *
michael@0 254 * @private
michael@0 255 */
michael@0 256 _okToRequest: function SAC__okToRequest() {
michael@0 257 return Date.now() > this._nextRequestTime;
michael@0 258 },
michael@0 259
michael@0 260 /**
michael@0 261 * This checks to see if the new search engine is different
michael@0 262 * from the previous one, and if so clears any error state that might
michael@0 263 * have accumulated for the old engine.
michael@0 264 *
michael@0 265 * @param engine The engine that the suggestion request would be sent to.
michael@0 266 * @private
michael@0 267 */
michael@0 268 _checkForEngineSwitch: function SAC__checkForEngineSwitch(engine) {
michael@0 269 if (engine == this._serverErrorEngine)
michael@0 270 return;
michael@0 271
michael@0 272 // must've switched search providers, clear old errors
michael@0 273 this._serverErrorEngine = engine;
michael@0 274 this._clearServerErrors();
michael@0 275 },
michael@0 276
michael@0 277 /**
michael@0 278 * This returns true if the status code of the HTTP response
michael@0 279 * represents a backoff-triggering error.
michael@0 280 *
michael@0 281 * @param status The status code from the HTTP response
michael@0 282 * @private
michael@0 283 */
michael@0 284 _isBackoffError: function SAC__isBackoffError(status) {
michael@0 285 return ((status == HTTP_INTERNAL_SERVER_ERROR) ||
michael@0 286 (status == HTTP_BAD_GATEWAY) ||
michael@0 287 (status == HTTP_SERVICE_UNAVAILABLE));
michael@0 288 },
michael@0 289
michael@0 290 /**
michael@0 291 * Called when the 'readyState' of the XMLHttpRequest changes. We only care
michael@0 292 * about state 4 (COMPLETED) - handle the response data.
michael@0 293 * @private
michael@0 294 */
michael@0 295 onReadyStateChange: function() {
michael@0 296 // xxx use the real const here
michael@0 297 if (!this._request || this._request.readyState != 4)
michael@0 298 return;
michael@0 299
michael@0 300 try {
michael@0 301 var status = this._request.status;
michael@0 302 } catch (e) {
michael@0 303 // The XML HttpRequest can throw NS_ERROR_NOT_AVAILABLE.
michael@0 304 return;
michael@0 305 }
michael@0 306
michael@0 307 if (this._isBackoffError(status)) {
michael@0 308 this._noteServerError();
michael@0 309 return;
michael@0 310 }
michael@0 311
michael@0 312 var responseText = this._request.responseText;
michael@0 313 if (status != HTTP_OK || responseText == "")
michael@0 314 return;
michael@0 315
michael@0 316 this._clearServerErrors();
michael@0 317
michael@0 318 try {
michael@0 319 var serverResults = JSON.parse(responseText);
michael@0 320 } catch(ex) {
michael@0 321 Components.utils.reportError("Failed to parse JSON from " + this._suggestURI.spec + ": " + ex);
michael@0 322 return;
michael@0 323 }
michael@0 324
michael@0 325 var searchString = serverResults[0] || "";
michael@0 326 var results = serverResults[1] || [];
michael@0 327
michael@0 328 var comments = []; // "comments" column values for suggestions
michael@0 329 var historyResults = [];
michael@0 330 var historyComments = [];
michael@0 331
michael@0 332 // If form history is enabled and has results, add them to the list.
michael@0 333 if (this._includeFormHistory && this._formHistoryResult &&
michael@0 334 (this._formHistoryResult.searchResult ==
michael@0 335 Ci.nsIAutoCompleteResult.RESULT_SUCCESS)) {
michael@0 336 var maxHistoryItems = Math.min(this._formHistoryResult.matchCount, this._historyLimit);
michael@0 337 for (var i = 0; i < maxHistoryItems; ++i) {
michael@0 338 var term = this._formHistoryResult.getValueAt(i);
michael@0 339
michael@0 340 // we don't want things to appear in both history and suggestions
michael@0 341 var dupIndex = results.indexOf(term);
michael@0 342 if (dupIndex != -1)
michael@0 343 results.splice(dupIndex, 1);
michael@0 344
michael@0 345 historyResults.push(term);
michael@0 346 historyComments.push("");
michael@0 347 }
michael@0 348 }
michael@0 349
michael@0 350 // fill out the comment column for the suggestions
michael@0 351 for (var i = 0; i < results.length; ++i)
michael@0 352 comments.push("");
michael@0 353
michael@0 354 // if we have any suggestions, put a label at the top
michael@0 355 if (comments.length > 0)
michael@0 356 comments[0] = this._suggestionLabel;
michael@0 357
michael@0 358 // now put the history results above the suggestions
michael@0 359 var finalResults = historyResults.concat(results);
michael@0 360 var finalComments = historyComments.concat(comments);
michael@0 361
michael@0 362 // Notify the FE of our new results
michael@0 363 this.onResultsReady(searchString, finalResults, finalComments,
michael@0 364 this._formHistoryResult);
michael@0 365
michael@0 366 // Reset our state for next time.
michael@0 367 this._reset();
michael@0 368 },
michael@0 369
michael@0 370 /**
michael@0 371 * Notifies the front end of new results.
michael@0 372 * @param searchString the user's query string
michael@0 373 * @param results an array of results to the search
michael@0 374 * @param comments an array of metadata corresponding to the results
michael@0 375 * @private
michael@0 376 */
michael@0 377 onResultsReady: function(searchString, results, comments,
michael@0 378 formHistoryResult) {
michael@0 379 if (this._listener) {
michael@0 380 var result = new FormAutoCompleteResult(
michael@0 381 searchString,
michael@0 382 Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
michael@0 383 0,
michael@0 384 "",
michael@0 385 results,
michael@0 386 results,
michael@0 387 comments,
michael@0 388 formHistoryResult);
michael@0 389
michael@0 390 this._listener.onSearchResult(this, result);
michael@0 391
michael@0 392 // Null out listener to make sure we don't notify it twice, in case our
michael@0 393 // timer callback still hasn't run.
michael@0 394 this._listener = null;
michael@0 395 }
michael@0 396 },
michael@0 397
michael@0 398 /**
michael@0 399 * Initiates the search result gathering process. Part of
michael@0 400 * nsIAutoCompleteSearch implementation.
michael@0 401 *
michael@0 402 * @param searchString the user's query string
michael@0 403 * @param searchParam unused, "an extra parameter"; even though
michael@0 404 * this parameter and the next are unused, pass
michael@0 405 * them through in case the form history
michael@0 406 * service wants them
michael@0 407 * @param previousResult unused, a client-cached store of the previous
michael@0 408 * generated resultset for faster searching.
michael@0 409 * @param listener object implementing nsIAutoCompleteObserver which
michael@0 410 * we notify when results are ready.
michael@0 411 */
michael@0 412 startSearch: function(searchString, searchParam, previousResult, listener) {
michael@0 413 // Don't reuse a previous form history result when it no longer applies.
michael@0 414 if (!previousResult)
michael@0 415 this._formHistoryResult = null;
michael@0 416
michael@0 417 var formHistorySearchParam = searchParam.split("|")[0];
michael@0 418
michael@0 419 // Receive the information about the privacy mode of the window to which
michael@0 420 // this search box belongs. The front-end's search.xml bindings passes this
michael@0 421 // information in the searchParam parameter. The alternative would have
michael@0 422 // been to modify nsIAutoCompleteSearch to add an argument to startSearch
michael@0 423 // and patch all of autocomplete to be aware of this, but the searchParam
michael@0 424 // argument is already an opaque argument, so this solution is hopefully
michael@0 425 // less hackish (although still gross.)
michael@0 426 var privacyMode = (searchParam.split("|")[1] == "private");
michael@0 427
michael@0 428 // Start search immediately if possible, otherwise once the search
michael@0 429 // service is initialized
michael@0 430 if (Services.search.isInitialized) {
michael@0 431 this._triggerSearch(searchString, formHistorySearchParam, listener, privacyMode);
michael@0 432 return;
michael@0 433 }
michael@0 434
michael@0 435 Services.search.init((function startSearch_cb(aResult) {
michael@0 436 if (!Components.isSuccessCode(aResult)) {
michael@0 437 Cu.reportError("Could not initialize search service, bailing out: " + aResult);
michael@0 438 return;
michael@0 439 }
michael@0 440 this._triggerSearch(searchString, formHistorySearchParam, listener, privacyMode);
michael@0 441 }).bind(this));
michael@0 442 },
michael@0 443
michael@0 444 /**
michael@0 445 * Actual implementation of search.
michael@0 446 */
michael@0 447 _triggerSearch: function(searchString, searchParam, listener, privacyMode) {
michael@0 448 // If there's an existing request, stop it. There is no smart filtering
michael@0 449 // here as there is when looking through history/form data because the
michael@0 450 // result set returned by the server is different for every typed value -
michael@0 451 // "ocean breathes" does not return a subset of the results returned for
michael@0 452 // "ocean", for example. This does nothing if there is no current request.
michael@0 453 this.stopSearch();
michael@0 454
michael@0 455 this._listener = listener;
michael@0 456
michael@0 457 var engine = Services.search.currentEngine;
michael@0 458
michael@0 459 this._checkForEngineSwitch(engine);
michael@0 460
michael@0 461 if (!searchString ||
michael@0 462 !this._suggestEnabled ||
michael@0 463 !engine.supportsResponseType(SEARCH_RESPONSE_SUGGESTION_JSON) ||
michael@0 464 !this._okToRequest()) {
michael@0 465 // We have an empty search string (user pressed down arrow to see
michael@0 466 // history), or search suggestions are disabled, or the current engine
michael@0 467 // has no suggest functionality, or we're in backoff mode; so just use
michael@0 468 // local history.
michael@0 469 this._sentSuggestRequest = false;
michael@0 470 this._startHistorySearch(searchString, searchParam);
michael@0 471 return;
michael@0 472 }
michael@0 473
michael@0 474 // Actually do the search
michael@0 475 this._request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
michael@0 476 createInstance(Ci.nsIXMLHttpRequest);
michael@0 477 var submission = engine.getSubmission(searchString,
michael@0 478 SEARCH_RESPONSE_SUGGESTION_JSON);
michael@0 479 this._suggestURI = submission.uri;
michael@0 480 var method = (submission.postData ? "POST" : "GET");
michael@0 481 this._request.open(method, this._suggestURI.spec, true);
michael@0 482 this._request.channel.notificationCallbacks = new AuthPromptOverride();
michael@0 483 if (this._request.channel instanceof Ci.nsIPrivateBrowsingChannel) {
michael@0 484 this._request.channel.setPrivate(privacyMode);
michael@0 485 }
michael@0 486
michael@0 487 var self = this;
michael@0 488 function onReadyStateChange() {
michael@0 489 self.onReadyStateChange();
michael@0 490 }
michael@0 491 this._request.onreadystatechange = onReadyStateChange;
michael@0 492 this._request.send(submission.postData);
michael@0 493
michael@0 494 if (this._includeFormHistory) {
michael@0 495 this._sentSuggestRequest = true;
michael@0 496 this._startHistorySearch(searchString, searchParam);
michael@0 497 }
michael@0 498 },
michael@0 499
michael@0 500 /**
michael@0 501 * Ends the search result gathering process. Part of nsIAutoCompleteSearch
michael@0 502 * implementation.
michael@0 503 */
michael@0 504 stopSearch: function() {
michael@0 505 if (this._request) {
michael@0 506 this._request.abort();
michael@0 507 this._reset();
michael@0 508 }
michael@0 509 },
michael@0 510
michael@0 511 /**
michael@0 512 * nsIObserver
michael@0 513 */
michael@0 514 observe: function SAC_observe(aSubject, aTopic, aData) {
michael@0 515 switch (aTopic) {
michael@0 516 case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
michael@0 517 this._suggestEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF);
michael@0 518 break;
michael@0 519 case XPCOM_SHUTDOWN_TOPIC:
michael@0 520 this._removeObservers();
michael@0 521 break;
michael@0 522 }
michael@0 523 },
michael@0 524
michael@0 525 _addObservers: function SAC_addObservers() {
michael@0 526 Services.prefs.addObserver(BROWSER_SUGGEST_PREF, this, false);
michael@0 527
michael@0 528 Services.obs.addObserver(this, XPCOM_SHUTDOWN_TOPIC, false);
michael@0 529 },
michael@0 530
michael@0 531 _removeObservers: function SAC_removeObservers() {
michael@0 532 Services.prefs.removeObserver(BROWSER_SUGGEST_PREF, this);
michael@0 533
michael@0 534 Services.obs.removeObserver(this, XPCOM_SHUTDOWN_TOPIC);
michael@0 535 },
michael@0 536
michael@0 537 // nsISupports
michael@0 538 QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteSearch,
michael@0 539 Ci.nsIAutoCompleteObserver])
michael@0 540 };
michael@0 541
michael@0 542 function AuthPromptOverride() {
michael@0 543 }
michael@0 544 AuthPromptOverride.prototype = {
michael@0 545 // nsIAuthPromptProvider
michael@0 546 getAuthPrompt: function (reason, iid) {
michael@0 547 // Return a no-op nsIAuthPrompt2 implementation.
michael@0 548 return {
michael@0 549 promptAuth: function () {
michael@0 550 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
michael@0 551 },
michael@0 552 asyncPromptAuth: function () {
michael@0 553 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
michael@0 554 }
michael@0 555 };
michael@0 556 },
michael@0 557
michael@0 558 // nsIInterfaceRequestor
michael@0 559 getInterface: function SSLL_getInterface(iid) {
michael@0 560 return this.QueryInterface(iid);
michael@0 561 },
michael@0 562
michael@0 563 // nsISupports
michael@0 564 QueryInterface: XPCOMUtils.generateQI([Ci.nsIAuthPromptProvider,
michael@0 565 Ci.nsIInterfaceRequestor])
michael@0 566 };
michael@0 567 /**
michael@0 568 * SearchSuggestAutoComplete is a service implementation that handles suggest
michael@0 569 * results specific to web searches.
michael@0 570 * @constructor
michael@0 571 */
michael@0 572 function SearchSuggestAutoComplete() {
michael@0 573 // This calls _init() in the parent class (SuggestAutoComplete) via the
michael@0 574 // prototype, below.
michael@0 575 this._init();
michael@0 576 }
michael@0 577 SearchSuggestAutoComplete.prototype = {
michael@0 578 classID: Components.ID("{aa892eb4-ffbf-477d-9f9a-06c995ae9f27}"),
michael@0 579 __proto__: SuggestAutoComplete.prototype,
michael@0 580 serviceURL: ""
michael@0 581 };
michael@0 582
michael@0 583 var component = [SearchSuggestAutoComplete];
michael@0 584 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component);

mercurial