Updates file type selector for fileSystem API

Allows developers to explicitly specify what accept types they would like to allow in their file selectors, as well as whether they allow all files as a last option.

BUG=133066
TEST=Test cases, manual testing

Review URL: https://chromiumcodereview.appspot.com/10692105

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@150515 0039d316-1c4b-4281-b951-d872f2087c98
parent 5dfb5270
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/file_util.h" #include "base/file_util.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/shell_window_registry.h" #include "chrome/browser/extensions/shell_window_registry.h"
#include "chrome/browser/platform_util.h" #include "chrome/browser/platform_util.h"
...@@ -16,6 +17,8 @@ ...@@ -16,6 +17,8 @@
#include "chrome/browser/ui/extensions/shell_window.h" #include "chrome/browser/ui/extensions/shell_window.h"
#include "chrome/common/extensions/api/file_system.h" #include "chrome/common/extensions/api/file_system.h"
#include "chrome/common/extensions/permissions/api_permission.h" #include "chrome/common/extensions/permissions/api_permission.h"
#include "grit/generated_resources.h"
#include "net/base/mime_util.h"
#include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
...@@ -23,6 +26,8 @@ ...@@ -23,6 +26,8 @@
#include "webkit/fileapi/file_system_types.h" #include "webkit/fileapi/file_system_types.h"
#include "webkit/fileapi/file_system_util.h" #include "webkit/fileapi/file_system_util.h"
#include "webkit/fileapi/isolated_context.h" #include "webkit/fileapi/isolated_context.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/dialogs/select_file_dialog.h"
using fileapi::IsolatedContext; using fileapi::IsolatedContext;
...@@ -132,6 +137,76 @@ bool DoCheckWritableFile(const FilePath& path) { ...@@ -132,6 +137,76 @@ bool DoCheckWritableFile(const FilePath& path) {
error == base::PLATFORM_FILE_ERROR_EXISTS; error == base::PLATFORM_FILE_ERROR_EXISTS;
} }
// Expand the mime-types and extensions provided in an AcceptOption, returning
// them within the passed extension vector. Returns false if no valid types
// were found.
bool GetFileTypesFromAcceptOption(
const file_system::AcceptOption& accept_option,
std::vector<FilePath::StringType>* extensions,
string16* description) {
std::set<FilePath::StringType> extension_set;
int description_id = 0;
bool valid_type = false;
if (accept_option.mime_types.get()) {
std::vector<std::string>* list = accept_option.mime_types.get();
for (std::vector<std::string>::const_iterator iter = list->begin();
iter != list->end(); ++iter) {
std::vector<FilePath::StringType> inner;
std::string accept_type = *iter;
StringToLowerASCII(&accept_type);
if (*iter == "image/*") {
description_id = IDS_IMAGE_FILES;
net::GetImageExtensions(&inner);
} else if (*iter == "audio/*") {
description_id = IDS_AUDIO_FILES;
net::GetAudioExtensions(&inner);
} else if (*iter == "video/*") {
description_id = IDS_VIDEO_FILES;
net::GetVideoExtensions(&inner);
} else {
net::GetExtensionsForMimeType(*iter, &inner);
}
if (inner.empty())
continue;
if (description_id && valid_type)
description_id = 0; // We already have an accept type with label; if
// we find another, give up and use the default.
extension_set.insert(inner.begin(), inner.end());
valid_type = true;
}
}
if (accept_option.extensions.get()) {
std::vector<std::string>* list = accept_option.extensions.get();
for (std::vector<std::string>::const_iterator iter = list->begin();
iter != list->end(); ++iter) {
std::string extension = *iter;
StringToLowerASCII(&extension);
#if defined(OS_WIN)
extension_set.insert(UTF8ToWide(*iter));
#else
extension_set.insert(*iter);
#endif
}
}
extensions->assign(extension_set.begin(), extension_set.end());
if (extensions->empty())
return false;
if (accept_option.description.get())
*description = UTF8ToUTF16(*accept_option.description.get());
else if (description_id)
*description = l10n_util::GetStringUTF16(description_id);
return true;
}
} // namespace } // namespace
namespace extensions { namespace extensions {
...@@ -264,6 +339,7 @@ class FileSystemChooseFileFunction::FilePicker ...@@ -264,6 +339,7 @@ class FileSystemChooseFileFunction::FilePicker
FilePicker(FileSystemChooseFileFunction* function, FilePicker(FileSystemChooseFileFunction* function,
content::WebContents* web_contents, content::WebContents* web_contents,
const FilePath& suggested_name, const FilePath& suggested_name,
const ui::SelectFileDialog::FileTypeInfo& file_type_info,
ui::SelectFileDialog::Type picker_type, ui::SelectFileDialog::Type picker_type,
EntryType entry_type) EntryType entry_type)
: suggested_name_(suggested_name), : suggested_name_(suggested_name),
...@@ -271,14 +347,6 @@ class FileSystemChooseFileFunction::FilePicker ...@@ -271,14 +347,6 @@ class FileSystemChooseFileFunction::FilePicker
function_(function) { function_(function) {
select_file_dialog_ = ui::SelectFileDialog::Create( select_file_dialog_ = ui::SelectFileDialog::Create(
this, new ChromeSelectFilePolicy(web_contents)); this, new ChromeSelectFilePolicy(web_contents));
ui::SelectFileDialog::FileTypeInfo file_type_info;
FilePath::StringType extension = suggested_name.Extension();
if (!extension.empty()) {
extension.erase(extension.begin()); // drop the .
file_type_info.extensions.resize(1);
file_type_info.extensions[0].push_back(extension);
}
file_type_info.include_all_files = true;
gfx::NativeWindow owning_window = web_contents ? gfx::NativeWindow owning_window = web_contents ?
platform_util::GetTopLevel(web_contents->GetNativeView()) : NULL; platform_util::GetTopLevel(web_contents->GetNativeView()) : NULL;
...@@ -309,7 +377,7 @@ class FileSystemChooseFileFunction::FilePicker ...@@ -309,7 +377,7 @@ class FileSystemChooseFileFunction::FilePicker
virtual ~FilePicker() {} virtual ~FilePicker() {}
private: private:
// SelectFileDialog::Listener implementation. // ui::SelectFileDialog::Listener implementation.
virtual void FileSelected(const FilePath& path, virtual void FileSelected(const FilePath& path,
int index, int index,
void* params) OVERRIDE { void* params) OVERRIDE {
...@@ -334,6 +402,7 @@ class FileSystemChooseFileFunction::FilePicker ...@@ -334,6 +402,7 @@ class FileSystemChooseFileFunction::FilePicker
bool FileSystemChooseFileFunction::ShowPicker( bool FileSystemChooseFileFunction::ShowPicker(
const FilePath& suggested_name, const FilePath& suggested_name,
const ui::SelectFileDialog::FileTypeInfo& file_type_info,
ui::SelectFileDialog::Type picker_type, ui::SelectFileDialog::Type picker_type,
EntryType entry_type) { EntryType entry_type) {
ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile());
...@@ -350,7 +419,7 @@ bool FileSystemChooseFileFunction::ShowPicker( ...@@ -350,7 +419,7 @@ bool FileSystemChooseFileFunction::ShowPicker(
// user has selected a file or cancelled the picker. At that point, the picker // user has selected a file or cancelled the picker. At that point, the picker
// will delete itself, which will also free the function instance. // will delete itself, which will also free the function instance.
new FilePicker(this, shell_window->web_contents(), suggested_name, new FilePicker(this, shell_window->web_contents(), suggested_name,
picker_type, entry_type); file_type_info, picker_type, entry_type);
return true; return true;
} }
...@@ -390,11 +459,72 @@ void FileSystemChooseFileFunction::FileSelectionCanceled() { ...@@ -390,11 +459,72 @@ void FileSystemChooseFileFunction::FileSelectionCanceled() {
SendResponse(false); SendResponse(false);
} }
void FileSystemChooseFileFunction::BuildFileTypeInfo(
ui::SelectFileDialog::FileTypeInfo* file_type_info,
const FilePath::StringType& suggested_extension,
const AcceptOptions* accepts,
const bool* acceptsAllTypes) {
file_type_info->include_all_files = true;
if (acceptsAllTypes)
file_type_info->include_all_files = *acceptsAllTypes;
bool need_suggestion = !file_type_info->include_all_files &&
!suggested_extension.empty();
if (accepts) {
typedef file_system::AcceptOption AcceptOption;
for (std::vector<linked_ptr<AcceptOption> >::const_iterator iter =
accepts->begin(); iter != accepts->end(); ++iter) {
string16 description;
std::vector<FilePath::StringType> extensions;
if (!GetFileTypesFromAcceptOption(**iter, &extensions, &description))
continue; // No extensions were found.
file_type_info->extensions.push_back(extensions);
file_type_info->extension_description_overrides.push_back(description);
// If we still need to find suggested_extension, hunt for it inside the
// extensions returned from GetFileTypesFromAcceptOption.
if (need_suggestion && std::find(extensions.begin(),
extensions.end(), suggested_extension) != extensions.end()) {
need_suggestion = false;
}
}
}
// If there's nothing in our accepted extension list or we couldn't find the
// suggested extension required, then default to accepting all types.
if (file_type_info->extensions.empty() || need_suggestion)
file_type_info->include_all_files = true;
}
void FileSystemChooseFileFunction::BuildSuggestion(
const std::string *opt_name,
FilePath* suggested_name,
FilePath::StringType* suggested_extension) {
if (opt_name) {
*suggested_name = FilePath::FromUTF8Unsafe(*opt_name);
// Don't allow any path components; shorten to the base name. This should
// result in a relative path, but in some cases may not. Clear the
// suggestion for safety if this is the case.
*suggested_name = suggested_name->BaseName();
if (suggested_name->IsAbsolute())
*suggested_name = FilePath();
*suggested_extension = suggested_name->Extension();
if (!suggested_extension->empty())
suggested_extension->erase(suggested_extension->begin()); // drop the .
}
}
bool FileSystemChooseFileFunction::RunImpl() { bool FileSystemChooseFileFunction::RunImpl() {
scoped_ptr<ChooseFile::Params> params(ChooseFile::Params::Create(*args_)); scoped_ptr<ChooseFile::Params> params(ChooseFile::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get()); EXTENSION_FUNCTION_VALIDATE(params.get());
FilePath suggested_name; FilePath suggested_name;
ui::SelectFileDialog::FileTypeInfo file_type_info;
EntryType entry_type = READ_ONLY; EntryType entry_type = READ_ONLY;
ui::SelectFileDialog::Type picker_type = ui::SelectFileDialog::Type picker_type =
ui::SelectFileDialog::SELECT_OPEN_FILE; ui::SelectFileDialog::SELECT_OPEN_FILE;
...@@ -413,18 +543,12 @@ bool FileSystemChooseFileFunction::RunImpl() { ...@@ -413,18 +543,12 @@ bool FileSystemChooseFileFunction::RunImpl() {
} }
} }
if (options->suggested_name.get()) { FilePath::StringType suggested_extension;
suggested_name = FilePath::FromUTF8Unsafe( BuildSuggestion(options->suggested_name.get(), &suggested_name,
*options->suggested_name.get()); &suggested_extension);
// Don't allow any path components; shorten to the base name. This should BuildFileTypeInfo(&file_type_info, suggested_extension,
// result in a relative path, but in some cases may not. Clear the options->accepts.get(), options->accepts_all_types.get());
// suggestion for safety if this is the case.
suggested_name = suggested_name.BaseName();
if (suggested_name.IsAbsolute()) {
suggested_name = FilePath();
}
}
} }
if (entry_type == WRITABLE && !HasFileSystemWritePermission()) { if (entry_type == WRITABLE && !HasFileSystemWritePermission()) {
...@@ -432,7 +556,7 @@ bool FileSystemChooseFileFunction::RunImpl() { ...@@ -432,7 +556,7 @@ bool FileSystemChooseFileFunction::RunImpl() {
return false; return false;
} }
return ShowPicker(suggested_name, picker_type, entry_type); return ShowPicker(suggested_name, file_type_info, picker_type, entry_type);
} }
} // namespace extensions } // namespace extensions
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_ #define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
#include "chrome/browser/extensions/extension_function.h" #include "chrome/browser/extensions/extension_function.h"
#include "chrome/common/extensions/api/file_system.h"
#include "ui/base/dialogs/select_file_dialog.h" #include "ui/base/dialogs/select_file_dialog.h"
namespace extensions { namespace extensions {
...@@ -72,12 +73,25 @@ class FileSystemChooseFileFunction : public FileSystemEntryFunction { ...@@ -72,12 +73,25 @@ class FileSystemChooseFileFunction : public FileSystemEntryFunction {
DECLARE_EXTENSION_FUNCTION_NAME("fileSystem.chooseFile"); DECLARE_EXTENSION_FUNCTION_NAME("fileSystem.chooseFile");
typedef std::vector<linked_ptr<extensions::api::file_system::AcceptOption> >
AcceptOptions;
static void BuildFileTypeInfo(
ui::SelectFileDialog::FileTypeInfo* file_type_info,
const FilePath::StringType& suggested_extension,
const AcceptOptions* accepts,
const bool* acceptsAllTypes);
static void BuildSuggestion(const std::string* opt_name,
FilePath* suggested_name,
FilePath::StringType* suggested_extension);
protected: protected:
class FilePicker; class FilePicker;
virtual ~FileSystemChooseFileFunction() {} virtual ~FileSystemChooseFileFunction() {}
virtual bool RunImpl() OVERRIDE; virtual bool RunImpl() OVERRIDE;
bool ShowPicker(const FilePath& suggested_path, bool ShowPicker(const FilePath& suggested_path,
const ui::SelectFileDialog::FileTypeInfo& file_type_info,
ui::SelectFileDialog::Type picker_type, ui::SelectFileDialog::Type picker_type,
EntryType entry_type); EntryType entry_type);
......
// Copyright (c) 2012 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.
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/string_split.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/api/file_system/file_system_api.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/dialogs/select_file_dialog.h"
using extensions::FileSystemChooseFileFunction;
using extensions::api::file_system::AcceptOption;
namespace {
void CheckExtensions(std::vector<FilePath::StringType>& expected,
std::vector<FilePath::StringType>& actual) {
EXPECT_EQ(expected.size(), actual.size());
if (expected.size() != actual.size())
return;
for (size_t i = 0; i < expected.size(); ++i) {
EXPECT_EQ(expected[i], actual[i]);
}
}
AcceptOption* BuildAcceptOption(std::string description,
std::string mime_types,
std::string extensions) {
AcceptOption* option = new AcceptOption();
if (!description.empty())
option->description.reset(new std::string(description));
if (!mime_types.empty()) {
option->mime_types.reset(new std::vector<std::string>());
base::SplitString(mime_types, ',', option->mime_types.get());
}
if (!extensions.empty()) {
option->extensions.reset(new std::vector<std::string>());
base::SplitString(extensions, ',', option->extensions.get());
}
return option;
}
#if defined(OS_WIN)
#define ToStringType UTF8ToWide
#else
#define ToStringType
#endif
} // namespace
class FileSystemApiUnitTest : public testing::Test {
};
TEST_F(FileSystemApiUnitTest, FileSystemChooseFileFunctionFileTypeInfoTest) {
// AcceptsAllTypes is ignored when no other extensions are available.
ui::SelectFileDialog::FileTypeInfo file_type_info;
bool acceptsAllTypes = false;
FileSystemChooseFileFunction::BuildFileTypeInfo(&file_type_info,
FilePath::StringType(), NULL, &acceptsAllTypes);
EXPECT_TRUE(file_type_info.include_all_files);
EXPECT_TRUE(file_type_info.extensions.empty());
// Test grouping of multiple types.
file_type_info = ui::SelectFileDialog::FileTypeInfo();
std::vector<linked_ptr<AcceptOption> > options;
options.push_back(linked_ptr<AcceptOption>(
BuildAcceptOption("", "application/x-chrome-extension", "jso")));
acceptsAllTypes = false;
FileSystemChooseFileFunction::BuildFileTypeInfo(&file_type_info,
FilePath::StringType(), &options, &acceptsAllTypes);
EXPECT_FALSE(file_type_info.include_all_files);
ASSERT_EQ(file_type_info.extensions.size(), (size_t) 1);
EXPECT_TRUE(file_type_info.extension_description_overrides[0].empty()) <<
"No override must be specified for boring accept types";
// Note here (and below) that the expectedTypes are sorted, because we use a
// set internally to generate the output: thus, the output is sorted.
std::vector<FilePath::StringType> expectedTypes;
expectedTypes.push_back(ToStringType("crx"));
expectedTypes.push_back(ToStringType("jso"));
CheckExtensions(expectedTypes, file_type_info.extensions[0]);
// Test that not satisfying the extension will force all types.
file_type_info = ui::SelectFileDialog::FileTypeInfo();
options.clear();
options.push_back(linked_ptr<AcceptOption>(
BuildAcceptOption("", "", "unrelated")));
acceptsAllTypes = false;
FileSystemChooseFileFunction::BuildFileTypeInfo(&file_type_info,
ToStringType(".jso"), &options, &acceptsAllTypes);
EXPECT_TRUE(file_type_info.include_all_files);
// Test multiple list entries, all containing their own types.
file_type_info = ui::SelectFileDialog::FileTypeInfo();
options.clear();
options.push_back(linked_ptr<AcceptOption>(
BuildAcceptOption("", "", "jso,js")));
options.push_back(linked_ptr<AcceptOption>(
BuildAcceptOption("", "", "cpp,cc")));
acceptsAllTypes = false;
FileSystemChooseFileFunction::BuildFileTypeInfo(&file_type_info,
FilePath::StringType(), &options, &acceptsAllTypes);
ASSERT_EQ(file_type_info.extensions.size(), options.size());
expectedTypes.clear();
expectedTypes.push_back(ToStringType("js"));
expectedTypes.push_back(ToStringType("jso"));
CheckExtensions(expectedTypes, file_type_info.extensions[0]);
expectedTypes.clear();
expectedTypes.push_back(ToStringType("cc"));
expectedTypes.push_back(ToStringType("cpp"));
CheckExtensions(expectedTypes, file_type_info.extensions[1]);
// Test accept type that causes description override.
file_type_info = ui::SelectFileDialog::FileTypeInfo();
options.clear();
options.push_back(linked_ptr<AcceptOption>(
BuildAcceptOption("", "image/*", "html")));
acceptsAllTypes = false;
FileSystemChooseFileFunction::BuildFileTypeInfo(&file_type_info,
FilePath::StringType(), &options, &acceptsAllTypes);
ASSERT_EQ(file_type_info.extension_description_overrides.size(), (size_t) 1);
EXPECT_FALSE(file_type_info.extension_description_overrides[0].empty()) <<
"Accept type \"image/*\" must generate description override";
// Test multiple accept types that cause description override causes us to
// still present the default.
file_type_info = ui::SelectFileDialog::FileTypeInfo();
options.clear();
options.push_back(linked_ptr<AcceptOption>(
BuildAcceptOption("", "image/*,audio/*,video/*", "")));
acceptsAllTypes = false;
FileSystemChooseFileFunction::BuildFileTypeInfo(&file_type_info,
FilePath::StringType(), &options, &acceptsAllTypes);
ASSERT_EQ(file_type_info.extension_description_overrides.size(), (size_t) 1);
EXPECT_TRUE(file_type_info.extension_description_overrides[0].empty());
// Test explicit description override.
file_type_info = ui::SelectFileDialog::FileTypeInfo();
options.clear();
options.push_back(linked_ptr<AcceptOption>(
BuildAcceptOption("File Types 101", "image/jpeg", "")));
acceptsAllTypes = false;
FileSystemChooseFileFunction::BuildFileTypeInfo(&file_type_info,
FilePath::StringType(), &options, &acceptsAllTypes);
EXPECT_EQ(file_type_info.extension_description_overrides[0],
UTF8ToUTF16("File Types 101"));
}
TEST_F(FileSystemApiUnitTest, FileSystemChooseFileFunctionSuggestionTest) {
std::string opt_name;
FilePath suggested_name;
FilePath::StringType suggested_extension;
opt_name = std::string("normal_path.txt");
FileSystemChooseFileFunction::BuildSuggestion(&opt_name, &suggested_name,
&suggested_extension);
EXPECT_FALSE(suggested_name.IsAbsolute());
EXPECT_EQ(suggested_name.MaybeAsASCII(), "normal_path.txt");
EXPECT_EQ(suggested_extension, ToStringType("txt"));
// We should provide just the basename, i.e., "path".
opt_name = std::string("/a/bad/path");
FileSystemChooseFileFunction::BuildSuggestion(&opt_name, &suggested_name,
&suggested_extension);
EXPECT_FALSE(suggested_name.IsAbsolute());
EXPECT_EQ(suggested_name.MaybeAsASCII(), "path");
EXPECT_TRUE(suggested_extension.empty());
#if !defined(OS_WIN)
// TODO(thorogood): Fix this test on Windows.
// Filter out absolute paths with no basename.
opt_name = std::string("/");
FileSystemChooseFileFunction::BuildSuggestion(&opt_name, &suggested_name,
&suggested_extension);
EXPECT_FALSE(suggested_name.IsAbsolute());
EXPECT_TRUE(suggested_name.MaybeAsASCII().empty());
EXPECT_TRUE(suggested_extension.empty());
#endif
}
...@@ -1226,6 +1226,7 @@ ...@@ -1226,6 +1226,7 @@
'browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc', 'browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc',
'browser/extensions/api/discovery/discovery_api_unittest.cc', 'browser/extensions/api/discovery/discovery_api_unittest.cc',
'browser/extensions/api/extension_action/extension_browser_actions_api_unittest.cc', 'browser/extensions/api/extension_action/extension_browser_actions_api_unittest.cc',
'browser/extensions/api/file_system/file_system_api_unittest.cc',
'browser/extensions/api/identity/web_auth_flow_unittest.cc', 'browser/extensions/api/identity/web_auth_flow_unittest.cc',
'browser/extensions/api/idle/idle_api_unittest.cc', 'browser/extensions/api/idle/idle_api_unittest.cc',
'browser/extensions/api/omnibox/omnibox_unittest.cc', 'browser/extensions/api/omnibox/omnibox_unittest.cc',
......
...@@ -5,6 +5,21 @@ ...@@ -5,6 +5,21 @@
// File-level comment to appease parser. Eventually this will not be necessary. // File-level comment to appease parser. Eventually this will not be necessary.
namespace fileSystem { namespace fileSystem {
dictionary AcceptOption {
// This is the optional text description for this option. If not present,
// a description will be automatically generated; typically containing an
// expanded list of valid extensions (e.g. "text/html" may expand to
// "*.html, *.htm").
DOMString? description;
// Mime-types to accept, e.g. "image/jpeg" or "audio/*". One of mimeTypes or
// extensions must contain at least one valid element.
DOMString[]? mimeTypes;
// Extensions to accept, e.g. "jpg", "gif", "crx".
DOMString[]? extensions;
};
dictionary ChooseFileOptions { dictionary ChooseFileOptions {
// Type of the prompt to show. Valid types are 'openFile', // Type of the prompt to show. Valid types are 'openFile',
// 'openWritableFile' or 'saveFile'. // 'openWritableFile' or 'saveFile'.
...@@ -22,6 +37,15 @@ namespace fileSystem { ...@@ -22,6 +37,15 @@ namespace fileSystem {
// The suggested file name that will be presented to the user as the // The suggested file name that will be presented to the user as the
// default name to read or write. This is optional. // default name to read or write. This is optional.
DOMString? suggestedName; DOMString? suggestedName;
// The optional list of accept options for this file opener. Each option
// will be presented as a unique group to the end-user.
AcceptOption[]? accepts;
// Whether to accept all file types, in addition to the options specified
// in the accepts argument. The default is true. If the accepts field is
// unset or contains no valid entries, this will always be reset to true.
boolean? acceptsAllTypes;
}; };
callback GetDisplayPathCallback = void (DOMString displayPath); callback GetDisplayPathCallback = void (DOMString displayPath);
callback FileEntryCallback = void ([instanceOf=FileEntry] object fileEntry); callback FileEntryCallback = void ([instanceOf=FileEntry] object fileEntry);
......
...@@ -184,6 +184,10 @@ ...@@ -184,6 +184,10 @@
<a href="#types">Types</a> <a href="#types">Types</a>
<ol> <ol>
<li> <li>
<a href="#type-fileSystem.AcceptOption">fileSystem.AcceptOption</a>
<ol>
</ol>
</li><li>
<a href="#type-fileSystem.ChooseFileOptions">fileSystem.ChooseFileOptions</a> <a href="#type-fileSystem.ChooseFileOptions">fileSystem.ChooseFileOptions</a>
<ol> <ol>
</ol> </ol>
...@@ -647,6 +651,121 @@ ...@@ -647,6 +651,121 @@
<h3 id="types">Types</h3> <h3 id="types">Types</h3>
<!-- iterates over all types --> <!-- iterates over all types -->
<div class="apiItem"> <div class="apiItem">
<a name="type-fileSystem.AcceptOption"></a>
<h4>fileSystem.AcceptOption</h4>
<div>
<dt>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span id="typeTemplate">
<span>
<span>object</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd class="todo">
Undocumented.
</dd>
<!-- OBJECT PROPERTIES -->
<dd>
<dl>
<div>
<div>
<dt>
<var>description</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>string</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>This is the optional text description for this option. If not present, a description will be automatically generated; typically containing an expanded list of valid extensions (e.g. \"text/html\" may expand to \"*.html, *.htm\").</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div><div>
<div>
<dt>
<var>extensions</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>
array of <span><span>
<span>
<span>string</span>
</span>
</span></span>
</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>Extensions to accept, e.g. \"jpg\", \"gif\", \"crx\".</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div><div>
<div>
<dt>
<var>mimeTypes</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>
array of <span><span>
<span>
<span>string</span>
</span>
</span></span>
</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>Mime-types to accept, e.g. \"image/jpeg\" or \"audio/*\". One of mimeTypes or extensions must contain at least one valid element.</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div>
</dl>
</dd>
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div><div class="apiItem">
<a name="type-fileSystem.ChooseFileOptions"></a> <a name="type-fileSystem.ChooseFileOptions"></a>
<h4>fileSystem.ChooseFileOptions</h4> <h4>fileSystem.ChooseFileOptions</h4>
<div> <div>
...@@ -672,6 +791,60 @@ ...@@ -672,6 +791,60 @@
<dl> <dl>
<div> <div>
<div> <div>
<dt>
<var>accepts</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>
array of <span><span>
<span>
<a href="fileSystem.html#type-fileSystem.AcceptOption">fileSystem.AcceptOption</a>
</span>
</span></span>
</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>The optional list of accept options for this file opener. Each option will be presented as a unique group to the end-user.</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div><div>
<div>
<dt>
<var>acceptsAllTypes</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>boolean</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>Whether to accept all file types, in addition to the options specified in the accepts argument. The default is true. If the accepts field is unset or contains no valid entries, this will always be reset to true.</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div><div>
<div>
<dt> <dt>
<var>suggestedName</var> <var>suggestedName</var>
<em> <em>
......
...@@ -215,6 +215,10 @@ ...@@ -215,6 +215,10 @@
<a href="#types">Types</a> <a href="#types">Types</a>
<ol> <ol>
<li> <li>
<a href="#type-fileSystem.AcceptOption">AcceptOption</a>
<ol>
</ol>
</li><li>
<a href="#type-fileSystem.ChooseFileOptions">ChooseFileOptions</a> <a href="#type-fileSystem.ChooseFileOptions">ChooseFileOptions</a>
<ol> <ol>
</ol> </ol>
...@@ -834,6 +838,121 @@ ...@@ -834,6 +838,121 @@
<h3 id="types">Types</h3> <h3 id="types">Types</h3>
<!-- iterates over all types --> <!-- iterates over all types -->
<div class="apiItem"> <div class="apiItem">
<a name="type-fileSystem.AcceptOption"></a>
<h4>fileSystem.AcceptOption</h4>
<div>
<dt>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span id="typeTemplate">
<span>
<span>object</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd class="todo">
Undocumented.
</dd>
<!-- OBJECT PROPERTIES -->
<dd>
<dl>
<div>
<div>
<dt>
<var>description</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>string</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>This is the optional text description for this option. If not present, a description will be automatically generated; typically containing an expanded list of valid extensions (e.g. \"text/html\" may expand to \"*.html, *.htm\").</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div><div>
<div>
<dt>
<var>extensions</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>
array of <span><span>
<span>
<span>string</span>
</span>
</span></span>
</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>Extensions to accept, e.g. \"jpg\", \"gif\", \"crx\".</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div><div>
<div>
<dt>
<var>mimeTypes</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>
array of <span><span>
<span>
<span>string</span>
</span>
</span></span>
</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>Mime-types to accept, e.g. \"image/jpeg\" or \"audio/*\". One of mimeTypes or extensions must contain at least one valid element.</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div>
</dl>
</dd>
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div><div class="apiItem">
<a name="type-fileSystem.ChooseFileOptions"></a> <a name="type-fileSystem.ChooseFileOptions"></a>
<h4>fileSystem.ChooseFileOptions</h4> <h4>fileSystem.ChooseFileOptions</h4>
<div> <div>
...@@ -859,6 +978,60 @@ ...@@ -859,6 +978,60 @@
<dl> <dl>
<div> <div>
<div> <div>
<dt>
<var>accepts</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>
array of <span><span>
<span>
<a href="fileSystem.html#type-fileSystem.AcceptOption">fileSystem.AcceptOption</a>
</span>
</span></span>
</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>The optional list of accept options for this file opener. Each option will be presented as a unique group to the end-user.</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div><div>
<div>
<dt>
<var>acceptsAllTypes</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>boolean</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>Whether to accept all file types, in addition to the options specified in the accepts argument. The default is true. If the accepts field is unset or contains no valid entries, this will always be reset to true.</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div>
</div><div>
<div>
<dt> <dt>
<var>suggestedName</var> <var>suggestedName</var>
<em> <em>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment