mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1258489 - Implement HTMLInputElement.webkitdirectory, r=smaug
This commit is contained in:
parent
b965617dd1
commit
3ad65f3a92
@ -1309,6 +1309,7 @@ GK_ATOM(visuallyselected, "visuallyselected")
|
||||
GK_ATOM(vlink, "vlink")
|
||||
GK_ATOM(vspace, "vspace")
|
||||
GK_ATOM(wbr, "wbr")
|
||||
GK_ATOM(webkitdirectory, "webkitdirectory")
|
||||
GK_ATOM(when, "when")
|
||||
GK_ATOM(where, "where")
|
||||
GK_ATOM(widget, "widget")
|
||||
|
@ -165,6 +165,21 @@ Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
|
||||
return task->GetPromise();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Directory>
|
||||
Directory::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aRealPath,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIFile> path;
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aRealPath),
|
||||
true, getter_AddRefs(path));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Create(aGlobal.GetAsSupports(), path);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Directory>
|
||||
Directory::Create(nsISupports* aParent, nsIFile* aFile,
|
||||
FileSystemBase* aFileSystem)
|
||||
|
@ -62,6 +62,11 @@ public:
|
||||
static already_AddRefed<Promise>
|
||||
GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<Directory>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aRealPath,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<Directory>
|
||||
Create(nsISupports* aParent, nsIFile* aDirectory,
|
||||
FileSystemBase* aFileSystem = 0);
|
||||
|
@ -5,4 +5,5 @@ support-files =
|
||||
worker_basic.js
|
||||
|
||||
[test_basic.html]
|
||||
[test_webkitdirectory.html]
|
||||
[test_worker_basic.html]
|
||||
|
122
dom/filesystem/tests/test_webkitdirectory.html
Normal file
122
dom/filesystem/tests/test_webkitdirectory.html
Normal file
@ -0,0 +1,122 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for webkitdirectory and webkitRelativePath</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<input id="inputFileWebkitDirectory" type="file" webkitdirectory></input>
|
||||
<input id="inputFileWebkitDirectoryAndDirectory" type="file" webkitdirectory directory></input>
|
||||
<input id="inputFileDirectory" type="file" directory></input>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function populateInputFile(aInputFile) {
|
||||
var url = SimpleTest.getTestFileURL("script_fileList.js");
|
||||
var script = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
var MockFilePicker = SpecialPowers.MockFilePicker;
|
||||
MockFilePicker.init(window, "A Mock File Picker", SpecialPowers.Ci.nsIFilePicker.modeOpen);
|
||||
|
||||
function onOpened(message) {
|
||||
MockFilePicker.useDirectory(message.dir);
|
||||
|
||||
var input = document.getElementById(aInputFile);
|
||||
input.addEventListener('change', function() {
|
||||
MockFilePicker.cleanup();
|
||||
script.destroy();
|
||||
next();
|
||||
});
|
||||
|
||||
input.click();
|
||||
}
|
||||
|
||||
script.addMessageListener("dir.opened", onOpened);
|
||||
script.sendAsyncMessage("dir.open", { path: 'test' });
|
||||
}
|
||||
|
||||
function checkFile(file, fileList) {
|
||||
for (var i = 0; i < fileList.length; ++i) {
|
||||
ok(fileList[i] instanceof File, "We want just files.");
|
||||
if (fileList[i].name == file.name) {
|
||||
is(fileList[i].webkitRelativePath, file.path, "Path matches");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ok(false, "File not found.");
|
||||
}
|
||||
|
||||
function test_fileList(aInputFile, aWhat) {
|
||||
var input = document.getElementById(aInputFile);
|
||||
var fileList = input.files;
|
||||
|
||||
if (aWhat == null) {
|
||||
is(fileList, null, "We want a null fileList for " + aInputFile);
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
is(fileList.length, aWhat.length, "We want just " + aWhat.length + " elements for " + aInputFile);
|
||||
for (var i = 0; i < aWhat.length; ++i) {
|
||||
checkFile(aWhat[i], fileList);
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
function test_webkitdirectory_attribute() {
|
||||
var a = document.createElement("input");
|
||||
a.setAttribute("type", "file");
|
||||
|
||||
ok("webkitdirectory" in a, "HTMLInputElement.webkitdirectory exists");
|
||||
|
||||
ok(!a.hasAttribute("webkitdirectory"), "No webkitdirectory DOM attribute by default");
|
||||
ok(!a.webkitdirectory, "No webkitdirectory attribute by default");
|
||||
|
||||
a.webkitdirectory = true;
|
||||
|
||||
ok(a.hasAttribute("webkitdirectory"), "Webkitdirectory DOM attribute is set");
|
||||
ok(a.webkitdirectory, "Webkitdirectory attribute is set");
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
function test_setup() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.input.dirpicker", true],
|
||||
["dom.webkitBlink.dirPicker.enabled", true]]}, next);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test_setup,
|
||||
|
||||
function() { populateInputFile('inputFileWebkitDirectory'); },
|
||||
function() { populateInputFile('inputFileWebkitDirectoryAndDirectory'); },
|
||||
function() { populateInputFile('inputFileDirectory'); },
|
||||
|
||||
function() { test_fileList('inputFileWebkitDirectory', [ { name: 'foo.txt', path: '/foo.txt' },
|
||||
{ name: 'bar.txt', path: '/subdir/bar.txt' }]); },
|
||||
function() { test_fileList('inputFileWebkitDirectoryAndDirectory', [ { name: 'foo.txt', path: '/foo.txt' },
|
||||
{ name: 'bar.txt', path: '/subdir/bar.txt' }]); },
|
||||
function() { test_fileList('inputFileDirectory', null); },
|
||||
|
||||
test_webkitdirectory_attribute,
|
||||
];
|
||||
|
||||
function next() {
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
next();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -218,6 +218,18 @@ const Decimal HTMLInputElement::kStepAny = Decimal(0);
|
||||
#define PROGRESS_STR "progress"
|
||||
static const uint32_t kProgressEventInterval = 50; // ms
|
||||
|
||||
class GetFilesCallback
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(GetFilesCallback);
|
||||
|
||||
virtual void
|
||||
Callback(nsresult aStatus, const Sequence<RefPtr<File>>& aFiles) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~GetFilesCallback() {}
|
||||
};
|
||||
|
||||
// Retrieving the list of files can be very time/IO consuming. We use this
|
||||
// helper class to do it just once.
|
||||
class GetFilesHelper final : public Runnable
|
||||
@ -295,6 +307,21 @@ public:
|
||||
ResolveOrRejectPromise(aPromise);
|
||||
}
|
||||
|
||||
void
|
||||
AddCallback(GetFilesCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
// Still working.
|
||||
if (!mListingCompleted) {
|
||||
mCallbacks.AppendElement(aCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCallbacks.IsEmpty());
|
||||
RunCallback(aCallback);
|
||||
}
|
||||
|
||||
// CC methods
|
||||
void Unlink()
|
||||
{
|
||||
@ -353,6 +380,14 @@ private:
|
||||
ResolveOrRejectPromise(promises[i]);
|
||||
}
|
||||
|
||||
// Let's process the pending callbacks.
|
||||
nsTArray<RefPtr<GetFilesCallback>> callbacks;
|
||||
callbacks.SwapElements(mCallbacks);
|
||||
|
||||
for (uint32_t i = 0; i < callbacks.Length(); ++i) {
|
||||
RunCallback(callbacks[i]);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -510,6 +545,16 @@ private:
|
||||
aPromise->MaybeResolve(mFiles);
|
||||
}
|
||||
|
||||
void
|
||||
RunCallback(GetFilesCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mListingCompleted);
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
aCallback->Callback(mErrorResult, mFiles);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
|
||||
bool mRecursiveFlag;
|
||||
@ -531,6 +576,78 @@ private:
|
||||
nsresult mErrorResult;
|
||||
|
||||
nsTArray<RefPtr<Promise>> mPromises;
|
||||
nsTArray<RefPtr<GetFilesCallback>> mCallbacks;
|
||||
};
|
||||
|
||||
// An helper class for the dispatching of the 'change' event.
|
||||
class DispatchChangeEventCallback final : public GetFilesCallback
|
||||
{
|
||||
public:
|
||||
explicit DispatchChangeEventCallback(HTMLInputElement* aInputElement)
|
||||
: mInputElement(aInputElement)
|
||||
{
|
||||
MOZ_ASSERT(aInputElement);
|
||||
}
|
||||
|
||||
virtual void
|
||||
Callback(nsresult aStatus, const Sequence<RefPtr<File>>& aFiles) override
|
||||
{
|
||||
nsTArray<OwningFileOrDirectory> array;
|
||||
for (uint32_t i = 0; i < aFiles.Length(); ++i) {
|
||||
OwningFileOrDirectory* element = array.AppendElement();
|
||||
element->SetAsFile() = aFiles[i];
|
||||
}
|
||||
|
||||
mInputElement->SetFilesOrDirectories(array, true);
|
||||
NS_WARN_IF(NS_FAILED(DispatchEvents()));
|
||||
}
|
||||
|
||||
nsresult
|
||||
DispatchEvents()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
rv = nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLInputElement*>(mInputElement.get()),
|
||||
NS_LITERAL_STRING("input"), true,
|
||||
false);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
rv = nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLInputElement*>(mInputElement.get()),
|
||||
NS_LITERAL_STRING("change"), true,
|
||||
false);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<HTMLInputElement> mInputElement;
|
||||
};
|
||||
|
||||
// This callback is used for postponing the calling of SetFilesOrDirectories
|
||||
// when the exploration of the directory is completed.
|
||||
class AfterSetFilesOrDirectoriesCallback : public GetFilesCallback
|
||||
{
|
||||
public:
|
||||
AfterSetFilesOrDirectoriesCallback(HTMLInputElement* aInputElement,
|
||||
bool aSetValueChanged)
|
||||
: mInputElement(aInputElement)
|
||||
, mSetValueChanged(aSetValueChanged)
|
||||
{
|
||||
MOZ_ASSERT(aInputElement);
|
||||
}
|
||||
|
||||
void
|
||||
Callback(nsresult aStatus, const Sequence<RefPtr<File>>& aFiles) override
|
||||
{
|
||||
if (NS_SUCCEEDED(aStatus)) {
|
||||
mInputElement->AfterSetFilesOrDirectoriesInternal(mSetValueChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<HTMLInputElement> mInputElement;
|
||||
bool mSetValueChanged;
|
||||
};
|
||||
|
||||
class HTMLInputElementState final : public nsISupports
|
||||
@ -865,19 +982,22 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
|
||||
// So, we can safely send one by ourself.
|
||||
mInput->SetFilesOrDirectories(newFilesOrDirectories, true);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
rv = nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
|
||||
NS_LITERAL_STRING("input"), true,
|
||||
false);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
RefPtr<DispatchChangeEventCallback> dispatchChangeEventCallback =
|
||||
new DispatchChangeEventCallback(mInput);
|
||||
|
||||
rv = nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
|
||||
NS_LITERAL_STRING("change"), true,
|
||||
false);
|
||||
if (Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) &&
|
||||
mInput->HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory)) {
|
||||
ErrorResult error;
|
||||
GetFilesHelper* helper = mInput->GetOrCreateGetFilesHelper(true, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
return rv;
|
||||
helper->AddCallback(dispatchChangeEventCallback);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return dispatchChangeEventCallback->DispatchEvents();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(HTMLInputElement::nsFilePickerShownCallback,
|
||||
@ -2920,6 +3040,19 @@ HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
|
||||
|
||||
void
|
||||
HTMLInputElement::AfterSetFilesOrDirectories(bool aSetValueChanged)
|
||||
{
|
||||
if (Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) &&
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory)) {
|
||||
// This will call AfterSetFilesOrDirectoriesInternal eventually.
|
||||
ExploreDirectoryRecursively(aSetValueChanged);
|
||||
return;
|
||||
}
|
||||
|
||||
AfterSetFilesOrDirectoriesInternal(aSetValueChanged);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::AfterSetFilesOrDirectoriesInternal(bool aSetValueChanged)
|
||||
{
|
||||
// No need to flush here, if there's no frame at this point we
|
||||
// don't need to force creation of one just to tell it about this
|
||||
@ -2983,7 +3116,9 @@ HTMLInputElement::GetFiles()
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("dom.input.dirpicker", false) &&
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::directory)) {
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::directory) &&
|
||||
(!Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) ||
|
||||
!HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -4073,8 +4208,10 @@ HTMLInputElement::MaybeInitPickers(EventChainPostVisitor& aVisitor)
|
||||
if (target &&
|
||||
target->GetParent() == this &&
|
||||
target->IsRootOfNativeAnonymousSubtree() &&
|
||||
target->HasAttr(kNameSpaceID_None, nsGkAtoms::directory)) {
|
||||
MOZ_ASSERT(Preferences::GetBool("dom.input.dirpicker", false),
|
||||
(target->HasAttr(kNameSpaceID_None, nsGkAtoms::directory) ||
|
||||
target->HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory))) {
|
||||
MOZ_ASSERT(Preferences::GetBool("dom.input.dirpicker", false) ||
|
||||
Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false),
|
||||
"No API or UI should have been exposed to allow this code to "
|
||||
"be reached");
|
||||
type = FILE_PICKER_DIRECTORY;
|
||||
@ -5284,7 +5421,8 @@ HTMLInputElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
if (aAttribute == nsGkAtoms::type ||
|
||||
// The presence or absence of the 'directory' attribute determines what
|
||||
// buttons we show for type=file.
|
||||
aAttribute == nsGkAtoms::directory) {
|
||||
aAttribute == nsGkAtoms::directory ||
|
||||
aAttribute == nsGkAtoms::webkitdirectory) {
|
||||
retval |= NS_STYLE_HINT_FRAMECHANGE;
|
||||
} else if (mType == NS_FORM_INPUT_IMAGE &&
|
||||
(aAttribute == nsGkAtoms::alt ||
|
||||
@ -5420,41 +5558,18 @@ HTMLInputElement::GetFiles(bool aRecursiveFlag, ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GetFilesHelper* helper = GetOrCreateGetFilesHelper(aRecursiveFlag, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(helper);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
MOZ_ASSERT(global);
|
||||
if (!global) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GetFilesHelper> helper;
|
||||
if (aRecursiveFlag) {
|
||||
if (!mGetFilesRecursiveHelper) {
|
||||
mGetFilesRecursiveHelper =
|
||||
GetFilesHelper::Create(global,
|
||||
GetFilesOrDirectoriesInternal(),
|
||||
aRecursiveFlag, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
helper = mGetFilesRecursiveHelper;
|
||||
} else {
|
||||
if (!mGetFilesNonRecursiveHelper) {
|
||||
mGetFilesNonRecursiveHelper =
|
||||
GetFilesHelper::Create(global,
|
||||
GetFilesOrDirectoriesInternal(),
|
||||
aRecursiveFlag, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
helper = mGetFilesNonRecursiveHelper;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(helper);
|
||||
|
||||
RefPtr<Promise> p = Promise::Create(global, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
@ -7975,6 +8090,60 @@ HTMLInputElement::ClearGetFilesHelpers()
|
||||
}
|
||||
}
|
||||
|
||||
GetFilesHelper*
|
||||
HTMLInputElement::GetOrCreateGetFilesHelper(bool aRecursiveFlag,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
MOZ_ASSERT(global);
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aRecursiveFlag) {
|
||||
if (!mGetFilesRecursiveHelper) {
|
||||
mGetFilesRecursiveHelper =
|
||||
GetFilesHelper::Create(global,
|
||||
GetFilesOrDirectoriesInternal(),
|
||||
aRecursiveFlag, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return mGetFilesRecursiveHelper;
|
||||
}
|
||||
|
||||
if (!mGetFilesNonRecursiveHelper) {
|
||||
mGetFilesNonRecursiveHelper =
|
||||
GetFilesHelper::Create(global,
|
||||
GetFilesOrDirectoriesInternal(),
|
||||
aRecursiveFlag, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return mGetFilesNonRecursiveHelper;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::ExploreDirectoryRecursively(bool aSetValueChanged)
|
||||
{
|
||||
ErrorResult rv;
|
||||
GetFilesHelper* helper = GetOrCreateGetFilesHelper(true /* recursionFlag */,
|
||||
rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
AfterSetFilesOrDirectoriesInternal(aSetValueChanged);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<AfterSetFilesOrDirectoriesCallback> callback =
|
||||
new AfterSetFilesOrDirectoriesCallback(this, aSetValueChanged);
|
||||
helper->AddCallback(callback);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -37,7 +37,9 @@ class EventChainPreVisitor;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class AfterSetFilesOrDirectoriesRunnable;
|
||||
class Date;
|
||||
class DispatchChangeEventCallback;
|
||||
class File;
|
||||
class FileList;
|
||||
class GetFilesHelper;
|
||||
@ -107,6 +109,9 @@ class HTMLInputElement final : public nsGenericHTMLFormElementWithState,
|
||||
public nsIDOMNSEditableElement,
|
||||
public nsIConstraintValidation
|
||||
{
|
||||
friend class AfterSetFilesOrDirectoriesCallback;
|
||||
friend class DispatchChangeEventCallback;
|
||||
|
||||
public:
|
||||
using nsIConstraintValidation::GetValidationMessage;
|
||||
using nsIConstraintValidation::CheckValidity;
|
||||
@ -700,6 +705,16 @@ public:
|
||||
SetHTMLBoolAttr(nsGkAtoms::directory, aValue, aRv);
|
||||
}
|
||||
|
||||
bool WebkitDirectoryAttr() const
|
||||
{
|
||||
return HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory);
|
||||
}
|
||||
|
||||
void SetWebkitDirectoryAttr(bool aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::webkitdirectory, aValue, aRv);
|
||||
}
|
||||
|
||||
bool IsFilesAndDirectoriesSupported() const;
|
||||
|
||||
already_AddRefed<Promise> GetFilesAndDirectories(ErrorResult& aRv);
|
||||
@ -938,8 +953,16 @@ protected:
|
||||
|
||||
/**
|
||||
* Called after calling one of the SetFilesOrDirectories() functions.
|
||||
* This method can explore the directory recursively if needed.
|
||||
*/
|
||||
void AfterSetFilesOrDirectories(bool aSetValueChanged);
|
||||
void AfterSetFilesOrDirectoriesInternal(bool aSetValueChanged);
|
||||
|
||||
/**
|
||||
* Recursively explore the directory and populate mFileOrDirectories correctly
|
||||
* for webkitdirectory.
|
||||
*/
|
||||
void ExploreDirectoryRecursively(bool aSetValuechanged);
|
||||
|
||||
/**
|
||||
* Determine whether the editor needs to be initialized explicitly for
|
||||
@ -1256,6 +1279,9 @@ protected:
|
||||
*/
|
||||
bool IsPopupBlocked() const;
|
||||
|
||||
GetFilesHelper* GetOrCreateGetFilesHelper(bool aRecursiveFlag,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void ClearGetFilesHelpers();
|
||||
|
||||
nsCOMPtr<nsIControllers> mControllers;
|
||||
|
@ -15,7 +15,10 @@
|
||||
* http://w3c.github.io/filesystem-api/#idl-def-Directory
|
||||
* https://microsoftedge.github.io/directory-upload/proposal.html#directory-interface
|
||||
*/
|
||||
[Exposed=(Window,Worker)]
|
||||
|
||||
// This chromeConstructor is used by the MockFilePicker for testing only.
|
||||
[ChromeConstructor(DOMString path),
|
||||
Exposed=(Window,Worker)]
|
||||
interface Directory {
|
||||
/*
|
||||
* The leaf name of the directory.
|
||||
|
@ -209,6 +209,9 @@ partial interface HTMLInputElement {
|
||||
|
||||
[Throws, Pref="dom.input.dirpicker"]
|
||||
void chooseDirectory();
|
||||
|
||||
[Pref="dom.webkitBlink.dirPicker.enabled", BinaryName="WebkitDirectoryAttr", SetterThrows]
|
||||
attribute boolean webkitdirectory;
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
|
@ -103,6 +103,11 @@ this.MockFilePicker = {
|
||||
this.returnFiles = [file];
|
||||
},
|
||||
|
||||
useDirectory: function(aPath) {
|
||||
var directory = new this.window.Directory(aPath);
|
||||
this.returnFiles = [directory];
|
||||
},
|
||||
|
||||
isNsIFile: function(aFile) {
|
||||
let ret = false;
|
||||
try {
|
||||
|
Loading…
Reference in New Issue
Block a user