Bug 1089005, add a third consume option that never consumes even over the anchor. This allows clicks on the location field to adjust the caret position, r=dao
authorNeil Deakin <neil@mozilla.com>
Fri, 09 Jan 2015 21:12:10 -0500
changeset 223100 203e26771e770b3d072e2e3f2e5bb7ca2ca93555
parent 223099 02ab5234c39e95266c536a9129ca56e87f9ea03e
child 223101 ca411b1cf0019393548598a66af9e08a711cd6f8
push id28082
push usercbook@mozilla.com
push dateMon, 12 Jan 2015 10:44:52 +0000
treeherdermozilla-central@643589c3ef94 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao
bugs1089005
milestone37.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 1089005, add a third consume option that never consumes even over the anchor. This allows clicks on the location field to adjust the caret position, r=dao
browser/base/content/urlbarBindings.xml
browser/components/search/content/search.xml
layout/xul/nsMenuPopupFrame.cpp
layout/xul/nsMenuPopupFrame.h
layout/xul/nsXULPopupManager.cpp
toolkit/content/widgets/autocomplete.xml
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -968,17 +968,17 @@
     </implementation>
   </binding>
 
   <!-- Note: this binding is applied to the autocomplete popup used in the Search bar -->
   <binding id="browser-search-autocomplete-result-popup" extends="chrome://browser/content/urlbarBindings.xml#browser-autocomplete-result-popup">
     <resources>
       <stylesheet src="chrome://browser/skin/searchbar.css"/>
     </resources>
-    <content ignorekeys="true" level="top">
+    <content ignorekeys="true" level="top" consumeoutsideclicks="never">
       <xul:hbox xbl:inherits="collapsed=showonlysettings" anonid="searchbar-engine"
                 class="search-panel-header search-panel-current-engine">
         <xul:image class="searchbar-engine-image" xbl:inherits="src"/>
         <xul:label anonid="searchbar-engine-name" flex="1" crop="end"
                    role="presentation"/>
       </xul:hbox>
       <xul:tree anonid="tree" flex="1"
                 class="autocomplete-tree plain search-panel-tree"
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -896,20 +896,16 @@
             // in browser.xul) is hidden to avoid impacting startup / new
             // window performance. The base binding's openPopup would normally
             // call the overriden openAutocompletePopup in urlbarBindings.xml's
             // browser-autocomplete-result-popup binding to unhide the popup,
             // but since we're overriding openPopup we need to unhide the panel
             // ourselves.
             popup.hidden = false;
 
-            // showHistoryPopup sets consumeoutsideclicks to true so reset it
-            // here
-            popup.setAttribute("consumeoutsideclicks", "false");
-
             popup.mInput = this;
             popup.view = this.controller.QueryInterface(Components.interfaces.nsITreeView);
             popup.invalidate();
 
             popup.showCommentColumn = this.showCommentColumn;
             popup.showImageColumn = this.showImageColumn;
 
             document.popupNode = null;
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -1502,62 +1502,67 @@ void nsMenuPopupFrame::CanAdjustEdges(in
   }
   else if (aVerticalSide == (mVFlip ? NS_SIDE_TOP : NS_SIDE_BOTTOM)) {
     if (popupAlign == POPUPALIGNMENT_BOTTOMLEFT || popupAlign == POPUPALIGNMENT_BOTTOMRIGHT) {
       aChange.y = 0;
     }
   }
 }
 
-bool nsMenuPopupFrame::ConsumeOutsideClicks()
+ConsumeOutsideClicksResult nsMenuPopupFrame::ConsumeOutsideClicks()
 {
   // If the popup has explicitly set a consume mode, honor that.
   if (mConsumeRollupEvent != PopupBoxObject::ROLLUP_DEFAULT) {
-    return (mConsumeRollupEvent == PopupBoxObject::ROLLUP_CONSUME);
+    return (mConsumeRollupEvent == PopupBoxObject::ROLLUP_CONSUME) ?
+           ConsumeOutsideClicks_True : ConsumeOutsideClicks_ParentOnly;
   }
 
   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::consumeoutsideclicks,
                             nsGkAtoms::_true, eCaseMatters)) {
-    return true;
+    return ConsumeOutsideClicks_True;
   }
   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::consumeoutsideclicks,
                             nsGkAtoms::_false, eCaseMatters)) {
-    return false;
+    return ConsumeOutsideClicks_ParentOnly;
+  }
+  if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::consumeoutsideclicks,
+                            nsGkAtoms::never, eCaseMatters)) {
+    return ConsumeOutsideClicks_Never;
   }
 
   nsCOMPtr<nsIContent> parentContent = mContent->GetParent();
   if (parentContent) {
     dom::NodeInfo *ni = parentContent->NodeInfo();
     if (ni->Equals(nsGkAtoms::menulist, kNameSpaceID_XUL)) {
-      return true;  // Consume outside clicks for combo boxes on all platforms
+      return ConsumeOutsideClicks_True;  // Consume outside clicks for combo boxes on all platforms
     }
 #if defined(XP_WIN)
     // Don't consume outside clicks for menus in Windows
     if (ni->Equals(nsGkAtoms::menu, kNameSpaceID_XUL) ||
         ni->Equals(nsGkAtoms::splitmenu, kNameSpaceID_XUL) ||
         ni->Equals(nsGkAtoms::popupset, kNameSpaceID_XUL) ||
         ((ni->Equals(nsGkAtoms::button, kNameSpaceID_XUL) ||
           ni->Equals(nsGkAtoms::toolbarbutton, kNameSpaceID_XUL)) &&
          (parentContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
                                      nsGkAtoms::menu, eCaseMatters) ||
           parentContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
                                      nsGkAtoms::menuButton, eCaseMatters)))) {
-      return false;
+      return ConsumeOutsideClicks_Never;
     }
 #endif
     if (ni->Equals(nsGkAtoms::textbox, kNameSpaceID_XUL)) {
       // Don't consume outside clicks for autocomplete widget
       if (parentContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
                                      nsGkAtoms::autocomplete, eCaseMatters)) {
-        return false;
+        return ConsumeOutsideClicks_Never;
       }
     }
   }
 
-  return true;
+  return ConsumeOutsideClicks_True;
 }
 
 // XXXroc this is megalame. Fossicking around for a frame of the right
 // type is a recipe for disaster in the long term.
 nsIScrollableFrame* nsMenuPopupFrame::GetScrollFrame(nsIFrame* aStart)
 {
   if (!aStart)
     return nullptr;  
--- a/layout/xul/nsMenuPopupFrame.h
+++ b/layout/xul/nsMenuPopupFrame.h
@@ -58,16 +58,22 @@ enum nsPopupState {
   // popuphiding or popuphidden events. It is used when executing a menu
   // command because the menu needs to be hidden before the command event
   // fires, yet the popuphiding and popuphidden events are fired after. This
   // state can also occur when the popup is removed because the document is
   // unloaded.
   ePopupInvisible
 };
 
+enum ConsumeOutsideClicksResult {
+  ConsumeOutsideClicks_ParentOnly = 0, // Only consume clicks on the parent anchor
+  ConsumeOutsideClicks_True = 1, // Always consume clicks
+  ConsumeOutsideClicks_Never = 2 // Never consume clicks
+};
+
 // How a popup may be flipped. Flipping to the outside edge is like how
 // a submenu would work. The entire popup is flipped to the opposite side
 // of the anchor.
 enum FlipStyle {
   FlipStyle_None = 0,
   FlipStyle_Outside = 1,
   FlipStyle_Inside = 2
 };
@@ -183,17 +189,17 @@ public:
    * Should clicks outside of a popup be eaten?
    *
    *       Menus     Autocomplete     Comboboxes
    * Mac     Eat           No              Eat
    * Win     No            No              Eat     
    * Unix    Eat           No              Eat
    *
    */
-  bool ConsumeOutsideClicks();
+  ConsumeOutsideClicksResult ConsumeOutsideClicks();
 
   virtual bool IsContextMenu() MOZ_OVERRIDE { return mIsContextMenu; }
 
   virtual bool MenuClosed() MOZ_OVERRIDE { return true; }
 
   virtual void LockMenuUntilClosed(bool aLock) MOZ_OVERRIDE;
   virtual bool IsMenuLocked() MOZ_OVERRIDE { return mIsMenuLocked; }
 
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -197,20 +197,23 @@ nsXULPopupManager::Rollup(uint32_t aCoun
       // that case we don't need to deal with the menu reopening as it will
       // already still be open.
       nsMenuChainItem* first = item;
       while (first->GetParent())
         first = first->GetParent();
       *aLastRolledUp = first->Content();
     }
 
-    consume = item->Frame()->ConsumeOutsideClicks();
-    // If the click was over the anchor, always consume the click. This way,
-    // clicking on a menu doesn't reopen the menu.
-    if (!consume && pos) {
+    ConsumeOutsideClicksResult consumeResult = item->Frame()->ConsumeOutsideClicks();
+    consume = (consumeResult == ConsumeOutsideClicks_True);
+
+    // If ConsumeOutsideClicks_ParentOnly was returned, then only consume the
+    // click is it was over the anchor. This way, clicking on a menu doesn't
+    // reopen the menu.
+    if (consumeResult == ConsumeOutsideClicks_ParentOnly && pos) {
       nsCOMPtr<nsIContent> anchor = item->Frame()->GetAnchor();
 
       // Check if the anchor has indicated another node to use for checking
       // for roll-up. That way, we can anchor a popup on anonymous content or
       // an individual icon, while clicking elsewhere within a button or other
       // container doesn't result in us re-opening the popup.
       if (anchor) {
         nsAutoString consumeAnchor;
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -350,34 +350,32 @@
       <method name="openPopup">
         <body><![CDATA[
           this.popup.openAutocompletePopup(this, this);
         ]]></body>
       </method>
 
       <method name="closePopup">
         <body><![CDATA[
-          this.popup.setAttribute("consumeoutsideclicks", "false");
           this.popup.closePopup();
         ]]></body>
       </method>
 
       <method name="showHistoryPopup">
         <body><![CDATA[
           // history dropmarker pushed state
           function cleanup(popup) {
             popup.removeEventListener("popupshowing", onShow, false);
           }
           function onShow(event) {
             var popup = event.target, input = popup.input;
             cleanup(popup);
             input.setAttribute("open", "true");
             function onHide() {
               input.removeAttribute("open");
-              popup.setAttribute("consumeoutsideclicks", "false");
               popup.removeEventListener("popuphiding", onHide, false);
             }
             popup.addEventListener("popuphiding", onHide, false);
           }
           this.popup.addEventListener("popupshowing", onShow, false);
           setTimeout(cleanup, 1000, this.popup);
 
           // Store our "normal" maxRows on the popup, so that it can reset the
@@ -387,17 +385,16 @@
           // Increase our maxRows temporarily, since we want the dropdown to
           // be bigger in this case. The popup's popupshowing/popuphiding
           // handlers will take care of resetting this.
           this.maxRows = this.maxDropMarkerRows;
 
           // Ensure that we have focus.
           if (!this.focused)
             this.focus();
-          this.popup.setAttribute("consumeoutsideclicks", "true");
           this.attachController();
           this.mController.startSearch("");
         ]]></body>
       </method>
 
       <method name="toggleHistoryPopup">
         <body><![CDATA[
           if (!this.popup.popupOpen)
@@ -608,17 +605,17 @@
 
   <binding id="autocomplete-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-base-popup">
     <resources>
       <stylesheet src="chrome://global/content/autocomplete.css"/>
       <stylesheet src="chrome://global/skin/tree.css"/>
       <stylesheet src="chrome://global/skin/autocomplete.css"/>
     </resources>
 
-    <content ignorekeys="true" level="top" consumeoutsideclicks="false">
+    <content ignorekeys="true" level="top" consumeoutsideclicks="never">
       <xul:tree anonid="tree" class="autocomplete-tree plain" hidecolumnpicker="true" flex="1" seltype="single">
         <xul:treecols anonid="treecols">
           <xul:treecol id="treecolAutoCompleteValue" class="autocomplete-treecol" flex="1" overflow="true"/>
         </xul:treecols>
         <xul:treechildren class="autocomplete-treebody"/>
       </xul:tree>
     </content>
 
@@ -961,17 +958,17 @@ extends="chrome://global/content/binding
   </binding>
 
   <binding id="autocomplete-rich-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-base-popup">
     <resources>
       <stylesheet src="chrome://global/content/autocomplete.css"/>
       <stylesheet src="chrome://global/skin/autocomplete.css"/>
     </resources>
 
-    <content ignorekeys="true" level="top" consumeoutsideclicks="false">
+    <content ignorekeys="true" level="top" consumeoutsideclicks="never">
       <xul:richlistbox anonid="richlistbox" class="autocomplete-richlistbox" flex="1"/>
       <xul:hbox>
         <children/>
       </xul:hbox>
     </content>
 
     <implementation implements="nsIAutoCompletePopup">
       <field name="_currentIndex">0</field>