mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
feat: use Downloads folder as default path for file dialogs (#49868)
* fix: use Downloads folder as default path for file dialogs Co-authored-by: Sourav Bera <sbera987654321@gmail.com> * chore: improve breaking change description --------- Co-authored-by: Sourav Bera <sbera987654321@gmail.com>
This commit is contained in:
@@ -28,7 +28,10 @@ added:
|
||||
* `window` [BaseWindow](base-window.md) (optional)
|
||||
* `options` Object
|
||||
* `title` string (optional)
|
||||
* `defaultPath` string (optional)
|
||||
* `defaultPath` string (optional) - Absolute directory path, absolute file
|
||||
path, or file name to use by default. If not provided, the dialog will
|
||||
default to the user's Downloads folder, or their home directory if Downloads
|
||||
doesn't exist.
|
||||
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
|
||||
left empty the default label will be used.
|
||||
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
|
||||
@@ -109,7 +112,10 @@ changes:
|
||||
* `window` [BaseWindow](base-window.md) (optional)
|
||||
* `options` Object
|
||||
* `title` string (optional)
|
||||
* `defaultPath` string (optional)
|
||||
* `defaultPath` string (optional) - Absolute directory path, absolute file
|
||||
path, or file name to use by default. If not provided, the dialog will
|
||||
default to the user's Downloads folder, or their home directory if Downloads
|
||||
doesn't exist.
|
||||
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
|
||||
left empty the default label will be used.
|
||||
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
|
||||
@@ -198,7 +204,9 @@ added:
|
||||
* `options` Object
|
||||
* `title` string (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments.
|
||||
* `defaultPath` string (optional) - Absolute directory path, absolute file
|
||||
path, or file name to use by default.
|
||||
path, or file name to use by default. If not provided, the dialog will
|
||||
default to the user's Downloads folder, or their home directory if Downloads
|
||||
doesn't exist.
|
||||
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
|
||||
left empty the default label will be used.
|
||||
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
|
||||
@@ -238,7 +246,9 @@ changes:
|
||||
* `options` Object
|
||||
* `title` string (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments.
|
||||
* `defaultPath` string (optional) - Absolute directory path, absolute file
|
||||
path, or file name to use by default.
|
||||
path, or file name to use by default. If not provided, the dialog will
|
||||
default to the user's Downloads folder, or their home directory if Downloads
|
||||
doesn't exist.
|
||||
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
|
||||
left empty the default label will be used.
|
||||
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
|
||||
|
||||
@@ -12,6 +12,34 @@ This document uses the following convention to categorize breaking changes:
|
||||
* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release.
|
||||
* **Removed:** An API or feature was removed, and is no longer supported by Electron.
|
||||
|
||||
## Planned Breaking API Changes (43.0)
|
||||
|
||||
### Behavior Changed: Dialog methods default to Downloads directory
|
||||
|
||||
The `defaultPath` option for the following methods now defaults to the user's Downloads folder (or their home directory if Downloads doesn't exist) when not explicitly provided:
|
||||
|
||||
* `dialog.showOpenDialog`
|
||||
* `dialog.showOpenDialogSync`
|
||||
* `dialog.showSaveDialog`
|
||||
* `dialog.showSaveDialogSync`
|
||||
|
||||
Previously, when no `defaultPath` was provided, the underlying OS file dialog would determine the initial directory — typically remembering the last directory the user navigated to, or falling back to an OS-specific default. Now, Electron explicitly sets the initial directory to Downloads, which also means the OS will no longer track and restore the last-used directory between dialog invocations.
|
||||
|
||||
To preserve the old behavior, you can track the last-used directory yourself and pass it as `defaultPath`:
|
||||
|
||||
```js
|
||||
const path = require('node:path')
|
||||
|
||||
let lastUsedPath
|
||||
const result = await dialog.showOpenDialog({
|
||||
defaultPath: lastUsedPath
|
||||
})
|
||||
|
||||
if (!result.canceled && result.filePaths.length > 0) {
|
||||
lastUsedPath = path.dirname(result.filePaths[0])
|
||||
}
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (42.0)
|
||||
|
||||
### Behavior Changed: macOS notifications now use `UNNotification` API
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/browser/native_window_views.h"
|
||||
#include "shell/browser/ui/file_dialog.h"
|
||||
#include "shell/common/electron_paths.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
@@ -81,14 +82,18 @@ class FileChooserDialog : public ui::SelectFileDialog::Listener {
|
||||
ui::SelectFileDialog::FileTypeInfo file_info =
|
||||
GetFilterInfo(settings.filters);
|
||||
ApplySettings(settings);
|
||||
dialog_->SelectFile(
|
||||
ui::SelectFileDialog::SELECT_SAVEAS_FILE,
|
||||
base::UTF8ToUTF16(settings.title), settings.default_path,
|
||||
&file_info /* file_types */, 0 /* file_type_index */,
|
||||
base::FilePath::StringType() /* default_extension */,
|
||||
settings.parent_window ? settings.parent_window->GetNativeWindow()
|
||||
: nullptr,
|
||||
nullptr);
|
||||
base::FilePath default_path = settings.default_path.empty()
|
||||
? electron::GetDefaultPath()
|
||||
: settings.default_path;
|
||||
|
||||
dialog_->SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE,
|
||||
base::UTF8ToUTF16(settings.title), default_path,
|
||||
&file_info /* file_types */, 0 /* file_type_index */,
|
||||
base::FilePath::StringType() /* default_extension */,
|
||||
settings.parent_window
|
||||
? settings.parent_window->GetNativeWindow()
|
||||
: nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void RunSaveDialog(gin_helper::Promise<gin_helper::Dictionary> promise,
|
||||
@@ -108,9 +113,13 @@ class FileChooserDialog : public ui::SelectFileDialog::Listener {
|
||||
ui::SelectFileDialog::FileTypeInfo file_info =
|
||||
GetFilterInfo(settings.filters);
|
||||
ApplySettings(settings);
|
||||
base::FilePath default_path = settings.default_path.empty()
|
||||
? electron::GetDefaultPath()
|
||||
: settings.default_path;
|
||||
|
||||
dialog_->SelectFile(
|
||||
GetDialogType(settings.properties), base::UTF8ToUTF16(settings.title),
|
||||
settings.default_path, &file_info, 0 /* file_type_index */,
|
||||
default_path, &file_info, 0 /* file_type_index */,
|
||||
base::FilePath::StringType() /* default_extension */,
|
||||
settings.parent_window ? settings.parent_window->GetNativeWindow()
|
||||
: nullptr,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "electron/mas.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "shell/common/electron_paths.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
@@ -186,14 +187,18 @@ void SetupDialog(NSSavePanel* dialog, const DialogSettings& settings) {
|
||||
|
||||
[dialog setShowsTagField:settings.shows_tag_field];
|
||||
|
||||
base::FilePath default_path = settings.default_path.empty()
|
||||
? electron::GetDefaultPath()
|
||||
: settings.default_path;
|
||||
|
||||
NSString* default_dir = nil;
|
||||
NSString* default_filename = nil;
|
||||
if (!settings.default_path.empty()) {
|
||||
if (!default_path.empty()) {
|
||||
electron::ScopedAllowBlockingForElectron allow_blocking;
|
||||
if (base::DirectoryExists(settings.default_path)) {
|
||||
default_dir = base::SysUTF8ToNSString(settings.default_path.value());
|
||||
if (base::DirectoryExists(default_path)) {
|
||||
default_dir = base::SysUTF8ToNSString(default_path.value());
|
||||
} else {
|
||||
if (settings.default_path.IsAbsolute()) {
|
||||
if (default_path.IsAbsolute()) {
|
||||
default_dir =
|
||||
base::SysUTF8ToNSString(settings.default_path.DirName().value());
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "base/win/registry.h"
|
||||
#include "shell/browser/native_window_views.h"
|
||||
#include "shell/browser/ui/win/dialog_thread.h"
|
||||
#include "shell/common/electron_paths.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
@@ -106,8 +107,12 @@ static HRESULT ShowFileDialog(IFileDialog* dialog,
|
||||
static void ApplySettings(IFileDialog* dialog, const DialogSettings& settings) {
|
||||
std::wstring file_part;
|
||||
|
||||
if (!IsDirectory(settings.default_path))
|
||||
file_part = settings.default_path.BaseName().value();
|
||||
base::FilePath default_path = settings.default_path.empty()
|
||||
? electron::GetDefaultPath()
|
||||
: settings.default_path;
|
||||
|
||||
if (!IsDirectory(default_path))
|
||||
file_part = default_path.BaseName().value();
|
||||
|
||||
dialog->SetFileName(file_part.c_str());
|
||||
|
||||
@@ -149,8 +154,8 @@ static void ApplySettings(IFileDialog* dialog, const DialogSettings& settings) {
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.default_path.IsAbsolute()) {
|
||||
SetDefaultFolder(dialog, settings.default_path);
|
||||
if (default_path.IsAbsolute()) {
|
||||
SetDefaultFolder(dialog, default_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,4 +114,18 @@ void RegisterPathProvider() {
|
||||
PATH_END);
|
||||
}
|
||||
|
||||
base::FilePath GetDefaultPath() {
|
||||
base::FilePath path;
|
||||
|
||||
ScopedAllowBlockingForElectron allow_blocking;
|
||||
if (base::PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &path) &&
|
||||
base::DirectoryExists(path))
|
||||
return path;
|
||||
|
||||
if (base::PathService::Get(base::DIR_HOME, &path))
|
||||
return path;
|
||||
|
||||
return base::FilePath();
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -51,6 +51,10 @@ static_assert(PATH_START < PATH_END, "invalid PATH boundaries");
|
||||
// Register the path provider with the base::PathService.
|
||||
void RegisterPathProvider();
|
||||
|
||||
// Returns a default directory for file dialogs when no default path is
|
||||
// provided.
|
||||
base::FilePath GetDefaultPath();
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_COMMON_ELECTRON_PATHS_H_
|
||||
|
||||
Reference in New Issue
Block a user