scripts/django_cradmin/components/CradminSelectedListItem.jsx
import React from "react";
import DomUtilities from "../utilities/DomUtilities";
import {HotKeys} from "react-hotkeys";
export default class CradminSelectedListItem extends React.Component {
static get defaultProps() {
return {
className: 'selectable-list__item selectable-list__item--selected',
contentClassName: 'selectable-list__itemcontent',
iconWrapperClassName: 'selectable-list__icon',
iconClassName: 'icon-close--light',
titleTagName: 'strong',
titleClassName: 'selectable-list__itemtitle',
descriptionClassName: '',
ariaTitlePrefix: 'Deselect',
renderMode: 'TitleAndDescription',
focusClosestSiblingOnDeSelect: true,
previousItemData: null,
nextItemData: null,
uniqueListId: '',
useHotKeys: false
}
}
constructor(props) {
super(props);
this._name = `django_cradmin.components.CradminSelectedListItem.${this.props.signalNameSpace}.${this.props.uniqueListId}.${this.props.itemKey}`;
this.handleDeSelect = this.handleDeSelect.bind(this);
this.handleFocus = this.handleFocus.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this._onFocusOnSelectedItemSignal = this._onFocusOnSelectedItemSignal.bind(this);
this.initializeSignalHandlers();
}
initializeSignalHandlers() {
new window.ievv_jsbase_core.SignalHandlerSingleton().addReceiver(
`${this.props.signalNameSpace}.FocusOnSelectedItem.${this.props.itemKey}`,
this._name,
this._onFocusOnSelectedItemSignal
);
}
componentWillUnmount() {
new window.ievv_jsbase_core.SignalHandlerSingleton()
.removeAllSignalsFromReceiver(this._name);
}
_deselectItem() {
new window.ievv_jsbase_core.SignalHandlerSingleton().send(
`${this.props.signalNameSpace}.DeSelectItem`,
this.props.data
);
if(this.props.focusClosestSiblingOnDeSelect) {
let closestSiblingData = this.props.previousItemData;
if(closestSiblingData == null) {
closestSiblingData = this.props.nextItemData;
}
if(closestSiblingData == null) {
new window.ievv_jsbase_core.SignalHandlerSingleton().send(
`${this.props.signalNameSpace}.CouldNotFocusOnClosestSelectedItem`);
} else {
new window.ievv_jsbase_core.SignalHandlerSingleton().send(
`${this.props.signalNameSpace}.FocusOnDeSelectableItem`,
closestSiblingData
);
}
}
}
handleDeSelect(event) {
event.preventDefault();
this._deselectItem();
}
handleFocus() {
if(this.props.setDataListFocus) {
new window.ievv_jsbase_core.SignalHandlerSingleton().send(
`${this.props.signalNameSpace}.Focus`
);
}
}
handleBlur() {
if(this.props.setDataListFocus) {
new window.ievv_jsbase_core.SignalHandlerSingleton().send(
`${this.props.signalNameSpace}.Blur`
);
}
}
_onFocusOnSelectedItemSignal() {
DomUtilities.forceFocus(this._domElement);
}
get ariaTitle() {
if(this.props.data.ariaTitle) {
return this.props.data.ariaTitle;
} else {
let ariaTitle = this.props.data.title;
if(this.props.ariaTitlePrefix) {
ariaTitle = `${this.props.ariaTitlePrefix} ${ariaTitle}`;
}
return ariaTitle;
}
}
renderTitle() {
return React.createElement(this.props.titleTagName, {
className: this.props.titleClassName
}, this.props.data.title);
}
renderDescription() {
if(this.props.data.description && this.props.data.description != '') {
return <p className={this.props.descriptionClassName}>{this.props.data.description}</p>;
} else {
return '';
}
}
renderIcon() {
return <i className={this.props.iconClassName} />;
}
renderIconWrapper() {
return <div className={this.props.iconWrapperClassName}>
{this.renderIcon()}
</div>;
}
renderContentModeTitleAndDescription() {
return <div className={this.props.contentClassName}>
{this.renderTitle()}
{this.renderDescription()}
</div>;
}
renderContentModeTitleOnly() {
return <div className={this.props.contentClassName}>
{this.props.data.title}
</div>;
}
renderContentModeHtml() {
return <div className={this.props.contentClassName}
dangerouslySetInnerHTML={{__html: this.props.data.html}}></div>;
}
renderContent() {
if(this.props.renderMode == 'TitleAndDescription') {
return this.renderContentModeTitleAndDescription();
} else if(this.props.renderMode == 'TitleOnly') {
return this.renderContentModeTitleOnly();
} else if(this.props.renderMode == 'html') {
return this.renderContentModeHtml();
} else {
throw new Error(`Invalid renderMode: ${this.props.renderMode}`);
}
}
_focusPreviousItem() {
if(this.props.previousItemData == null) {
new window.ievv_jsbase_core.SignalHandlerSingleton().send(
`${this.props.signalNameSpace}.FocusBeforeFirstSelectableItem`);
} else {
new window.ievv_jsbase_core.SignalHandlerSingleton().send(
`${this.props.signalNameSpace}.FocusOnSelectableItem`,
this.props.previousItemData
);
}
}
_focusNextItem() {
if(this.props.nextItemData == null) {
new window.ievv_jsbase_core.SignalHandlerSingleton().send(
`${this.props.signalNameSpace}.FocusAfterLastSelectableItem`);
} else {
new window.ievv_jsbase_core.SignalHandlerSingleton().send(
`${this.props.signalNameSpace}.FocusOnSelectableItem`,
this.props.nextItemData
);
}
}
get hotKeysMap() {
return {
'deselect': ['delete', 'backspace']
};
}
get hotKeysHandlers() {
return {
'deselect': (event) => {
event.preventDefault();
this._deselectItem();
}
}
}
renderWrapper() {
return <a href="#" className={this.props.className}
ref={(domElement) => { this._domElement = domElement; }}
onClick={this.handleDeSelect}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
aria-label={this.ariaTitle}
role="button">
{this.renderContent()}
{this.renderIconWrapper()}
</a>
}
render() {
if(this.props.useHotKeys) {
return <HotKeys keyMap={this.hotKeysMap} handlers={this.hotKeysHandlers}>
{this.renderWrapper()}
</HotKeys>
} else {
return this.renderWrapper();
}
}
}