@pnp/spfx-property-controls
Version:
Reusable property pane controls for SharePoint Framework solutions
183 lines • 8.34 kB
JavaScript
import * as React from 'react';
import { Async } from '@fluentui/react/lib/Utilities';
import { PrimaryButton, DefaultButton, IconButton } from '@fluentui/react/lib/Button';
import { Panel, PanelType } from '@fluentui/react/lib/Panel';
import { PropertyFieldCodeEditorLanguages } from './IPropertyFieldCodeEditor';
import { Label } from '@fluentui/react/lib/Label';
import { TextField } from '@fluentui/react/lib/TextField';
import { CodeFormatter } from './CodeFormatter';
import styles from './PropertyFieldCodeEditorHost.module.scss';
import FieldErrorMessage from '../errorMessage/FieldErrorMessage';
import * as telemetry from '../../common/telemetry';
import * as strings from 'PropertyControlStrings';
import AceEditor from 'react-ace';
import 'brace/mode/json';
import 'brace/mode/javascript';
import 'brace/mode/sass';
import 'brace/mode/typescript';
import 'brace/mode/html';
import 'brace/mode/handlebars';
import 'brace/mode/xml';
import 'brace/theme/monokai';
import { setPropertyValue } from '../../helpers/GeneralHelper';
/**
* Renders the controls for PropertyFieldCodeEditor component
*/
export default class PropertyFieldCodeEditorHost extends React.Component {
/**
* Constructor method
*/
constructor(props) {
super(props);
this.cancel = true;
telemetry.track('PropertyFieldCodeEditor', {
language: props.language,
disabled: props.disabled
});
this.state = {
code: typeof this.props.initialValue !== 'undefined' ? this.props.initialValue : '',
loaded: false,
openPanel: false,
errorMessage: ''
};
this.onOpenPanel = this.onOpenPanel.bind(this);
this.onClosePanel = this.onClosePanel.bind(this);
this.onFormatCode = this.onFormatCode.bind(this);
this.onChange = this.onChange.bind(this);
this.onSave = this.onSave.bind(this);
this.async = new Async(this);
}
/**
* UNSAFE_componentWillUpdate lifecycle hook
*
* @param nextProps
* @param nextState
*/
UNSAFE_componentWillUpdate(nextProps, nextState) {
if (nextProps.initialValue !== this.props.initialValue) {
this.setState({
code: typeof nextProps.initialValue !== 'undefined' ? nextProps.initialValue : ''
});
}
}
/**
* Open the right Panel
*/
onOpenPanel() {
if (this.props.disabled) {
return;
}
// Store the current code value
this.previousValue = this.state.code;
this.cancel = true;
this.setState({
openPanel: true,
loaded: false
});
}
/**
* Close the panel
*/
onClosePanel() {
this.setState((crntState) => {
const newState = {
openPanel: false,
loaded: false
};
// Check if the property has to be reset
if (this.cancel) {
newState.code = this.previousValue;
}
return newState;
});
}
/**
* Format the code
*/
onFormatCode() {
let formattedCode;
const codeFormatter = new CodeFormatter();
switch (this.props.language) {
case PropertyFieldCodeEditorLanguages.JSON: {
formattedCode = codeFormatter.formatJSON(this.state.code.trim());
break;
}
case PropertyFieldCodeEditorLanguages.XML:
case PropertyFieldCodeEditorLanguages.HTML: {
formattedCode = codeFormatter.formatHTML(this.state.code.trim());
break;
}
case PropertyFieldCodeEditorLanguages.Sass:
case PropertyFieldCodeEditorLanguages.css: {
formattedCode = codeFormatter.formatCSS(this.state.code.trim());
break;
}
case PropertyFieldCodeEditorLanguages.JavaScript:
case PropertyFieldCodeEditorLanguages.TypeScript:
case PropertyFieldCodeEditorLanguages.Handlebars: {
formattedCode = codeFormatter.formatScript(this.state.code.trim());
break;
}
}
// const beautify = require('beautify');
// let formattedCode: any = beautify(this.state.code.trim(), { format: codeLanguage });
this.setState({ code: formattedCode });
}
/**
* Called when the component will unmount
*/
componentWillUnmount() {
if (typeof this.async !== 'undefined') {
this.async.dispose();
}
}
/**
* Called when the save button gets clicked
*/
onSave() {
this.cancel = false;
setPropertyValue(this.props.properties, this.props.targetProperty, this.state.code);
this.props.onPropertyChange(this.props.targetProperty, this.props.initialValue, this.state.code);
// Trigger the apply button
if (typeof this.props.onChange !== 'undefined' && this.props.onChange !== null) {
this.props.onChange(this.props.targetProperty, this.state.code);
}
this.setState((current) => (Object.assign(Object.assign({}, current), { openPanel: false })));
}
/**
* Called when the code gets changed
*/
onChange(newValue) {
this.setState((current) => (Object.assign(Object.assign({}, current), { code: newValue })));
}
/**
* Renders the SPListpicker controls with Office UI Fabric
*/
render() {
return (React.createElement("div", null,
this.props.label && React.createElement(Label, null, this.props.label),
React.createElement("table", { className: styles.codeFieldTable },
React.createElement("tbody", null,
React.createElement("tr", null,
React.createElement("td", null,
React.createElement(TextField, { disabled: this.props.disabled, readOnly: true, value: this.state.code, onClick: this.onOpenPanel })),
React.createElement("td", { className: styles.codeFieldRow },
React.createElement(IconButton, { disabled: this.props.disabled, iconProps: { iconName: 'Code' }, onClick: this.onOpenPanel }))))),
React.createElement(FieldErrorMessage, { errorMessage: this.state.errorMessage }),
React.createElement(Panel, { isOpen: this.state.openPanel, hasCloseButton: true, onDismiss: this.onClosePanel, isLightDismiss: true, type: this.props.panelWidth ? PanelType.custom : PanelType.medium, customWidth: this.props.panelWidth, headerText: this.props.panelTitle, isFooterAtBottom: true, styles: {
content: {
height: '100%',
width: '100%',
boxSizing: 'border-box'
}
}, layerProps: { eventBubblingEnabled: true }, onRenderFooterContent: () => (React.createElement("div", { className: styles.actions },
React.createElement("div", { className: "ms-Grid", dir: "ltr" },
React.createElement("div", { className: "ms-Grid-row" },
React.createElement(PrimaryButton, { iconProps: { iconName: 'Save' }, text: strings.SaveButtonLabel, value: strings.SaveButtonLabel, onClick: this.onSave }),
React.createElement(DefaultButton, { iconProps: { iconName: 'Cancel' }, text: strings.CancelButtonLabel, value: strings.CancelButtonLabel, onClick: this.onClosePanel }),
this.props.language !== PropertyFieldCodeEditorLanguages["Plain Text"] &&
React.createElement(DefaultButton, { color: "ms-bgColor-themeLight", iconProps: { iconName: 'ClearFormatting' }, text: strings.FormatCodeButtonLabel, value: strings.ExportButtonLabel, onClick: this.onFormatCode }))))) },
React.createElement(AceEditor, { mode: this.props.language, theme: "monokai", onChange: this.onChange, value: this.state.code, name: `code-${this.props.targetProperty}`, editorProps: { $blockScrolling: true }, setOptions: this.props.options, width: "100%", height: "100%" }))));
}
}
//# sourceMappingURL=PropertyFieldCodeEditorHost.js.map