Bug 1885565 - Part 1: Add mozac_ic_avatar_circle_24 to ui-icons r=android-reviewers...
[gecko.git] / toolkit / modules / KeywordUtils.sys.mjs
blob2765dd3ce9697258fa54abaabf1d2447f6ede68d
1 /* -*- mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 const lazy = {};
8 ChromeUtils.defineESModuleGetters(lazy, {
9   PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
10 });
12 export var KeywordUtils = {
13   /**
14    * Replaces %s or %S in the provided url or postData with the given parameter,
15    * acccording to the best charset for the given url.
16    *
17    * @return [url, postData]
18    * @throws if nor url nor postData accept a param, but a param was provided.
19    */
20   async parseUrlAndPostData(url, postData, param) {
21     let hasGETParam = /%s/i.test(url);
22     let decodedPostData = postData ? unescape(postData) : "";
23     let hasPOSTParam = /%s/i.test(decodedPostData);
25     if (!hasGETParam && !hasPOSTParam) {
26       if (param) {
27         // If nor the url, nor postData contain parameters, but a parameter was
28         // provided, return the original input.
29         throw new Error(
30           "A param was provided but there's nothing to bind it to"
31         );
32       }
33       return [url, postData];
34     }
36     let charset = "";
37     const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
38     let matches = url.match(re);
39     if (matches) {
40       [, url, charset] = matches;
41     } else {
42       // Try to fetch a charset from History.
43       try {
44         // Will return an empty string if character-set is not found.
45         let pageInfo = await lazy.PlacesUtils.history.fetch(url, {
46           includeAnnotations: true,
47         });
48         if (
49           pageInfo &&
50           pageInfo.annotations.has(lazy.PlacesUtils.CHARSET_ANNO)
51         ) {
52           charset = pageInfo.annotations.get(lazy.PlacesUtils.CHARSET_ANNO);
53         }
54       } catch (ex) {
55         // makeURI() throws if url is invalid.
56         console.error(ex);
57       }
58     }
60     // encodeURIComponent produces UTF-8, and cannot be used for other charsets.
61     // escape() works in those cases, but it doesn't uri-encode +, @, and /.
62     // Therefore we need to manually replace these ASCII characters by their
63     // encodeURIComponent result, to match the behavior of nsEscape() with
64     // url_XPAlphas.
65     let encodedParam = "";
66     if (charset && charset != "UTF-8") {
67       try {
68         let converter = Cc[
69           "@mozilla.org/intl/scriptableunicodeconverter"
70         ].createInstance(Ci.nsIScriptableUnicodeConverter);
71         converter.charset = charset;
72         encodedParam = converter.ConvertFromUnicode(param) + converter.Finish();
73       } catch (ex) {
74         encodedParam = param;
75       }
76       encodedParam = escape(encodedParam).replace(
77         /[+@\/]+/g,
78         encodeURIComponent
79       );
80     } else {
81       // Default charset is UTF-8
82       encodedParam = encodeURIComponent(param);
83     }
85     url = url.replace(/%s/g, encodedParam).replace(/%S/g, param);
86     if (hasPOSTParam) {
87       postData = decodedPostData
88         .replace(/%s/g, encodedParam)
89         .replace(/%S/g, param);
90     }
91     return [url, postData];
92   },
94   /**
95    * Returns a set of parameters if a keyword is registered and the search
96    * string can be bound to it.
97    *
98    * @param {string} keyword The typed keyword.
99    * @param {string} searchString The full search string, including the keyword.
100    * @returns { entry, url, postData }
101    */
102   async getBindableKeyword(keyword, searchString) {
103     let entry = await lazy.PlacesUtils.keywords.fetch(keyword);
104     if (!entry) {
105       return {};
106     }
108     try {
109       let [url, postData] = await this.parseUrlAndPostData(
110         entry.url.href,
111         entry.postData,
112         searchString
113       );
114       return { entry, url, postData };
115     } catch (ex) {
116       return {};
117     }
118   },