Bug 1164310, part 4 - Implement the new HTMLInputElement API including the new Promise returning GetFilesAndDirectories. r=baku
This commit is contained in:
@@ -10,7 +10,11 @@
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/Date.h"
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/OSFileSystem.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsCRTGlue.h"
|
||||
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
#include "nsITextControlElement.h"
|
||||
@@ -373,7 +377,8 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
|
||||
|
||||
// Collect new selected filenames
|
||||
nsTArray<nsRefPtr<File>> newFiles;
|
||||
if (mode == static_cast<int16_t>(nsIFilePicker::modeOpenMultiple)) {
|
||||
if (mode == static_cast<int16_t>(nsIFilePicker::modeOpenMultiple) ||
|
||||
mode == static_cast<int16_t>(nsIFilePicker::modeGetFolder)) {
|
||||
nsCOMPtr<nsISimpleEnumerator> iter;
|
||||
nsresult rv = mFilePicker->GetDomfiles(getter_AddRefs(iter));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@@ -2876,7 +2881,9 @@ HTMLInputElement::Focus(ErrorResult& aError)
|
||||
return;
|
||||
}
|
||||
|
||||
// For file inputs, focus the button instead.
|
||||
// For file inputs, focus the first button instead. In the case of there
|
||||
// being two buttons (when the picker is a directory picker) the user can
|
||||
// tab to the next one.
|
||||
nsIFrame* frame = GetPrimaryFrame();
|
||||
if (frame) {
|
||||
for (nsIFrame* childFrame = frame->GetFirstPrincipalChild();
|
||||
@@ -3544,7 +3551,21 @@ HTMLInputElement::MaybeInitPickers(EventChainPostVisitor& aVisitor)
|
||||
return NS_OK;
|
||||
}
|
||||
if (mType == NS_FORM_INPUT_FILE) {
|
||||
return InitFilePicker(FILE_PICKER_FILE);
|
||||
// If the user clicked on the "Choose folder..." button we open the
|
||||
// directory picker, else we open the file picker.
|
||||
FilePickerType type = FILE_PICKER_FILE;
|
||||
nsCOMPtr<nsIContent> target =
|
||||
do_QueryInterface(aVisitor.mEvent->originalTarget);
|
||||
if (target &&
|
||||
target->GetParent() == this &&
|
||||
target->IsRootOfNativeAnonymousSubtree() &&
|
||||
target->HasAttr(kNameSpaceID_None, nsGkAtoms::directory)) {
|
||||
MOZ_ASSERT(Preferences::GetBool("dom.input.dirpicker", false),
|
||||
"No API or UI should have been exposed to allow this code to "
|
||||
"be reached");
|
||||
type = FILE_PICKER_DIRECTORY;
|
||||
}
|
||||
return InitFilePicker(type);
|
||||
}
|
||||
if (mType == NS_FORM_INPUT_COLOR) {
|
||||
return InitColorPicker();
|
||||
@@ -4797,6 +4818,110 @@ HTMLInputElement::GetAttributeMappingFunction() const
|
||||
}
|
||||
|
||||
|
||||
// Directory picking methods:
|
||||
|
||||
bool
|
||||
HTMLInputElement::IsFilesAndDirectoriesSupported() const
|
||||
{
|
||||
// This method is supposed to return true if a file and directory picker
|
||||
// supports the selection of both files and directories *at the same time*.
|
||||
// Only Mac currently supports that. We could implement it for Mac, but
|
||||
// currently we do not.
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::ChooseDirectory(ErrorResult& aRv)
|
||||
{
|
||||
if (mType != NS_FORM_INPUT_FILE) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
InitFilePicker(
|
||||
#if defined(ANDROID) || defined(MOZ_B2G)
|
||||
// No native directory picker - redirect to plain file picker
|
||||
FILE_PICKER_FILE
|
||||
#else
|
||||
FILE_PICKER_DIRECTORY
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
static already_AddRefed<OSFileSystem>
|
||||
MakeOrReuseFileSystem(const nsAString& aNewLocalRootPath,
|
||||
OSFileSystem* aFS,
|
||||
nsPIDOMWindow* aWindow)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
|
||||
nsRefPtr<OSFileSystem> fs;
|
||||
if (aFS) {
|
||||
const nsAString& prevLocalRootPath = aFS->GetLocalRootPath();
|
||||
if (aNewLocalRootPath == prevLocalRootPath) {
|
||||
fs = aFS;
|
||||
}
|
||||
}
|
||||
if (!fs) {
|
||||
fs = new OSFileSystem(aNewLocalRootPath);
|
||||
fs->Init(aWindow);
|
||||
}
|
||||
return fs.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
MOZ_ASSERT(global);
|
||||
if (!global) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> p = Promise::Create(global, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const nsTArray<nsRefPtr<File>>& filesAndDirs = GetFilesInternal();
|
||||
|
||||
Sequence<OwningFileOrDirectory> filesAndDirsSeq;
|
||||
|
||||
if (!filesAndDirsSeq.SetLength(filesAndDirs.Length(), mozilla::fallible_t())) {
|
||||
p->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
nsPIDOMWindow* window = OwnerDoc()->GetInnerWindow();
|
||||
nsRefPtr<OSFileSystem> fs;
|
||||
for (uint32_t i = 0; i < filesAndDirs.Length(); ++i) {
|
||||
if (filesAndDirs[i]->IsDirectory()) {
|
||||
#if defined(ANDROID) || defined(MOZ_B2G)
|
||||
MOZ_ASSERT(false,
|
||||
"Directory picking should have been redirected to normal "
|
||||
"file picking for platforms that don't have a directory "
|
||||
"picker");
|
||||
#endif
|
||||
nsAutoString path;
|
||||
filesAndDirs[i]->GetMozFullPathInternal(path, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
int32_t leafSeparatorIndex = path.RFind(FILE_PATH_SEPARATOR);
|
||||
nsDependentSubstring dirname = Substring(path, 0, leafSeparatorIndex);
|
||||
nsDependentSubstring basename = Substring(path, leafSeparatorIndex);
|
||||
fs = MakeOrReuseFileSystem(dirname, fs, window);
|
||||
filesAndDirsSeq[i].SetAsDirectory() = new Directory(fs, basename);
|
||||
} else {
|
||||
filesAndDirsSeq[i].SetAsFile() = filesAndDirs[i];
|
||||
}
|
||||
}
|
||||
|
||||
p->MaybeResolve(filesAndDirsSeq);
|
||||
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
|
||||
// Controllers Methods
|
||||
|
||||
nsIControllers*
|
||||
|
||||
Reference in New Issue
Block a user