Bug 894840, part 5 - Add a 'path' property to the File objects in the input.files FileList, and set it when a directory is picked. r=khuey
authorJonathan Watt <jwatt@jwatt.org>
Fri, 23 Aug 2013 08:41:17 +0100
changeset 145235 e5e6c3bb26b359ddd0c02a37a6f992e2b3cbaf09
parent 145234 be3663c7c734fb4681ed967bee9b19b150ceae44
child 145236 068c13777f4d3a082804ead9a417d3636c212f36
push id33204
push userjwatt@jwatt.org
push dateMon, 02 Sep 2013 14:21:37 +0000
treeherdermozilla-inbound@068c13777f4d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs894840
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 894840, part 5 - Add a 'path' property to the File objects in the input.files FileList, and set it when a directory is picked. r=khuey
content/base/public/nsDOMFile.h
content/base/public/nsIDOMFile.idl
content/base/src/nsDOMFile.cpp
content/html/content/src/HTMLInputElement.cpp
dom/workers/File.cpp
dom/workers/test/file_worker.js
dom/workers/test/test_file.xul
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -144,16 +144,17 @@ protected:
     return mFileInfos.ElementAt(0);
   }
 
   bool mIsFile;
   bool mImmutable;
 
   nsString mContentType;
   nsString mName;
+  nsString mPath; // The path relative to a directory chosen by the user
 
   uint64_t mStart;
   uint64_t mLength;
 
   uint64_t mLastModificationDate;
 
   // Protected by IndexedDatabaseManager::FileMutex()
   nsTArray<nsRefPtr<FileInfo> > mFileInfos;
@@ -295,16 +296,18 @@ public:
   // Overrides
   NS_IMETHOD GetSize(uint64_t* aSize) MOZ_OVERRIDE;
   NS_IMETHOD GetType(nsAString& aType) MOZ_OVERRIDE;
   NS_IMETHOD GetLastModifiedDate(JSContext* cx, JS::Value* aLastModifiedDate) MOZ_OVERRIDE;
   NS_IMETHOD GetMozLastModifiedDate(uint64_t* aLastModifiedDate) MOZ_OVERRIDE;
   NS_IMETHOD GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
   NS_IMETHOD GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
 
+  void SetPath(const nsAString& aFullPath);
+
 protected:
   // Create slice
   nsDOMFileFile(const nsDOMFileFile* aOther, uint64_t aStart, uint64_t aLength,
                 const nsAString& aContentType)
     : nsDOMFile(aContentType, aOther->mStart + aStart, aLength),
       mFile(aOther->mFile), mWholeFile(false),
       mStoredFile(aOther->mStoredFile)
   {
--- a/content/base/public/nsIDOMFile.idl
+++ b/content/base/public/nsIDOMFile.idl
@@ -54,21 +54,23 @@ interface nsIDOMBlob : nsISupports
   // the blob is initialized from a database. It can be called on any thread.
   [notxpcom] void addFileInfo(in FileInfo aFileInfo);
 
   // Called before the blob is stored in a database to decide if it can be
   // shared or needs to be copied. It can be called on any thread.
   [notxpcom] FileInfo getFileInfo(in FileManager aFileManager);
 };
 
-[scriptable, builtinclass, uuid(6928584d-7d87-4d56-9ce1-1c89c24f2c6a)]
+[scriptable, builtinclass, uuid(0acb4135-9f79-4516-ba92-b5fba5203620)]
 interface nsIDOMFile : nsIDOMBlob
 {
   readonly attribute DOMString name;
 
+  readonly attribute DOMString path;
+
   [implicit_jscontext]
   readonly attribute jsval lastModifiedDate;
 
   readonly attribute DOMString mozFullPath;
 
   // This performs no security checks!
   [noscript] readonly attribute DOMString mozFullPathInternal;
 
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -122,16 +122,24 @@ NS_IMETHODIMP
 nsDOMFileBase::GetName(nsAString &aFileName)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aFileName = mName;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDOMFileBase::GetPath(nsAString &aPath)
+{
+  NS_ASSERTION(mIsFile, "Should only be called on files");
+  aPath = mPath;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMFileBase::GetLastModifiedDate(JSContext* cx, JS::Value *aLastModifiedDate)
 {
   JSObject* date = JS_NewDateObjectMsec(cx, JS_Now() / PR_USEC_PER_MSEC);
   aLastModifiedDate->setObject(*date);
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -586,16 +594,22 @@ NS_IMETHODIMP
 nsDOMFileFile::GetInternalStream(nsIInputStream **aStream)
 {
   return mWholeFile ?
     NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags) :
     NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
                                       -1, -1, sFileStreamFlags);
 }
 
+void
+nsDOMFileFile::SetPath(const nsAString& aPath)
+{
+  mPath = aPath;
+}
+
 ////////////////////////////////////////////////////////////////////////////
 // nsDOMMemoryFile implementation
 
 already_AddRefed<nsIDOMBlob>
 nsDOMMemoryFile::CreateSlice(uint64_t aStart, uint64_t aLength,
                              const nsAString& aContentType)
 {
   nsCOMPtr<nsIDOMBlob> t =
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -363,16 +363,28 @@ public:
     MOZ_ASSERT(!NS_IsMainThread(),
                "Walking the directory tree involves I/O, so using this "
                "enumerator can block a thread for a long time!");
 
     if (!mNextFile) {
       return NS_ERROR_FAILURE;
     }
     nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(mNextFile);
+    nsCString relDescriptor;
+    nsresult rv = mNextFile->GetRelativeDescriptor(mTopDir, relDescriptor);
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ConvertUTF8toUTF16 path(relDescriptor);
+    nsAutoString leafName;
+    mNextFile->GetLeafName(leafName);
+    MOZ_ASSERT(leafName.Length() <= path.Length());
+    int32_t length = path.Length() - leafName.Length() - 1; // -1 for "/"
+    MOZ_ASSERT(length >= -1);
+    if (length > 0) {
+      domFile->SetPath(Substring(path, 0, uint32_t(length)));
+    }
     *aResult = static_cast<nsIDOMFile*>(domFile.forget().get());
     LookupAndCacheNext();
     return NS_OK;
   }
 
   NS_IMETHOD
   HasMoreElements(bool* aResult)
   {
--- a/dom/workers/File.cpp
+++ b/dom/workers/File.cpp
@@ -349,16 +349,39 @@ private:
       return false;
     }
 
     aVp.set(STRING_TO_JSVAL(jsName));
     return true;
   }
 
   static bool
+  GetPath(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aIdval,
+          JS::MutableHandle<JS::Value> aVp)
+  {
+    nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "path");
+    if (!file) {
+      return false;
+    }
+
+    nsString path;
+    if (NS_FAILED(file->GetPath(path))) {
+      path.Truncate();
+    }
+
+    JSString* jsPath = JS_NewUCStringCopyN(aCx, path.get(), path.Length());
+    if (!jsPath) {
+      return false;
+    }
+
+    aVp.set(STRING_TO_JSVAL(jsPath));
+    return true;
+  }
+
+  static bool
   GetLastModifiedDate(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aIdval,
                       JS::MutableHandle<JS::Value> aVp)
   {
     nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "lastModifiedDate");
     if (!file) {
       return false;
     }
 
@@ -377,16 +400,18 @@ JSClass File::sClass = {
   JSCLASS_HAS_PRIVATE,
   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize
 };
 
 const JSPropertySpec File::sProperties[] = {
   { "name", 0, PROPERTY_FLAGS, JSOP_WRAPPER(GetName),
     JSOP_WRAPPER(js_GetterOnlyPropertyStub) },
+  { "path", 0, PROPERTY_FLAGS, JSOP_WRAPPER(GetPath),
+    JSOP_WRAPPER(js_GetterOnlyPropertyStub) },
   { "lastModifiedDate", 0, PROPERTY_FLAGS, JSOP_WRAPPER(GetLastModifiedDate),
     JSOP_WRAPPER(js_GetterOnlyPropertyStub) },
   { "mozFullPath", 0, PROPERTY_FLAGS, JSOP_WRAPPER(GetMozFullPath),
     JSOP_WRAPPER(js_GetterOnlyPropertyStub) },
   { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }
 };
 
 nsIDOMBlob*
--- a/dom/workers/test/file_worker.js
+++ b/dom/workers/test/file_worker.js
@@ -4,13 +4,14 @@
 onmessage = function(event) {
   var file = event.data;
 
   var rtnObj = new Object();
 
   rtnObj.size = file.size;
   rtnObj.type = file.type;
   rtnObj.name = file.name;
+  rtnObj.path = file.path;
   rtnObj.lastModifiedDate = file.lastModifiedDate;
   rtnObj.mozFullPath = file.mozFullPath;
 
   postMessage(rtnObj);
 };
--- a/dom/workers/test/test_file.xul
+++ b/dom/workers/test/test_file.xul
@@ -64,16 +64,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       ok(false, "Worker had an error: " + event.data);
       finish();
     };
 
     worker.onmessage = function(event) {
       is(event.data.size, expectedSize, "size proproperty accessed from worker is not the same as on main thread.");
       is(event.data.type, expectedType, "type proproperty accessed from worker is incorrect.");
       is(event.data.name, file.name, "name proproperty accessed from worker is incorrect.");
+      is(event.data.path, file.path, "path proproperty accessed from worker is incorrect.");
       is(event.data.lastModifiedDate.toString(), file.lastModifiedDate.toString(), "lastModifiedDate proproperty accessed from worker is incorrect.");
       is(event.data.mozFullPath, file.mozFullPath, "mozFullPath proproperty accessed from worker is not the same as on main thread.");
       finish();
     };
 
     worker.postMessage(file);
   }