Skip to content

feat: keyboard shortcut to export all bookmarks #25827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/brave_command_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@

// Bookmark commands.
#define IDC_TOGGLE_ALL_BOOKMARKS_BUTTON_VISIBILITY 56300
#define IDC_EXPORT_ALL_BOOKMARKS 56312

#define IDC_COMMANDER 56301

Expand Down
4 changes: 4 additions & 0 deletions browser/ui/brave_browser_command_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ void BraveBrowserCommandController::InitBraveCommandState() {
UpdateCommandsForPin();

UpdateCommandEnabled(IDC_TOGGLE_ALL_BOOKMARKS_BUTTON_VISIBILITY, true);
UpdateCommandEnabled(IDC_EXPORT_ALL_BOOKMARKS, true);

if (browser_->is_type_normal()) {
// Delete these when upstream enables by default.
Expand Down Expand Up @@ -654,6 +655,9 @@ bool BraveBrowserCommandController::ExecuteBraveCommandWithDisposition(
case IDC_TOGGLE_ALL_BOOKMARKS_BUTTON_VISIBILITY:
brave::ToggleAllBookmarksButtonVisibility(base::to_address(browser_));
break;
case IDC_EXPORT_ALL_BOOKMARKS:
brave::ExportAllBookmarks(&*browser_);
break;
case IDC_COMMANDER:
#if BUILDFLAG(ENABLE_COMMANDER)
brave::ToggleCommander(base::to_address(browser_));
Expand Down
73 changes: 73 additions & 0 deletions browser/ui/browser_commands.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

#include "base/feature_list.h"
#include "base/functional/callback_helpers.h"
#include "base/i18n/file_util_icu.h"
#include "base/i18n/time_formatting.h"
#include "base/path_service.h"
#include "base/ranges/algorithm.h"
#include "base/strings/utf_string_conversions.h"
#include "brave/app/brave_command_ids.h"
Expand All @@ -35,6 +38,7 @@
#include "brave/components/speedreader/common/buildflags/buildflags.h"
#include "brave/components/tor/buildflags/buildflags.h"
#include "brave/components/url_sanitizer/browser/url_sanitizer_service.h"
#include "chrome/browser/bookmarks/bookmark_html_writer.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
Expand All @@ -54,12 +58,16 @@
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_utils.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/shell_dialogs/select_file_policy.h"
#include "ui/shell_dialogs/selected_file_info.h"
#include "url/origin.h"

#if defined(TOOLKIT_VIEWS)
Expand Down Expand Up @@ -137,6 +145,67 @@ std::vector<int> GetSelectedIndices(Browser* browser) {

} // namespace

/**
* @note This function creates a default filename like
* "bookmarks_10_31_24.html", for example, if the date was October 31, 2024.
*
* @note This function mimics the behavior of a function with the same name in
* the Chromium source code.
*
* @see
* https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc;l=205-222?q=IDS_EXPORT_BOOKMARKS_DEFAULT_FILENAME
*/
base::FilePath GetDefaultFilepathForBookmarkExport() {
std::string bookmarks_MM_DD_YY = l10n_util::GetStringFUTF8(
IDS_EXPORT_BOOKMARKS_DEFAULT_FILENAME,
base::TimeFormatShortDateNumeric(base::Time::Now()));

base::FilePath path = base::FilePath::FromUTF8Unsafe(bookmarks_MM_DD_YY);
base::FilePath::StringType path_str = path.value();
base::i18n::ReplaceIllegalCharactersInPath(&path_str, '_');
base::FilePath default_path;
base::PathService::Get(chrome::DIR_USER_DOCUMENTS, &default_path);
return default_path.Append(base::FilePath(path_str));
}

/**
* @class BookmarksExportListener
* @brief A listener class for handling bookmark export file selection.
*
* This class is responsible for showing a file dialog to the user for selecting
* the location to save exported bookmarks.
*
* @note The lifetime of this class is tied to the FileSelected dialog. It will
* be automatically deleted when the dialog is closed, a file is selected, or
* the dialog is cancelled.
*/
class BookmarksExportListener : public ui::SelectFileDialog::Listener {
public:
explicit BookmarksExportListener(Profile* profile)
: profile_(profile),
file_selector_(ui::SelectFileDialog::Create(this, nullptr)) {}
void FileSelected(const ui::SelectedFileInfo& file, int index) override {
bookmark_html_writer::WriteBookmarks(profile_, file.file_path, nullptr);
delete this;
}
void ShowFileDialog(Browser* browser) {
ui::SelectFileDialog::FileTypeInfo file_types;

// Only show HTML files in the file dialog.
file_types.extensions.push_back({FILE_PATH_LITERAL("html")});
file_selector_->SelectFile(
ui::SelectFileDialog::SELECT_SAVEAS_FILE,
l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_MENU_EXPORT),
GetDefaultFilepathForBookmarkExport(), &file_types, 1,
FILE_PATH_LITERAL("html"), browser->window()->GetNativeWindow(),
nullptr);
}

private:
raw_ptr<Profile> profile_;
scoped_refptr<ui::SelectFileDialog> file_selector_;
};

void NewOffTheRecordWindowTor(Browser* browser) {
CHECK(browser);
NewOffTheRecordWindowTor(browser->profile());
Expand Down Expand Up @@ -898,6 +967,10 @@ void ScrollTabToBottom(Browser* browser) {
contents->ScrollToBottomOfDocument();
}

void ExportAllBookmarks(Browser* browser) {
(new BookmarksExportListener(browser->profile()))->ShowFileDialog(browser);
}

void ToggleAllBookmarksButtonVisibility(Browser* browser) {
auto* prefs = browser->profile()->GetPrefs();
prefs->SetBoolean(
Expand Down
1 change: 1 addition & 0 deletions browser/ui/browser_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ void UnmuteAllTabs(Browser* browser);
void ScrollTabToTop(Browser* browser);
void ScrollTabToBottom(Browser* browser);

void ExportAllBookmarks(Browser* browser);
void ToggleAllBookmarksButtonVisibility(Browser* browser);

// In case |tab| is not provided, the active tab will be used.
Expand Down
3 changes: 3 additions & 0 deletions components/resources/commands.grdp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@
<message name="IDS_IDC_BRAVE_BOOKMARK_BAR_NEVER">
Hide bookmark bar
</message>
<message name="IDS_IDC_EXPORT_ALL_BOOKMARKS">
Export all bookmarks
</message>
<message name="IDS_IDC_TOGGLE_ALL_BOOKMARKS_BUTTON_VISIBILITY">
Toggle All bookmarks button visibility
</message>
Expand Down