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 223158 203e26771e770b3d072e2e3f2e5bb7ca2ca93555
parent 223157 02ab5234c39e95266c536a9129ca56e87f9ea03e
child 223159 ca411b1cf0019393548598a66af9e08a711cd6f8
push id10769
push usercbook@mozilla.com
push dateMon, 12 Jan 2015 14:15:52 +0000
treeherderfx-team@0e9765732906 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao
bugs1089005
milestone37.0a1
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>