Index: ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm |
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1c01fe309b6d0f33f8d3f5b70d5761913c1ff796 |
--- /dev/null |
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm |
@@ -0,0 +1,595 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h" |
+ |
+#include <memory> |
+#include <set> |
+ |
+#include "base/auto_reset.h" |
+#include "base/ios/block_types.h" |
+#include "base/ios/weak_nsobject.h" |
+#include "base/logging.h" |
+#include "base/mac/bind_objc_block.h" |
+#import "base/mac/foundation_util.h" |
+#include "base/mac/objc_property_releaser.h" |
+#include "base/mac/scoped_cftyperef.h" |
+#include "base/mac/scoped_nsobject.h" |
+#include "base/strings/sys_string_conversions.h" |
+#include "components/bookmarks/browser/bookmark_model.h" |
+#include "components/url_formatter/url_fixer.h" |
+#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" |
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
+#import "ios/chrome/browser/ui/bookmarks/bookmark_elevated_toolbar.h" |
+#import "ios/chrome/browser/ui/bookmarks/bookmark_extended_button.h" |
+#import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h" |
+#import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h" |
+#import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h" |
+#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" |
+#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h" |
+#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h" |
+#import "ios/chrome/browser/ui/collection_view/collection_view_model.h" |
+#import "ios/chrome/browser/ui/icons/chrome_icon.h" |
+#import "ios/chrome/browser/ui/image_util.h" |
+#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h" |
+#include "ios/chrome/browser/ui/rtl_geometry.h" |
+#include "ios/chrome/browser/ui/ui_util.h" |
+#include "ios/chrome/grit/ios_strings.h" |
+#import "ios/public/provider/chrome/browser/chrome_browser_provider.h" |
+#import "ios/public/provider/chrome/browser/ui/text_field_styling.h" |
+#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h" |
+#import "ios/third_party/material_components_ios/src/components/ShadowElevations/src/MaterialShadowElevations.h" |
+#import "ios/third_party/material_components_ios/src/components/ShadowLayer/src/MaterialShadowLayer.h" |
+#include "ui/base/l10n/l10n_util_mac.h" |
+#include "ui/gfx/image/image.h" |
+#include "url/gurl.h" |
+ |
+using bookmarks::BookmarkModel; |
+using bookmarks::BookmarkNode; |
+ |
+namespace { |
+// Converts NSString entered by the user to a GURL. |
+GURL ConvertUserDataToGURL(NSString* urlString) { |
+ if (urlString) { |
+ return url_formatter::FixupURL(base::SysNSStringToUTF8(urlString), |
+ std::string()); |
+ } else { |
+ return GURL(); |
+ } |
+} |
+ |
+typedef NS_ENUM(NSInteger, SectionIdentifier) { |
+ SectionIdentifierInfo = kSectionIdentifierEnumZero, |
+}; |
+ |
+typedef NS_ENUM(NSInteger, ItemType) { |
+ ItemTypeName = kItemTypeEnumZero, |
+ ItemTypeFolder, |
+ ItemTypeURL, |
+}; |
+} // namespace |
+ |
+@interface BookmarkEditViewController ()<BookmarkFolderViewControllerDelegate, |
+ BookmarkModelBridgeObserver, |
+ BookmarkTextFieldItemDelegate, |
+ TextFieldValidation> { |
+ // Flag to ignore bookmark model changes notifications. |
+ BOOL _ignoresBookmarkModelChanges; |
+ |
+ std::unique_ptr<bookmarks::BookmarkModelBridge> _modelBridge; |
+ |
+ base::mac::ObjCPropertyReleaser _propertyReleaser_BookmarkEditViewController; |
+} |
+ |
+// The bookmark this controller displays or edits. |
+// Redefined to be readwrite. |
+@property(nonatomic, assign) const BookmarkNode* bookmark; |
+ |
+// Reference to the bookmark model. |
+@property(nonatomic, assign) BookmarkModel* bookmarkModel; |
+ |
+// The parent of the bookmark. This may be different from |bookmark->parent()| |
+// if the changes have not been saved yet. |folder| then represents the |
+// candidate for the new parent of |bookmark|. This property is always a |
+// non-NULL, valid folder. |
+@property(nonatomic, assign) const BookmarkNode* folder; |
+ |
+// The folder picker view controller. |
+// Redefined to be readwrite. |
+@property(nonatomic, retain) BookmarkFolderViewController* folderViewController; |
+ |
+@property(nonatomic, assign) ios::ChromeBrowserState* browserState; |
+ |
+// Cancel button item in navigation bar. |
+@property(nonatomic, retain) UIBarButtonItem* cancelItem; |
+ |
+// Done button item in navigation bar. |
+@property(nonatomic, retain) UIBarButtonItem* doneItem; |
+ |
+// CollectionViewItem-s from the collection. |
+@property(nonatomic, retain) BookmarkTextFieldItem* nameItem; |
+@property(nonatomic, retain) BookmarkParentFolderItem* folderItem; |
+@property(nonatomic, retain) BookmarkTextFieldItem* URLItem; |
+ |
+// Reports the changes to the delegate, that has the responsibility to save the |
+// bookmark. |
+- (void)commitBookmarkChanges; |
+ |
+// Changes |self.folder| and updates the UI accordingly. |
+// The change is not committed until the user taps the Save button. |
+- (void)changeFolder:(const BookmarkNode*)folder; |
+ |
+// The Save button is disabled if the form values are deemed non-valid. This |
+// method updates the state of the Save button accordingly. |
+- (void)updateSaveButtonState; |
+ |
+// Reloads the folder label text. |
+- (void)updateFolderLabel; |
+ |
+// Populates the UI with information from the models. |
+- (void)updateUIFromBookmark; |
+ |
+// Called when the Delete button is pressed. |
+- (void)deleteBookmark; |
+ |
+// Called when the Folder button is pressed. |
+- (void)moveBookmark; |
+ |
+// Called when the Cancel button is pressed. |
+- (void)cancel; |
+ |
+// Called when the Done button is pressed. |
+- (void)save; |
+ |
+@end |
+ |
+#pragma mark |
+ |
+@implementation BookmarkEditViewController |
+ |
+@synthesize bookmark = _bookmark; |
+@synthesize bookmarkModel = _bookmarkModel; |
+@synthesize delegate = _delegate; |
+@synthesize folder = _folder; |
+@synthesize folderViewController = _folderViewController; |
+@synthesize browserState = _browserState; |
+@synthesize cancelItem = _cancelItem; |
+@synthesize doneItem = _doneItem; |
+@synthesize nameItem = _nameItem; |
+@synthesize folderItem = _folderItem; |
+@synthesize URLItem = _URLItem; |
+ |
+#pragma mark - Lifecycle |
+ |
+- (instancetype)initWithBookmark:(const BookmarkNode*)bookmark |
+ browserState:(ios::ChromeBrowserState*)browserState { |
+ DCHECK(bookmark); |
+ DCHECK(browserState); |
+ self = [super initWithStyle:CollectionViewControllerStyleAppBar]; |
+ if (self) { |
+ _propertyReleaser_BookmarkEditViewController.Init( |
+ self, [BookmarkEditViewController class]); |
+ DCHECK(!bookmark->is_folder()); |
+ DCHECK(!browserState->IsOffTheRecord()); |
+ _bookmark = bookmark; |
+ _bookmarkModel = |
+ ios::BookmarkModelFactory::GetForBrowserState(browserState); |
+ |
+ _folder = bookmark->parent(); |
+ |
+ // Set up the bookmark model oberver. |
+ _modelBridge.reset( |
+ new bookmarks::BookmarkModelBridge(self, _bookmarkModel)); |
+ |
+ _browserState = browserState; |
+ } |
+ return self; |
+} |
+ |
+- (void)dealloc { |
+ _folderViewController.delegate = nil; |
+ [super dealloc]; |
+} |
+ |
+#pragma mark View lifecycle |
+ |
+- (void)viewDidLoad { |
+ [super viewDidLoad]; |
+ self.collectionView.backgroundColor = [UIColor whiteColor]; |
+ self.view.accessibilityIdentifier = @"Single Bookmark Editor"; |
+ |
+ self.title = l10n_util::GetNSString(IDS_IOS_BOOKMARK_EDIT_SCREEN_TITLE); |
+ |
+ self.navigationItem.hidesBackButton = YES; |
+ |
+ UIBarButtonItem* cancelItem = |
+ [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon closeIcon] |
+ target:self |
+ action:@selector(cancel)]; |
+ cancelItem.accessibilityIdentifier = @"Cancel"; |
+ self.navigationItem.leftBarButtonItem = cancelItem; |
+ self.cancelItem = cancelItem; |
+ |
+ base::scoped_nsobject<UIBarButtonItem> doneItem([[UIBarButtonItem alloc] |
+ initWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_DONE_BUTTON) |
+ style:UIBarButtonItemStylePlain |
+ target:self |
+ action:@selector(save)]); |
+ doneItem.get().accessibilityIdentifier = @"Done"; |
+ self.navigationItem.rightBarButtonItem = doneItem; |
+ self.doneItem = doneItem; |
+ |
+ base::scoped_nsobject<BookmarksElevatedToolbar> buttonBar( |
+ [[BookmarksElevatedToolbar alloc] init]); |
+ base::scoped_nsobject<UIBarButtonItem> deleteItem([[UIBarButtonItem alloc] |
+ initWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_DELETE) |
+ style:UIBarButtonItemStylePlain |
+ target:self |
+ action:@selector(deleteBookmark)]); |
+ deleteItem.get().accessibilityIdentifier = @"Delete_action"; |
+ [deleteItem setTitleTextAttributes:@{ |
+ NSForegroundColorAttributeName : [UIColor blackColor] |
+ } |
+ forState:UIControlStateNormal]; |
+ [buttonBar.get().layer |
+ addSublayer:[[[MDCShadowLayer alloc] init] autorelease]]; |
+ buttonBar.get().shadowElevation = MDCShadowElevationSearchBarResting; |
+ buttonBar.get().backgroundColor = [UIColor whiteColor]; |
+ buttonBar.get().items = @[ deleteItem ]; |
+ [self.view addSubview:buttonBar]; |
+ |
+ // Constraint |buttonBar| to be in bottom |
+ buttonBar.get().translatesAutoresizingMaskIntoConstraints = NO; |
+ [self.view addConstraints: |
+ [NSLayoutConstraint |
+ constraintsWithVisualFormat:@"H:|[buttonBar]|" |
+ options:0 |
+ metrics:nil |
+ views:NSDictionaryOfVariableBindings( |
+ buttonBar)]]; |
+ [self.view addConstraint:[NSLayoutConstraint |
+ constraintWithItem:buttonBar |
+ attribute:NSLayoutAttributeBottom |
+ relatedBy:NSLayoutRelationEqual |
+ toItem:self.view |
+ attribute:NSLayoutAttributeBottom |
+ multiplier:1.0 |
+ constant:0.0]]; |
+ [self.view |
+ addConstraint:[NSLayoutConstraint |
+ constraintWithItem:buttonBar |
+ attribute:NSLayoutAttributeHeight |
+ relatedBy:NSLayoutRelationEqual |
+ toItem:nil |
+ attribute:NSLayoutAttributeNotAnAttribute |
+ multiplier:1.0 |
+ constant:48.0]]; |
+ [self updateUIFromBookmark]; |
+} |
+ |
+#pragma mark - Accessibility |
+ |
+- (BOOL)accessibilityPerformEscape { |
+ [self cancel]; |
+ return YES; |
+} |
+ |
+#pragma mark - Private |
+ |
+- (BOOL)inputURLIsValid { |
+ return ConvertUserDataToGURL([self inputURLString]).is_valid(); |
+} |
+ |
+// Retrieves input URL string from UI. |
+- (NSString*)inputURLString { |
+ return self.URLItem.text; |
+} |
+ |
+// Retrieves input bookmark name string from UI. |
+- (NSString*)inputBookmarkName { |
+ return self.nameItem.text; |
+} |
+ |
+- (void)commitBookmarkChanges { |
+ // To stop getting recursive events from committed bookmark editing changes |
+ // ignore bookmark model updates notifications. |
+ base::AutoReset<BOOL> autoReset(&_ignoresBookmarkModelChanges, YES); |
+ |
+ GURL url = ConvertUserDataToGURL([self inputURLString]); |
+ // If the URL was not valid, the |save| message shouldn't have been sent. |
+ DCHECK([self inputURLIsValid]); |
+ bookmark_utils_ios::CreateOrUpdateBookmarkWithUndoToast( |
+ self.bookmark, [self inputBookmarkName], url, self.folder, |
+ self.bookmarkModel, self.browserState); |
+} |
+ |
+- (void)changeFolder:(const BookmarkNode*)folder { |
+ DCHECK(folder->is_folder()); |
+ self.folder = folder; |
+ [BookmarkInteractionController setFolderForNewBookmarks:self.folder |
+ inBrowserState:self.browserState]; |
+ [self updateFolderLabel]; |
+} |
+ |
+- (void)dismiss { |
+ [self.view resignFirstResponder]; |
+ |
+ // Dismiss this controller. |
+ [self.delegate bookmarkEditorWantsDismissal:self]; |
+} |
+ |
+#pragma mark - Layout |
+ |
+- (void)updateSaveButtonState { |
+ self.doneItem.enabled = [self inputURLIsValid]; |
+} |
+ |
+- (void)updateFolderLabel { |
+ NSIndexPath* indexPath = |
+ [self.collectionViewModel indexPathForItemType:ItemTypeFolder |
+ sectionIdentifier:SectionIdentifierInfo]; |
+ NSString* folderName = @""; |
+ if (self.bookmark) { |
+ folderName = bookmark_utils_ios::TitleForBookmarkNode(self.folder); |
+ } |
+ |
+ self.folderItem.title = folderName; |
+ [self.collectionView reloadItemsAtIndexPaths:@[ indexPath ]]; |
+} |
+ |
+- (void)updateUIFromBookmark { |
+ // If there is no current bookmark, don't update. |
+ if (!self.bookmark) |
+ return; |
+ |
+ [self loadModel]; |
+ CollectionViewModel* model = self.collectionViewModel; |
+ |
+ [model addSectionWithIdentifier:SectionIdentifierInfo]; |
+ |
+ self.nameItem = |
+ [[[BookmarkTextFieldItem alloc] initWithType:ItemTypeName] autorelease]; |
+ self.nameItem.accessibilityIdentifier = @"Title Field"; |
+ self.nameItem.placeholder = |
+ l10n_util::GetNSString(IDS_IOS_BOOKMARK_NAME_FIELD_HEADER); |
+ self.nameItem.text = bookmark_utils_ios::TitleForBookmarkNode(self.bookmark); |
+ self.nameItem.delegate = self; |
+ [model addItem:self.nameItem toSectionWithIdentifier:SectionIdentifierInfo]; |
+ |
+ self.folderItem = |
+ [[BookmarkParentFolderItem alloc] initWithType:ItemTypeFolder]; |
+ self.folderItem.title = bookmark_utils_ios::TitleForBookmarkNode(self.folder); |
+ [model addItem:self.folderItem toSectionWithIdentifier:SectionIdentifierInfo]; |
+ |
+ self.URLItem = |
+ [[[BookmarkTextFieldItem alloc] initWithType:ItemTypeURL] autorelease]; |
+ self.URLItem.accessibilityIdentifier = @"URL Field"; |
+ self.URLItem.placeholder = |
+ l10n_util::GetNSString(IDS_IOS_BOOKMARK_URL_FIELD_HEADER); |
+ self.URLItem.text = base::SysUTF8ToNSString(self.bookmark->url().spec()); |
+ self.URLItem.delegate = self; |
+ [model addItem:self.URLItem toSectionWithIdentifier:SectionIdentifierInfo]; |
+ |
+ // Save button state. |
+ [self updateSaveButtonState]; |
+} |
+ |
+#pragma mark - Actions |
+ |
+- (void)deleteBookmark { |
+ if (self.bookmark && self.bookmarkModel->loaded()) { |
+ // To stop getting recursive events from committed bookmark editing changes |
+ // ignore bookmark model updates notifications. |
+ base::AutoReset<BOOL> autoReset(&_ignoresBookmarkModelChanges, YES); |
+ |
+ std::set<const BookmarkNode*> nodes; |
+ if ([self.delegate bookmarkEditor:self |
+ shoudDeleteAllOccurencesOfBookmark:self.bookmark]) { |
+ // When launched from the star button, removing the current bookmark |
+ // removes all matching nodes. |
+ std::vector<const BookmarkNode*> nodesVector; |
+ self.bookmarkModel->GetNodesByURL(self.bookmark->url(), &nodesVector); |
+ for (const BookmarkNode* node : nodesVector) |
+ nodes.insert(node); |
+ } else { |
+ // When launched from the info button, removing the current bookmark only |
+ // removes the current node. |
+ nodes.insert(self.bookmark); |
+ } |
+ bookmark_utils_ios::DeleteBookmarksWithUndoToast(nodes, self.bookmarkModel, |
+ self.browserState); |
+ self.bookmark = nil; |
+ } |
+ [self.delegate bookmarkEditorWantsDismissal:self]; |
+} |
+ |
+- (void)moveBookmark { |
+ DCHECK(self.bookmarkModel); |
+ DCHECK(!self.folderViewController); |
+ |
+ std::set<const BookmarkNode*> editedNodes; |
+ editedNodes.insert(self.bookmark); |
+ base::scoped_nsobject<BookmarkFolderViewController> folderViewController( |
+ [[BookmarkFolderViewController alloc] |
+ initWithBookmarkModel:self.bookmarkModel |
+ allowsNewFolders:YES |
+ editedNodes:editedNodes |
+ allowsCancel:NO |
+ selectedFolder:self.folder]); |
+ folderViewController.get().delegate = self; |
+ self.folderViewController = folderViewController; |
+ |
+ [self.navigationController pushViewController:self.folderViewController |
+ animated:YES]; |
+} |
+ |
+- (void)cancel { |
+ [self dismiss]; |
+} |
+ |
+- (void)save { |
+ [self commitBookmarkChanges]; |
+ [self dismiss]; |
+} |
+ |
+#pragma mark - BookmarkTextFieldItemDelegate |
+ |
+- (void)textDidChangeForItem:(BookmarkTextFieldItem*)item { |
+ [self updateSaveButtonState]; |
+} |
+ |
+- (BOOL)textFieldShouldReturn:(UITextField*)textField { |
+ [textField resignFirstResponder]; |
+ return YES; |
+} |
+ |
+#pragma mark - TextFieldValidation |
+ |
+- (NSString*)validationErrorForTextField:(id<TextFieldStyling>)field { |
+ [self updateSaveButtonState]; |
+ if ([self inputURLIsValid]) { |
+ return nil; |
+ } else { |
+ return l10n_util::GetNSString(IDS_IOS_BOOKMARK_URL_FIELD_VALIDATION_FAILED); |
+ } |
+} |
+ |
+#pragma mark - UICollectionViewDataSource |
+ |
+- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView |
+ cellForItemAtIndexPath:(NSIndexPath*)indexPath { |
+ UICollectionViewCell* cell = |
+ [super collectionView:collectionView cellForItemAtIndexPath:indexPath]; |
+ if ([self.collectionViewModel itemTypeForIndexPath:indexPath] == |
+ ItemTypeURL) { |
+ BookmarkTextFieldCell* URLCell = |
+ base::mac::ObjCCastStrict<BookmarkTextFieldCell>(cell); |
+ URLCell.textField.textValidator = self; |
+ } |
+ return cell; |
+} |
+ |
+#pragma mark - UICollectionViewDelegate |
+ |
+- (void)collectionView:(UICollectionView*)collectionView |
+ didSelectItemAtIndexPath:(NSIndexPath*)indexPath { |
+ [super collectionView:collectionView didSelectItemAtIndexPath:indexPath]; |
+ if ([self.collectionViewModel itemTypeForIndexPath:indexPath] == |
+ ItemTypeFolder) { |
+ [self moveBookmark]; |
+ } |
+} |
+ |
+#pragma mark - MDCCollectionViewStylingDelegate |
+ |
+- (CGFloat)collectionView:(UICollectionView*)collectionView |
+ cellHeightAtIndexPath:(NSIndexPath*)indexPath { |
+ switch ([self.collectionViewModel itemTypeForIndexPath:indexPath]) { |
+ case ItemTypeName: |
+ case ItemTypeURL: |
+ return 88; |
+ case ItemTypeFolder: |
+ return 50; |
+ default: |
+ NOTREACHED(); |
+ return 0; |
+ } |
+} |
+ |
+#pragma mark - BookmarkFolderViewControllerDelegate |
+ |
+- (void)folderPicker:(BookmarkFolderViewController*)folderPicker |
+ didFinishWithFolder:(const BookmarkNode*)folder { |
+ [self changeFolder:folder]; |
+ // This delegate method can be called on two occasions: |
+ // - the user selected a folder in the folder picker. In that case, the folder |
+ // picker should be popped; |
+ // - the user created a new folder, in which case the navigation stack |
+ // contains this bookmark editor (|self|), a folder picker and a folder |
+ // creator. In such a case, both the folder picker and creator shoud be popped |
+ // to reveal this bookmark editor. Thus the call to |
+ // |popToViewController:animated:|. |
+ [self.navigationController popToViewController:self animated:YES]; |
+ self.folderViewController.delegate = nil; |
+ self.folderViewController = nil; |
+} |
+ |
+- (void)folderPickerDidCancel:(BookmarkFolderViewController*)folderPicker { |
+ // This delegate method can only be called from the folder picker, which is |
+ // the only view controller on top of this bookmark editor (|self|). Thus the |
+ // call to |popViewControllerAnimated:|. |
+ [self.navigationController popViewControllerAnimated:YES]; |
+ self.folderViewController.delegate = nil; |
+ self.folderViewController = nil; |
+} |
+ |
+#pragma mark - BookmarkModelBridgeObserver |
+ |
+- (void)bookmarkModelLoaded { |
+ // No-op. |
+} |
+ |
+- (void)bookmarkNodeChanged:(const BookmarkNode*)bookmarkNode { |
+ if (_ignoresBookmarkModelChanges) |
+ return; |
+ |
+ if (self.bookmark == bookmarkNode) |
+ [self updateUIFromBookmark]; |
+} |
+ |
+- (void)bookmarkNodeChildrenChanged:(const BookmarkNode*)bookmarkNode { |
+ if (_ignoresBookmarkModelChanges) |
+ return; |
+ |
+ [self updateFolderLabel]; |
+} |
+ |
+- (void)bookmarkNode:(const BookmarkNode*)bookmarkNode |
+ movedFromParent:(const BookmarkNode*)oldParent |
+ toParent:(const BookmarkNode*)newParent { |
+ if (_ignoresBookmarkModelChanges) |
+ return; |
+ |
+ if (self.bookmark == bookmarkNode) |
+ [self.folderViewController changeSelectedFolder:newParent]; |
+} |
+ |
+- (void)bookmarkNodeDeleted:(const BookmarkNode*)bookmarkNode |
+ fromFolder:(const BookmarkNode*)folder { |
+ if (_ignoresBookmarkModelChanges) |
+ return; |
+ |
+ if (self.bookmark == bookmarkNode) { |
+ self.bookmark = nil; |
+ [self.delegate bookmarkEditorWantsDismissal:self]; |
+ } else if (self.folder == bookmarkNode) { |
+ [self changeFolder:self.bookmarkModel->mobile_node()]; |
+ } |
+} |
+ |
+- (void)bookmarkModelRemovedAllNodes { |
+ if (_ignoresBookmarkModelChanges) |
+ return; |
+ |
+ self.bookmark = nil; |
+ if (!self.bookmarkModel->is_permanent_node(self.folder)) { |
+ [self changeFolder:self.bookmarkModel->mobile_node()]; |
+ } |
+ |
+ [self.delegate bookmarkEditorWantsDismissal:self]; |
+} |
+ |
+#pragma mark - UIResponder |
+ |
+- (NSArray*)keyCommands { |
+ base::WeakNSObject<BookmarkEditViewController> weakSelf(self); |
+ return @[ [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape |
+ modifierFlags:Cr_UIKeyModifierNone |
+ title:nil |
+ action:^{ |
+ [weakSelf dismiss]; |
+ }] ]; |
+} |
+ |
+@end |