layout/forms/nsFileControlFrame.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsFileControlFrame.h"
     8 #include "nsGkAtoms.h"
     9 #include "nsCOMPtr.h"
    10 #include "nsIDocument.h"
    11 #include "nsINodeInfo.h"
    12 #include "mozilla/dom/Element.h"
    13 #include "mozilla/dom/DataTransfer.h"
    14 #include "mozilla/dom/HTMLButtonElement.h"
    15 #include "mozilla/dom/HTMLInputElement.h"
    16 #include "nsNodeInfoManager.h"
    17 #include "nsContentCreatorFunctions.h"
    18 #include "nsContentUtils.h"
    19 #include "mozilla/EventStates.h"
    20 #include "mozilla/dom/DOMStringList.h"
    21 #include "nsIDOMDragEvent.h"
    22 #include "nsIDOMFileList.h"
    23 #include "nsContentList.h"
    24 #include "nsIDOMMutationEvent.h"
    25 #include "nsTextNode.h"
    27 using namespace mozilla;
    28 using namespace mozilla::dom;
    30 nsIFrame*
    31 NS_NewFileControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    32 {
    33   return new (aPresShell) nsFileControlFrame(aContext);
    34 }
    36 NS_IMPL_FRAMEARENA_HELPERS(nsFileControlFrame)
    38 nsFileControlFrame::nsFileControlFrame(nsStyleContext* aContext)
    39   : nsBlockFrame(aContext)
    40 {
    41   AddStateBits(NS_BLOCK_FLOAT_MGR);
    42 }
    45 void
    46 nsFileControlFrame::Init(nsIContent* aContent,
    47                          nsIFrame*   aParent,
    48                          nsIFrame*   aPrevInFlow)
    49 {
    50   nsBlockFrame::Init(aContent, aParent, aPrevInFlow);
    52   mMouseListener = new DnDListener(this);
    53 }
    55 void
    56 nsFileControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
    57 {
    58   ENSURE_TRUE(mContent);
    60   // Remove the events.
    61   if (mContent) {
    62     mContent->RemoveSystemEventListener(NS_LITERAL_STRING("drop"),
    63                                         mMouseListener, false);
    64     mContent->RemoveSystemEventListener(NS_LITERAL_STRING("dragover"),
    65                                         mMouseListener, false);
    66   }
    68   nsContentUtils::DestroyAnonymousContent(&mTextContent);
    69   nsContentUtils::DestroyAnonymousContent(&mBrowse);
    71   mMouseListener->ForgetFrame();
    72   nsBlockFrame::DestroyFrom(aDestructRoot);
    73 }
    75 nsresult
    76 nsFileControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
    77 {
    78   nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
    80   // Create and setup the file picking button.
    81   mBrowse = doc->CreateHTMLElement(nsGkAtoms::button);
    82   // NOTE: SetIsNativeAnonymousRoot() has to be called before setting any
    83   // attribute.
    84   mBrowse->SetIsNativeAnonymousRoot();
    85   mBrowse->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
    86                    NS_LITERAL_STRING("button"), false);
    88   // Set the file picking button text depending on the current locale.
    89   nsXPIDLString buttonTxt;
    90   nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
    91                                      "Browse", buttonTxt);
    93   // Set the browse button text. It's a bit of a pain to do because we want to
    94   // make sure we are not notifying.
    95   nsRefPtr<nsTextNode> textContent =
    96     new nsTextNode(mBrowse->NodeInfo()->NodeInfoManager());
    98   textContent->SetText(buttonTxt, false);
   100   nsresult rv = mBrowse->AppendChildTo(textContent, false);
   101   NS_ENSURE_SUCCESS(rv, rv);
   103   // Make sure access key and tab order for the element actually redirect to the
   104   // file picking button.
   105   nsRefPtr<HTMLInputElement> fileContent = HTMLInputElement::FromContentOrNull(mContent);
   106   nsRefPtr<HTMLButtonElement> browseControl = HTMLButtonElement::FromContentOrNull(mBrowse);
   108   nsAutoString accessKey;
   109   fileContent->GetAccessKey(accessKey);
   110   browseControl->SetAccessKey(accessKey);
   112   int32_t tabIndex;
   113   fileContent->GetTabIndex(&tabIndex);
   114   browseControl->SetTabIndex(tabIndex);
   116   if (!aElements.AppendElement(mBrowse)) {
   117     return NS_ERROR_OUT_OF_MEMORY;
   118   }
   120   // Create and setup the text showing the selected files.
   121   nsCOMPtr<nsINodeInfo> nodeInfo;
   122   nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::label, nullptr,
   123                                                  kNameSpaceID_XUL,
   124                                                  nsIDOMNode::ELEMENT_NODE);
   125   NS_TrustedNewXULElement(getter_AddRefs(mTextContent), nodeInfo.forget());
   126   // NOTE: SetIsNativeAnonymousRoot() has to be called before setting any
   127   // attribute.
   128   mTextContent->SetIsNativeAnonymousRoot();
   129   mTextContent->SetAttr(kNameSpaceID_None, nsGkAtoms::crop,
   130                         NS_LITERAL_STRING("center"), false);
   132   // Update the displayed text to reflect the current element's value.
   133   nsAutoString value;
   134   HTMLInputElement::FromContent(mContent)->GetDisplayFileName(value);
   135   UpdateDisplayedValue(value, false);
   137   if (!aElements.AppendElement(mTextContent)) {
   138     return NS_ERROR_OUT_OF_MEMORY;
   139   }
   141   // We should be able to interact with the element by doing drag and drop.
   142   mContent->AddSystemEventListener(NS_LITERAL_STRING("drop"),
   143                                    mMouseListener, false);
   144   mContent->AddSystemEventListener(NS_LITERAL_STRING("dragover"),
   145                                    mMouseListener, false);
   147   SyncDisabledState();
   149   return NS_OK;
   150 }
   152 void
   153 nsFileControlFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
   154                                              uint32_t aFilter)
   155 {
   156   aElements.MaybeAppendElement(mBrowse);
   157   aElements.MaybeAppendElement(mTextContent);
   158 }
   160 NS_QUERYFRAME_HEAD(nsFileControlFrame)
   161   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
   162   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
   163 NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
   165 void 
   166 nsFileControlFrame::SetFocus(bool aOn, bool aRepaint)
   167 {
   168 }
   170 /**
   171  * This is called when we receive a drop or a dragover.
   172  */
   173 NS_IMETHODIMP
   174 nsFileControlFrame::DnDListener::HandleEvent(nsIDOMEvent* aEvent)
   175 {
   176   NS_ASSERTION(mFrame, "We should have been unregistered");
   178   bool defaultPrevented = false;
   179   aEvent->GetDefaultPrevented(&defaultPrevented);
   180   if (defaultPrevented) {
   181     return NS_OK;
   182   }
   184   nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
   185   if (!dragEvent || !IsValidDropData(dragEvent)) {
   186     return NS_OK;
   187   }
   189   nsAutoString eventType;
   190   aEvent->GetType(eventType);
   191   if (eventType.EqualsLiteral("dragover")) {
   192     // Prevent default if we can accept this drag data
   193     aEvent->PreventDefault();
   194     return NS_OK;
   195   }
   197   if (eventType.EqualsLiteral("drop")) {
   198     aEvent->StopPropagation();
   199     aEvent->PreventDefault();
   201     nsIContent* content = mFrame->GetContent();
   202     NS_ASSERTION(content, "The frame has no content???");
   204     HTMLInputElement* inputElement = HTMLInputElement::FromContent(content);
   205     NS_ASSERTION(inputElement, "No input element for this file upload control frame!");
   207     nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
   208     dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
   210     nsCOMPtr<nsIDOMFileList> fileList;
   211     dataTransfer->GetFiles(getter_AddRefs(fileList));
   213     inputElement->SetFiles(fileList, true);
   214     nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(), content,
   215                                          NS_LITERAL_STRING("change"), true,
   216                                          false);
   217   }
   219   return NS_OK;
   220 }
   222 /* static */ bool
   223 nsFileControlFrame::DnDListener::IsValidDropData(nsIDOMDragEvent* aEvent)
   224 {
   225   nsCOMPtr<nsIDOMDataTransfer> domDataTransfer;
   226   aEvent->GetDataTransfer(getter_AddRefs(domDataTransfer));
   227   nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(domDataTransfer);
   228   NS_ENSURE_TRUE(dataTransfer, false);
   230   // We only support dropping files onto a file upload control
   231   nsRefPtr<DOMStringList> types = dataTransfer->Types();
   232   return types->Contains(NS_LITERAL_STRING("Files"));
   233 }
   235 nscoord
   236 nsFileControlFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
   237 {
   238   nscoord result;
   239   DISPLAY_MIN_WIDTH(this, result);
   241   // Our min width is our pref width
   242   result = GetPrefWidth(aRenderingContext);
   243   return result;
   244 }
   246 void
   247 nsFileControlFrame::SyncDisabledState()
   248 {
   249   EventStates eventStates = mContent->AsElement()->State();
   250   if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
   251     mBrowse->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, EmptyString(),
   252                      true);
   253   } else {
   254     mBrowse->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
   255   }
   256 }
   258 nsresult
   259 nsFileControlFrame::AttributeChanged(int32_t  aNameSpaceID,
   260                                      nsIAtom* aAttribute,
   261                                      int32_t  aModType)
   262 {
   263   if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::tabindex) {
   264     if (aModType == nsIDOMMutationEvent::REMOVAL) {
   265       mBrowse->UnsetAttr(aNameSpaceID, aAttribute, true);
   266     } else {
   267       nsAutoString value;
   268       mContent->GetAttr(aNameSpaceID, aAttribute, value);
   269       mBrowse->SetAttr(aNameSpaceID, aAttribute, value, true);
   270     }
   271   }
   273   return nsBlockFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
   274 }
   276 void
   277 nsFileControlFrame::ContentStatesChanged(EventStates aStates)
   278 {
   279   if (aStates.HasState(NS_EVENT_STATE_DISABLED)) {
   280     nsContentUtils::AddScriptRunner(new SyncDisabledStateEvent(this));
   281   }
   282 }
   284 #ifdef DEBUG_FRAME_DUMP
   285 nsresult
   286 nsFileControlFrame::GetFrameName(nsAString& aResult) const
   287 {
   288   return MakeFrameName(NS_LITERAL_STRING("FileControl"), aResult);
   289 }
   290 #endif
   292 void
   293 nsFileControlFrame::UpdateDisplayedValue(const nsAString& aValue, bool aNotify)
   294 {
   295   mTextContent->SetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue, aNotify);
   296 }
   298 nsresult
   299 nsFileControlFrame::SetFormProperty(nsIAtom* aName,
   300                                     const nsAString& aValue)
   301 {
   302   if (nsGkAtoms::value == aName) {
   303     UpdateDisplayedValue(aValue, true);
   304   }
   305   return NS_OK;
   306 }
   308 void
   309 nsFileControlFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   310                                      const nsRect&           aDirtyRect,
   311                                      const nsDisplayListSet& aLists)
   312 {
   313   BuildDisplayListForInline(aBuilder, aDirtyRect, aLists);
   314 }
   316 #ifdef ACCESSIBILITY
   317 a11y::AccType
   318 nsFileControlFrame::AccessibleType()
   319 {
   320   return a11y::eHTMLFileInputType;
   321 }
   322 #endif
   324 ////////////////////////////////////////////////////////////
   325 // Mouse listener implementation
   327 NS_IMPL_ISUPPORTS(nsFileControlFrame::MouseListener,
   328                   nsIDOMEventListener)

mercurial