@qooxdoo/framework
Version:
The JS Framework for Coders
405 lines (347 loc) • 10.8 kB
JavaScript
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
License:
MIT: https://opensource.org/licenses/MIT
See the LICENSE file in the project's top-level directory for details.
Authors:
* Sebastian Werner (wpbasti)
* Fabian Jakobs (fjakobs)
************************************************************************ */
/**
* The abstract menu button class is used for all type of menu content
* for example normal buttons, checkboxes or radiobuttons.
*
* @childControl icon {qx.ui.basic.Image} icon of the button
* @childControl label {qx.ui.basic.Label} label of the button
* @childControl shortcut {qx.ui.basic.Label} shows if specified the shortcut
* @childControl arrow {qx.ui.basic.Image} shows the arrow to show an additional widget (e.g. popup or submenu)
*/
qx.Class.define("qx.ui.menu.AbstractButton", {
extend: qx.ui.core.Widget,
include: [qx.ui.core.MExecutable],
implement: [qx.ui.form.IExecutable],
type: "abstract",
/*
*****************************************************************************
CONSTRUCTOR
*****************************************************************************
*/
construct() {
super();
// Use hard coded layout
this._setLayout(new qx.ui.menu.ButtonLayout());
// Add listeners
this.addListener("tap", this._onTap);
this.addListener("keypress", this._onKeyPress);
// Add command listener
this.addListener("changeCommand", this._onChangeCommand, this);
},
/*
*****************************************************************************
PROPERTIES
*****************************************************************************
*/
properties: {
// overridden
blockToolTip: {
refine: true,
init: true
},
/** The label text of the button */
label: {
check: "String",
apply: "_applyLabel",
nullable: true,
event: "changeLabel"
},
/** Whether a sub menu should be shown and which one */
menu: {
check: "qx.ui.menu.Menu",
apply: "_applyMenu",
nullable: true,
dereference: true,
event: "changeMenu"
},
/** The icon to use */
icon: {
check: "String",
apply: "_applyIcon",
themeable: true,
nullable: true,
event: "changeIcon"
},
/** Indicates whether the label for the command (shortcut) should be visible or not. */
showCommandLabel: {
check: "Boolean",
apply: "_applyShowCommandLabel",
themeable: true,
init: true,
event: "changeShowCommandLabel"
}
},
/*
*****************************************************************************
MEMBERS
*****************************************************************************
*/
members: {
/*
---------------------------------------------------------------------------
WIDGET API
---------------------------------------------------------------------------
*/
// overridden
_createChildControlImpl(id, hash) {
var control;
switch (id) {
case "icon":
control = new qx.ui.basic.Image();
control.setAnonymous(true);
this._add(control, { column: 0 });
break;
case "label":
control = new qx.ui.basic.Label();
control.setAnonymous(true);
this._add(control, { column: 1 });
break;
case "shortcut":
control = new qx.ui.basic.Label();
control.setAnonymous(true);
if (!this.getShowCommandLabel()) {
control.exclude();
}
this._add(control, { column: 2 });
break;
case "arrow":
control = new qx.ui.basic.Image();
control.setAnonymous(true);
this._add(control, { column: 3 });
break;
}
return control || super._createChildControlImpl(id);
},
// overridden
/**
* @lint ignoreReferenceField(_forwardStates)
*/
_forwardStates: {
selected: 1
},
/*
---------------------------------------------------------------------------
LAYOUT UTILS
---------------------------------------------------------------------------
*/
/**
* Returns the dimensions of all children
*
* @return {Array} Preferred width of each child
*/
getChildrenSizes() {
var iconWidth = 0,
labelWidth = 0,
shortcutWidth = 0,
arrowWidth = 0;
if (this._isChildControlVisible("icon")) {
var icon = this.getChildControl("icon");
iconWidth =
icon.getMarginLeft() +
icon.getSizeHint().width +
icon.getMarginRight();
}
if (this._isChildControlVisible("label")) {
var label = this.getChildControl("label");
labelWidth =
label.getMarginLeft() +
label.getSizeHint().width +
label.getMarginRight();
}
if (this._isChildControlVisible("shortcut")) {
var shortcut = this.getChildControl("shortcut");
shortcutWidth =
shortcut.getMarginLeft() +
shortcut.getSizeHint().width +
shortcut.getMarginRight();
}
if (this._isChildControlVisible("arrow")) {
var arrow = this.getChildControl("arrow");
arrowWidth =
arrow.getMarginLeft() +
arrow.getSizeHint().width +
arrow.getMarginRight();
}
return [iconWidth, labelWidth, shortcutWidth, arrowWidth];
},
/*
---------------------------------------------------------------------------
EVENT LISTENERS
---------------------------------------------------------------------------
*/
/**
* Event listener for tap
*
* @param e {qx.event.type.Pointer} pointer event
*/
_onTap(e) {
if (e.isLeftPressed()) {
this.execute();
qx.event.Timer.once(
qx.ui.menu.Manager.getInstance().hideAll,
qx.ui.menu.Manager.getInstance(),
0
);
}
// right click
else {
// only prevent contextmenu event if button has no further context menu.
if (!this.getContextMenu()) {
qx.ui.menu.Manager.getInstance().preventContextMenuOnce();
}
}
},
/**
* Event listener for keypress event
*
* @param e {qx.event.type.KeySequence} keypress event
*/
_onKeyPress(e) {
this.execute();
},
/**
* Event listener for command changes. Updates the text of the shortcut.
*
* @param e {qx.event.type.Data} Property change event
*/
_onChangeCommand(e) {
var command = e.getData();
// do nothing if no command is set
if (command == null) {
return;
}
if (qx.core.Environment.get("qx.dynlocale")) {
var oldCommand = e.getOldData();
if (!oldCommand) {
this.__changeLocaleCommandListenerId = qx.locale.Manager.getInstance().addListener(
"changeLocale",
this._onChangeLocale,
this
);
}
if (!command && this.__changeLocaleCommandListenerId) {
qx.locale.Manager.getInstance().removeListenerById(
this.__changeLocaleCommandListenerId
);
}
}
var cmdString = command != null ? command.toString() : "";
this.getChildControl("shortcut").setValue(cmdString);
},
/**
* Update command string on locale changes
*/
_onChangeLocale: qx.core.Environment.select("qx.dynlocale", {
true(e) {
var command = this.getCommand();
if (command != null) {
this.getChildControl("shortcut").setValue(command.toString());
}
},
false: null
}),
/*
---------------------------------------------------------------------------
PROPERTY APPLY ROUTINES
---------------------------------------------------------------------------
*/
// property apply
_applyIcon(value, old) {
if (value) {
this._showChildControl("icon").setSource(value);
} else {
this._excludeChildControl("icon");
}
},
// property apply
_applyLabel(value, old) {
if (value) {
this._showChildControl("label").setValue(value);
} else {
this._excludeChildControl("label");
}
},
// property apply
_applyMenu(value, old) {
if (old) {
old.removeListener("changeVisibility", this._onMenuChange, this);
old.resetOpener();
old.removeState("submenu");
}
if (value) {
this._showChildControl("arrow");
value.addListener("changeVisibility", this._onMenuChange, this);
value.setOpener(this);
value.addState("submenu");
} else {
this._excludeChildControl("arrow");
}
// ARIA attrs
const contentEl = this.getContentElement();
if (!contentEl) {
return;
}
if (value) {
contentEl.setAttribute("aria-haspopup", "menu");
contentEl.setAttribute("aria-expanded", value.isVisible());
contentEl.setAttribute(
"aria-controls",
value.getContentElement().getAttribute("id")
);
} else {
contentEl.removeAttribute("aria-haspopup");
contentEl.removeAttribute("aria-expanded");
contentEl.removeAttribute("aria-controls");
}
},
/**
* Listener for visibility property changes of the attached menu
*
* @param e {qx.event.type.Data} Property change event
*/
_onMenuChange(e) {
// ARIA attrs
this.getContentElement().setAttribute(
"aria-expanded",
this.getMenu().isVisible()
);
},
// property apply
_applyShowCommandLabel(value, old) {
if (value) {
this._showChildControl("shortcut");
} else {
this._excludeChildControl("shortcut");
}
}
},
/*
*****************************************************************************
DESTRUCTOR
*****************************************************************************
*/
destruct() {
this.removeListener("changeCommand", this._onChangeCommand, this);
if (this.getMenu()) {
if (!qx.core.ObjectRegistry.inShutDown) {
this.getMenu().destroy();
}
}
if (qx.core.Environment.get("qx.dynlocale") && this.__changeLocaleCommandListenerId) {
qx.locale.Manager.getInstance().removeListenerById(
this.__changeLocaleCommandListenerId
);
}
}
});