Bug 1446830 - Alternate implementation that uses HTML label with end crop instead of center draft
authorBrian Grinstead <bgrinstead@mozilla.com>
Wed, 11 Jul 2018 21:30:27 -0700
changeset 817146 e251fa71750fd79fb1c6185a46cad24319723833
parent 808182 9b74b9f2939a7ae3a0ea6e711dc32ed5203e03ff
push id115970
push userbgrinstead@mozilla.com
push dateThu, 12 Jul 2018 04:34:38 +0000
bugs1446830
milestone62.0a1
Bug 1446830 - Alternate implementation that uses HTML label with end crop instead of center MozReview-Commit-ID: 8Ya6L4xFVkx
layout/forms/nsFileControlFrame.cpp
layout/forms/nsFileControlFrame.h
layout/style/res/forms.css
--- a/layout/forms/nsFileControlFrame.cpp
+++ b/layout/forms/nsFileControlFrame.cpp
@@ -64,18 +64,17 @@ nsFileControlFrame::DestroyFrom(nsIFrame
   // Remove the events.
   if (mContent) {
     mContent->RemoveSystemEventListener(NS_LITERAL_STRING("drop"),
                                         mMouseListener, false);
     mContent->RemoveSystemEventListener(NS_LITERAL_STRING("dragover"),
                                         mMouseListener, false);
   }
 
-  aPostDestroyData.AddAnonymousContent(mTextContent.forget());
-  aPostDestroyData.AddAnonymousContent(mBrowseFilesOrDirs.forget());
+  aPostDestroyData.AddAnonymousContent(mContentContainer.forget());
 
   mMouseListener->ForgetFrame();
   nsBlockFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
 }
 
 static already_AddRefed<Element>
 MakeAnonButton(nsIDocument* aDoc, const char* labelKey,
                HTMLInputElement* aInputElement,
@@ -130,39 +129,32 @@ nsFileControlFrame::CreateAnonymousConte
   RefPtr<HTMLInputElement> fileContent = HTMLInputElement::FromNodeOrNull(mContent);
 
   // The access key is transferred to the "Choose files..." button only. In
   // effect that access key allows access to the control via that button, then
   // the user can tab between the two buttons.
   nsAutoString accessKey;
   fileContent->GetAccessKey(accessKey);
 
-  mBrowseFilesOrDirs = MakeAnonButton(doc, "Browse", fileContent, accessKey);
-  if (!mBrowseFilesOrDirs || !aElements.AppendElement(mBrowseFilesOrDirs)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
+  mContentContainer = doc->CreateHTMLElement(nsGkAtoms::div);
+  mContentContainer->SetIsNativeAnonymousRoot();
 
-  // Create and setup the text showing the selected files.
-  RefPtr<NodeInfo> nodeInfo;
-  nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::label, nullptr,
-                                                 kNameSpaceID_XUL,
-                                                 nsINode::ELEMENT_NODE);
-  NS_TrustedNewXULElement(getter_AddRefs(mTextContent), nodeInfo.forget());
-  // NOTE: SetIsNativeAnonymousRoot() has to be called before setting any
-  // attribute.
-  mTextContent->SetIsNativeAnonymousRoot();
-  mTextContent->SetAttr(kNameSpaceID_None, nsGkAtoms::crop,
-                        NS_LITERAL_STRING("center"), false);
+  mBrowseFilesOrDirs = MakeAnonButton(doc, "Browse", fileContent, accessKey);
+  mContentContainer->AppendChildTo(mBrowseFilesOrDirs, false);
+
+  RefPtr<Element> textLabel = doc->CreateHTMLElement(nsGkAtoms::label);
+  textLabel->AppendChildTo(new nsTextNode(doc->NodeInfoManager()), false);
+  mContentContainer->AppendChildTo(textLabel, false);
 
   // Update the displayed text to reflect the current element's value.
   nsAutoString value;
   HTMLInputElement::FromNode(mContent)->GetDisplayFileName(value);
   UpdateDisplayedValue(value, false);
 
-  if (!aElements.AppendElement(mTextContent)) {
+  if (!mContentContainer || !aElements.AppendElement(mContentContainer)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // We should be able to interact with the element by doing drag and drop.
   mContent->AddSystemEventListener(NS_LITERAL_STRING("drop"),
                                    mMouseListener, false);
   mContent->AddSystemEventListener(NS_LITERAL_STRING("dragover"),
                                    mMouseListener, false);
@@ -171,22 +163,18 @@ nsFileControlFrame::CreateAnonymousConte
 
   return NS_OK;
 }
 
 void
 nsFileControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                              uint32_t aFilter)
 {
-  if (mBrowseFilesOrDirs) {
-    aElements.AppendElement(mBrowseFilesOrDirs);
-  }
-
-  if (mTextContent) {
-    aElements.AppendElement(mTextContent);
+  if (mContentContainer) {
+    aElements.AppendElement(mContentContainer);
   }
 }
 
 NS_QUERYFRAME_HEAD(nsFileControlFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
 
@@ -464,17 +452,17 @@ nsFileControlFrame::GetFrameName(nsAStri
 {
   return MakeFrameName(NS_LITERAL_STRING("FileControl"), aResult);
 }
 #endif
 
 void
 nsFileControlFrame::UpdateDisplayedValue(const nsAString& aValue, bool aNotify)
 {
-  mTextContent->SetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue, aNotify);
+  mContentContainer->GetLastChild()->GetFirstChild()->AsText()->SetText(aValue, aNotify);
 }
 
 nsresult
 nsFileControlFrame::SetFormProperty(nsAtom* aName,
                                     const nsAString& aValue)
 {
   if (nsGkAtoms::value == aName) {
     UpdateDisplayedValue(aValue, true);
--- a/layout/forms/nsFileControlFrame.h
+++ b/layout/forms/nsFileControlFrame.h
@@ -129,20 +129,20 @@ protected:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
     return nsBlockFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
   /**
-   * The text box input.
+   * The container for the button and label.
    * @see nsFileControlFrame::CreateAnonymousContent
    */
-  RefPtr<Element> mTextContent;
+  RefPtr<Element> mContentContainer;
   /**
    * The button to open a file or directory picker.
    * @see nsFileControlFrame::CreateAnonymousContent
    */
   RefPtr<Element> mBrowseFilesOrDirs;
 
   /**
    * Drag and drop mouse listener.
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
   Styles for old GFX form widgets
  **/
 
 
 @namespace url(http://www.w3.org/1999/xhtml); /* set default namespace to HTML */
-@namespace xul url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
 
 *|*::-moz-fieldset-content {
   display: block; /* nsRuleNode::ComputeDisplayData overrules this in some cases */
   unicode-bidi: inherit;
   text-overflow: inherit;
   overflow: inherit;
   overflow-clip-box: inherit;
   /* Need to inherit border-radius too, so when the fieldset has rounded
@@ -474,49 +473,60 @@ input[type="image"]:disabled {
 input[type="image"]:-moz-focusring {
   /* Don't specify the outline-color, we should always use initial value. */
   outline: 1px dotted;
 }
 
 /* file selector */
 input[type="file"] {
   display: inline-block;
-  white-space: nowrap;
+  white-space: -moz-pre-space;
   overflow: hidden;
   overflow-clip-box: padding-box;
   color: inherit;
 
   /* Revert rules which apply on all inputs. */
   -moz-appearance: none;
   -moz-binding: none;
   cursor: default;
 
   border: none;
   background-color: transparent;
   padding: 0;
 }
 
-input[type="file"] > xul|label {
+input[type="file"] > div {
+  display: inline-flex;
+  width: 100%;
+  -moz-user-select: none;
+  align-items: center;
+}
+
+input[type="file"] > div > label {
   min-inline-size: 12em;
   padding-inline-start: 5px;
   text-align: match-parent;
 
   color: inherit;
   font-size: inherit;
   letter-spacing: inherit;
 
+  flex: 1;
+  text-overflow: ellipsis;
+  overflow: hidden;
+
   /*
    * Force the text to have LTR directionality. Otherwise filenames containing
    * RTL characters will be reordered with chaotic results.
    */
   direction: ltr !important;
 }
 
 /* button part of file selector */
-input[type="file"] > button[type="button"] {
+input[type="file"] > div > button {
   block-size: inherit;
   font-size: inherit;
   letter-spacing: inherit;
   cursor: inherit;
 }
 
 /* colored part of the color selector button */
 input[type="color"]::-moz-color-swatch {
@@ -529,17 +539,17 @@ input[type="color"]::-moz-color-swatch {
   box-sizing: border-box;
   border: 1px solid grey;
   display: block;
 }
 
 /* Try to make RTL <input type='file'> look nicer. */
 /* TODO: find a better solution than forcing direction: ltr on all file
    input labels and remove this override -- bug 1161482 */
-input[type="file"]:dir(rtl) > xul|label {
+input[type="file"]:dir(rtl) > div > label {
   padding-inline-start: 0px;
   padding-inline-end: 5px;
 }
 
 /* radio buttons */
 input[type="radio"] {
   display: inline-block;
   -moz-appearance: radio;
@@ -724,32 +734,30 @@ input[type="button"]:active:hover,
 input[type="submit"]:active:hover {
   color: ButtonText;
 }
 
 button::-moz-focus-inner,
 input[type="color"]::-moz-focus-inner,
 input[type="reset"]::-moz-focus-inner,
 input[type="button"]::-moz-focus-inner,
-input[type="submit"]::-moz-focus-inner,
-input[type="file"] > button[type="button"]::-moz-focus-inner {
+input[type="submit"]::-moz-focus-inner {
   /* Note this padding only affects the -moz-focus-inner ring, not the button itself */
   padding-block-start: 0px;
   padding-inline-end: 2px;
   padding-block-end: 0px;
   padding-inline-start: 2px;
   border: 1px dotted transparent;
 }
 
 button:-moz-focusring::-moz-focus-inner,
 input[type="color"]:-moz-focusring::-moz-focus-inner,
 input[type="reset"]:-moz-focusring::-moz-focus-inner,
 input[type="button"]:-moz-focusring::-moz-focus-inner,
-input[type="submit"]:-moz-focusring::-moz-focus-inner,
-input[type="file"] > button[type="button"]:-moz-focusring::-moz-focus-inner {
+input[type="submit"]:-moz-focusring::-moz-focus-inner {
   border-color: ButtonText;
 }
 
 button:disabled:active, button:disabled,
 input[type="color"]:disabled:active,
 input[type="color"]:disabled,
 input[type="reset"]:disabled:active,
 input[type="reset"]:disabled,