import React from 'react'; import PropTypes from 'prop-types'; import TranslatedComponent from './TranslatedComponent'; import cn from 'classnames'; import { ListModifications, Modified } from './SvgIcons'; import AvailableModulesMenu from './AvailableModulesMenu'; import ModificationsMenu from './ModificationsMenu'; import { stopCtxPropagation, wrapCtxMenu } from '../utils/UtilityFunctions'; import { blueprintTooltip } from '../utils/BlueprintFunctions'; import { Module } from 'ed-forge'; import { TYPES } from 'ed-forge/lib/src/data/slots'; import autoBind from 'auto-bind'; import { toPairs } from 'lodash'; const HARDPOINT_SLOT_LABELS = { 1: 'S', 2: 'M', 3: 'L', 4: 'H', }; /** * Abstract Slot */ export default class Slot extends TranslatedComponent { static propTypes = { currentMenu: PropTypes.any, hideSearch: PropTypes.bool, m: PropTypes.instanceOf(Module), warning: PropTypes.func, drag: PropTypes.func, drop: PropTypes.func, dropClass: PropTypes.string, propsToShow: PropTypes.object.isRequired, onPropToggle: PropTypes.func.isRequired, }; /** * Constructor * @param {Object} props React Component properties */ constructor(props) { super(props); autoBind(this); this.state = { menuIndex: 0 }; } /** * Opens a menu while setting state. * @param {Object} newMenuIndex New menu index * @param {Event} event Event object */ _openMenu(newMenuIndex, event) { const slotName = this.props.m.getSlot(); if ( this.props.currentMenu === slotName && newMenuIndex === this.state.menuIndex ) { this.context.closeMenu(); } { this.setState({ menuIndex: newMenuIndex }); this.context.openMenu(slotName); } // If we don't stop event propagation, the underlying divs also might // get clicked which would open up other menus event.stopPropagation(); } /** * Generate the slot contents * @return {React.Component} Slot contents */ _getSlotDetails() { const { m, propsToShow } = this.props; let { termtip, tooltip, language } = this.context; const { translate, units, formats } = language; if (m.isEmpty()) { return
{translate( m.isOnSlot(TYPES.MILITARY) ? 'emptyrestricted' : 'empty' )}
; } else { let classRating = m.getClassRating(); let { drag, drop } = this.props; // Modifications tooltip shows blueprint and grade, if available let modTT = translate('modified'); const blueprint = m.getBlueprint(); const experimental = m.getExperimental(); const grade = m.getBlueprintGrade(); if (blueprint) { modTT = `${translate(blueprint)} ${translate('grade')}: ${grade}`; if (experimental) { modTT += `, ${translate(experimental)}`; } modTT = (
{modTT}
{blueprintTooltip(language, m)}
); } let mass = m.get('mass') || m.get('cargo') || m.get('fuel') || 0; return (
{classRating} {translate(m.readMeta('type'))} {blueprint && ( )}
{propsToShow.mass ?
{formats.round(mass)} {units.T}
: null}
{toPairs(propsToShow).sort().map(([prop, show]) => { const { unit, value } = m.getFormatted(prop, true); // Don't show mass again; it's already shown on the top right // corner of a slot if (!show || isNaN(value) || prop == 'mass') { return null; } else { return (
{translate(prop)}: {formats.round(value)}{unit}
); } })} {(m.getApplicableBlueprints() || []).length > 0 ? (
) : null}
); } } /** * Get the label for the slot size/class * Should be overriden if necessary * @return {string} label */ _getMaxClassLabel() { const { m } = this.props; let size = m.getSizeNum(); switch (true) { case m.getSlot() === 'armour': return ''; case size === 0: // This can also happen for armour but that case was handled above return 'U'; case m.isOnSlot(TYPES.HARDPOINT): return HARDPOINT_SLOT_LABELS[size]; default: return size; } } /** * Empty slot on right-click * @param {SyntheticEvent} event Event */ _contextMenu(event) { event.stopPropagation(); event.preventDefault(); const { m } = this.props; m.reset(); if (this.props.currentMenu === m.getSlot()) { this.context.closeMenu(); } else { this.forceUpdate(); } } /** * Render the slot * @return {React.Component} The slot */ render() { let language = this.context.language; let translate = language.translate; let { currentMenu, m, dropClass, dragOver, warning, hideSearch, propsToShow, onPropToggle, } = this.props; const { menuIndex } = this.state; // TODO: implement touch dragging const selected = currentMenu === m.getSlot(); return (
{this._getMaxClassLabel(translate)}
{this._getSlotDetails()}
{selected && menuIndex === 0 && { m.setItem(item); this.context.closeMenu(); }} warning={warning} />} {selected && menuIndex === 1 && }
); } }