Bug 850213 - Update nsHTMLInputElement to nsIContentPrefService2. r=smaug

This commit is contained in:
Felipe Gomes 2013-03-29 23:08:57 -03:00
parent d03f3261e7
commit 04b26e63a2
3 changed files with 168 additions and 86 deletions

View File

@ -260,6 +260,48 @@ HTMLInputElement::nsFilePickerShownCallback::nsFilePickerShownCallback(
{
}
NS_IMPL_ISUPPORTS1(UploadLastDir::ContentPrefCallback, nsIContentPrefCallback2)
NS_IMETHODIMP
UploadLastDir::ContentPrefCallback::HandleCompletion(uint16_t aReason)
{
nsCOMPtr<nsIFile> localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
NS_ENSURE_STATE(localFile);
if (aReason == nsIContentPrefCallback2::COMPLETE_ERROR ||
!mResult) {
// Default to "desktop" directory for each platform
nsCOMPtr<nsIFile> homeDir;
NS_GetSpecialDirectory(NS_OS_DESKTOP_DIR, getter_AddRefs(homeDir));
localFile = do_QueryInterface(homeDir);
} else {
nsAutoString prefStr;
nsCOMPtr<nsIVariant> pref;
mResult->GetValue(getter_AddRefs(pref));
pref->GetAsAString(prefStr);
localFile->InitWithPath(prefStr);
}
mFilePicker->SetDisplayDirectory(localFile);
mFilePicker->Open(mFpCallback);
return NS_OK;
}
NS_IMETHODIMP
UploadLastDir::ContentPrefCallback::HandleResult(nsIContentPref* pref)
{
mResult = pref;
return NS_OK;
}
NS_IMETHODIMP
UploadLastDir::ContentPrefCallback::HandleError(nsresult error)
{
// HandleCompletion is always called (even with HandleError was called),
// so we don't need to do anything special here.
return NS_OK;
}
NS_IMETHODIMP
HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
{
@ -389,6 +431,9 @@ HTMLInputElement::AsyncClickHandler::Run()
const nsCOMArray<nsIDOMFile>& oldFiles = mInput->GetFilesInternal();
nsCOMPtr<nsIFilePickerShownCallback> callback =
new HTMLInputElement::nsFilePickerShownCallback(mInput, filePicker, multi);
if (oldFiles.Count()) {
nsString path;
@ -415,23 +460,13 @@ HTMLInputElement::AsyncClickHandler::Run()
filePicker->SetDefaultString(leafName);
}
}
} else {
// Attempt to retrieve the last used directory from the content pref service
nsCOMPtr<nsIFile> localFile;
HTMLInputElement::gUploadLastDir->FetchLastUsedDirectory(doc,
getter_AddRefs(localFile));
if (!localFile) {
// Default to "desktop" directory for each platform
nsCOMPtr<nsIFile> homeDir;
NS_GetSpecialDirectory(NS_OS_DESKTOP_DIR, getter_AddRefs(homeDir));
localFile = do_QueryInterface(homeDir);
}
filePicker->SetDisplayDirectory(localFile);
return filePicker->Open(callback);
}
nsCOMPtr<nsIFilePickerShownCallback> callback =
new HTMLInputElement::nsFilePickerShownCallback(mInput, filePicker, multi);
return filePicker->Open(callback);
HTMLInputElement::gUploadLastDir->FetchDirectoryAndDisplayPicker(doc, filePicker, callback);
return NS_OK;
}
#define CPS_PREF_NAME NS_LITERAL_STRING("browser.upload.lastDir")
@ -456,10 +491,13 @@ HTMLInputElement::DestroyUploadLastDir() {
}
nsresult
UploadLastDir::FetchLastUsedDirectory(nsIDocument* aDoc, nsIFile** aFile)
UploadLastDir::FetchDirectoryAndDisplayPicker(nsIDocument* aDoc,
nsIFilePicker* aFilePicker,
nsIFilePickerShownCallback* aFpCallback)
{
NS_PRECONDITION(aDoc, "aDoc is null");
NS_PRECONDITION(aFile, "aFile is null");
NS_PRECONDITION(aFilePicker, "aFilePicker is null");
NS_PRECONDITION(aFpCallback, "aFpCallback is null");
nsIURI* docURI = aDoc->GetDocumentURI();
NS_PRECONDITION(docURI, "docURI is null");
@ -467,30 +505,22 @@ UploadLastDir::FetchLastUsedDirectory(nsIDocument* aDoc, nsIFile** aFile)
nsCOMPtr<nsISupports> container = aDoc->GetContainer();
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(container);
// Attempt to get the CPS, if it's not present we'll just return
nsCOMPtr<nsIContentPrefService> contentPrefService =
nsCOMPtr<nsIContentPrefCallback2> prefCallback =
new UploadLastDir::ContentPrefCallback(aFilePicker, aFpCallback);
// Attempt to get the CPS, if it's not present we'll fallback to use the Desktop folder
nsCOMPtr<nsIContentPrefService2> contentPrefService =
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
if (!contentPrefService)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
if (!uri)
return NS_ERROR_OUT_OF_MEMORY;
uri->SetAsISupports(docURI);
// Get the last used directory, if it is stored
bool hasPref;
if (NS_SUCCEEDED(contentPrefService->HasPref(uri, CPS_PREF_NAME, loadContext, &hasPref)) && hasPref) {
nsCOMPtr<nsIVariant> pref;
contentPrefService->GetPref(uri, CPS_PREF_NAME, loadContext, nullptr, getter_AddRefs(pref));
nsString prefStr;
pref->GetAsAString(prefStr);
nsCOMPtr<nsIFile> localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
if (!localFile)
return NS_ERROR_OUT_OF_MEMORY;
localFile->InitWithPath(prefStr);
localFile.forget(aFile);
if (!contentPrefService) {
prefCallback->HandleCompletion(nsIContentPrefCallback2::COMPLETE_ERROR);
return NS_OK;
}
nsAutoCString cstrSpec;
docURI->GetSpec(cstrSpec);
NS_ConvertUTF8toUTF16 spec(cstrSpec);
contentPrefService->GetByDomainAndName(spec, CPS_PREF_NAME, loadContext, prefCallback);
return NS_OK;
}
@ -521,14 +551,14 @@ UploadLastDir::StoreLastUsedDirectory(nsIDocument* aDoc, nsIDOMFile* aDomFile)
}
// Attempt to get the CPS, if it's not present we'll just return
nsCOMPtr<nsIContentPrefService> contentPrefService =
nsCOMPtr<nsIContentPrefService2> contentPrefService =
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
if (!contentPrefService)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
if (!uri)
return NS_ERROR_OUT_OF_MEMORY;
uri->SetAsISupports(docURI);
nsAutoCString cstrSpec;
docURI->GetSpec(cstrSpec);
NS_ConvertUTF8toUTF16 spec(cstrSpec);
// Find the parent of aFile, and store it
nsString unicodePath;
@ -542,17 +572,17 @@ UploadLastDir::StoreLastUsedDirectory(nsIDocument* aDoc, nsIDOMFile* aDomFile)
nsCOMPtr<nsISupports> container = aDoc->GetContainer();
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(container);
return contentPrefService->SetPref(uri, CPS_PREF_NAME, prefValue, loadContext);
return contentPrefService->Set(spec, CPS_PREF_NAME, prefValue, loadContext, nullptr);
}
NS_IMETHODIMP
UploadLastDir::Observe(nsISupports* aSubject, char const* aTopic, PRUnichar const* aData)
{
if (strcmp(aTopic, "browser:purge-session-history") == 0) {
nsCOMPtr<nsIContentPrefService> contentPrefService =
nsCOMPtr<nsIContentPrefService2> contentPrefService =
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
if (contentPrefService)
contentPrefService->RemovePrefsByName(CPS_PREF_NAME, nullptr);
contentPrefService->RemoveByName(CPS_PREF_NAME, nullptr, nullptr);
}
return NS_OK;
}

View File

@ -19,6 +19,7 @@
#include "nsHTMLFormElement.h" // for ShouldShowInvalidUI()
#include "nsIFile.h"
#include "nsIFilePicker.h"
#include "nsIContentPrefService2.h"
class nsDOMFileList;
class nsIFilePicker;
@ -36,12 +37,15 @@ public:
/**
* Fetch the last used directory for this location from the content
* pref service, if it is available.
* pref service, and display the file picker opened in that directory.
*
* @param aDoc current document
* @param aFile path to the last used directory
* @param aDoc current document
* @param aFilePicker the file picker to open
* @param aFpCallback the callback object to be run when the file is shown.
*/
nsresult FetchLastUsedDirectory(nsIDocument* aDoc, nsIFile** aFile);
nsresult FetchDirectoryAndDisplayPicker(nsIDocument* aDoc,
nsIFilePicker* aFilePicker,
nsIFilePickerShownCallback* aFpCallback);
/**
* Store the last used directory for this location using the
@ -51,6 +55,25 @@ public:
* file will be stored
*/
nsresult StoreLastUsedDirectory(nsIDocument* aDoc, nsIDOMFile* aDomFile);
class ContentPrefCallback MOZ_FINAL : public nsIContentPrefCallback2
{
public:
ContentPrefCallback(nsIFilePicker* aFilePicker, nsIFilePickerShownCallback* aFpCallback)
: mFilePicker(aFilePicker)
, mFpCallback(aFpCallback)
{ }
virtual ~ContentPrefCallback()
{ }
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPREFCALLBACK2
nsCOMPtr<nsIFilePicker> mFilePicker;
nsCOMPtr<nsIFilePickerShownCallback> mFpCallback;
nsCOMPtr<nsIContentPref> mResult;
};
};
class HTMLInputElement : public nsGenericHTMLFormElement,

View File

@ -19,10 +19,37 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=36619
<button id='c' onmousedown="document.getElementById('a').click();">Show Filepicker</button>
<button id='d' onmouseup="document.getElementById('a').click();">Show Filepicker</button>
<pre id="test">
<script type="application/javascript">
<script type="application/javascript;version=1.8">
/** Test for Bug 36619 **/
let gGen = doTest();
function continueTest() {
gGen.next();
}
function waitForCondition(condition, errorMsg) {
var tries = 0;
var interval = setInterval(function() {
if (tries >= 10) {
ok(false, errorMsg);
moveOn();
}
if (condition()) {
moveOn();
}
tries++;
}, 100);
var moveOn = function() {
clearInterval(interval);
try {
continueTest();
} catch (e if e instanceof StopIteration) {
SimpleTest.finish();
}
};
}
SimpleTest.waitForExplicitFinish();
var MockFilePicker = SpecialPowers.MockFilePicker;
@ -34,43 +61,45 @@ SpecialPowers.pushPrefEnv({'set': [
["privacy.popups.showBrowserMessage", false]
]}, function() {
SimpleTest.waitForFocus(function() {
// Tests that a click on 'b' calls the show method.
var b = document.getElementById('b');
b.focus(); // Be sure the element is visible.
synthesizeMouseAtCenter(b, {});
SimpleTest.executeSoon(function() {
ok(MockFilePicker.showing,
"File picker showAsync method should have been called");
MockFilePicker.reset();
// Tests that a click on 'a' doesn't call the show method, because it is hidden.
document.getElementById("a").click();
SimpleTest.executeSoon(function() {
ok(!MockFilePicker.showing,
"File picker showAsync method should not have been called");
MockFilePicker.reset();
synthesizeMouseAtCenter(document.getElementById('c'), {});
SimpleTest.executeSoon(function() {
ok(!MockFilePicker.showing,
"File picker showAsync method should have been called");
MockFilePicker.reset();
synthesizeMouseAtCenter(document.getElementById('d'), {});
SimpleTest.executeSoon(function() {
ok(MockFilePicker.showing,
"File picker showAsync method should have been called");
MockFilePicker.cleanup();
SimpleTest.finish();
});
});
});
});
continueTest();
});
});
let showing = function() MockFilePicker.showing;
let notShowing = function() !MockFilePicker.showing;
function doTest() {
ok(true, "Test start");
var b = document.getElementById('b');
b.focus(); // Be sure the element is visible.
synthesizeMouseAtCenter(b, {});
yield waitForCondition(showing,
"File picker showAsync method should have been called");
MockFilePicker.reset();
// Tests that a click on 'a' doesn't call the show method, because it is hidden.
document.getElementById("a").click();
yield waitForCondition(notShowing,
"File picker showAsync method should not have been called");
MockFilePicker.reset();
synthesizeMouseAtCenter(document.getElementById('c'), {});
yield waitForCondition(notShowing,
"File picker showAsync method should not have been called");
MockFilePicker.reset();
synthesizeMouseAtCenter(document.getElementById('d'), {});
yield waitForCondition(showing,
"File picker showAsync method should have been called");
ok(true, "Test completed");
MockFilePicker.cleanup();
}
</script>
</pre>
</body>