Home | History | Annotate | Download | only in bookmark_manager_private
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/lazy_instance.h"
     10 #include "base/memory/linked_ptr.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
     16 #include "chrome/browser/bookmarks/bookmark_stats.h"
     17 #include "chrome/browser/bookmarks/chrome_bookmark_client.h"
     18 #include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h"
     19 #include "chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.h"
     20 #include "chrome/browser/extensions/extension_web_ui.h"
     21 #include "chrome/browser/profiles/profile.h"
     22 #include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h"
     23 #include "chrome/browser/undo/bookmark_undo_service.h"
     24 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
     25 #include "chrome/common/extensions/api/bookmark_manager_private.h"
     26 #include "chrome/common/pref_names.h"
     27 #include "chrome/grit/generated_resources.h"
     28 #include "components/bookmarks/browser/bookmark_model.h"
     29 #include "components/bookmarks/browser/bookmark_node_data.h"
     30 #include "components/bookmarks/browser/bookmark_utils.h"
     31 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
     32 #include "components/user_prefs/user_prefs.h"
     33 #include "content/public/browser/render_view_host.h"
     34 #include "content/public/browser/web_contents.h"
     35 #include "content/public/browser/web_ui.h"
     36 #include "extensions/browser/extension_function_dispatcher.h"
     37 #include "extensions/browser/view_type_utils.h"
     38 #include "ui/base/dragdrop/drag_drop_types.h"
     39 #include "ui/base/l10n/l10n_util.h"
     40 #include "ui/base/webui/web_ui_util.h"
     41 
     42 using bookmarks::BookmarkNodeData;
     43 
     44 namespace extensions {
     45 
     46 namespace bookmark_keys = bookmark_api_constants;
     47 namespace bookmark_manager_private = api::bookmark_manager_private;
     48 namespace CanPaste = api::bookmark_manager_private::CanPaste;
     49 namespace Copy = api::bookmark_manager_private::Copy;
     50 namespace CreateWithMetaInfo =
     51     api::bookmark_manager_private::CreateWithMetaInfo;
     52 namespace Cut = api::bookmark_manager_private::Cut;
     53 namespace Drop = api::bookmark_manager_private::Drop;
     54 namespace GetSubtree = api::bookmark_manager_private::GetSubtree;
     55 namespace GetMetaInfo = api::bookmark_manager_private::GetMetaInfo;
     56 namespace Paste = api::bookmark_manager_private::Paste;
     57 namespace RedoInfo = api::bookmark_manager_private::GetRedoInfo;
     58 namespace RemoveTrees = api::bookmark_manager_private::RemoveTrees;
     59 namespace SetMetaInfo = api::bookmark_manager_private::SetMetaInfo;
     60 namespace SortChildren = api::bookmark_manager_private::SortChildren;
     61 namespace StartDrag = api::bookmark_manager_private::StartDrag;
     62 namespace UndoInfo = api::bookmark_manager_private::GetUndoInfo;
     63 namespace UpdateMetaInfo = api::bookmark_manager_private::UpdateMetaInfo;
     64 
     65 using content::WebContents;
     66 
     67 namespace {
     68 
     69 // Returns a single bookmark node from the argument ID.
     70 // This returns NULL in case of failure.
     71 const BookmarkNode* GetNodeFromString(BookmarkModel* model,
     72                                       const std::string& id_string) {
     73   int64 id;
     74   if (!base::StringToInt64(id_string, &id))
     75     return NULL;
     76   return bookmarks::GetBookmarkNodeByID(model, id);
     77 }
     78 
     79 // Gets a vector of bookmark nodes from the argument list of IDs.
     80 // This returns false in the case of failure.
     81 bool GetNodesFromVector(BookmarkModel* model,
     82                         const std::vector<std::string>& id_strings,
     83                         std::vector<const BookmarkNode*>* nodes) {
     84   if (id_strings.empty())
     85     return false;
     86 
     87   for (size_t i = 0; i < id_strings.size(); ++i) {
     88     const BookmarkNode* node = GetNodeFromString(model, id_strings[i]);
     89     if (!node)
     90       return false;
     91     nodes->push_back(node);
     92   }
     93 
     94   return true;
     95 }
     96 
     97 // Recursively create a bookmark_manager_private::BookmarkNodeDataElement from
     98 // a bookmark node. This is by used |BookmarkNodeDataToJSON| when the data comes
     99 // from the current profile. In this case we have a BookmarkNode since we got
    100 // the data from the current profile.
    101 linked_ptr<bookmark_manager_private::BookmarkNodeDataElement>
    102 CreateNodeDataElementFromBookmarkNode(const BookmarkNode& node) {
    103   linked_ptr<bookmark_manager_private::BookmarkNodeDataElement> element(
    104       new bookmark_manager_private::BookmarkNodeDataElement);
    105   // Add id and parentId so we can associate the data with existing nodes on the
    106   // client side.
    107   element->id.reset(new std::string(base::Int64ToString(node.id())));
    108   element->parent_id.reset(
    109       new std::string(base::Int64ToString(node.parent()->id())));
    110 
    111   if (node.is_url())
    112     element->url.reset(new std::string(node.url().spec()));
    113 
    114   element->title = base::UTF16ToUTF8(node.GetTitle());
    115   for (int i = 0; i < node.child_count(); ++i) {
    116     element->children.push_back(
    117         CreateNodeDataElementFromBookmarkNode(*node.GetChild(i)));
    118   }
    119 
    120   return element;
    121 }
    122 
    123 // Recursively create a bookmark_manager_private::BookmarkNodeDataElement from
    124 // a BookmarkNodeData::Element. This is used by |BookmarkNodeDataToJSON| when
    125 // the data comes from a different profile. When the data comes from a different
    126 // profile we do not have any IDs or parent IDs.
    127 linked_ptr<bookmark_manager_private::BookmarkNodeDataElement>
    128 CreateApiNodeDataElement(const BookmarkNodeData::Element& element) {
    129   linked_ptr<bookmark_manager_private::BookmarkNodeDataElement> node_element(
    130       new bookmark_manager_private::BookmarkNodeDataElement);
    131 
    132   if (element.is_url)
    133     node_element->url.reset(new std::string(element.url.spec()));
    134   node_element->title = base::UTF16ToUTF8(element.title);
    135   for (size_t i = 0; i < element.children.size(); ++i) {
    136     node_element->children.push_back(
    137         CreateApiNodeDataElement(element.children[i]));
    138   }
    139 
    140   return node_element;
    141 }
    142 
    143 // Creates a bookmark_manager_private::BookmarkNodeData from a BookmarkNodeData.
    144 scoped_ptr<bookmark_manager_private::BookmarkNodeData>
    145 CreateApiBookmarkNodeData(Profile* profile, const BookmarkNodeData& data) {
    146   const base::FilePath& profile_path = profile->GetPath();
    147 
    148   scoped_ptr<bookmark_manager_private::BookmarkNodeData> node_data(
    149       new bookmark_manager_private::BookmarkNodeData);
    150   node_data->same_profile = data.IsFromProfilePath(profile_path);
    151 
    152   if (node_data->same_profile) {
    153     std::vector<const BookmarkNode*> nodes = data.GetNodes(
    154         BookmarkModelFactory::GetForProfile(profile), profile_path);
    155     for (size_t i = 0; i < nodes.size(); ++i) {
    156       node_data->elements.push_back(
    157           CreateNodeDataElementFromBookmarkNode(*nodes[i]));
    158     }
    159   } else {
    160     // We do not have a node IDs when the data comes from a different profile.
    161     std::vector<BookmarkNodeData::Element> elements = data.elements;
    162     for (size_t i = 0; i < elements.size(); ++i)
    163       node_data->elements.push_back(CreateApiNodeDataElement(elements[i]));
    164   }
    165   return node_data.Pass();
    166 }
    167 
    168 }  // namespace
    169 
    170 BookmarkManagerPrivateEventRouter::BookmarkManagerPrivateEventRouter(
    171     content::BrowserContext* browser_context,
    172     BookmarkModel* bookmark_model)
    173     : browser_context_(browser_context), bookmark_model_(bookmark_model) {
    174   bookmark_model_->AddObserver(this);
    175 }
    176 
    177 BookmarkManagerPrivateEventRouter::~BookmarkManagerPrivateEventRouter() {
    178   if (bookmark_model_)
    179     bookmark_model_->RemoveObserver(this);
    180 }
    181 
    182 void BookmarkManagerPrivateEventRouter::DispatchEvent(
    183     const std::string& event_name,
    184     scoped_ptr<base::ListValue> event_args) {
    185   extensions::EventRouter::Get(browser_context_)->BroadcastEvent(
    186       make_scoped_ptr(new extensions::Event(event_name, event_args.Pass())));
    187 }
    188 
    189 void BookmarkManagerPrivateEventRouter::BookmarkModelChanged() {}
    190 
    191 void BookmarkManagerPrivateEventRouter::BookmarkModelBeingDeleted(
    192     BookmarkModel* model) {
    193   bookmark_model_ = NULL;
    194 }
    195 
    196 void BookmarkManagerPrivateEventRouter::OnWillChangeBookmarkMetaInfo(
    197     BookmarkModel* model,
    198     const BookmarkNode* node) {
    199   DCHECK(prev_meta_info_.empty());
    200   if (node->GetMetaInfoMap())
    201     prev_meta_info_ = *node->GetMetaInfoMap();
    202 }
    203 
    204 void BookmarkManagerPrivateEventRouter::BookmarkMetaInfoChanged(
    205     BookmarkModel* model,
    206     const BookmarkNode* node) {
    207   const BookmarkNode::MetaInfoMap* new_meta_info = node->GetMetaInfoMap();
    208   bookmark_manager_private::MetaInfoFields changes;
    209 
    210   // Identify changed/removed fields:
    211   for (BookmarkNode::MetaInfoMap::const_iterator it = prev_meta_info_.begin();
    212        it != prev_meta_info_.end();
    213        ++it) {
    214     if (!new_meta_info) {
    215       changes.additional_properties[it->first] = "";
    216     } else {
    217       BookmarkNode::MetaInfoMap::const_iterator new_meta_field =
    218           new_meta_info->find(it->first);
    219       if (new_meta_field == new_meta_info->end()) {
    220         changes.additional_properties[it->first] = "";
    221       } else if (it->second != new_meta_field->second) {
    222         changes.additional_properties[it->first] = new_meta_field->second;
    223       }
    224     }
    225   }
    226 
    227   // Identify added fields:
    228   if (new_meta_info) {
    229     for (BookmarkNode::MetaInfoMap::const_iterator it = new_meta_info->begin();
    230          it != new_meta_info->end();
    231          ++it) {
    232       BookmarkNode::MetaInfoMap::const_iterator prev_meta_field =
    233           prev_meta_info_.find(it->first);
    234       if (prev_meta_field == prev_meta_info_.end())
    235         changes.additional_properties[it->first] = it->second;
    236     }
    237   }
    238 
    239   prev_meta_info_.clear();
    240   DispatchEvent(bookmark_manager_private::OnMetaInfoChanged::kEventName,
    241                 bookmark_manager_private::OnMetaInfoChanged::Create(
    242                     base::Int64ToString(node->id()), changes));
    243 }
    244 
    245 BookmarkManagerPrivateAPI::BookmarkManagerPrivateAPI(
    246     content::BrowserContext* browser_context)
    247     : browser_context_(browser_context) {
    248   EventRouter* event_router = EventRouter::Get(browser_context);
    249   event_router->RegisterObserver(
    250       this, bookmark_manager_private::OnMetaInfoChanged::kEventName);
    251 }
    252 
    253 BookmarkManagerPrivateAPI::~BookmarkManagerPrivateAPI() {}
    254 
    255 void BookmarkManagerPrivateAPI::Shutdown() {
    256   EventRouter::Get(browser_context_)->UnregisterObserver(this);
    257 }
    258 
    259 static base::LazyInstance<
    260     BrowserContextKeyedAPIFactory<BookmarkManagerPrivateAPI> > g_factory =
    261     LAZY_INSTANCE_INITIALIZER;
    262 
    263 // static
    264 BrowserContextKeyedAPIFactory<BookmarkManagerPrivateAPI>*
    265 BookmarkManagerPrivateAPI::GetFactoryInstance() {
    266   return g_factory.Pointer();
    267 }
    268 
    269 void BookmarkManagerPrivateAPI::OnListenerAdded(
    270     const EventListenerInfo& details) {
    271   EventRouter::Get(browser_context_)->UnregisterObserver(this);
    272   event_router_.reset(new BookmarkManagerPrivateEventRouter(
    273       browser_context_,
    274       BookmarkModelFactory::GetForProfile(
    275           Profile::FromBrowserContext(browser_context_))));
    276 }
    277 
    278 BookmarkManagerPrivateDragEventRouter::BookmarkManagerPrivateDragEventRouter(
    279     Profile* profile,
    280     content::WebContents* web_contents)
    281     : profile_(profile), web_contents_(web_contents) {
    282   BookmarkTabHelper* bookmark_tab_helper =
    283       BookmarkTabHelper::FromWebContents(web_contents_);
    284   bookmark_tab_helper->set_bookmark_drag_delegate(this);
    285 }
    286 
    287 BookmarkManagerPrivateDragEventRouter::
    288     ~BookmarkManagerPrivateDragEventRouter() {
    289   BookmarkTabHelper* bookmark_tab_helper =
    290       BookmarkTabHelper::FromWebContents(web_contents_);
    291   if (bookmark_tab_helper->bookmark_drag_delegate() == this)
    292     bookmark_tab_helper->set_bookmark_drag_delegate(NULL);
    293 }
    294 
    295 void BookmarkManagerPrivateDragEventRouter::DispatchEvent(
    296     const std::string& event_name,
    297     scoped_ptr<base::ListValue> args) {
    298   EventRouter* event_router = EventRouter::Get(profile_);
    299   if (!event_router)
    300     return;
    301 
    302   scoped_ptr<Event> event(new Event(event_name, args.Pass()));
    303   event_router->BroadcastEvent(event.Pass());
    304 }
    305 
    306 void BookmarkManagerPrivateDragEventRouter::OnDragEnter(
    307     const BookmarkNodeData& data) {
    308   if (data.size() == 0)
    309     return;
    310   DispatchEvent(bookmark_manager_private::OnDragEnter::kEventName,
    311                 bookmark_manager_private::OnDragEnter::Create(
    312                     *CreateApiBookmarkNodeData(profile_, data)));
    313 }
    314 
    315 void BookmarkManagerPrivateDragEventRouter::OnDragOver(
    316     const BookmarkNodeData& data) {
    317   // Intentionally empty since these events happens too often and floods the
    318   // message queue. We do not need this event for the bookmark manager anyway.
    319 }
    320 
    321 void BookmarkManagerPrivateDragEventRouter::OnDragLeave(
    322     const BookmarkNodeData& data) {
    323   if (data.size() == 0)
    324     return;
    325   DispatchEvent(bookmark_manager_private::OnDragLeave::kEventName,
    326                 bookmark_manager_private::OnDragLeave::Create(
    327                     *CreateApiBookmarkNodeData(profile_, data)));
    328 }
    329 
    330 void BookmarkManagerPrivateDragEventRouter::OnDrop(
    331     const BookmarkNodeData& data) {
    332   if (data.size() == 0)
    333     return;
    334   DispatchEvent(bookmark_manager_private::OnDrop::kEventName,
    335                 bookmark_manager_private::OnDrop::Create(
    336                     *CreateApiBookmarkNodeData(profile_, data)));
    337 
    338   // Make a copy that is owned by this instance.
    339   ClearBookmarkNodeData();
    340   bookmark_drag_data_ = data;
    341 }
    342 
    343 const BookmarkNodeData*
    344 BookmarkManagerPrivateDragEventRouter::GetBookmarkNodeData() {
    345   if (bookmark_drag_data_.is_valid())
    346     return &bookmark_drag_data_;
    347   return NULL;
    348 }
    349 
    350 void BookmarkManagerPrivateDragEventRouter::ClearBookmarkNodeData() {
    351   bookmark_drag_data_.Clear();
    352 }
    353 
    354 bool ClipboardBookmarkManagerFunction::CopyOrCut(bool cut,
    355     const std::vector<std::string>& id_list) {
    356   BookmarkModel* model = GetBookmarkModel();
    357   ChromeBookmarkClient* client = GetChromeBookmarkClient();
    358   std::vector<const BookmarkNode*> nodes;
    359   EXTENSION_FUNCTION_VALIDATE(GetNodesFromVector(model, id_list, &nodes));
    360   if (cut && client->HasDescendantsOfManagedNode(nodes)) {
    361     error_ = bookmark_keys::kModifyManagedError;
    362     return false;
    363   }
    364   bookmarks::CopyToClipboard(model, nodes, cut);
    365   return true;
    366 }
    367 
    368 bool BookmarkManagerPrivateCopyFunction::RunOnReady() {
    369   scoped_ptr<Copy::Params> params(Copy::Params::Create(*args_));
    370   EXTENSION_FUNCTION_VALIDATE(params);
    371   return CopyOrCut(false, params->id_list);
    372 }
    373 
    374 bool BookmarkManagerPrivateCutFunction::RunOnReady() {
    375   if (!EditBookmarksEnabled())
    376     return false;
    377 
    378   scoped_ptr<Cut::Params> params(Cut::Params::Create(*args_));
    379   EXTENSION_FUNCTION_VALIDATE(params);
    380   return CopyOrCut(true, params->id_list);
    381 }
    382 
    383 bool BookmarkManagerPrivatePasteFunction::RunOnReady() {
    384   if (!EditBookmarksEnabled())
    385     return false;
    386 
    387   scoped_ptr<Paste::Params> params(Paste::Params::Create(*args_));
    388   EXTENSION_FUNCTION_VALIDATE(params);
    389   BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
    390   const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
    391   if (!CanBeModified(parent_node))
    392     return false;
    393   bool can_paste = bookmarks::CanPasteFromClipboard(model, parent_node);
    394   if (!can_paste)
    395     return false;
    396 
    397   // We want to use the highest index of the selected nodes as a destination.
    398   std::vector<const BookmarkNode*> nodes;
    399   // No need to test return value, if we got an empty list, we insert at end.
    400   if (params->selected_id_list)
    401     GetNodesFromVector(model, *params->selected_id_list, &nodes);
    402   int highest_index = -1;  // -1 means insert at end of list.
    403   for (size_t i = 0; i < nodes.size(); ++i) {
    404     // + 1 so that we insert after the selection.
    405     int index = parent_node->GetIndexOf(nodes[i]) + 1;
    406     if (index > highest_index)
    407       highest_index = index;
    408   }
    409 
    410   bookmarks::PasteFromClipboard(model, parent_node, highest_index);
    411   return true;
    412 }
    413 
    414 bool BookmarkManagerPrivateCanPasteFunction::RunOnReady() {
    415   if (!EditBookmarksEnabled())
    416     return false;
    417 
    418   scoped_ptr<CanPaste::Params> params(CanPaste::Params::Create(*args_));
    419   EXTENSION_FUNCTION_VALIDATE(params);
    420 
    421   BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
    422   const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
    423   if (!parent_node) {
    424     error_ = bookmark_keys::kNoParentError;
    425     return false;
    426   }
    427   bool can_paste = bookmarks::CanPasteFromClipboard(model, parent_node);
    428   SetResult(new base::FundamentalValue(can_paste));
    429   return true;
    430 }
    431 
    432 bool BookmarkManagerPrivateSortChildrenFunction::RunOnReady() {
    433   if (!EditBookmarksEnabled())
    434     return false;
    435 
    436   scoped_ptr<SortChildren::Params> params(SortChildren::Params::Create(*args_));
    437   EXTENSION_FUNCTION_VALIDATE(params);
    438 
    439   BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
    440   const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
    441   if (!CanBeModified(parent_node))
    442     return false;
    443   model->SortChildren(parent_node);
    444   return true;
    445 }
    446 
    447 bool BookmarkManagerPrivateGetStringsFunction::RunAsync() {
    448   base::DictionaryValue* localized_strings = new base::DictionaryValue();
    449 
    450   localized_strings->SetString("title",
    451       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TITLE));
    452   localized_strings->SetString("search_button",
    453       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH_BUTTON));
    454   localized_strings->SetString("organize_menu",
    455       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU));
    456   localized_strings->SetString("show_in_folder",
    457       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
    458   localized_strings->SetString("sort",
    459       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SORT));
    460   localized_strings->SetString("import_menu",
    461       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_IMPORT_MENU));
    462   localized_strings->SetString("export_menu",
    463       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_EXPORT_MENU));
    464   localized_strings->SetString("rename_folder",
    465       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_RENAME_FOLDER));
    466   localized_strings->SetString("edit",
    467       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_EDIT));
    468   localized_strings->SetString("should_open_all",
    469       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL));
    470   localized_strings->SetString("open_incognito",
    471       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_INCOGNITO));
    472   localized_strings->SetString("open_in_new_tab",
    473       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_IN_NEW_TAB));
    474   localized_strings->SetString("open_in_new_window",
    475       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_IN_NEW_WINDOW));
    476   localized_strings->SetString("add_new_bookmark",
    477       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
    478   localized_strings->SetString("new_folder",
    479       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_NEW_FOLDER));
    480   localized_strings->SetString("open_all",
    481       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL));
    482   localized_strings->SetString("open_all_new_window",
    483       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
    484   localized_strings->SetString("open_all_incognito",
    485       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
    486   localized_strings->SetString("remove",
    487       l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_REMOVE));
    488   localized_strings->SetString("copy",
    489       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_COPY));
    490   localized_strings->SetString("cut",
    491       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_CUT));
    492   localized_strings->SetString("paste",
    493       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PASTE));
    494   localized_strings->SetString("delete",
    495       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_DELETE));
    496   localized_strings->SetString("undo_delete",
    497       l10n_util::GetStringUTF16(IDS_UNDO_DELETE));
    498   localized_strings->SetString("new_folder_name",
    499       l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME));
    500   localized_strings->SetString("name_input_placeholder",
    501       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER));
    502   localized_strings->SetString("url_input_placeholder",
    503       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER));
    504   localized_strings->SetString("invalid_url",
    505       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_INVALID_URL));
    506   localized_strings->SetString("recent",
    507       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_RECENT));
    508   localized_strings->SetString("search",
    509       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH));
    510   localized_strings->SetString("save",
    511       l10n_util::GetStringUTF16(IDS_SAVE));
    512   localized_strings->SetString("cancel",
    513       l10n_util::GetStringUTF16(IDS_CANCEL));
    514 
    515   webui::SetFontAndTextDirection(localized_strings);
    516 
    517   SetResult(localized_strings);
    518 
    519   // This is needed because unlike the rest of these functions, this class
    520   // inherits from AsyncFunction directly, rather than BookmarkFunction.
    521   SendResponse(true);
    522 
    523   return true;
    524 }
    525 
    526 bool BookmarkManagerPrivateStartDragFunction::RunOnReady() {
    527   if (!EditBookmarksEnabled())
    528     return false;
    529 
    530   scoped_ptr<StartDrag::Params> params(StartDrag::Params::Create(*args_));
    531   EXTENSION_FUNCTION_VALIDATE(params);
    532 
    533   BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
    534   std::vector<const BookmarkNode*> nodes;
    535   EXTENSION_FUNCTION_VALIDATE(
    536       GetNodesFromVector(model, params->id_list, &nodes));
    537 
    538   WebContents* web_contents =
    539       WebContents::FromRenderViewHost(render_view_host_);
    540   if (GetViewType(web_contents) == VIEW_TYPE_TAB_CONTENTS) {
    541     WebContents* web_contents =
    542         dispatcher()->delegate()->GetAssociatedWebContents();
    543     CHECK(web_contents);
    544 
    545     ui::DragDropTypes::DragEventSource source =
    546         ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE;
    547     if (params->is_from_touch)
    548       source = ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH;
    549 
    550     chrome::DragBookmarks(
    551         GetProfile(), nodes, web_contents->GetNativeView(), source);
    552 
    553     return true;
    554   } else {
    555     NOTREACHED();
    556     return false;
    557   }
    558 }
    559 
    560 bool BookmarkManagerPrivateDropFunction::RunOnReady() {
    561   if (!EditBookmarksEnabled())
    562     return false;
    563 
    564   scoped_ptr<Drop::Params> params(Drop::Params::Create(*args_));
    565   EXTENSION_FUNCTION_VALIDATE(params);
    566 
    567   BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
    568 
    569   const BookmarkNode* drop_parent = GetNodeFromString(model, params->parent_id);
    570   if (!CanBeModified(drop_parent))
    571     return false;
    572 
    573   int drop_index;
    574   if (params->index)
    575     drop_index = *params->index;
    576   else
    577     drop_index = drop_parent->child_count();
    578 
    579   WebContents* web_contents =
    580       WebContents::FromRenderViewHost(render_view_host_);
    581   if (GetViewType(web_contents) == VIEW_TYPE_TAB_CONTENTS) {
    582     WebContents* web_contents =
    583         dispatcher()->delegate()->GetAssociatedWebContents();
    584     CHECK(web_contents);
    585     ExtensionWebUI* web_ui =
    586         static_cast<ExtensionWebUI*>(web_contents->GetWebUI()->GetController());
    587     CHECK(web_ui);
    588     BookmarkManagerPrivateDragEventRouter* router =
    589         web_ui->bookmark_manager_private_drag_event_router();
    590 
    591     DCHECK(router);
    592     const BookmarkNodeData* drag_data = router->GetBookmarkNodeData();
    593     if (drag_data == NULL) {
    594       NOTREACHED() <<"Somehow we're dropping null bookmark data";
    595       return false;
    596     }
    597     const bool copy = false;
    598     chrome::DropBookmarks(
    599         GetProfile(), *drag_data, drop_parent, drop_index, copy);
    600 
    601     router->ClearBookmarkNodeData();
    602     return true;
    603   } else {
    604     NOTREACHED();
    605     return false;
    606   }
    607 }
    608 
    609 bool BookmarkManagerPrivateGetSubtreeFunction::RunOnReady() {
    610   scoped_ptr<GetSubtree::Params> params(GetSubtree::Params::Create(*args_));
    611   EXTENSION_FUNCTION_VALIDATE(params);
    612 
    613   const BookmarkNode* node = NULL;
    614 
    615   if (params->id == "") {
    616     BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
    617     node = model->root_node();
    618   } else {
    619     node = GetBookmarkNodeFromId(params->id);
    620     if (!node)
    621       return false;
    622   }
    623 
    624   std::vector<linked_ptr<api::bookmarks::BookmarkTreeNode> > nodes;
    625   ChromeBookmarkClient* client = GetChromeBookmarkClient();
    626   if (params->folders_only)
    627     bookmark_api_helpers::AddNodeFoldersOnly(client, node, &nodes, true);
    628   else
    629     bookmark_api_helpers::AddNode(client, node, &nodes, true);
    630   results_ = GetSubtree::Results::Create(nodes);
    631   return true;
    632 }
    633 
    634 bool BookmarkManagerPrivateCanEditFunction::RunOnReady() {
    635   PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile());
    636   SetResult(new base::FundamentalValue(
    637       prefs->GetBoolean(bookmarks::prefs::kEditBookmarksEnabled)));
    638   return true;
    639 }
    640 
    641 bool BookmarkManagerPrivateRecordLaunchFunction::RunOnReady() {
    642   RecordBookmarkLaunch(NULL, BOOKMARK_LAUNCH_LOCATION_MANAGER);
    643   return true;
    644 }
    645 
    646 bool BookmarkManagerPrivateCreateWithMetaInfoFunction::RunOnReady() {
    647   scoped_ptr<CreateWithMetaInfo::Params> params(
    648       CreateWithMetaInfo::Params::Create(*args_));
    649   EXTENSION_FUNCTION_VALIDATE(params);
    650 
    651   BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
    652   const BookmarkNode* node = CreateBookmarkNode(
    653       model, params->bookmark, &params->meta_info.additional_properties);
    654   if (!node)
    655     return false;
    656 
    657   scoped_ptr<api::bookmarks::BookmarkTreeNode> result_node(
    658       bookmark_api_helpers::GetBookmarkTreeNode(
    659           GetChromeBookmarkClient(), node, false, false));
    660   results_ = CreateWithMetaInfo::Results::Create(*result_node);
    661 
    662   return true;
    663 }
    664 
    665 bool BookmarkManagerPrivateGetMetaInfoFunction::RunOnReady() {
    666   scoped_ptr<GetMetaInfo::Params> params(GetMetaInfo::Params::Create(*args_));
    667   EXTENSION_FUNCTION_VALIDATE(params);
    668 
    669   if (params->id) {
    670     const BookmarkNode* node = GetBookmarkNodeFromId(*params->id);
    671     if (!node)
    672       return false;
    673 
    674     if (params->key) {
    675       std::string value;
    676       if (node->GetMetaInfo(*params->key, &value)) {
    677         GetMetaInfo::Results::Value result;
    678         result.as_string.reset(new std::string(value));
    679         results_ = GetMetaInfo::Results::Create(result);
    680       }
    681     } else {
    682       GetMetaInfo::Results::Value result;
    683       result.as_object.reset(new GetMetaInfo::Results::Value::Object);
    684 
    685       const BookmarkNode::MetaInfoMap* meta_info = node->GetMetaInfoMap();
    686       if (meta_info) {
    687         BookmarkNode::MetaInfoMap::const_iterator itr;
    688         base::DictionaryValue& temp = result.as_object->additional_properties;
    689         for (itr = meta_info->begin(); itr != meta_info->end(); itr++) {
    690           temp.SetStringWithoutPathExpansion(itr->first, itr->second);
    691         }
    692       }
    693       results_ = GetMetaInfo::Results::Create(result);
    694     }
    695   } else {
    696     if (params->key) {
    697       error_ = bookmark_api_constants::kInvalidParamError;
    698       return true;
    699     }
    700 
    701     BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
    702     const BookmarkNode* node = model->root_node();
    703 
    704     GetMetaInfo::Results::Value result;
    705     result.as_object.reset(new GetMetaInfo::Results::Value::Object);
    706 
    707     bookmark_api_helpers::GetMetaInfo(*node,
    708         &result.as_object->additional_properties);
    709 
    710     results_ = GetMetaInfo::Results::Create(result);
    711   }
    712 
    713   return true;
    714 }
    715 
    716 bool BookmarkManagerPrivateSetMetaInfoFunction::RunOnReady() {
    717   scoped_ptr<SetMetaInfo::Params> params(SetMetaInfo::Params::Create(*args_));
    718   EXTENSION_FUNCTION_VALIDATE(params);
    719 
    720   const BookmarkNode* node = GetBookmarkNodeFromId(params->id);
    721   if (!node)
    722     return false;
    723 
    724   BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
    725   model->SetNodeMetaInfo(node, params->key, params->value);
    726   return true;
    727 }
    728 
    729 bool BookmarkManagerPrivateUpdateMetaInfoFunction::RunOnReady() {
    730   scoped_ptr<UpdateMetaInfo::Params> params(
    731       UpdateMetaInfo::Params::Create(*args_));
    732   EXTENSION_FUNCTION_VALIDATE(params);
    733 
    734   const BookmarkNode* node = GetBookmarkNodeFromId(params->id);
    735   if (!node)
    736     return false;
    737 
    738   BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
    739   BookmarkNode::MetaInfoMap new_meta_info(
    740       params->meta_info_changes.additional_properties);
    741   if (node->GetMetaInfoMap()) {
    742     new_meta_info.insert(node->GetMetaInfoMap()->begin(),
    743                          node->GetMetaInfoMap()->end());
    744   }
    745   model->SetNodeMetaInfoMap(node, new_meta_info);
    746 
    747   return true;
    748 }
    749 
    750 bool BookmarkManagerPrivateCanOpenNewWindowsFunction::RunOnReady() {
    751   bool can_open_new_windows = true;
    752   SetResult(new base::FundamentalValue(can_open_new_windows));
    753   return true;
    754 }
    755 
    756 bool BookmarkManagerPrivateRemoveTreesFunction::RunOnReady() {
    757   scoped_ptr<RemoveTrees::Params> params(RemoveTrees::Params::Create(*args_));
    758   EXTENSION_FUNCTION_VALIDATE(params);
    759 
    760   BookmarkModel* model = GetBookmarkModel();
    761   ChromeBookmarkClient* client = GetChromeBookmarkClient();
    762   bookmarks::ScopedGroupBookmarkActions group_deletes(model);
    763   int64 id;
    764   for (size_t i = 0; i < params->id_list.size(); ++i) {
    765     if (!GetBookmarkIdAsInt64(params->id_list[i], &id))
    766       return false;
    767     if (!bookmark_api_helpers::RemoveNode(model, client, id, true, &error_))
    768       return false;
    769   }
    770 
    771   return true;
    772 }
    773 
    774 bool BookmarkManagerPrivateUndoFunction::RunOnReady() {
    775   BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
    776       Undo();
    777   return true;
    778 }
    779 
    780 bool BookmarkManagerPrivateRedoFunction::RunOnReady() {
    781   BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
    782       Redo();
    783   return true;
    784 }
    785 
    786 bool BookmarkManagerPrivateGetUndoInfoFunction::RunOnReady() {
    787   UndoManager* undo_manager =
    788       BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager();
    789 
    790   UndoInfo::Results::Result result;
    791   result.enabled = undo_manager->undo_count() > 0;
    792   result.label = base::UTF16ToUTF8(undo_manager->GetUndoLabel());
    793 
    794   results_ = UndoInfo::Results::Create(result);
    795   return true;
    796 }
    797 
    798 bool BookmarkManagerPrivateGetRedoInfoFunction::RunOnReady() {
    799   UndoManager* undo_manager =
    800       BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager();
    801 
    802   RedoInfo::Results::Result result;
    803   result.enabled = undo_manager->redo_count() > 0;
    804   result.label = base::UTF16ToUTF8(undo_manager->GetRedoLabel());
    805 
    806   results_ = RedoInfo::Results::Create(result);
    807   return true;
    808 }
    809 
    810 }  // namespace extensions
    811