Bug 1508209 - remove broadcasters from mail/components/addrbook/. r=aceman
authorMagnus Melin <mkmelin+mozilla@iki.fi>
Tue, 27 Nov 2018 11:28:01 +0200
changeset 33796 214b702ef3435adcc6ad826646af44861b0e83a8
parent 33795 2a56bbf3704832de7085764738e0d32c354208e7
child 33797 f35c6c93bcd8a9e91a74cc83bd3be2d68d409186
push id388
push userclokep@gmail.com
push dateMon, 28 Jan 2019 20:54:56 +0000
reviewersaceman
bugs1508209
Bug 1508209 - remove broadcasters from mail/components/addrbook/. r=aceman
mail/components/addrbook/content/abCommon.js
mail/components/addrbook/content/abContactsPanel.xul
mail/components/addrbook/content/addressbook.xul
mailnews/addrbook/content/abResultsPane.js
--- a/mail/components/addrbook/content/abCommon.js
+++ b/mail/components/addrbook/content/abCommon.js
@@ -122,37 +122,38 @@ var DirPaneController =
 
         // Else return true to enable deletion (default).
         return true;
       }
       case "cmd_printcard":
       case "cmd_printcardpreview":
         return (GetSelectedCardIndex() != -1);
       case "cmd_properties": {
-        let labelAttr = "valueGeneric";
-        let accKeyAttr = "valueGenericAccessKey";
-        let tooltipTextAttr = "valueGenericTooltipText";
-        let isMailList;
+        let attrs = {
+          label: "valueGeneric",
+          accesskey: "valueGenericAccessKey",
+          tooltiptext: "valueGenericTooltipText",
+        };
         let selectedDir = getSelectedDirectory();
         if (selectedDir) {
-          isMailList = selectedDir.isMailList;
-          labelAttr = isMailList ? "valueMailingList"
-                                 : "valueAddressBook";
-          accKeyAttr = isMailList ? "valueMailingListAccessKey"
-                                  : "valueAddressBookAccessKey";
-          tooltipTextAttr = isMailList ? "valueMailingListTooltipText"
-                                       : "valueAddressBookTooltipText";
+          let isMailList = selectedDir.isMailList;
+          attrs.label = isMailList ? "valueMailingList" : "valueAddressBook";
+          attrs.accesskey = isMailList ? "valueMailingListAccessKey" : "valueAddressBookAccessKey";
+          attrs.tooltiptext = isMailList ? "valueMailingListTooltipText" : "valueAddressBookTooltipText";
         }
-        goSetLabelAccesskeyTooltiptext("cmd_properties-button", null, null,
-          tooltipTextAttr);
-        goSetLabelAccesskeyTooltiptext("cmd_properties-contextMenu",
-          labelAttr, accKeyAttr);
-        goSetLabelAccesskeyTooltiptext("cmd_properties-menu",
-          labelAttr, accKeyAttr);
-        return (selectedDir != null);
+        let enabled = (selectedDir != null);
+        document.querySelectorAll("[command=cmd_properties]").forEach(e => {
+          e.disabled = !enabled;
+          for (let [attr, name] of Object.entries(attrs)) {
+            if (e.hasAttribute(attr) && e.getAttribute(name)) {
+              e.setAttribute(attr, e.getAttribute(name));
+            }
+          }
+        });
+        return enabled;
       }
       case "cmd_abToggleStartupDir":
         return !!getSelectedDirectoryURI();
       case "cmd_newlist":
       case "cmd_newCard":
         return true;
       default:
         return false;
@@ -1200,60 +1201,8 @@ function saneBirthYear(aYear) {
  */
 function nearestLeap(aYear) {
   for (let year = aYear; year > 0; year--) {
     if (new Date(year, 1, 29).getMonth() == 1)
       return year;
   }
   return 2000;
 }
-
-/**
- * Sets the label, accesskey, and tooltiptext attributes of an element from
- * custom attributes of the same element. Typically, the element will be a
- * command or broadcaster element. JS does not allow omitting function arguments
- * in the middle of the arguments list, so in that case, please pass an explicit
- * falsy argument like null or undefined instead; the respective attributes will
- * not be touched. Empty strings ("") from custom attributes will be applied
- * correctly. Hacker's shortcut: Passing empty string ("") for any of the custom
- * attribute names will also set the respective main attribute to empty string ("").
- * Examples:
- *
- * goSetLabelAccesskeyTooltiptext("cmd_foo", "valueFlavor", "valueFlavorAccesskey");
- * goSetLabelAccesskeyTooltiptext("cmd_foo", "valueFlavor", "valueFlavorAccesskey",
- *                                           "valueFlavorTooltiptext");
- * goSetLabelAccesskeyTooltiptext("cmd_foo", null, null, "valueFlavorTooltiptext");
- * goSetLabelAccesskeyTooltiptext("cmd_foo", "", "", "valueFlavorTooltiptext");
- *
- * @param aID                    the ID of an XUL element (attribute source and target)
- * @param aLabelAttribute        (optional) the name of a custom label attribute of aID, or ""
- * @param aAccessKeyAttribute    (optional) the name of a custom accesskey attribute of aID, or ""
- * @param aTooltipTextAttribute  (optional) the name of a custom tooltiptext attribute of aID, or ""
- */
-function goSetLabelAccesskeyTooltiptext(aID, aLabelAttribute, aAccessKeyAttribute,
-                                             aTooltipTextAttribute) {
-  let node = top.document.getElementById(aID);
-  if (!node) {
-    // tweak for composition's abContactsPanel
-    node = document.getElementById(aID);
-  }
-  if (!node)
-    return;
-
-  for (let [attr, customAttr] of [["label",       aLabelAttribute      ],
-                                  ["accesskey",   aAccessKeyAttribute  ],
-                                  ["tooltiptext", aTooltipTextAttribute]]) {
-    if (customAttr) {
-      // In XUL (DOM Level 3), getAttribute() on non-existing attributes returns
-      // "" (instead of null), which is indistinguishable from existing valid
-      // attributes with value="", so we have to check using hasAttribute().
-      if (node.hasAttribute(customAttr)) {
-        let value = node.getAttribute(customAttr);
-        node.setAttribute(attr, value);
-      } else {  // missing custom attribute
-        dump('Something wrong here: goSetLabelAccesskeyTooltiptext("' + aID + '", ...): ' +
-             "Missing custom attribute: " + customAttr + "\n");
-      }
-    } else if (customAttr === "") {
-      node.removeAttribute(attr);
-    }
-  }
-}
--- a/mail/components/addrbook/content/abContactsPanel.xul
+++ b/mail/components/addrbook/content/abContactsPanel.xul
@@ -40,36 +40,16 @@
     <command id="cmd_addrTo" oncommand="addSelectedAddresses('addr_to')" disabled="true"/>
     <command id="cmd_addrCc" oncommand="addSelectedAddresses('addr_cc')" disabled="true"/>
     <command id="cmd_addrBcc" oncommand="addSelectedAddresses('addr_bcc')" disabled="true"/>
     <command id="cmd_delete" oncommand="goDoCommand('cmd_delete');"/>
     <command id="cmd_properties" oncommand="goDoCommand('cmd_properties');"/>
     <command id="cmd_newCard" oncommand="AbPanelNewCard();"/>
     <command id="cmd_newlist" oncommand="AbPanelNewList();"/>
   </commandset>
-  <broadcasterset id="cmd_properties-flavors">
-    <broadcaster id="cmd_properties-contextMenu" observes="cmd_properties"
-                 valueGeneric="&propertiesContext.label;"
-                 valueGenericAccessKey="&propertiesContext.accesskey;"
-                 valueAddressBook="&abPropertiesContext.label;"
-                 valueAddressBookAccessKey="&abPropertiesContext.accesskey;"
-                 valueContact="&editContactContext.label;"
-                 valueContactAccessKey="&editContactContext.accesskey;"
-                 valueMailingList="&editMailingListContext.label;"
-                 valueMailingListAccessKey="&editMailingListContext.accesskey;"/>
-    <broadcaster id="cmd_properties-menu" observes="cmd_properties"
-                 valueGeneric="&propertiesMenu.label;"
-                 valueGenericAccessKey="&propertiesMenu.accesskey;"
-                 valueAddressBook="&abPropertiesMenu.label;"
-                 valueAddressBookAccessKey="&abPropertiesMenu.accesskey;"
-                 valueContact="&contactPropertiesMenu.label;"
-                 valueContactAccessKey="&contactPropertiesMenu.accesskey;"
-                 valueMailingList="&mailingListPropertiesMenu.label;"
-                 valueMailingListAccessKey="&mailingListPropertiesMenu.accesskey;"/>
-  </broadcasterset>
 
   <keyset id="keyset_abContactsPanel">
     <!-- This key (key_delete) does not trigger any command, but it is used
          only to show the hotkey on the corresponding menuitem. -->
     <key id="key_delete" keycode="VK_DELETE"/>
 #ifdef XP_MACOSX
     <key id="key_properties" modifiers="accel" key="&propertiesCmd.key;" command="cmd_properties"/>
 #else
@@ -91,17 +71,27 @@
     <menuseparator/>
     <menuitem label="&deleteAddrBookCard.label;"
               accesskey="&deleteAddrBookCard.accesskey;"
               key="key_delete"
               command="cmd_delete"/>
     <menuseparator/>
     <menuitem label="&propertiesContext.label;"
               key="key_properties"
-              command="cmd_properties-contextMenu"/>
+              command="cmd_properties"
+              accesskey="&propertiesContext.accesskey;"
+              valueGeneric="&propertiesContext.label;"
+              valueGenericAccessKey="&propertiesContext.accesskey;"
+              valueAddressBook="&abPropertiesContext.label;"
+              valueAddressBookAccessKey="&abPropertiesContext.accesskey;"
+              valueContact="&editContactContext.label;"
+              valueContactAccessKey="&editContactContext.accesskey;"
+              valueMailingList="&editMailingListContext.label;"
+              valueMailingListAccessKey="&editMailingListContext.accesskey;"
+              />
   </menupopup>
 
   <menupopup id="sidebarAbContextMenu">
     <menuitem label="&newContactAbContext.label;"
               accesskey="&newContactAbContext.accesskey;"
               command="cmd_newCard"/>
     <menuitem label="&newListAbContext.label;"
               accesskey="&newListAbContext.accesskey;"
--- a/mail/components/addrbook/content/addressbook.xul
+++ b/mail/components/addrbook/content/addressbook.xul
@@ -81,73 +81,44 @@
               events="focus"
               oncommandupdate="goUpdateGlobalEditMenuItems()"/>
     <command id="cmd_newlist" oncommand="goDoCommand('cmd_newlist');"/>
     <command id="cmd_newCard" oncommand="goDoCommand('cmd_newCard');"/>
     <command id="cmd_printcardpreview" oncommand="AbPrintPreviewCard();"/>
     <command id="cmd_printcard" oncommand="AbPrintCard();"/>
     <command id="cmd_newMessage" oncommand="AbNewMessage();" disabled="true"/>
     <command id="cmd_properties" oncommand="goDoCommand('cmd_properties');" disabled="true"/>
-    <broadcasterset id="cmd_properties-flavors">
-      <broadcaster id="cmd_properties-button" observes="cmd_properties"
-                   valueGenericTooltipText="&editPropertiesButton.tooltip;"
-                   valueAddressBookTooltipText="&editAbPropertiesButton.tooltip;"
-                   valueContactTooltipText="&editContactPropertiesButton.tooltip;"
-                   valueMailingListTooltipText="&editMailingListPropertiesButton.tooltip;"/>
-      <broadcaster id="cmd_properties-contextMenu" observes="cmd_properties"
-                   valueGeneric="&propertiesContext.label;"
-                   valueGenericAccessKey="&propertiesContext.accesskey;"
-                   valueAddressBook="&abPropertiesContext.label;"
-                   valueAddressBookAccessKey="&abPropertiesContext.accesskey;"
-                   valueContact="&editContactContext.label;"
-                   valueContactAccessKey="&editContactContext.accesskey;"
-                   valueMailingList="&editMailingListContext.label;"
-                   valueMailingListAccessKey="&editMailingListContext.accesskey;"/>
-      <broadcaster id="cmd_properties-menu" observes="cmd_properties"
-                   valueGeneric="&propertiesMenu.label;"
-                   valueGenericAccessKey="&propertiesMenu.accesskey;"
-                   valueAddressBook="&abPropertiesMenu.label;"
-                   valueAddressBookAccessKey="&abPropertiesMenu.accesskey;"
-                   valueContact="&contactPropertiesMenu.label;"
-                   valueContactAccessKey="&contactPropertiesMenu.accesskey;"
-                   valueMailingList="&mailingListPropertiesMenu.label;"
-                   valueMailingListAccessKey="&mailingListPropertiesMenu.accesskey;"/>
-    </broadcasterset>
     <command id="cmd_undo" oncommand="goDoCommand('cmd_undo')" disabled="true"/>
     <command id="cmd_redo" oncommand="goDoCommand('cmd_redo')" disabled="true"/>
     <command id="cmd_cut" oncommand="goDoCommand('cmd_cut')" disabled="true"/>
     <command id="cmd_copy" oncommand="goDoCommand('cmd_copy')" disabled="true"/>
     <command id="cmd_paste" oncommand="goDoCommand('cmd_paste')" disabled="true"/>
     <command id="cmd_delete" oncommand="goDoCommand('cmd_delete')"
              valueAddressBook="&deleteAbCmd.label;"
              valueCard="&deleteContactCmd.label;"
              valueCards="&deleteContactsCmd.label;"
              valueList="&deleteListCmd.label;"
              valueLists="&deleteListsCmd.label;"
              valueItems="&deleteItemsCmd.label;"
              disabled="true"/>
+    <command id="button_delete" oncommand="goDoCommand('button_delete');"/>
     <command id="cmd_selectAll" oncommand="goDoCommand('cmd_selectAll')" disabled="true"/>
     <command id="cmd_preferences"
              oncommand="openOptionsDialog('paneCompose', 'addressingTab');"/>
 #ifdef XP_MACOSX
     <!-- Mac Window menu -->
     <command id="minimizeWindow" label="&minimizeWindow.label;" oncommand="window.minimize();"/>
     <command id="zoomWindow" label="&zoomWindow.label;" oncommand="zoomWindow();"/>
     <command id="Tasks:Mail" oncommand="toMessengerWindow();"/>
 #endif
     <command id="cmd_CustomizeABToolbar"
              oncommand="CustomizeMailToolbar('ab-toolbox', 'CustomizeABToolbar')"/>
     <command id="cmd_chatWithCard" oncommand="goDoCommand('cmd_chatWithCard')" disabled="true" />
 </commandset>
 
-<broadcasterset id="abBroadcasters">
-  <!-- Edit Menu -->
-  <broadcaster id="button_delete" disabled="true"/>
-</broadcasterset>
-
 <keyset id="tasksKeys">
   <!-- File Menu -->
 #ifdef XP_MACOSX
   <key id="key_newMessage" key="&newMessageCmd.key;" modifiers="accel,shift" command="cmd_newMessage"/>
 #else
   <key id="key_newMessage" key="&newMessageCmd.key;" modifiers="accel" command="cmd_newMessage"/>
 #endif
   <key id="key_newCard" key="&newContact.key;" modifiers="accel"
@@ -202,17 +173,25 @@
   <key id="key_openHelp" oncommand="openSupportURL();" key="&openHelpMac2.commandkey;" modifiers="&openHelpMac2.modifiers;"/>
 #else
   <key id="key_openHelp" oncommand="openSupportURL();" keycode="&openHelp.commandkey;"/>
 #endif
 </keyset>
 
 <menupopup id="dirTreeContext" onpopupshowing="updateDirTreeContext();">
   <menuitem id="dirTreeContext-properties"
-            command="cmd_properties-contextMenu"/>
+            command="cmd_properties"
+            label="&propertiesContext.label;"
+            accesskey="&propertiesContext.accesskey;"
+            valueGeneric="&propertiesContext.label;"
+            valueGenericAccessKey="&propertiesContext.accesskey;"
+            valueAddressBook="&abPropertiesContext.label;"
+            valueAddressBookAccessKey="&abPropertiesContext.accesskey;"
+            valueMailingList="&editMailingListContext.label;"
+            valueMailingListAccessKey="&editMailingListContext.accesskey;"/>
   <menuseparator/>
   <menuitem id="dirTreeContext-newcard" label="&newContactButton.label;"
             accesskey="&newContactButton.accesskey;" command="cmd_newCard"/>
   <menuitem id="dirTreeContext-newlist"
             label="&newlistButton.label;"
             accesskey="&newlistButton.accesskey;"
             command="cmd_newlist"/>
   <menuitem id="dirTreeContext-startupDir"
@@ -220,23 +199,30 @@
             accesskey="&showAsDefault.accesskey;"
             type="checkbox"
             checked="false"
             oncommand="goDoCommand('cmd_abToggleStartupDir');"/>
   <menuseparator/>
   <menuitem id="dirTreeContext-delete"
             label="&deleteButton2.label;"
             accesskey="&deleteButton2.accesskey;"
-            observes="button_delete"
-            oncommand="goDoCommand('button_delete');"/>
+            command="button_delete"/>
 </menupopup>
 
 <menupopup id="abResultsTreeContext">
   <menuitem id="abResultsTreeContext-properties"
-            command="cmd_properties-contextMenu"/>
+            command="cmd_properties"
+            label="&propertiesContext.label;"
+            accesskey="&propertiesContext.accesskey;"
+            valueGeneric="&propertiesContext.label;"
+            valueGenericAccessKey="&propertiesContext.accesskey;"
+            valueContact="&editContactContext.label;"
+            valueContactAccessKey="&editContactContext.accesskey;"
+            valueMailingList="&editMailingListContext.label;"
+            valueMailingListAccessKey="&editMailingListContext.accesskey;"/>
   <menuseparator/>
   <menuitem id="abResultsTreeContext-newmessage"
             label="&newmsgButton.label;"
             accesskey="&newmsgButton.accesskey;"
             command="cmd_newMessage"/>
   <menuitem id="abResultsTreeContext-newim"
             label="&newIM.label;"
             accesskey="&newIM.accesskey;"
@@ -245,18 +231,17 @@
   <menuitem id="abResultsTreeContext-print"
             label="&printButton.label;"
             accesskey="&printButton.accesskey;"
             command="cmd_printcard"/>
   <menuseparator/>
   <menuitem id="abResultsTreeContext-delete"
             label="&deleteButton2.label;"
             accesskey="&deleteButton2.accesskey;"
-            observes="button_delete"
-            oncommand="goDoCommand('button_delete');"/>
+            command="button_delete"/>
 </menupopup>
 
 <menupopup id="toolbar-context-menu"
            onpopupshowing="onViewToolbarsPopupShowing(event, 'ab-toolbox');">
   <menuseparator id="customizeABToolbarMenuSeparator"/>
   <menuitem id="CustomizeABToolbar"
             command="cmd_CustomizeABToolbar"
             label="&customizeToolbar.label;"
@@ -426,17 +411,28 @@
             <menuseparator/>
             <!-- LOCALIZATION NOTE: set "hideSwapFnLnUI" to false in .dtd to enable the UI -->
             <menuitem label="&swapFirstNameLastNameCmd.label;"
                       accesskey="&swapFirstNameLastNameCmd.accesskey;"
                       hidden="&hideSwapFnLnUI;"
                       oncommand="AbSwapFirstNameLastName()"/>
             <menuitem id="menu_properties"
                       key="key_properties"
-                      command="cmd_properties-menu"/>
+                      command="cmd_properties"
+                      label="&propertiesContext.label;"
+                      accesskey="&propertiesContext.accesskey;"
+                      valueGeneric="&propertiesMenu.label;"
+                      valueGenericAccessKey="&propertiesMenu.accesskey;"
+                      valueAddressBook="&abPropertiesMenu.label;"
+                      valueAddressBookAccessKey="&abPropertiesMenu.accesskey;"
+                      valueContact="&contactPropertiesMenu.label;"
+                      valueContactAccessKey="&contactPropertiesMenu.accesskey;"
+                      valueMailingList="&mailingListPropertiesMenu.label;"
+                      valueMailingListAccessKey="&mailingListPropertiesMenu.accesskey;"/>
+
 #ifdef XP_UNIX
 #ifndef XP_MACOSX
         <menuseparator id="prefSep"/>
         <menuitem id="menu_preferences" label="&preferencesCmdUnix.label;" accesskey="&preferencesCmdUnix.accesskey;"
                   command="cmd_preferences"/>
 #endif
 #endif
           </menupopup>
@@ -621,23 +617,29 @@
 
   <toolbarpalette id="AddressBookToolbarPalette">
       <toolbarbutton class="toolbarbutton-1" id="button-newcard"
                      label="&newContactButton.label;" command="cmd_newCard"
                      tooltiptext="&newContactButton.tooltip;"/>
       <toolbarbutton class="toolbarbutton-1" id="button-newlist" label="&newlistButton.label;" tooltiptext="&newlistButton.tooltip;" command="cmd_newlist"/>
       <toolbarbutton class="toolbarbutton-1" id="button-editcard"
                      label="&editPropertiesButton.label;"
-                     command="cmd_properties-button"/>
+                     command="cmd_properties"
+                     tooltiptext="&editPropertiesButton.tooltip;"
+                     valueGenericTooltipText="&editPropertiesButton.tooltip;"
+                     valueAddressBookTooltipText="&editAbPropertiesButton.tooltip;"
+                     valueContactTooltipText="&editContactPropertiesButton.tooltip;"
+                     valueMailingListTooltipText="&editMailingListPropertiesButton.tooltip;"/>
       <toolbarbutton class="toolbarbutton-1" id="button-newmessage" label="&newmsgButton.label;" tooltiptext="&newmsgButton.tooltip;" command="cmd_newMessage"/>
       <toolbarbutton class="toolbarbutton-1" id="button-newim" label="&newIM.label;" tooltiptext="&newIM.tooltip;" command="cmd_chatWithCard"/>
       <toolbarbutton class="toolbarbutton-1" id="button-abdelete"
-                     observes="button_delete" label="&deleteButton2.label;"
+                     label="&deleteButton2.label;"
+                     disabled="true"
                      tooltiptext="&deleteButton2.tooltip;"
-                     oncommand="goDoCommand('button_delete');"/>
+                     command="button_delete"/>
       <toolbaritem id="search-container"
                    title="&searchItem.title;"
                    align="center" flex="1"
                    class="chromeclass-toolbar-additional">
         <textbox id="peopleSearchInput"
                  class="searchBox"
                  flex="1"
                  timeout="800"
--- a/mailnews/addrbook/content/abResultsPane.js
+++ b/mailnews/addrbook/content/abResultsPane.js
@@ -378,94 +378,94 @@ var ResultsPaneController =
   },
 
   isCommandEnabled: function(command)
   {
     switch (command) {
       case "cmd_selectAll":
         return true;
       case "cmd_delete":
-      case "button_delete":
-        var numSelected;
-        var enabled = false;
+      case "button_delete": {
+        let numSelected;
+        let enabled = false;
         if (gAbView && gAbView.selection) {
           if (gAbView.directory)
             enabled = !gAbView.directory.readOnly;
           numSelected = gAbView.selection.count;
-        }
-        else
+        } else {
           numSelected = 0;
+        }
+        enabled = enabled && (numSelected > 0);
 
-        // fix me, don't update on isCommandEnabled
+        let labelAttr = null;
         if (command == "cmd_delete") {
           switch (GetSelectedCardTypes()) {
             case kSingleListOnly:
-              goSetMenuValue(command, "valueList");
+              labelAttr = "valueList";
               break;
             case kMultipleListsOnly:
-              goSetMenuValue(command, "valueLists");
+              labelAttr = "valueLists";
               break;
             case kListsAndCards:
-              goSetMenuValue(command, "valueItems");
+              labelAttr = "valueItems";
               break;
             case kCardsOnly:
             default:
-              if (numSelected < 2)
-                goSetMenuValue(command, "valueCard");
-              else
-                goSetMenuValue(command, "valueCards");
-              break;
+              labelAttr = (numSelected < 2) ? "valueCard" : "valueCards";
           }
         }
-        return (enabled && (numSelected > 0));
+        document.querySelectorAll(`[command=${command}]`).forEach(e => {
+          e.disabled = !enabled;
+          if (labelAttr && e.hasAttribute(labelAttr)) {
+            e.setAttribute("label", e.getAttribute(labelAttr));
+          }
+        });
+        return enabled;
+      }
       case "cmd_printcardpreview":
       case "cmd_printcard":
         return (GetNumSelectedCards() > 0);
-      case "cmd_properties":
-        // Temporary fix for SeaMonkey (see bug  1318852).
-        // goSetLabelAccesskeyTooltiptext() is only defined in mail/.
-        // This will be removed in due course and therefore the
-        // block wasn't indented.
-        if (typeof goSetLabelAccesskeyTooltiptext == "function") {
-        let labelAttr = "valueGeneric";
-        let accKeyAttr = "valueGenericAccessKey";
-        let tooltipTextAttr = "valueGenericTooltipText";
+      case "cmd_properties": {
+        let attrs = {
+          label: "valueGeneric",
+          accesskey: "valueGenericAccessKey",
+          tooltiptext: "valueGenericTooltipText",
+        };
         switch (GetSelectedCardTypes()) {
           // Set cmd_properties UI according to the type of the selected item(s),
           // even with multiple selections for which cmd_properties is
           // not yet available and hence disabled.
           case kMultipleListsOnly:
           case kSingleListOnly:
-            labelAttr = "valueMailingList";
-            accKeyAttr = "valueMailingListAccessKey";
-            tooltipTextAttr = "valueMailingListTooltipText";
+            attrs.label = "valueMailingList";
+            attrs.accesskey = "valueMailingListAccessKey";
+            attrs.tooltiptext = "valueMailingListTooltipText";
             break;
           case kCardsOnly:
-            labelAttr = "valueContact";
-            accKeyAttr = "valueContactAccessKey";
-            tooltipTextAttr = "valueContactTooltipText";
+            attrs.label = "valueContact";
+            attrs.accesskey = "valueContactAccessKey";
+            attrs.tooltiptext = "valueContactTooltipText";
             break;
           case kListsAndCards:
           default:
-            //use generic set of attributes declared above
+            // use generic set of attributes declared above
             break;
         }
-        // This code is shared between main AB and composition's contacts sidebar.
-        // Note that in composition, there's no cmd_properties-button (yet);
-        // the resulting dump() should be ignored.
-        goSetLabelAccesskeyTooltiptext("cmd_properties-button", null, null,
-          tooltipTextAttr);
-        goSetLabelAccesskeyTooltiptext("cmd_properties-contextMenu",
-          labelAttr, accKeyAttr);
-        goSetLabelAccesskeyTooltiptext("cmd_properties-menu",
-          labelAttr, accKeyAttr);
-        }
-        // While "Edit Contact" dialogue is still modal (bug 115904, bug 135126),
-        // only enable "Properties" button for single selection; then fix bug 119999.
-        return (GetNumSelectedCards() == 1);
+
+        let enabled = (GetNumSelectedCards() == 1);
+        document.querySelectorAll("[command=cmd_properties]").forEach(e => {
+          e.disabled = !enabled;
+          for (let [attr, name] of Object.entries(attrs)) {
+            if (e.hasAttribute(attr) && e.getAttribute(name)) {
+              e.setAttribute(attr, e.getAttribute(name));
+            }
+          }
+        });
+        return enabled;
+      }
       case "cmd_newlist":
       case "cmd_newCard":
         return true;
       default:
         return false;
     }
   },