Bug 1531296 - [de-xbl] convert task progress and priority menupopup bindings to custom elements. r=philipp
authorPaul Morris <paul@paulwmorris.com>
Tue, 16 Apr 2019 10:18:55 +0200
changeset 26359 29de53dcff07
parent 26358 205c80a11ab9
child 26360 b8523a5ed09c
push id15800
push usermozilla@jorgk.com
push dateTue, 16 Apr 2019 08:27:34 +0000
treeherdercomm-central@e8744607741f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersphilipp
bugs1531296
Bug 1531296 - [de-xbl] convert task progress and priority menupopup bindings to custom elements. r=philipp
calendar/base/content/calendar-bindings.css
calendar/base/content/calendar-common-sets.xul
calendar/base/content/calendar-menus.js
calendar/base/content/calendar-menus.xml
calendar/base/content/calendar-task-tree.js
calendar/base/content/calendar-task-view.xul
calendar/base/jar.mn
calendar/lightning/content/lightning-item-panel.js
calendar/lightning/content/lightning-menus.xul
calendar/test/mozmill/views/testTaskView.js
--- a/calendar/base/content/calendar-bindings.css
+++ b/calendar/base/content/calendar-bindings.css
@@ -20,19 +20,13 @@ calendar-multiweek-view {
 calendar-month-view {
   -moz-binding: url(chrome://calendar/content/calendar-views.xml#calendar-month-view);
 }
 
 calendar-task-tree {
   -moz-binding: url(chrome://calendar/content/calendar-task-tree.xml#calendar-task-tree);
 }
 
-menupopup[type="task-progress"] > arrowscrollbox {
-  -moz-binding: url(chrome://calendar/content/calendar-menus.xml#task-progress-menupopup);
+/* Needed until menupopup is fully converted to a custom element (see bug 1531296). */
+menupopup[is="calendar-task-progress-menupopup"],
+menupopup[is="calendar-task-priority-menupopup"] {
+  -moz-binding: none;
 }
-
-menupopup[type="task-priority"] > arrowscrollbox {
-  -moz-binding: url(chrome://calendar/content/calendar-menus.xml#task-priority-menupopup);
-}
-
-task-menupopup {
-  -moz-binding: url(chrome://calendar/content/calendar-menus.xml#task-menupopup);
-}
--- a/calendar/base/content/calendar-common-sets.xul
+++ b/calendar/base/content/calendar-common-sets.xul
@@ -482,24 +482,24 @@
                 accesskey="&calendar.context.markcompleted.accesskey;"
                 observes="calendar_toggle_completed_command"
                 command="calendar_toggle_completed_command"/>
       <menu id="task-context-menu-progress"
             label="&calendar.context.progress.label;"
             accesskey="&calendar.context.progress.accesskey;"
             command="calendar_general-progress_command"
             observes="calendar_general-progress_command">
-        <menupopup id="progress-menupopup" type="task-progress"/>
+        <menupopup is="calendar-task-progress-menupopup"/>
       </menu>
       <menu id="task-context-menu-priority"
             label="&calendar.context.priority.label;"
             accesskey="&calendar.context.priority.accesskey;"
             command="calendar_general-priority_command"
             observes="calendar_general-priority_command">
-        <menupopup id="priority-menupopup" type="task-priority"/>
+        <menupopup is="calendar-task-priority-menupopup"/>
       </menu>
       <menu id="task-context-menu-postpone"
             label="&calendar.context.postpone.label;"
             accesskey="&calendar.context.postpone.accesskey;"
             command="calendar_general-postpone_command"
             observes="calendar_general-postpone_command">
         <menupopup id="task-context-postpone-menupopup">
           <menuitem id="task-context-postpone-1hour"
rename from calendar/base/content/calendar-menus.xml
rename to calendar/base/content/calendar-menus.js
--- a/calendar/base/content/calendar-menus.xml
+++ b/calendar/base/content/calendar-menus.js
@@ -1,168 +1,169 @@
-<?xml version="1.0"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!-- import-globals-from calendar-task-tree.js -->
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-<!DOCTYPE bindings SYSTEM "chrome://calendar/locale/calendar.dtd">
+/* globals gConfig getSelectedTasks gTabmail MozElements MozXULElement
+   setAttributeOnChildrenOrTheirCommands */
 
-<bindings id="calendar-menu-bindings"
-          xmlns="http://www.mozilla.org/xbl"
-          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-          xmlns:xbl="http://www.mozilla.org/xbl">
+"use strict";
 
-  <binding id="task-menupopup">
-    <implementation>
-      <field name="mType">null</field>;
-      <field name="mPopupHandler">null</field>
-      <field name="mParentMenuPopup">null</field>
-
-      <constructor><![CDATA[
-          const { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-
-          this.mPopupHandler = () => { this.changeMenuByPropertyName(); };
-          this.mParentMenuPopup = cal.view.getParentNodeOrThis(this, "menupopup");
-          this.mParentMenuPopup.addEventListener("popupshowing", this.mPopupHandler, true);
-      ]]></constructor>
-
-      <destructor><![CDATA[
-          this.mParentMenuPopup.removeEventListener("popupshowing", this.mPopupHandler, true);
-      ]]></destructor>
+// Wrap in a block and use const to define functions to prevent leaking to window scope.
+{
+    /**
+     * Get a property value for a group of tasks. If all the tasks have the same property value
+     * then return that value, otherwise return null.
+     *
+     * @param {string} propertyKey  The property key.
+     * @param {Object[]} tasks      The tasks.
+     * @returns {string|null}       The property value or null.
+     */
+    const getPropertyValue = (propertyKey, tasks) => {
+        let propertyValue = null;
+        const tasksSelected = (tasks != null) && (tasks.length > 0);
+        if (tasksSelected && tasks.every(task => task[propertyKey] == tasks[0][propertyKey])) {
+            propertyValue = tasks[0][propertyKey];
+        }
+        return propertyValue;
+    };
 
-      <!-- This method checks a command which naming follows
-           the notation 'calendar_' +  mType + ' + '-' + propertyValue + 'command',
-           when its propertyValue part matches the propertyValue of the selected tasks
-           as long as the selected tasks share common propertyValues. -->
-      <method name="changeMenuByPropertyName">
-        <body><![CDATA[
-            let liveList = document.getAnonymousNodes(this);
-            for (let item of liveList) {
-                let commandName = item.getAttribute("command");
-                let command = document.getElementById(commandName);
-                if (command) {
-                    command.setAttribute("checked", "false");
-                    item.setAttribute("checked", "false");
-                }
+    /**
+     * Updates the 'checked' state of menu items so they reflect the state of the relevant task(s),
+     * for example, tasks currently selected in the task list, or a task being edited in the
+     * current tab. It operates on commands that are named using the following pattern:
+     *
+     *   'calendar_' +  propertyKey + ' + '-' + propertyValue + '_command'
+     *
+     * When the propertyValue part of a command's name matches the propertyValue of the tasks,
+     * set the command to 'checked=true', as long as the tasks all have the same propertyValue.
+     *
+     * @param parent {Element}      Parent element that contains the menu items as direct children.
+     * @param propertyKey {string}  The property key, for example "priority" or "percentComplete".
+    */
+    const updateMenuItemsState = (parent, propertyKey) => {
+        setAttributeOnChildrenOrTheirCommands("checked", false, parent);
+
+        const inSingleTaskTab = gTabmail &&
+            gTabmail.currentTabInfo &&
+            gTabmail.currentTabInfo.mode.type == "calendarTask";
+
+        const propertyValue = inSingleTaskTab
+            ? gConfig[propertyKey]
+            : getPropertyValue(propertyKey, getSelectedTasks());
+
+        if (propertyValue || propertyValue === 0) {
+            const commandName = "calendar_" + propertyKey + "-" + propertyValue + "_command";
+            const command = document.getElementById(commandName);
+            if (command) {
+                command.setAttribute("checked", "true");
             }
-            let propertyValue;
-            // eslint-disable-next-line no-undef
-            if (gTabmail && gTabmail.currentTabInfo.mode.type == "calendarTask") {
-                // We are in a task tab (editing a single task).
-                propertyValue = gConfig[this.mType]; // eslint-disable-line no-undef
-            } else {
-                // We are in the Tasks tab.
-                let tasks = getSelectedTasks();
-                let tasksSelected = (tasks != null) && (tasks.length > 0);
-                if (tasksSelected) {
-                    if (tasks.every(task => task[this.mType] == tasks[0][this.mType])) {
-                        propertyValue = tasks[0][this.mType];
-                    }
-                } else {
-                    let sibling = this.firstChild;
+        }
+    };
 
-                    while (sibling) {
-                        let domObject = sibling;
-
-                        if (domObject.hasAttribute("command")) {
-                            let commandName = domObject.getAttribute("command");
-                            let command = document.getElementById(commandName);
-                            if (command) {
-                                domObject = command;
-                            }
-                        }
-
-                        domObject.setAttribute("disabled", false);
-                        sibling = sibling.nextSibling;
-                    }
-                }
+    /**
+     * A menu for changing the "progress" (percent complete) status for a task or tasks. It
+     * indicates the current status by displaying a checkmark next to the menu item for that status.
+     * @extends MozElements.MozMenuPopup
+     */
+    class CalendarTaskProgressMenupopup extends MozElements.MozMenuPopup {
+        connectedCallback() {
+            if (this.delayConnectedCallback() || this.hasConnected) {
+                return;
             }
-            if (propertyValue || propertyValue == 0) {
-                let command = document.getElementById("calendar_" + this.mType + "-" + propertyValue + "_command");
-                if (command) {
-                    command.setAttribute("checked", "true");
-                }
-            }
-        ]]></body>
-      </method>
-    </implementation>
-  </binding>
+            // this.hasConnected is set to true in super.connectedCallback
+            super.connectedCallback();
+
+            const scrollbox = this.querySelector(".popup-internal-box");
+            scrollbox.appendChild(MozXULElement.parseXULToFragment(`
+                <menuitem class="percent-0-menuitem"
+                          type="checkbox"
+                          label="&progress.level.0;"
+                          accesskey="&progress.level.0.accesskey;"
+                          observes="calendar_percentComplete-0_command"
+                          command="calendar_percentComplete-0_command"/>
+                <menuitem class="percent-25-menuitem"
+                          type="checkbox"
+                          label="&progress.level.25;"
+                          accesskey="&progress.level.25.accesskey;"
+                          observes="calendar_percentComplete-25_command"
+                          command="calendar_percentComplete-25_command"/>
+                <menuitem class="percent-50-menuitem"
+                          type="checkbox"
+                          label="&progress.level.50;"
+                          accesskey="&progress.level.50.accesskey;"
+                          observes="calendar_percentComplete-50_command"
+                          command="calendar_percentComplete-50_command"/>
+                <menuitem class="percent-75-menuitem"
+                          type="checkbox"
+                          label="&progress.level.75;"
+                          accesskey="&progress.level.75.accesskey;"
+                          observes="calendar_percentComplete-75_command"
+                          command="calendar_percentComplete-75_command"/>
+                <menuitem class="percent-100-menuitem"
+                          type="checkbox"
+                          label="&progress.level.100;"
+                          accesskey="&progress.level.100.accesskey;"
+                          observes="calendar_percentComplete-100_command"
+                          command="calendar_percentComplete-100_command"/>
+                `,
+                ["chrome://calendar/locale/calendar.dtd"]
+            ));
+
+            this.addEventListener("popupshowing",
+                updateMenuItemsState.bind(null, scrollbox, "percentComplete"), true);
+        }
+    }
+
+    customElements.define("calendar-task-progress-menupopup",
+        CalendarTaskProgressMenupopup, { "extends": "menupopup" });
 
-  <binding id="task-progress-menupopup" extends="chrome://calendar/content/calendar-menus.xml#task-menupopup">
-    <content>
-      <xul:menuitem anonid="percent-0-menuitem"
-                type="checkbox"
-                label="&progress.level.0;"
-                accesskey="&progress.level.0.accesskey;"
-                observes="calendar_percentComplete-0_command"
-                command="calendar_percentComplete-0_command"/>
-      <xul:menuitem anonid="percent-25-menuitem"
-                type="checkbox"
-                label="&progress.level.25;"
-                accesskey="&progress.level.25.accesskey;"
-                observes="calendar_percentComplete-25_command"
-                command="calendar_percentComplete-25_command"/>
-      <xul:menuitem anonid="percent-50-menuitem"
-                type="checkbox"
-                label="&progress.level.50;"
-                accesskey="&progress.level.50.accesskey;"
-                observes="calendar_percentComplete-50_command"
-                command="calendar_percentComplete-50_command"/>
-      <xul:menuitem anonid="percent-75-menuitem"
-                type="checkbox"
-                label="&progress.level.75;"
-                accesskey="&progress.level.75.accesskey;"
-                observes="calendar_percentComplete-75_command"
-                command="calendar_percentComplete-75_command"/>
-      <xul:menuitem anonid="percent-100-menuitem"
-                type="checkbox"
-                label="&progress.level.100;"
-                accesskey="&progress.level.100.accesskey;"
-                observes="calendar_percentComplete-100_command"
-                command="calendar_percentComplete-100_command"/>
-      <children/>
-    </content>
-    <implementation>
-      <constructor><![CDATA[
-          this.mType = "percentComplete";
-          this.changeMenuByPropertyName();
-      ]]></constructor>
-    </implementation>
-  </binding>
+    /**
+     * A menu for changing the "priority" status for a task or tasks. It indicates the current
+     * status by displaying a checkmark next to the menu item for that status.
+     * @extends MozElements.MozMenuPopup
+     */
+    class CalendarTaskPriorityMenupopup extends MozElements.MozMenuPopup {
+        connectedCallback() {
+            if (this.delayConnectedCallback() || this.hasConnected) {
+                return;
+            }
+            // this.hasConnected is set to true in super.connectedCallback
+            super.connectedCallback();
 
-  <binding id="task-priority-menupopup" extends="chrome://calendar/content/calendar-menus.xml#task-menupopup">
-    <content>
-      <xul:menuitem id="priority-0-menuitem"
-                    type="checkbox"
-                    label="&priority.level.none;"
-                    accesskey="&priority.level.none.accesskey;"
-                    command="calendar_priority-0_command"
-                    observes="calendar_priority-0_command"/>
-      <xul:menuitem id="priority-9-menuitem"
-                    type="checkbox"
-                    label="&priority.level.low;"
-                    accesskey="&priority.level.low.accesskey;"
-                    command="calendar_priority-9_command"
-                    observes="calendar_priority-9_command"/>
-      <xul:menuitem id="priority-5-menuitem"
-                    type="checkbox"
-                    label="&priority.level.normal;"
-                    accesskey="&priority.level.normal.accesskey;"
-                    command="calendar_priority-5_command"
-                    observes="calendar_priority-5_command"/>
-      <xul:menuitem id="priority-1-menuitem"
-                type="checkbox"
-                label="&priority.level.high;"
-                accesskey="&priority.level.high.accesskey;"
-                command="calendar_priority-1_command"
-                observes="calendar_priority-1_command"/>
-      <children/>
-    </content>
-    <implementation>
-      <constructor><![CDATA[
-          this.mType = "priority";
-          this.changeMenuByPropertyName();
-      ]]></constructor>
-    </implementation>
-  </binding>
-</bindings>
+            const scrollbox = this.querySelector(".popup-internal-box");
+            scrollbox.appendChild(MozXULElement.parseXULToFragment(`
+                <menuitem class="priority-0-menuitem"
+                          type="checkbox"
+                          label="&priority.level.none;"
+                          accesskey="&priority.level.none.accesskey;"
+                          command="calendar_priority-0_command"
+                          observes="calendar_priority-0_command"/>
+                <menuitem class="priority-9-menuitem"
+                          type="checkbox"
+                          label="&priority.level.low;"
+                          accesskey="&priority.level.low.accesskey;"
+                          command="calendar_priority-9_command"
+                          observes="calendar_priority-9_command"/>
+                <menuitem class="priority-5-menuitem"
+                          type="checkbox"
+                          label="&priority.level.normal;"
+                          accesskey="&priority.level.normal.accesskey;"
+                          command="calendar_priority-5_command"
+                          observes="calendar_priority-5_command"/>
+                <menuitem class="priority-1-menuitem"
+                          type="checkbox"
+                          label="&priority.level.high;"
+                          accesskey="&priority.level.high.accesskey;"
+                          command="calendar_priority-1_command"
+                          observes="calendar_priority-1_command"/>
+                `,
+                ["chrome://calendar/locale/calendar.dtd"]
+            ));
+
+            this.addEventListener("popupshowing",
+                updateMenuItemsState.bind(null, scrollbox, "priority"), true);
+        }
+    }
+
+    customElements.define("calendar-task-priority-menupopup",
+        CalendarTaskPriorityMenupopup, { "extends": "menupopup" });
+}
--- a/calendar/base/content/calendar-task-tree.js
+++ b/calendar/base/content/calendar-task-tree.js
@@ -6,16 +6,18 @@
  *          contextChangeTaskCalendar, contextChangeTaskPriority,
  *          contextPostponeTask, modifyTaskFromContext, deleteToDoCommand,
  *          tasksToMail, tasksToEvents, toggleCompleted,
  */
 
 /* import-globals-from calendar-common-sets.js */
 /* import-globals-from calendar-dnd-listener.js */
 
+/* globals gTabmail editToDoStatus editConfigState postponeTask */
+
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
 
 /**
  * Add registered calendars to the given menupopup. Removes all previous
  * children.
  *
  * XXX Either replace the existing items using replaceNode, or use helper
  * functions (cal.removeChildren).
@@ -33,39 +35,30 @@ function addCalendarNames(aEvent) {
         let selIndex = appendCalendarItems(tasks[0], calendarMenuPopup, null, "contextChangeTaskCalendar(event);");
         if (tasks.every(task => task.calendar == tasks[0].calendar) && selIndex > -1) {
             calendarMenuPopup.childNodes[selIndex].setAttribute("checked", "true");
         }
     }
 }
 
 /**
- * Applies a value to all children of a menu. If the respective child nodes define
- * a command the value is applied to the disabled attribute of the command of the
- * child node.
+ * For each child of an element (for example all menuitems in a menu), if it defines a command
+ * set an attribute on the command, otherwise set it on the child node itself.
  *
- * @param aElement The parent node of the elements
- * @param aValue The value of the attribute
+ * @param aAttribute {string}       The attribute to set.
+ * @param aValue {boolean|string}   The value to set.
+ * @param aElement {Element}        The parent node.
  */
-function applyDisabledAttributeToMenuChildren(aElement, aValue) {
-    let sibling = aElement.firstChild;
+function setAttributeOnChildrenOrTheirCommands(aAttribute, aValue, aElement) {
+    for (let child of aElement.children) {
+        const commandName = child.getAttribute("command");
+        const command = commandName && document.getElementById(commandName);
 
-    while (sibling) {
-        let domObject = sibling;
-
-        if (domObject.hasAttribute("command")) {
-            let commandName = domObject.getAttribute("command");
-            let command = document.getElementById(commandName);
-            if (command) {
-                domObject = command;
-            }
-        }
-
-        domObject.setAttribute("disabled", aValue);
-        sibling = sibling.nextSibling;
+        const domObject = command || child;
+        domObject.setAttribute(aAttribute, aValue);
     }
 }
 
 /**
  * Change the opening context menu for the selected tasks.
  *
  * @param aEvent    The popupshowing event of the opening menu.
  */
@@ -83,37 +76,37 @@ function changeContextMenuForTask(aEvent
     document.getElementById("task-context-menu-modify-todaypane").hidden =
         (idnode == "calendar-task-tree");
     document.getElementById("task-context-menu-filter-todaypane").hidden =
         (idnode == "calendar-task-tree");
     document.getElementById("task-context-menu-separator-filter").hidden =
         (idnode == "calendar-task-tree");
 
     let tasksSelected = (items.length > 0);
-    applyDisabledAttributeToMenuChildren(aEvent.target, !tasksSelected);
+
+    setAttributeOnChildrenOrTheirCommands("disabled", !tasksSelected, aEvent.target);
 
     if (calendarController.isCommandEnabled("calendar_new_todo_command") &&
         calendarController.isCommandEnabled("calendar_new_todo_todaypane_command")) {
         document.getElementById("calendar_new_todo_command").removeAttribute("disabled");
         document.getElementById("calendar_new_todo_todaypane_command").removeAttribute("disabled");
     } else {
         document.getElementById("calendar_new_todo_command").setAttribute("disabled", "true");
         document.getElementById("calendar_new_todo_todaypane_command").setAttribute("disabled", "true");
     }
 
     // make sure the "Paste" and "Cut" menu items are enabled
     goUpdateCommand("cmd_paste");
     goUpdateCommand("cmd_cut");
 
     // make sure the filter menu is enabled
     document.getElementById("task-context-menu-filter-todaypane").removeAttribute("disabled");
-    applyDisabledAttributeToMenuChildren(
-        document.getElementById("task-context-menu-filter-todaypane-popup"),
-        false
-    );
+
+    setAttributeOnChildrenOrTheirCommands("disabled", false,
+        document.getElementById("task-context-menu-filter-todaypane-popup"));
 
     changeMenuForTask(aEvent);
 
     let menu = document.getElementById("task-context-menu-attendance-menu");
     setupAttendanceMenu(menu, items);
 }
 
 /**
--- a/calendar/base/content/calendar-task-view.xul
+++ b/calendar/base/content/calendar-task-view.xul
@@ -17,16 +17,17 @@
   xmlns:html="http://www.w3.org/1999/xhtml">
   <script type="application/javascript" src="chrome://calendar/content/calendar-task-tree.js"/>
   <script type="application/javascript" src="chrome://calendar/content/calendar-task-view.js"/>
   <script type="application/javascript" src="chrome://calendar/content/calendar-dialog-utils.js"/>
   <script type="application/javascript" src="chrome://calendar/content/calApplicationUtils.js"/>
   <script type="application/javascript" src="chrome://calendar/content/calendar-item-bindings.js"/>
   <script type="application/javascript" src="chrome://calendar/content/calFilter.js"/>
   <script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
+  <script type="application/javascript" src="chrome://calendar/content/calendar-menus.js"/>
 
   <vbox id="calendarDisplayDeck">
     <vbox id="calendar-task-box" flex="1"
           onselect="taskDetailsView.onSelect(event);">
       <hbox id="task-addition-box" align="center">
         <box align="center" flex="1">
           <toolbarbutton id="calendar-add-task-button"
                          label="&calendar.newtask.button.label;"
@@ -135,26 +136,26 @@
                           </toolbarbutton>
                           <toolbarbutton id="task-actions-markcompleted"
                                          type="menu-button"
                                          label="&calendar.context.markcompleted.label;"
                                          tooltiptext="&calendar.task.complete.button.tooltip;"
                                          command="calendar_toggle_completed_command"
                                          observes="calendar_toggle_completed_command"
                                          class="toolbarbutton-1 msgHeaderView-button">
-                            <menupopup id="task-actions-markcompleted-menupopup" type="task-progress"/>
+                            <menupopup is="calendar-task-progress-menupopup" id="task-actions-markcompleted-menupopup"/>
                           </toolbarbutton>
                           <toolbarbutton id="task-actions-priority"
                                          type="menu"
                                          label="&calendar.context.priority.label;"
                                          tooltiptext="&calendar.task.priority.button.tooltip;"
                                          command="calendar_general-priority_command"
                                          observes="calendar_general-priority_command"
                                          class="toolbarbutton-1 msgHeaderView-button">
-                            <menupopup id="task-actions-priority-menupopup" type="task-priority"/>
+                            <menupopup is="calendar-task-priority-menupopup" id="task-actions-priority-menupopup"/>
                           </toolbarbutton>
                           <toolbarbutton id="calendar-delete-task-button"
                                          class="toolbarbutton-1 msgHeaderView-button"
                                          label="&calendar.taskview.delete.label;"
                                          tooltiptext="&calendar.context.deletetask.label;"
                                          observes="calendar_delete_todo_command"/>
                         </toolbarpalette>
 
--- a/calendar/base/jar.mn
+++ b/calendar/base/jar.mn
@@ -18,17 +18,17 @@ calendar.jar:
     content/calendar/calendar-event-gripbar.js             (content/calendar-event-gripbar.js)
     content/calendar/calendar-views.xml                    (content/calendar-views.xml)
     content/calendar/calendar-dnd-listener.js              (content/calendar-dnd-listener.js)
     content/calendar/calendar-extract.js                   (content/calendar-extract.js)
     content/calendar/calendar-invitations-manager.js       (content/calendar-invitations-manager.js)
     content/calendar/calendar-item-editing.js              (content/calendar-item-editing.js)
     content/calendar/calendar-item-bindings.js             (content/calendar-item-bindings.js)
     content/calendar/calendar-management.js                (content/calendar-management.js)
-    content/calendar/calendar-menus.xml                    (content/calendar-menus.xml)
+    content/calendar/calendar-menus.js                     (content/calendar-menus.js)
     content/calendar/calendar-views.xul                    (content/calendar-views.xul)
     content/calendar/calendar-month-view.xml               (content/calendar-month-view.xml)
     content/calendar/calendar-multiday-view.xml            (content/calendar-multiday-view.xml)
     content/calendar/calendar-base-view.xml                (content/calendar-base-view.xml)
     content/calendar/calendar-base-view.js                 (content/calendar-base-view.js)
     content/calendar/calendar-statusbar.js                 (content/calendar-statusbar.js)
     content/calendar/calendar-task-editing.js              (content/calendar-task-editing.js)
     content/calendar/calendar-task-tree.xml                (content/calendar-task-tree.xml)
--- a/calendar/lightning/content/lightning-item-panel.js
+++ b/calendar/lightning/content/lightning-item-panel.js
@@ -802,18 +802,17 @@ function updateShowTimeAs(aArg) {
  * @param {short} aPercentComplete  The new percent complete value
  */
 function editToDoStatus(aPercentComplete) {
     sendMessage({ command: "editToDoStatus", value: aPercentComplete });
 }
 
 /**
  * Check or uncheck the "Mark updated" menu item in "Events and Tasks"
- * menu based on the percent complete value. (The percent complete menu
- * items are updated by changeMenuByPropertyName in calendar-menus.xml)
+ * menu based on the percent complete value.
  *
  * @param {Object} aArg                 Container
  * @param {short} aArg.percentComplete  The percent complete value
  */
 function updateMarkCompletedMenuItem(aArg) {
     // Command only for tab case, function only to be executed in dialog windows.
     if (gTabmail) {
         let completedCommand = document.getElementById("calendar_toggle_completed_command");
--- a/calendar/lightning/content/lightning-menus.xul
+++ b/calendar/lightning/content/lightning-menus.xul
@@ -401,24 +401,24 @@
                   accesskey="&calendar.context.markcompleted.accesskey;"
                   command="calendar_toggle_completed_command"
                   observes="calendar_toggle_completed_command"/>
         <menu id="ltnTaskActionsPriorityMenuitem"
               label="&calendar.context.priority.label;"
               accesskey="&calendar.context.priority.accesskey;"
               command="calendar_general-priority_command"
               observes="calendar_general-priority_command">
-          <menupopup type="task-priority"/>
+          <menupopup is="calendar-task-priority-menupopup"/>
         </menu>
         <menu id="ltnTaskActionsProgressMenuitem"
               label="&calendar.context.progress.label;"
               accesskey="&calendar.context.progress.accesskey;"
               command="calendar_general-progress_command"
               observes="calendar_general-progress_command">
-          <menupopup type="task-progress"/>
+          <menupopup is="calendar-task-progress-menupopup"/>
         </menu>
         <menu id="ltnTaskActionsPostponeMenuitem"
               label="&calendar.context.postpone.label;"
               accesskey="&calendar.context.postpone.accesskey;"
               observes="calendar_general-postpone_command">
           <menupopup id="ltnTaskActionsPostponeMenuPopup">
             <menuitem id="ltnTaskActionsPostponeMenu-1hour"
                       label="&calendar.context.postpone.1hour.label;"
@@ -763,23 +763,23 @@
                   type="checkbox"
                   label="&calendar.context.markcompleted.label;"
                   command="calendar_toggle_completed_command"
                   observes="calendar_toggle_completed_command"/>
         <menu id="appmenu_ltnTaskActionsPriorityMenuitem"
               label="&calendar.context.priority.label;"
               command="calendar_general-priority_command"
               observes="calendar_general-priority_command">
-          <menupopup type="task-priority"/>
+          <menupopup is="calendar-task-priority-menupopup"/>
         </menu>
         <menu id="appmenu_ltnTaskActionsProgressMenuitem"
               label="&calendar.context.progress.label;"
               command="calendar_general-progress_command"
               observes="calendar_general-progress_command">
-          <menupopup type="task-progress"/>
+          <menupopup is="calendar-task-progress-menupopup"/>
         </menu>
         <menu id="appmenu_ltnTaskActionsPostponeMenuitem"
               label="&calendar.context.postpone.label;"
               observes="calendar_general-postpone_command">
           <menupopup id="appmenu_ltnTaskActionsPostponeMenuPopup">
             <menuitem id="ltnTaskActionsPostponeMenu-1hour"
                       label="&calendar.context.postpone.1hour.label;"
                       observes="calendar_postpone-1hour_command"/>
--- a/calendar/test/mozmill/views/testTaskView.js
+++ b/calendar/test/mozmill/views/testTaskView.js
@@ -119,17 +119,17 @@ function testTaskView() {
     sleep();
     controller.click(lookup(
         `${TASK_VIEW}/{"flex":"1"}/id("calendar-task-details-container")/
         id("calendar-task-details")/id("calendar-task-details-grid")/
         id("calendar-task-details-rows")/
         id("calendar-task-details-priority-row")/{"flex":"1"}/
         id("other-actions-box")/id("task-actions-toolbox")/id("task-actions-toolbar")/
         id("task-actions-priority")/id("task-actions-priority-menupopup")/
-        anon({"class":"popup-internal-box"})/anon({"id":"priority-1-menuitem"})`));
+        {"class":"popup-internal-box"}/{"class":"priority-1-menuitem"}`));
     sleep();
     let priorityNode = eid("calendar-task-details-priority-high");
     controller.assertNotDOMProperty(priorityNode, "hidden");
 
     // Verify that tooltip shows status, priority and percent complete.
     let toolTipNode = lookup(toolTip).getNode();
     toolTipNode.ownerGlobal.showToolTip(toolTipNode, taskTreeNode.getTaskAtRow(0));