UrlbarProviderHistoryUrlHeuristic.sys.mjs (3838B)
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 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /** 6 * This module exports a provider that provides a heuristic result. The result 7 * will be provided if the query requests the URL and the URL is in Places with 8 * the page title. 9 */ 10 11 import { 12 UrlbarProvider, 13 UrlbarUtils, 14 } from "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs"; 15 16 const lazy = {}; 17 18 ChromeUtils.defineESModuleGetters(lazy, { 19 PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs", 20 UrlbarResult: "moz-src:///browser/components/urlbar/UrlbarResult.sys.mjs", 21 }); 22 23 /** 24 * Class used to create the provider. 25 */ 26 export class UrlbarProviderHistoryUrlHeuristic extends UrlbarProvider { 27 /** 28 * @returns {Values<typeof UrlbarUtils.PROVIDER_TYPE>} 29 */ 30 get type() { 31 return UrlbarUtils.PROVIDER_TYPE.HEURISTIC; 32 } 33 34 /** 35 * Whether this provider should be invoked for the given context. 36 * If this method returns false, the providers manager won't start a query 37 * with this provider, to save on resources. 38 * 39 * @param {UrlbarQueryContext} queryContext The query context object 40 */ 41 async isActive(queryContext) { 42 // For better performance, this provider tries to return a result only when 43 // the input value can become a URL of the http(s) protocol and its length 44 // is less than `MAX_TEXT_LENGTH`. That way its SQL query avoids calling 45 // `hash()` on atypical or very long URLs. 46 return ( 47 queryContext.fixupInfo?.href && 48 !queryContext.fixupInfo.isSearch && 49 queryContext.fixupInfo.scheme.startsWith("http") && 50 queryContext.fixupInfo.href.length <= UrlbarUtils.MAX_TEXT_LENGTH 51 ); 52 } 53 54 /** 55 * Starts querying. 56 * 57 * @param {UrlbarQueryContext} queryContext 58 * @param {(provider: UrlbarProvider, result: UrlbarResult) => void} addCallback 59 * Callback invoked by the provider to add a new result. 60 */ 61 async startQuery(queryContext, addCallback) { 62 const instance = this.queryInstance; 63 const result = await this.#getResult(queryContext); 64 if (result && instance === this.queryInstance) { 65 addCallback(this, result); 66 } 67 } 68 69 async #getResult(queryContext) { 70 const inputedURL = queryContext.fixupInfo.href; 71 const [strippedURL] = UrlbarUtils.stripPrefixAndTrim(inputedURL, { 72 stripHttp: true, 73 stripHttps: true, 74 stripWww: true, 75 trimEmptyQuery: true, 76 }); 77 const connection = await lazy.PlacesUtils.promiseLargeCacheDBConnection(); 78 const resultSet = await connection.executeCached( 79 ` 80 SELECT url, IIF(last_visit_date NOTNULL, h.title, b.title) AS _title, frecency 81 FROM moz_places h 82 LEFT JOIN moz_bookmarks b ON b.fk = h.id 83 WHERE 84 url_hash IN ( 85 hash('https://' || :strippedURL), 86 hash('https://www.' || :strippedURL), 87 hash('http://' || :strippedURL), 88 hash('http://www.' || :strippedURL) 89 ) 90 AND frecency <> 0 91 ORDER BY 92 _title NOTNULL DESC, 93 _title || '/' <> :strippedURL DESC, 94 h.url = :inputedURL DESC, 95 h.frecency DESC, 96 h.id DESC 97 LIMIT 1 98 `, 99 { inputedURL, strippedURL } 100 ); 101 102 if (!resultSet.length) { 103 return null; 104 } 105 106 const title = resultSet[0].getResultByName("_title"); 107 if (!title) { 108 return null; 109 } 110 111 return new lazy.UrlbarResult({ 112 type: UrlbarUtils.RESULT_TYPE.URL, 113 source: UrlbarUtils.RESULT_SOURCE.HISTORY, 114 heuristic: true, 115 payload: { 116 url: inputedURL, 117 title, 118 icon: UrlbarUtils.getIconForUrl(resultSet[0].getResultByName("url")), 119 }, 120 highlights: { 121 url: UrlbarUtils.HIGHLIGHT.TYPED, 122 }, 123 }); 124 } 125 }