summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.cc45
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.h27
-rw-r--r--chrome/browser/bookmarks/bookmark_utils_unittest.cc143
-rw-r--r--chrome/browser/extensions/api/bookmarks/bookmarks_api.cc34
-rw-r--r--chrome/common/extensions/api/bookmarks.json32
5 files changed, 244 insertions, 37 deletions
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
index 0c4cd01..f2397ac 100644
--- a/chrome/browser/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -95,6 +95,9 @@ bool PruneInvisibleFolders(const BookmarkNode* node) {
namespace bookmark_utils {
+QueryFields::QueryFields() {}
+QueryFields::~QueryFields() {}
+
void CloneBookmarkNode(BookmarkModel* model,
const std::vector<BookmarkNodeData::Element>& elements,
const BookmarkNode* parent,
@@ -216,25 +219,41 @@ bool MoreRecentlyAdded(const BookmarkNode* n1, const BookmarkNode* n2) {
return n1->date_added() > n2->date_added();
}
-void GetBookmarksContainingText(BookmarkModel* model,
- const base::string16& text,
- size_t max_count,
- const std::string& languages,
- std::vector<const BookmarkNode*>* nodes) {
- std::vector<base::string16> words;
+void GetBookmarksMatchingProperties(BookmarkModel* model,
+ const QueryFields& query,
+ size_t max_count,
+ const std::string& languages,
+ std::vector<const BookmarkNode*>* nodes) {
+ std::vector<base::string16> query_words;
QueryParser parser;
- parser.ParseQueryWords(base::i18n::ToLower(text), &words);
- if (words.empty())
- return;
+ if (query.word_phrase_query) {
+ parser.ParseQueryWords(base::i18n::ToLower(*query.word_phrase_query),
+ &query_words);
+ }
ui::TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
while (iterator.has_next()) {
const BookmarkNode* node = iterator.Next();
- if (DoesBookmarkContainWords(node, words, languages)) {
- nodes->push_back(node);
- if (nodes->size() == max_count)
- return;
+ if (!query_words.empty() &&
+ !DoesBookmarkContainWords(node, query_words, languages)) {
+ continue;
}
+ if (query.url) {
+ // Check against bare url spec and IDN-decoded url.
+ if (!node->is_url() ||
+ !(UTF8ToUTF16(node->url().spec()) == *query.url ||
+ net::FormatUrl(
+ node->url(), languages, net::kFormatUrlOmitNothing,
+ net::UnescapeRule::NORMAL, NULL, NULL, NULL) == *query.url)) {
+ continue;
+ }
+ }
+ if (query.title && node->GetTitle() != *query.title)
+ continue;
+
+ nodes->push_back(node);
+ if (nodes->size() == max_count)
+ return;
}
}
diff --git a/chrome/browser/bookmarks/bookmark_utils.h b/chrome/browser/bookmarks/bookmark_utils.h
index 49272f9..fa5086d 100644
--- a/chrome/browser/bookmarks/bookmark_utils.h
+++ b/chrome/browser/bookmarks/bookmark_utils.h
@@ -22,6 +22,16 @@ class PrefRegistrySyncable;
// that show bookmarks: bookmark manager, bookmark bar view ...
namespace bookmark_utils {
+// Fields to use when finding matching bookmarks.
+struct QueryFields {
+ QueryFields();
+ ~QueryFields();
+
+ scoped_ptr<base::string16> word_phrase_query;
+ scoped_ptr<base::string16> url;
+ scoped_ptr<base::string16> title;
+};
+
// Clones bookmark node, adding newly created nodes to |parent| starting at
// |index_to_add_at|. If |reset_node_times| is true cloned bookmarks and
// folders will receive new creation times and folder modification times
@@ -63,14 +73,15 @@ void GetMostRecentlyAddedEntries(BookmarkModel* model,
// Returns true if |n1| was added more recently than |n2|.
bool MoreRecentlyAdded(const BookmarkNode* n1, const BookmarkNode* n2);
-// Returns up to |max_count| bookmarks from |model| whose url or title contains
-// the text |text|. |languages| is user's accept-language setting to decode
-// IDN.
-void GetBookmarksContainingText(BookmarkModel* model,
- const base::string16& text,
- size_t max_count,
- const std::string& languages,
- std::vector<const BookmarkNode*>* nodes);
+// Returns up to |max_count| bookmarks from |model| whose url or title contain
+// the text |query.word_phrase_query| and exactly match |query.url| and
+// |query.title|, for all of the preceding fields that are not NULL.
+// |languages| is user's accept-language setting to decode IDN.
+void GetBookmarksMatchingProperties(BookmarkModel* model,
+ const QueryFields& query,
+ size_t max_count,
+ const std::string& languages,
+ std::vector<const BookmarkNode*>* nodes);
// Register user preferences for Bookmarks Bar.
void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
diff --git a/chrome/browser/bookmarks/bookmark_utils_unittest.cc b/chrome/browser/bookmarks/bookmark_utils_unittest.cc
index bfd284e..c2aac0c 100644
--- a/chrome/browser/bookmarks/bookmark_utils_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_utils_unittest.cc
@@ -30,7 +30,7 @@ class BookmarkUtilsTest : public ::testing::Test {
base::MessageLoopForUI loop;
};
-TEST_F(BookmarkUtilsTest, GetBookmarksContainingText) {
+TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesWordPhraseQuery) {
BookmarkModel model(NULL);
const BookmarkNode* node1 = model.AddURL(model.other_node(),
0,
@@ -46,26 +46,155 @@ TEST_F(BookmarkUtilsTest, GetBookmarksContainingText) {
ASCIIToUTF16("foo"));
std::vector<const BookmarkNode*> nodes;
- GetBookmarksContainingText(
- &model, ASCIIToUTF16("foo"), 100, string(), &nodes);
+ QueryFields query;
+ query.word_phrase_query.reset(new string16);
+ *query.word_phrase_query = ASCIIToUTF16("foo");
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
ASSERT_EQ(2U, nodes.size());
EXPECT_TRUE(nodes[0] == folder1);
EXPECT_TRUE(nodes[1] == node1);
nodes.clear();
- GetBookmarksContainingText(
- &model, ASCIIToUTF16("cnn"), 100, string(), &nodes);
+ *query.word_phrase_query = ASCIIToUTF16("cnn");
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
ASSERT_EQ(1U, nodes.size());
EXPECT_TRUE(nodes[0] == node2);
nodes.clear();
- GetBookmarksContainingText(
- &model, ASCIIToUTF16("foo bar"), 100, string(), &nodes);
+ *query.word_phrase_query = ASCIIToUTF16("foo bar");
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
ASSERT_EQ(1U, nodes.size());
EXPECT_TRUE(nodes[0] == node1);
nodes.clear();
}
+// Check exact matching against a URL query.
+TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesUrl) {
+ BookmarkModel model(NULL);
+ const BookmarkNode* node1 = model.AddURL(model.other_node(),
+ 0,
+ ASCIIToUTF16("Google"),
+ GURL("https://www.google.com/"));
+ model.AddURL(model.other_node(),
+ 0,
+ ASCIIToUTF16("Google Calendar"),
+ GURL("https://www.google.com/calendar"));
+
+ model.AddFolder(model.other_node(),
+ 0,
+ ASCIIToUTF16("Folder"));
+
+ std::vector<const BookmarkNode*> nodes;
+ QueryFields query;
+ query.url.reset(new string16);
+ *query.url = ASCIIToUTF16("https://www.google.com/");
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
+ ASSERT_EQ(1U, nodes.size());
+ EXPECT_TRUE(nodes[0] == node1);
+ nodes.clear();
+
+ *query.url = ASCIIToUTF16("calendar");
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
+ ASSERT_EQ(0U, nodes.size());
+ nodes.clear();
+
+ // Empty URL should not match folders.
+ *query.url = ASCIIToUTF16("");
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
+ ASSERT_EQ(0U, nodes.size());
+ nodes.clear();
+}
+
+// Check exact matching against a title query.
+TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesTitle) {
+ BookmarkModel model(NULL);
+ const BookmarkNode* node1 = model.AddURL(model.other_node(),
+ 0,
+ ASCIIToUTF16("Google"),
+ GURL("https://www.google.com/"));
+ model.AddURL(model.other_node(),
+ 0,
+ ASCIIToUTF16("Google Calendar"),
+ GURL("https://www.google.com/calendar"));
+
+ const BookmarkNode* folder1 = model.AddFolder(model.other_node(),
+ 0,
+ ASCIIToUTF16("Folder"));
+
+ std::vector<const BookmarkNode*> nodes;
+ QueryFields query;
+ query.title.reset(new string16);
+ *query.title = ASCIIToUTF16("Google");
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
+ ASSERT_EQ(1U, nodes.size());
+ EXPECT_TRUE(nodes[0] == node1);
+ nodes.clear();
+
+ *query.title = ASCIIToUTF16("Calendar");
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
+ ASSERT_EQ(0U, nodes.size());
+ nodes.clear();
+
+ // Title should match folders.
+ *query.title = ASCIIToUTF16("Folder");
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
+ ASSERT_EQ(1U, nodes.size());
+ EXPECT_TRUE(nodes[0] == folder1);
+ nodes.clear();
+}
+
+// Check matching against a query with multiple predicates.
+TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesConjunction) {
+ BookmarkModel model(NULL);
+ const BookmarkNode* node1 = model.AddURL(model.other_node(),
+ 0,
+ ASCIIToUTF16("Google"),
+ GURL("https://www.google.com/"));
+ model.AddURL(model.other_node(),
+ 0,
+ ASCIIToUTF16("Google Calendar"),
+ GURL("https://www.google.com/calendar"));
+
+ model.AddFolder(model.other_node(),
+ 0,
+ ASCIIToUTF16("Folder"));
+
+ std::vector<const BookmarkNode*> nodes;
+ QueryFields query;
+
+ // Test all fields matching.
+ query.word_phrase_query.reset(new string16(ASCIIToUTF16("www")));
+ query.url.reset(new string16(ASCIIToUTF16("https://www.google.com/")));
+ query.title.reset(new string16(ASCIIToUTF16("Google")));
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
+ ASSERT_EQ(1U, nodes.size());
+ EXPECT_TRUE(nodes[0] == node1);
+ nodes.clear();
+
+ scoped_ptr<string16>* fields[] = {
+ &query.word_phrase_query, &query.url, &query.title };
+
+ // Test two fields matching.
+ for (size_t i = 0; i < arraysize(fields); i++) {
+ scoped_ptr<string16> original_value(fields[i]->release());
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
+ ASSERT_EQ(1U, nodes.size());
+ EXPECT_TRUE(nodes[0] == node1);
+ nodes.clear();
+ fields[i]->reset(original_value.release());
+ }
+
+ // Test two fields matching with one non-matching field.
+ for (size_t i = 0; i < arraysize(fields); i++) {
+ scoped_ptr<string16> original_value(fields[i]->release());
+ fields[i]->reset(new string16(ASCIIToUTF16("fjdkslafjkldsa")));
+ GetBookmarksMatchingProperties(&model, query, 100, string(), &nodes);
+ ASSERT_EQ(0U, nodes.size());
+ nodes.clear();
+ fields[i]->reset(original_value.release());
+ }
+}
+
TEST_F(BookmarkUtilsTest, CopyPaste) {
BookmarkModel model(NULL);
const BookmarkNode* node = model.AddURL(model.other_node(),
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
index ccfed7e..9f6dbd6 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -438,12 +438,34 @@ bool BookmarksSearchFunction::RunImpl() {
PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile());
std::string lang = prefs->GetString(prefs::kAcceptLanguages);
std::vector<const BookmarkNode*> nodes;
- bookmark_utils::GetBookmarksContainingText(
- BookmarkModelFactory::GetForProfile(GetProfile()),
- UTF8ToUTF16(params->query),
- std::numeric_limits<int>::max(),
- lang,
- &nodes);
+ if (params->query.as_string) {
+ bookmark_utils::QueryFields query;
+ query.word_phrase_query.reset(
+ new string16(UTF8ToUTF16(*params->query.as_string)));
+ bookmark_utils::GetBookmarksMatchingProperties(
+ BookmarkModelFactory::GetForProfile(GetProfile()),
+ query,
+ std::numeric_limits<int>::max(),
+ lang,
+ &nodes);
+ } else {
+ DCHECK(params->query.as_object);
+ const bookmarks::Search::Params::Query::Object& object =
+ *params->query.as_object;
+ bookmark_utils::QueryFields query;
+ if (object.query)
+ query.word_phrase_query.reset(new string16(UTF8ToUTF16(*object.query)));
+ if (object.url)
+ query.url.reset(new string16(UTF8ToUTF16(*object.url)));
+ if (object.title)
+ query.title.reset(new string16(UTF8ToUTF16(*object.title)));
+ bookmark_utils::GetBookmarksMatchingProperties(
+ BookmarkModelFactory::GetForProfile(GetProfile()),
+ query,
+ std::numeric_limits<int>::max(),
+ lang,
+ &nodes);
+ }
std::vector<linked_ptr<BookmarkTreeNode> > tree_nodes;
for (std::vector<const BookmarkNode*>::iterator node_iter = nodes.begin();
diff --git a/chrome/common/extensions/api/bookmarks.json b/chrome/common/extensions/api/bookmarks.json
index e168362..fc0d1fe 100644
--- a/chrome/common/extensions/api/bookmarks.json
+++ b/chrome/common/extensions/api/bookmarks.json
@@ -195,11 +195,37 @@
{
"name": "search",
"type": "function",
- "description": "Searches for BookmarkTreeNodes matching the given query.",
+ "description": "Searches for BookmarkTreeNodes matching the given query. Queries specified with an object produce BookmarkTreeNodes matching all specified properties.",
"parameters": [
{
- "type": "string",
- "name": "query"
+ "name": "query",
+ "choices": [
+ {
+ "type": "string",
+ "description": "A string of words and quoted phrases that are matched against bookmark URLs and titles."
+ },
+ {
+ "type": "object",
+ "description": "An object specifying properties and values to match when searching. Produces bookmarks matching all properties.",
+ "properties": {
+ "query": {
+ "type": "string",
+ "optional": true,
+ "description": "A string of words and quoted phrases that are matched against bookmark URLs and titles."
+ },
+ "url": {
+ "type": "string",
+ "optional": true,
+ "description": "The URL of the bookmark; matches verbatim. Note that folders have no URL."
+ },
+ "title": {
+ "type": "string",
+ "optional": true,
+ "description": "The title of the bookmark; matches verbatim."
+ }
+ }
+ }
+ ]
},
{
"type": "function",