kopia lustrzana https://github.com/wagtail/wagtail
Add ActionMenuItem sidebar component
This represents a button wrapped in a form element with customisable action and method attributespull/10060/head
rodzic
b17c72cf3d
commit
cf269272be
|
@ -0,0 +1,111 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import Tippy from '@tippyjs/react';
|
||||
import Icon from '../../Icon/Icon';
|
||||
import { MenuItemDefinition, MenuItemProps } from './MenuItem';
|
||||
import { gettext } from '../../../utils/gettext';
|
||||
import { isDismissed } from '../modules/MainMenu';
|
||||
import { WAGTAIL_CONFIG } from '../../../config/wagtailConfig';
|
||||
|
||||
export const ActionMenuItem: React.FunctionComponent<
|
||||
MenuItemProps<ActionMenuItemDefinition>
|
||||
> = ({ item, slim, path, state, dispatch }) => {
|
||||
const isActive = state.activePath.startsWith(path);
|
||||
const isInSubMenu = path.split('.').length > 2;
|
||||
|
||||
const onClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
// Do not capture click events with modifier keys or non-main buttons.
|
||||
if (e.ctrlKey || e.shiftKey || e.metaKey || (e.button && e.button !== 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isDismissed(item, state)) {
|
||||
dispatch({
|
||||
type: 'set-dismissible-state',
|
||||
item,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const className =
|
||||
'sidebar-menu-item' +
|
||||
(isActive ? ' sidebar-menu-item--active' : '') +
|
||||
(isInSubMenu ? ' sidebar-menu-item--in-sub-menu' : '');
|
||||
|
||||
return (
|
||||
<li className={className}>
|
||||
<Tippy
|
||||
disabled={!slim || isInSubMenu}
|
||||
content={item.label}
|
||||
placement="right"
|
||||
>
|
||||
<form {...item.attrs} method={item.method} action={item.action}>
|
||||
<input
|
||||
type="hidden"
|
||||
name="csrfmiddlewaretoken"
|
||||
value={WAGTAIL_CONFIG.CSRF_TOKEN}
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className={`sidebar-menu-item__link ${item.classNames}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
{item.iconName && (
|
||||
<Icon name={item.iconName} className="icon--menuitem" />
|
||||
)}
|
||||
<span className="menuitem">
|
||||
<span className="menuitem-label">{item.label}</span>
|
||||
{!isDismissed(item, state) && (
|
||||
<span className="w-dismissible-badge">
|
||||
<span className="w-sr-only">{gettext('(New)')}</span>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
</Tippy>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export class ActionMenuItemDefinition implements MenuItemDefinition {
|
||||
name: string;
|
||||
label: string;
|
||||
action: string;
|
||||
attrs: { [key: string]: any };
|
||||
iconName: string | null;
|
||||
classNames?: string;
|
||||
method: string;
|
||||
|
||||
constructor({
|
||||
name,
|
||||
label,
|
||||
action,
|
||||
attrs,
|
||||
icon_name: iconName = null,
|
||||
classnames = undefined,
|
||||
method = 'POST',
|
||||
}) {
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.action = action;
|
||||
this.attrs = attrs;
|
||||
this.iconName = iconName;
|
||||
this.classNames = classnames;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
render({ path, slim, state, dispatch, navigate }) {
|
||||
return (
|
||||
<ActionMenuItem
|
||||
key={this.name}
|
||||
item={this}
|
||||
path={path}
|
||||
slim={slim}
|
||||
state={state}
|
||||
dispatch={dispatch}
|
||||
navigate={navigate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import { initSidebar } from '../../components/Sidebar';
|
||||
import { ActionMenuItemDefinition } from '../../components/Sidebar/menu/ActionMenuItem';
|
||||
import { LinkMenuItemDefinition } from '../../components/Sidebar/menu/LinkMenuItem';
|
||||
import { SubMenuItemDefinition } from '../../components/Sidebar/menu/SubMenuItem';
|
||||
import { PageExplorerMenuItemDefinition } from '../../components/Sidebar/menu/PageExplorerMenuItem';
|
||||
|
@ -7,6 +8,10 @@ import { WagtailBrandingModuleDefinition } from '../../components/Sidebar/module
|
|||
import { SearchModuleDefinition } from '../../components/Sidebar/modules/Search';
|
||||
import { MainMenuModuleDefinition } from '../../components/Sidebar/modules/MainMenu';
|
||||
|
||||
window.telepath.register(
|
||||
'wagtail.sidebar.ActionMenuItem',
|
||||
ActionMenuItemDefinition,
|
||||
);
|
||||
window.telepath.register(
|
||||
'wagtail.sidebar.LinkMenuItem',
|
||||
LinkMenuItemDefinition,
|
||||
|
|
|
@ -85,6 +85,47 @@ class LinkMenuItem(MenuItem):
|
|||
)
|
||||
|
||||
|
||||
@adapter("wagtail.sidebar.ActionMenuItem", base=BaseSidebarAdapter)
|
||||
class ActionMenuItem(MenuItem):
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
label: str,
|
||||
action: str,
|
||||
icon_name: str = "",
|
||||
classnames: str = "",
|
||||
method: str = "POST",
|
||||
attrs: Mapping[str, Any] = None,
|
||||
):
|
||||
super().__init__(
|
||||
name,
|
||||
label,
|
||||
icon_name=icon_name,
|
||||
classnames=classnames,
|
||||
attrs=attrs,
|
||||
)
|
||||
self.action = action
|
||||
self.method = method
|
||||
|
||||
def js_args(self):
|
||||
args = super().js_args()
|
||||
args[0]["action"] = self.action
|
||||
args[0]["method"] = self.method
|
||||
return args
|
||||
|
||||
def __eq__(self, other):
|
||||
return (
|
||||
self.__class__ == other.__class__
|
||||
and self.name == other.name
|
||||
and self.label == other.label
|
||||
and self.action == other.action
|
||||
and self.method == other.method
|
||||
and self.icon_name == other.icon_name
|
||||
and self.classnames == other.classnames
|
||||
and self.attrs == other.attrs
|
||||
)
|
||||
|
||||
|
||||
@adapter("wagtail.sidebar.SubMenuItem", base=BaseSidebarAdapter)
|
||||
class SubMenuItem(MenuItem):
|
||||
def __init__(
|
||||
|
|
Ładowanie…
Reference in New Issue