import React from 'react'; import PropTypes from 'prop-types'; import { translate } from 'react-i18next'; import FormGroup from 'react-bootstrap/es/FormGroup'; import FormControl from 'react-bootstrap/es/FormControl'; import ControlLabel from 'react-bootstrap/es/ControlLabel'; import Dropdown from 'react-bootstrap/es/Dropdown'; import MenuItem from 'react-bootstrap/es/MenuItem'; export class EditorOptions { constructor(props) { this.theme = 'elegant'; this.keymapMode = 'default'; this.styleActiveLine = false; Object.assign(this, props); } } export class PreviewOptions { constructor(props) { this.renderMathJaxInRealtime = false; Object.assign(this, props); } } class OptionsSelector extends React.Component { constructor(props) { super(props); const config = this.props.crowi.getConfig(); const isMathJaxEnabled = !!config.env.MATHJAX; this.state = { editorOptions: this.props.editorOptions || new EditorOptions(), previewOptions: this.props.previewOptions || new PreviewOptions(), isCddMenuOpened: false, isMathJaxEnabled, }; this.availableThemes = [ 'eclipse', 'elegant', 'neo', 'mdn-like', 'material', 'dracula', 'monokai', 'twilight', ]; this.keymapModes = { default: 'Default', vim: 'Vim', emacs: 'Emacs', sublime: 'Sublime Text', }; this.onChangeTheme = this.onChangeTheme.bind(this); this.onChangeKeymapMode = this.onChangeKeymapMode.bind(this); this.onClickStyleActiveLine = this.onClickStyleActiveLine.bind(this); this.onClickRenderMathJaxInRealtime = this.onClickRenderMathJaxInRealtime.bind(this); this.onToggleConfigurationDropdown = this.onToggleConfigurationDropdown.bind(this); } componentDidMount() { this.init(); } init() { this.themeSelectorInputEl.value = this.state.editorOptions.theme; this.keymapModeSelectorInputEl.value = this.state.editorOptions.keymapMode; } onChangeTheme() { const newValue = this.themeSelectorInputEl.value; const newOpts = Object.assign(this.state.editorOptions, { theme: newValue }); this.setState({ editorOptions: newOpts }); // dispatch event this.dispatchOnChange(); } onChangeKeymapMode() { const newValue = this.keymapModeSelectorInputEl.value; const newOpts = Object.assign(this.state.editorOptions, { keymapMode: newValue }); this.setState({ editorOptions: newOpts }); // dispatch event this.dispatchOnChange(); } onClickStyleActiveLine(event) { // keep dropdown opened this._cddForceOpen = true; const newValue = !this.state.editorOptions.styleActiveLine; const newOpts = Object.assign(this.state.editorOptions, { styleActiveLine: newValue }); this.setState({ editorOptions: newOpts }); // dispatch event this.dispatchOnChange(); } onClickRenderMathJaxInRealtime(event) { // keep dropdown opened this._cddForceOpen = true; const newValue = !this.state.previewOptions.renderMathJaxInRealtime; const newOpts = Object.assign(this.state.previewOptions, { renderMathJaxInRealtime: newValue }); this.setState({ previewOptions: newOpts }); // dispatch event this.dispatchOnChange(); } /* * see: https://github.com/react-bootstrap/react-bootstrap/issues/1490#issuecomment-207445759 */ onToggleConfigurationDropdown(newValue) { if (this._cddForceOpen) { this.setState({ isCddMenuOpened: true }); this._cddForceOpen = false; } else { this.setState({ isCddMenuOpened: newValue }); } } /** * dispatch onChange event */ dispatchOnChange() { this.props.onChange(this.state.editorOptions, this.state.previewOptions); } renderThemeSelector() { const optionElems = this.availableThemes.map((theme) => { return ; }); const bsClassName = 'form-control-dummy'; // set form-control* to shrink width return ( Theme: { return this.themeSelectorInputEl = el }} > {optionElems} ); } renderKeymapModeSelector() { const optionElems = []; // eslint-disable-next-line guard-for-in, no-restricted-syntax for (const mode in this.keymapModes) { const label = this.keymapModes[mode]; const dataContent = (mode === 'default') ? label : ` ${label}`; optionElems.push( , ); } const bsClassName = 'form-control-dummy'; // set form-control* to shrink width return ( Keymap: { return this.keymapModeSelectorInputEl = el }} > {optionElems} ); } renderConfigurationDropdown() { return ( {this.renderActiveLineMenuItem()} {this.renderRealtimeMathJaxMenuItem()} {/* */} ); } renderActiveLineMenuItem() { const { t } = this.props; const isActive = this.state.editorOptions.styleActiveLine; const iconClasses = ['text-info']; if (isActive) { iconClasses.push('ti-check'); } const iconClassName = iconClasses.join(' '); return ( { t('page_edit.Show active line') } ); } renderRealtimeMathJaxMenuItem() { if (!this.state.isMathJaxEnabled) { return; } const isEnabled = this.state.isMathJaxEnabled; const isActive = isEnabled && this.state.previewOptions.renderMathJaxInRealtime; const iconClasses = ['text-info']; if (isActive) { iconClasses.push('ti-check'); } const iconClassName = iconClasses.join(' '); return ( fx MathJax Rendering ); } render() { return (
{this.renderThemeSelector()} {this.renderKeymapModeSelector()} {this.renderConfigurationDropdown()}
); } } OptionsSelector.propTypes = { t: PropTypes.func.isRequired, // i18next crowi: PropTypes.object.isRequired, editorOptions: PropTypes.instanceOf(EditorOptions).isRequired, previewOptions: PropTypes.instanceOf(PreviewOptions).isRequired, onChange: PropTypes.func.isRequired, }; export default translate()(OptionsSelector);