mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1251809 - Add input[type=file] tooltip support for e10s. r=ehsan
MozReview-Commit-ID: FpwKGrFQNrK
This commit is contained in:
parent
5b87f86e00
commit
9b52f45b30
@ -5,7 +5,7 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[uuid(57128a85-34de-42db-a252-84dd57724a59)]
|
||||
[builtinclass, uuid(57128a85-34de-42db-a252-84dd57724a59)]
|
||||
interface nsIDOMFileList : nsISupports
|
||||
{
|
||||
readonly attribute unsigned long length;
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/SVGTitleElement.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDOMFileList.h"
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
@ -48,6 +49,7 @@
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsPIWindowRoot.h"
|
||||
#include "nsIDOMWindowCollection.h"
|
||||
@ -68,6 +70,8 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
|
||||
#include "mozilla/dom/File.h" // for input type=file
|
||||
#include "mozilla/dom/FileList.h" // for input type=file
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -1071,9 +1075,7 @@ public:
|
||||
protected:
|
||||
~DefaultTooltipTextProvider() {}
|
||||
|
||||
nsCOMPtr<nsIAtom> mTag_dialog;
|
||||
nsCOMPtr<nsIAtom> mTag_dialogheader;
|
||||
nsCOMPtr<nsIAtom> mTag_window;
|
||||
nsCOMPtr<nsIAtom> mTag_dialogHeader;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(DefaultTooltipTextProvider, nsITooltipTextProvider)
|
||||
@ -1082,9 +1084,7 @@ DefaultTooltipTextProvider::DefaultTooltipTextProvider()
|
||||
{
|
||||
// There are certain element types which we don't want to use
|
||||
// as tool tip text.
|
||||
mTag_dialog = do_GetAtom("dialog");
|
||||
mTag_dialogheader = do_GetAtom("dialogheader");
|
||||
mTag_window = do_GetAtom("window");
|
||||
mTag_dialogHeader = do_GetAtom("dialogheader");
|
||||
}
|
||||
|
||||
// A helper routine that determines whether we're still interested in SVG
|
||||
@ -1142,13 +1142,66 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode* aNode, char16_t** aText,
|
||||
if (currElement) {
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(currElement));
|
||||
if (content) {
|
||||
if (!content->IsAnyOfXULElements(mTag_dialog,
|
||||
mTag_dialogheader,
|
||||
mTag_window)) {
|
||||
if (!content->IsAnyOfXULElements(nsGkAtoms::dialog,
|
||||
mTag_dialogHeader,
|
||||
nsGkAtoms::window)) {
|
||||
// first try the normal title attribute...
|
||||
if (!content->IsSVGElement()) {
|
||||
currElement->GetAttribute(NS_LITERAL_STRING("title"), outText);
|
||||
if (outText.Length()) {
|
||||
// If the element is an <input type="file"> without a title,
|
||||
// we should show the current file selection.
|
||||
if (content->IsHTMLElement(nsGkAtoms::input) &&
|
||||
content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
NS_LITERAL_STRING("file"), eIgnoreCase) &&
|
||||
!content->HasAttr(kNameSpaceID_None, nsGkAtoms::title)) {
|
||||
found = true;
|
||||
nsCOMPtr<nsIDOMFileList> fileList;
|
||||
nsCOMPtr<nsIDOMHTMLInputElement> currInputElement(do_QueryInterface(currElement));
|
||||
nsresult rv = currInputElement->GetFiles(getter_AddRefs(fileList));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!fileList) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStringBundleService> bundleService =
|
||||
mozilla::services::GetStringBundleService();
|
||||
if (!bundleService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
rv = bundleService->CreateBundle("chrome://global/locale/layout/HtmlForm.properties",
|
||||
getter_AddRefs(bundle));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
uint32_t listLength = 0;
|
||||
rv = fileList->GetLength(&listLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (listLength == 0) {
|
||||
if (content->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
||||
rv = bundle->GetStringFromName(MOZ_UTF16("NoFilesSelected"),
|
||||
getter_Copies(outText));
|
||||
} else {
|
||||
rv = bundle->GetStringFromName(MOZ_UTF16("NoFileSelected"),
|
||||
getter_Copies(outText));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
FileList* fl = static_cast<FileList*>(fileList.get());
|
||||
fl->Item(0)->GetName(outText);
|
||||
|
||||
// For UX and performance (jank) reasons we cap the number of
|
||||
// files that we list in the tooltip to 20 plus a "and xxx more"
|
||||
// line, or to 21 if exactly 21 files were picked.
|
||||
const uint32_t TRUNCATED_FILE_COUNT = 20;
|
||||
uint32_t count = std::min(listLength, TRUNCATED_FILE_COUNT);
|
||||
for (uint32_t i = 1; i < count; ++i) {
|
||||
nsString fileName;
|
||||
fl->Item(i)->GetName(fileName);
|
||||
outText.Append(NS_LITERAL_STRING("\n"));
|
||||
outText.Append(fileName);
|
||||
}
|
||||
}
|
||||
} else if (NS_SUCCEEDED(currElement->GetAttribute(NS_LITERAL_STRING("title"), outText)) &&
|
||||
outText.Length()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ skip-if = e10s # Bug 1064580
|
||||
skip-if = e10s
|
||||
[browser_findbar.js]
|
||||
[browser_input_file_tooltips.js]
|
||||
skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
|
||||
[browser_isSynthetic.js]
|
||||
support-files =
|
||||
empty.png
|
||||
|
@ -1,29 +1,53 @@
|
||||
function test()
|
||||
{
|
||||
let data = [
|
||||
{ value: "/tmp", result: "tmp" },
|
||||
{ title: "foo", result: "foo" },
|
||||
{ result: "No file selected." },
|
||||
{ multiple: true, result: "No files selected." },
|
||||
{ required: true, result: "Please select a file." }
|
||||
];
|
||||
|
||||
let doc = gBrowser.contentDocument;
|
||||
let tooltip = document.getElementById("aHTMLTooltip");
|
||||
let tempFile;
|
||||
add_task(function* setup() {
|
||||
yield new Promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv({"set": [["ui.tooltipDelay", 0]]}, resolve);
|
||||
});
|
||||
tempFile = createTempFile();
|
||||
registerCleanupFunction(function() {
|
||||
tempFile.remove(true);
|
||||
});
|
||||
});
|
||||
|
||||
for (let test of data) {
|
||||
let input = doc.createElement('input');
|
||||
add_task(function* test_singlefile_selected() {
|
||||
yield do_test({value: true, result: "testfile_bug1251809"});
|
||||
});
|
||||
|
||||
add_task(function* test_title_set() {
|
||||
yield do_test({title: "foo", result: "foo"});
|
||||
});
|
||||
|
||||
add_task(function* test_nofile_selected() {
|
||||
yield do_test({result: "No file selected."});
|
||||
});
|
||||
|
||||
add_task(function* test_multipleset_nofile_selected() {
|
||||
yield do_test({multiple: true, result: "No files selected."});
|
||||
});
|
||||
|
||||
add_task(function* test_requiredset() {
|
||||
yield do_test({required: true, result: "Please select a file."});
|
||||
});
|
||||
|
||||
function* do_test(test) {
|
||||
info(`starting test ${JSON.stringify(test)}`);
|
||||
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
|
||||
|
||||
yield new Promise(resolve => {
|
||||
EventUtils.synthesizeNativeMouseMove(tab.linkedBrowser, 300, 300, resolve);
|
||||
});
|
||||
|
||||
ContentTask.spawn(tab.linkedBrowser, test, function*(test) {
|
||||
let doc = content.document;
|
||||
let input = doc.createElement("input");
|
||||
doc.body.appendChild(input);
|
||||
input.type = 'file';
|
||||
input.id = "test_input";
|
||||
input.setAttribute("style", "position: absolute; top: 0; left: 0;");
|
||||
input.type = "file";
|
||||
if (test.title) {
|
||||
input.setAttribute('title', test.title);
|
||||
}
|
||||
if (test.value) {
|
||||
if (test.value == "/tmp" && navigator.platform.indexOf('Win') != -1) {
|
||||
test.value = "C:\\Temp";
|
||||
test.result = "Temp";
|
||||
}
|
||||
input.value = test.value;
|
||||
input.setAttribute("title", test.title);
|
||||
}
|
||||
if (test.multiple) {
|
||||
input.multiple = true;
|
||||
@ -31,8 +55,57 @@ function test()
|
||||
if (test.required) {
|
||||
input.required = true;
|
||||
}
|
||||
});
|
||||
|
||||
ok(tooltip.fillInPageTooltip(input));
|
||||
is(tooltip.getAttribute('label'), test.result);
|
||||
if (test.value) {
|
||||
let MockFilePicker = SpecialPowers.MockFilePicker;
|
||||
MockFilePicker.init(window);
|
||||
MockFilePicker.returnValue = MockFilePicker.returnOK;
|
||||
MockFilePicker.displayDirectory = FileUtils.getDir("TmpD", [], false);
|
||||
MockFilePicker.returnFiles = [tempFile];
|
||||
|
||||
try {
|
||||
// Open the File Picker dialog (MockFilePicker) to select
|
||||
// the files for the test.
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter("#test_input", {}, tab.linkedBrowser);
|
||||
yield ContentTask.spawn(tab.linkedBrowser, {}, function*() {
|
||||
let input = content.document.querySelector("#test_input");
|
||||
yield ContentTaskUtils.waitForCondition(() => input.files.length,
|
||||
"The input should have at least one file selected");
|
||||
info(`The input has ${input.files.length} file(s) selected.`);
|
||||
});
|
||||
} finally {
|
||||
MockFilePicker.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
let awaitTooltipOpen = new Promise(resolve => {
|
||||
let tooltipId = Services.appinfo.browserTabsRemoteAutostart ?
|
||||
"remoteBrowserTooltip" :
|
||||
"aHTMLTooltip";
|
||||
let tooltip = document.getElementById(tooltipId);
|
||||
tooltip.addEventListener("popupshown", function onpopupshown(event) {
|
||||
tooltip.removeEventListener("popupshown", onpopupshown);
|
||||
resolve(event.target);
|
||||
});
|
||||
});
|
||||
yield new Promise(resolve => {
|
||||
EventUtils.synthesizeNativeMouseMove(tab.linkedBrowser, 100, 5, resolve);
|
||||
});
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
yield new Promise(resolve => {
|
||||
EventUtils.synthesizeNativeMouseMove(tab.linkedBrowser, 110, 15, resolve);
|
||||
});
|
||||
let tooltip = yield awaitTooltipOpen;
|
||||
|
||||
is(tooltip.getAttribute("label"), test.result, "tooltip label should match expectation");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
|
||||
function createTempFile() {
|
||||
let file = FileUtils.getDir("TmpD", [], false);
|
||||
file.append("testfile_bug1251809");
|
||||
file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
|
||||
return file;
|
||||
}
|
||||
|
@ -538,8 +538,9 @@
|
||||
<parameter name="tipElement"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
// Don't show the tooltip if the tooltip node is a document or disconnected.
|
||||
// Don't show the tooltip if the tooltip node is a document, browser, or disconnected.
|
||||
if (!tipElement || !tipElement.ownerDocument ||
|
||||
tipElement.localName == "browser" ||
|
||||
(tipElement.ownerDocument.compareDocumentPosition(tipElement) & document.DOCUMENT_POSITION_DISCONNECTED)) {
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user