MenuManager.showPopup Member

Internal use only.

Syntax

object.showPopup(event);

Arguments

ArgumentSummary
event

Returns

Remarks

showPopup is called from the "onpopupshowing" event of menus managed by the CommandManager. If a command is disabled, represents a command that cannot be "satisfied" by the current command context cx, or has an "enabledif" attribute that eval()s to false, then the menuitem is disabled. In addition "checkedif" and "visibleif" attributes are eval()d and acted upon accordingly.

See Also

Source Code

function mmgr_showpop (event)
{
/* returns true if the command context has the properties required to
* execute the command associated with |menuitem|.
*/
function satisfied()
{
if (menuitem.hasAttribute("isSeparator") ||
!menuitem.hasAttribute("commandname"))
{
return true;
}
if (menuitem.hasAttribute("repeatfor"))
return false;
if (!("menuManager" in cx))
{
dd ("no menuManager in cx");
return false;
}
var name = menuitem.getAttribute("commandname");
var commandManager = cx.menuManager.commandManager;
var commands = commandManager.commands;
if (!ASSERT (name in commands,
"menu contains unknown command '" + name + "'"))
{
return false;
}
var rv = commandManager.isCommandSatisfied(cx, commands[name]);
delete cx.parseError;
return rv;
};
/* Convenience function for "enabledif", etc, attributes. */
function has (prop)
{
return (prop in cx);
};
/* evals the attribute named |attr| on the node |node|. */
function evalIfAttribute (node, attr)
{
var ex;
var expr = node.getAttribute(attr);
if (!expr)
return true;
expr = expr.replace (/\Wand\W/gi, " && ");
expr = expr.replace (/\Wor\W/gi, " || ");
try
{
return eval("(" + expr + ")");
}
catch (ex)
{
dd ("caught exception evaling '" + node.getAttribute("id") + "'.'" +
attr + "': '" + expr + "'\n" + ex);
}
return true;
};
/* evals the attribute named |attr| on the node |node|. */
function evalAttribute(node, attr)
{
var ex;
var expr = node.getAttribute(attr);
if (!expr)
return null;
try
{
return eval(expr);
}
catch (ex)
{
dd ("caught exception evaling '" + node.getAttribute("id") + "'.'" +
attr + "': '" + expr + "'\n" + ex);
}
return null;
};
var cx;
var popup = event.originalTarget;
var menuName = popup.getAttribute("menuName");
/* If the host provided a |contextFunction|, use it now. Remember the
* return result as this.cx for use if something from this menu is actually
* dispatched. */
if (typeof this.contextFunction == "function")
{
cx = this.cx = this.contextFunction(menuName, event);
}
else
{
cx = this.cx = { menuManager: this, originalEvent: event };
}
// Keep the context around by menu name. Removed in hidePopup.
this.cxStore[menuName] = cx;
var menuitem = popup.firstChild;
do
{
if (!menuitem.hasAttribute("repeatfor"))
continue;
// Remove auto-generated items (located prior to real item).
while (menuitem.previousSibling &&
menuitem.previousSibling.hasAttribute("repeatgenerated"))
{
menuitem.parentNode.removeChild(menuitem.previousSibling);
}
if (!("repeatList" in cx))
cx.repeatList = new Object();
/* Get the array of new items to add by evaluating "repeatfor" with
* "cx" in scope. Usually will return an already-calculated Array
* either from "cx" or somewhere in the object model.
*/
var ary = evalAttribute(menuitem, "repeatfor");
if ((typeof ary != "object") || !isinstance(ary, Array))
ary = [];
/* The item itself should only be shown if there's no items in the
* array - this base item is always disabled.
*/
if (ary.length > 0)
menuitem.setAttribute("hidden", "true");
else
menuitem.removeAttribute("hidden");
// Save the array in the context object.
cx.repeatList[menuitem.getAttribute("repeatid")] = ary;
/* Get the maximum number of items we're allowed to show from |ary| by
* evaluating "repeatlimit" with "cx" in scope. This could be a fixed
* limit or dynamically calculated (e.g. from prefs).
*/
var limit = evalAttribute(menuitem, "repeatlimit");
// Make sure we've got a number at all...
if (typeof limit != "number")
limit = ary.length;
// ...and make sure it's no higher than |ary.length|.
limit = Math.min(ary.length, limit);
var cmd = menuitem.getAttribute("commandname");
var props = { repeatgenerated: true, repeatindex: -1,
repeatid: menuitem.getAttribute("repeatid"),
repeatmap: menuitem.getAttribute("repeatmap") };
/* Clone non-repeat attributes. All attributes except those starting
* with 'repeat', and those matching 'hidden' or 'disabled' are saved
* to |props|, which is then supplied to |appendMenuItem| later.
*/
for (var i = 0; i < menuitem.attributes.length; i++)
{
var name = menuitem.attributes[i].nodeName;
if (!name.match(/^(repeat|(hidden|disabled)$)/))
props[name] = menuitem.getAttribute(name);
}
var lastGroup = "";
for (i = 0; i < limit; i++)
{
/* Check for groupings. For each item we add, if "repeatgroup" gives
* a different value, we insert a separator.
*/
if (menuitem.getAttribute("repeatgroup"))
{
cx.index = i;
ary = cx.repeatList[menuitem.getAttribute("repeatid")];
var item = ary[i];
/* Apply any updates to "cx" for this item by evaluating
* "repeatmap" with "cx" and "item" in scope. This may just
* copy some attributes from "item" to "cx" or it may do more.
*/
evalAttribute(menuitem, "repeatmap");
/* Get the item's group by evaluating "repeatgroup" with "cx"
* and "item" in scope. Usually will return an appropriate
* property from "item".
*/
var group = evalAttribute(menuitem, "repeatgroup");
if ((i > 0) && (lastGroup != group))
this.appendMenuSeparator(popup, menuitem, props);
lastGroup = group;
}
props.repeatindex = i;
this.appendMenuItem(popup, menuitem, cmd, props);
}
} while ((menuitem = menuitem.nextSibling));
menuitem = popup.firstChild;
do
{
if (menuitem.hasAttribute("repeatgenerated") &&
menuitem.hasAttribute("repeatmap"))
{
cx.index = menuitem.getAttribute("repeatindex");
ary = cx.repeatList[menuitem.getAttribute("repeatid")];
var item = ary[cx.index];
/* Apply any updates to "cx" for this item by evaluating
* "repeatmap" with "cx" and "item" in scope. This may just
* copy some attributes from "item" to "cx" or it may do more.
*/
evalAttribute(menuitem, "repeatmap");
}
/* should it be visible? */
if (menuitem.hasAttribute("visibleif"))
{
if (evalIfAttribute(menuitem, "visibleif"))
menuitem.removeAttribute ("hidden");
else
{
menuitem.setAttribute ("hidden", "true");
continue;
}
}
/* it's visible, maybe it has a dynamic label? */
if (menuitem.hasAttribute("format"))
{
var label = replaceVars(menuitem.getAttribute("format"), cx);
if (label.indexOf("\$") != -1)
label = menuitem.getAttribute("backupLabel");
menuitem.setAttribute("label", label);
}
/* ok, it's visible, maybe it should be disabled? */
if (satisfied())
{
if (menuitem.hasAttribute("enabledif"))
{
if (evalIfAttribute(menuitem, "enabledif"))
menuitem.removeAttribute ("disabled");
else
menuitem.setAttribute ("disabled", "true");
}
else
menuitem.removeAttribute ("disabled");
}
else
{
menuitem.setAttribute ("disabled", "true");
}
/* should it have a check? */
if (menuitem.hasAttribute("checkedif"))
{
if (evalIfAttribute(menuitem, "checkedif"))
menuitem.setAttribute ("checked", "true");
else
menuitem.removeAttribute ("checked");
}
} while ((menuitem = menuitem.nextSibling));
if (typeof this.onCallbackPopupShowing == "function")
this.onCallbackPopupShowing(event, cx, popup);
return true;
}