Bug 1091675 - Implement quoting to disable multi-word search in addressbook. r=mkmelin, a=me
This commit is contained in:
Родитель
eb1c1450f8
Коммит
13755795bb
|
@ -607,6 +607,74 @@ function GetSelectedDirectory()
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* There is an exact replica of this method in mailnews/.
|
||||
* We need to remove this duplication with the help of a jsm in mailnews/
|
||||
*
|
||||
* Parse the multiword search string to extract individual search terms
|
||||
* (separated on the basis of spaces) or quoted exact phrases to search
|
||||
* against multiple fields of the addressbook cards.
|
||||
*
|
||||
* @param aSearchString The full search string entered by the user.
|
||||
*
|
||||
* @return an array of separated search terms from the full search string.
|
||||
*/
|
||||
function getSearchTokens(aSearchString)
|
||||
{
|
||||
let searchString = aSearchString.trim();
|
||||
if (searchString == "")
|
||||
return searchString;
|
||||
|
||||
let quotedTerms = [];
|
||||
|
||||
// Split up multiple search words to create a *foo* and *bar* search against
|
||||
// search fields, using the OR-search template from modelQuery for each word.
|
||||
// If the search query has quoted terms as "foo bar", extract them as is.
|
||||
let startIndex;
|
||||
while ((startIndex = searchString.indexOf('"')) != -1) {
|
||||
let endIndex = searchString.indexOf('"', startIndex + 1);
|
||||
if (endIndex == -1)
|
||||
endIndex = searchString.length;
|
||||
|
||||
quotedTerms.push(searchString.substring(startIndex + 1, endIndex));
|
||||
let query = searchString.substring(0, startIndex);
|
||||
if (endIndex < searchString.length)
|
||||
query += searchString.substr(endIndex + 1);
|
||||
|
||||
searchString = query.trim();
|
||||
}
|
||||
|
||||
let searchWords = [];
|
||||
if (searchString.length != 0) {
|
||||
searchWords = quotedTerms.concat(searchString.split(/\s+/));
|
||||
} else {
|
||||
searchWords = quotedTerms;
|
||||
}
|
||||
|
||||
return searchWords;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a database model query and a list of search tokens,
|
||||
* return query URI.
|
||||
*
|
||||
* @param aModelQuery database model query
|
||||
* @param aSearchWords an array of search tokens.
|
||||
*
|
||||
* @return query URI.
|
||||
*/
|
||||
function generateQueryURI(aModelQuery, aSearchWords)
|
||||
{
|
||||
let queryURI = "";
|
||||
aSearchWords.forEach(searchWord =>
|
||||
queryURI += aModelQuery.replace(/@V/g, encodeABTermValue(searchWord)));
|
||||
|
||||
// queryURI has all the (or(...)) searches, link them up with (and(...)).
|
||||
queryURI = "?(and" + queryURI + ")";
|
||||
|
||||
return queryURI;
|
||||
}
|
||||
|
||||
function onAbClearSearch()
|
||||
{
|
||||
var searchInput = document.getElementById("peopleSearchInput");
|
||||
|
|
|
@ -154,16 +154,11 @@ function onEnterInSearchBar()
|
|||
var searchURI = GetSelectedDirectory();
|
||||
var searchInput = document.getElementById("peopleSearchInput");
|
||||
|
||||
// Split up multiple search words to create a *foo* and *bar* search against
|
||||
// search fields, using the OR-search template from gQueryURIFormat for each word.
|
||||
if (searchInput.value != "") {
|
||||
let searchWords = searchInput.value.trim().split(/\s+/);
|
||||
let queryURI = "";
|
||||
searchWords.forEach(searchWord =>
|
||||
queryURI += gQueryURIFormat.replace(/@V/g, encodeABTermValue(searchWord)));
|
||||
|
||||
// queryURI has all the (or(...)) searches, link them up with (and(...)).
|
||||
searchURI += "?(and" + queryURI + ")";
|
||||
// Use helper method to split up search query to multi-word search
|
||||
// query against multiple fields.
|
||||
if (searchInput) {
|
||||
let searchWords = getSearchTokens(searchInput.value);
|
||||
searchURI += generateQueryURI(gQueryURIFormat, searchWords);
|
||||
}
|
||||
|
||||
SetAbView(searchURI);
|
||||
|
|
|
@ -519,16 +519,11 @@ function onEnterInSearchBar()
|
|||
moz-abldapdirectory://nsdirectory.netscape.com:389/ou=People,dc=netscape,dc=com?(or(Department,=,Applications))
|
||||
*/
|
||||
var searchInput = document.getElementById("peopleSearchInput");
|
||||
if (searchInput && searchInput.value != "") {
|
||||
// Split up multiple search words to create a *foo* and *bar* search against
|
||||
// search fields, using the OR-search template from gQueryURIFormat for each word.
|
||||
let searchWords = searchInput.value.trim().split(/\s+/);
|
||||
let queryURI = "";
|
||||
searchWords.forEach(searchWord =>
|
||||
queryURI += gQueryURIFormat.replace(/@V/g, encodeABTermValue(searchWord)));
|
||||
|
||||
// queryURI has all the (or(...)) searches, link them up with (and(...)).
|
||||
searchURI += "?(and" + queryURI + ")";
|
||||
// Use helper method to split up search query to multi-word search
|
||||
// query against multiple fields.
|
||||
if (searchInput) {
|
||||
let searchWords = getSearchTokens(searchInput.value);
|
||||
searchURI += generateQueryURI(gQueryURIFormat, searchWords);
|
||||
}
|
||||
|
||||
SetAbView(searchURI);
|
||||
|
|
|
@ -334,8 +334,9 @@ nsAbAutoCompleteSearch.prototype = {
|
|||
}
|
||||
|
||||
// Array of all the terms from the fullString search query
|
||||
// (separated on the basis of spaces).
|
||||
let searchWords = fullString.split(/\s+/);
|
||||
// (separated on the basis of spaces or exact terms on the
|
||||
// basis of quotes).
|
||||
let searchWords = getSearchTokens(fullString);
|
||||
|
||||
// Find out about the comment column
|
||||
try {
|
||||
|
@ -371,14 +372,14 @@ nsAbAutoCompleteSearch.prototype = {
|
|||
// for each word separately so that each result contains all the words
|
||||
// from the fullstring in the fields of the addressbook card
|
||||
// (see bug 558931 for explanations).
|
||||
let searchQuery = "";
|
||||
let modelQuery = "(or(DisplayName,c,@V)(FirstName,c,@V)(LastName,c,@V)" +
|
||||
"(NickName,c,@V)(PrimaryEmail,c,@V)(SecondEmail,c,@V)" +
|
||||
"(and(IsMailList,=,TRUE)(Notes,c,@V)))";
|
||||
for (let searchWord of searchWords) {
|
||||
searchQuery += modelQuery.replace(/@V/g, encodeABTermValue(searchWord));
|
||||
}
|
||||
searchQuery = "?(and" + searchQuery + ")";
|
||||
// Use helper method to split up search query to multi-word search
|
||||
// query against multiple fields.
|
||||
let searchWords = getSearchTokens(fullString);
|
||||
let searchQuery = generateQueryURI(modelQuery, searchWords);
|
||||
|
||||
// Now do the searching
|
||||
let allABs = this._abManager.directories;
|
||||
|
||||
|
@ -434,6 +435,75 @@ function encodeABTermValue(aString) {
|
|||
return encodeURIComponent(aString).replace(/\(/g, "%28").replace(/\)/g, "%29");
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an exact replica of the method in abCommon.js and needs to
|
||||
* be merged to remove this duplication.
|
||||
*
|
||||
* Parse the multiword search string to extract individual search terms
|
||||
* (separated on the basis of spaces) or quoted exact phrases to search
|
||||
* against multiple fields of the addressbook cards.
|
||||
*
|
||||
* @param aSearchString The full search string entered by the user.
|
||||
*
|
||||
* @return an array of separated search terms from the full search string.
|
||||
*/
|
||||
function getSearchTokens(aSearchString)
|
||||
{
|
||||
let searchString = aSearchString.trim();
|
||||
|
||||
if (searchString == "")
|
||||
return searchString;
|
||||
|
||||
let quotedTerms = [];
|
||||
|
||||
// Split up multiple search words to create a *foo* and *bar* search against
|
||||
// search fields, using the OR-search template from modelQuery for each word.
|
||||
// If the search query has quoted terms as "foo bar", extract them as is.
|
||||
let startIndex;
|
||||
while ((startIndex = searchString.indexOf('"')) != -1) {
|
||||
let endIndex = searchString.indexOf('"', startIndex + 1);
|
||||
if (endIndex == -1)
|
||||
endIndex = searchString.length;
|
||||
|
||||
quotedTerms.push(searchString.substring(startIndex + 1, endIndex));
|
||||
let query = searchString.substring(0, startIndex);
|
||||
if (endIndex < searchString.length)
|
||||
query += searchString.substr(endIndex + 1);
|
||||
|
||||
searchString = query.trim();
|
||||
}
|
||||
|
||||
let searchWords = [];
|
||||
if (searchString.length != 0) {
|
||||
searchWords = quotedTerms.concat(searchString.split(/\s+/));
|
||||
} else {
|
||||
searchWords = quotedTerms;
|
||||
}
|
||||
|
||||
return searchWords;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a database model query and a list of search tokens,
|
||||
* return query URI.
|
||||
*
|
||||
* @param aModelQuery database model query
|
||||
* @param aSearchWords an array of search tokens.
|
||||
*
|
||||
* @return query URI.
|
||||
*/
|
||||
function generateQueryURI(aModelQuery, aSearchWords)
|
||||
{
|
||||
let queryURI = "";
|
||||
aSearchWords.forEach(searchWord =>
|
||||
queryURI += aModelQuery.replace(/@V/g, encodeABTermValue(searchWord)));
|
||||
|
||||
// queryURI has all the (or(...)) searches, link them up with (and(...)).
|
||||
queryURI = "?(and" + queryURI + ")";
|
||||
|
||||
return queryURI;
|
||||
}
|
||||
|
||||
// Module
|
||||
|
||||
var components = [nsAbAutoCompleteSearch];
|
||||
|
|
|
@ -59,6 +59,24 @@ const cards = [
|
|||
{ // 10
|
||||
email: "10@example.com", displayName: "däsh l18n",
|
||||
popularityIndex: 0, value: "däsh l18n <10@example.com>"
|
||||
},
|
||||
|
||||
{ // 11
|
||||
email: "11@example.com", displayName: "paul mary",
|
||||
popularityIndex: 0, firstName: "paul", lastName: "mary meyer",
|
||||
value: "paul mary <11@example.com>"
|
||||
},
|
||||
|
||||
{ // 12
|
||||
email: "12@example.com", displayName: "paul meyer",
|
||||
popularityIndex: 0, firstName: "paul", lastName: "mary meyer",
|
||||
value: "paul meyer <12@example.com>"
|
||||
},
|
||||
|
||||
{ // 13
|
||||
email: "13@example.com", displayName: "mr robert downey (exp dev)",
|
||||
popularityIndex: 0, firstName: "robert", lastName: "downey",
|
||||
value: "mr robert downey (exp dev) <13@example.com>"
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -70,7 +88,10 @@ const inputs = [
|
|||
{ search: "xx", expected: [0, 5] },
|
||||
{ search: "jan", expected: [1, 3] },
|
||||
{ search: "sh", expected: [2, 10, 7] },
|
||||
{ search: "st", expected: [3,8] }
|
||||
{ search: "st", expected: [3,8] },
|
||||
{ search: "paul mary", expected: [11, 12] },
|
||||
{ search: "\"paul mary\"", expected: [11] },
|
||||
{ search: "\"robert downey\" mr \"exp dev\"", expected: [13] }
|
||||
];
|
||||
|
||||
function acObserver() {}
|
||||
|
@ -103,6 +124,7 @@ function run_test()
|
|||
card.displayName = element.displayName;
|
||||
card.setProperty("PopularityIndex", element.popularityIndex);
|
||||
card.firstName = element.firstName;
|
||||
card.lastName = element.lastName;
|
||||
|
||||
ab.addCard(card);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче