gecko-dev/toolkit/modules/KeywordUtils.jsm

121 строка
3.7 KiB
JavaScript

/* -*- mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
"use strict";
var EXPORTED_SYMBOLS = ["KeywordUtils"];
ChromeUtils.defineModuleGetter(
this,
"PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm"
);
var KeywordUtils = {
/**
* Replaces %s or %S in the provided url or postData with the given parameter,
* acccording to the best charset for the given url.
*
* @return [url, postData]
* @throws if nor url nor postData accept a param, but a param was provided.
*/
async parseUrlAndPostData(url, postData, param) {
let hasGETParam = /%s/i.test(url);
let decodedPostData = postData ? unescape(postData) : "";
let hasPOSTParam = /%s/i.test(decodedPostData);
if (!hasGETParam && !hasPOSTParam) {
if (param) {
// If nor the url, nor postData contain parameters, but a parameter was
// provided, return the original input.
throw new Error(
"A param was provided but there's nothing to bind it to"
);
}
return [url, postData];
}
let charset = "";
const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
let matches = url.match(re);
if (matches) {
[, url, charset] = matches;
} else {
// Try to fetch a charset from History.
try {
// Will return an empty string if character-set is not found.
let pageInfo = await PlacesUtils.history.fetch(url, {
includeAnnotations: true,
});
if (pageInfo && pageInfo.annotations.has(PlacesUtils.CHARSET_ANNO)) {
charset = pageInfo.annotations.get(PlacesUtils.CHARSET_ANNO);
}
} catch (ex) {
// makeURI() throws if url is invalid.
Cu.reportError(ex);
}
}
// encodeURIComponent produces UTF-8, and cannot be used for other charsets.
// escape() works in those cases, but it doesn't uri-encode +, @, and /.
// Therefore we need to manually replace these ASCII characters by their
// encodeURIComponent result, to match the behavior of nsEscape() with
// url_XPAlphas.
let encodedParam = "";
if (charset && charset != "UTF-8") {
try {
let converter = Cc[
"@mozilla.org/intl/scriptableunicodeconverter"
].createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = charset;
encodedParam = converter.ConvertFromUnicode(param) + converter.Finish();
} catch (ex) {
encodedParam = param;
}
encodedParam = escape(encodedParam).replace(
/[+@\/]+/g,
encodeURIComponent
);
} else {
// Default charset is UTF-8
encodedParam = encodeURIComponent(param);
}
url = url.replace(/%s/g, encodedParam).replace(/%S/g, param);
if (hasPOSTParam) {
postData = decodedPostData
.replace(/%s/g, encodedParam)
.replace(/%S/g, param);
}
return [url, postData];
},
/**
* Returns a set of parameters if a keyword is registered and the search
* string can be bound to it.
*
* @param {string} keyword The typed keyword.
* @param {string} searchString The full search string, including the keyword.
* @returns { entry, url, postData }
*/
async getBindableKeyword(keyword, searchString) {
let entry = await PlacesUtils.keywords.fetch(keyword);
if (!entry) {
return {};
}
try {
let [url, postData] = await this.parseUrlAndPostData(
entry.url.href,
entry.postData,
searchString
);
return { entry, url, postData };
} catch (ex) {
return {};
}
},
};