2015-07-15 12:30:11 +08:00
|
|
|
import Component from 'flarum/Component';
|
|
|
|
import icon from 'flarum/helpers/icon';
|
|
|
|
import listItems from 'flarum/helpers/listItems';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The `Dropdown` component displays a button which, when clicked, shows a
|
|
|
|
* dropdown menu beneath it.
|
|
|
|
*
|
|
|
|
* ### Props
|
|
|
|
*
|
|
|
|
* - `buttonClassName` A class name to apply to the dropdown toggle button.
|
|
|
|
* - `menuClassName` A class name to apply to the dropdown menu.
|
2015-07-31 18:46:47 +08:00
|
|
|
* - `icon` The name of an icon to show in the dropdown toggle button.
|
|
|
|
* - `caretIcon` The name of an icon to show on the right of the button.
|
2015-07-15 12:30:11 +08:00
|
|
|
* - `label` The label of the dropdown toggle button. Defaults to 'Controls'.
|
2015-07-31 18:46:47 +08:00
|
|
|
* - `onhide`
|
2015-09-22 15:35:14 +08:00
|
|
|
* - `onshow`
|
2015-07-15 12:30:11 +08:00
|
|
|
*
|
|
|
|
* The children will be displayed as a list inside of the dropdown menu.
|
|
|
|
*/
|
|
|
|
export default class Dropdown extends Component {
|
|
|
|
static initProps(props) {
|
2015-07-17 13:17:49 +08:00
|
|
|
super.initProps(props);
|
|
|
|
|
2015-07-15 12:30:11 +08:00
|
|
|
props.className = props.className || '';
|
|
|
|
props.buttonClassName = props.buttonClassName || '';
|
2015-09-04 10:45:11 +08:00
|
|
|
props.menuClassName = props.menuClassName || '';
|
2015-09-16 08:42:49 +08:00
|
|
|
props.label = props.label || '';
|
2015-08-04 10:12:24 +08:00
|
|
|
props.caretIcon = typeof props.caretIcon !== 'undefined' ? props.caretIcon : 'caret-down';
|
2015-07-15 12:30:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
view() {
|
2015-09-04 10:45:11 +08:00
|
|
|
const items = this.props.children ? listItems(this.props.children) : [];
|
2015-07-17 13:17:49 +08:00
|
|
|
|
2015-07-15 12:30:11 +08:00
|
|
|
return (
|
2015-09-16 15:00:33 +08:00
|
|
|
<div className={'ButtonGroup Dropdown dropdown ' + this.props.className + ' itemCount' + items.length}>
|
2015-07-15 12:30:11 +08:00
|
|
|
{this.getButton()}
|
2015-09-04 10:45:11 +08:00
|
|
|
{this.getMenu(items)}
|
2015-07-15 12:30:11 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-07-31 18:46:47 +08:00
|
|
|
config(isInitialized) {
|
|
|
|
if (isInitialized) return;
|
|
|
|
|
|
|
|
// When opening the dropdown menu, work out if the menu goes beyond the
|
|
|
|
// bottom of the viewport. If it does, we will apply class to make it show
|
|
|
|
// above the toggle button instead of below it.
|
|
|
|
this.$().on('shown.bs.dropdown', () => {
|
2015-12-03 12:21:55 +08:00
|
|
|
const $menu = this.$('.Dropdown-menu');
|
|
|
|
const isRight = $menu.hasClass('Dropdown-menu--right');
|
|
|
|
$menu.removeClass('Dropdown-menu--top Dropdown-menu--right');
|
2015-07-31 18:46:47 +08:00
|
|
|
|
|
|
|
$menu.toggleClass(
|
|
|
|
'Dropdown-menu--top',
|
|
|
|
$menu.offset().top + $menu.height() > $(window).scrollTop() + $(window).height()
|
|
|
|
);
|
2015-09-22 15:35:14 +08:00
|
|
|
|
2015-11-20 10:04:49 +08:00
|
|
|
$menu.toggleClass(
|
|
|
|
'Dropdown-menu--right',
|
2015-12-03 12:21:55 +08:00
|
|
|
isRight || $menu.offset().left + $menu.width() > $(window).scrollLeft() + $(window).width()
|
2015-11-20 10:04:49 +08:00
|
|
|
);
|
|
|
|
|
2015-09-22 15:35:14 +08:00
|
|
|
if (this.props.onshow) {
|
|
|
|
this.props.onshow();
|
|
|
|
m.redraw();
|
|
|
|
}
|
2015-07-31 18:46:47 +08:00
|
|
|
});
|
|
|
|
|
2015-09-22 15:35:14 +08:00
|
|
|
this.$().on('hidden.bs.dropdown', () => {
|
2015-07-31 18:46:47 +08:00
|
|
|
if (this.props.onhide) {
|
|
|
|
this.props.onhide();
|
|
|
|
m.redraw();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-07-15 12:30:11 +08:00
|
|
|
/**
|
|
|
|
* Get the template for the button.
|
|
|
|
*
|
|
|
|
* @return {*}
|
|
|
|
* @protected
|
|
|
|
*/
|
|
|
|
getButton() {
|
|
|
|
return (
|
2015-07-17 13:17:49 +08:00
|
|
|
<button
|
|
|
|
className={'Dropdown-toggle ' + this.props.buttonClassName}
|
2015-07-15 12:30:11 +08:00
|
|
|
data-toggle="dropdown"
|
|
|
|
onclick={this.props.onclick}>
|
|
|
|
{this.getButtonContent()}
|
2015-07-17 13:17:49 +08:00
|
|
|
</button>
|
2015-07-15 12:30:11 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the template for the button's content.
|
|
|
|
*
|
|
|
|
* @return {*}
|
|
|
|
* @protected
|
|
|
|
*/
|
|
|
|
getButtonContent() {
|
|
|
|
return [
|
2015-07-31 18:46:47 +08:00
|
|
|
this.props.icon ? icon(this.props.icon, {className: 'Button-icon'}) : '',
|
2015-08-05 17:51:00 +08:00
|
|
|
<span className="Button-label">{this.props.label}</span>,
|
2015-07-31 18:46:47 +08:00
|
|
|
this.props.caretIcon ? icon(this.props.caretIcon, {className: 'Button-caret'}) : ''
|
2015-07-15 12:30:11 +08:00
|
|
|
];
|
|
|
|
}
|
2015-09-04 10:45:11 +08:00
|
|
|
|
|
|
|
getMenu(items) {
|
|
|
|
return (
|
|
|
|
<ul className={'Dropdown-menu dropdown-menu ' + this.props.menuClassName}>
|
|
|
|
{items}
|
|
|
|
</ul>
|
|
|
|
);
|
|
|
|
}
|
2015-07-15 12:30:11 +08:00
|
|
|
}
|