feat(editor): Adjust HTML editor component for use in params (#5285)

*  Adjust HTML editor component

* ♻️ Apply feedback

* ♻️ Apply feedback

* 🔥 Remove unused ndv store refs
This commit is contained in:
Iván Ovejero 2023-02-02 14:00:16 +01:00 committed by GitHub
parent 3b5e1d127f
commit 8b09e98654
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 16 deletions

View file

@ -36,11 +36,20 @@ export default mixins(expressionManager).extend({
props: {
html: {
type: String,
required: true,
},
isReadOnly: {
type: Boolean,
default: false,
},
rows: {
type: Number,
default: -1,
},
disableExpressionColoring: {
type: Boolean,
default: false,
},
},
data() {
return {
@ -72,8 +81,8 @@ export default mixins(expressionManager).extend({
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
if (!viewUpdate.docChanged) return;
highlighter.removeColor(this.editor, this.htmlSegments);
highlighter.addColor(this.editor, this.resolvableSegments);
this.getHighlighter()?.removeColor(this.editor, this.htmlSegments);
this.getHighlighter()?.addColor(this.editor, this.resolvableSegments);
this.$emit('valueChanged', this.doc);
}),
@ -144,7 +153,31 @@ export default mixins(expressionManager).extend({
return root;
},
isMissingHtmlTags() {
const zerothSection = this.sections.at(0);
return (
!zerothSection?.content.trim().startsWith('<html') &&
!zerothSection?.content.trim().endsWith('</html>')
);
},
format() {
if (this.sections.length === 1 && this.isMissingHtmlTags()) {
const zerothSection = this.sections.at(0) as Section;
const formatted = prettier
.format(zerothSection.content, {
parser: 'html',
plugins: [htmlParser],
})
.trim();
return this.editor.dispatch({
changes: { from: 0, to: this.doc.length, insert: formatted },
});
}
const formatted = [];
for (const { kind, content } of this.sections) {
@ -185,20 +218,34 @@ export default mixins(expressionManager).extend({
}
}
if (formatted.length === 0) return;
this.editor.dispatch({
changes: { from: 0, to: this.doc.length, insert: formatted.join('\n\n') },
});
},
getHighlighter() {
if (this.disableExpressionColoring) return;
return highlighter;
},
},
mounted() {
htmlEditorEventBus.$on('format-html', this.format);
const state = EditorState.create({ doc: this.html, extensions: this.extensions });
let doc = this.html;
if (this.html === '' && this.rows > 0) {
doc = '\n'.repeat(this.rows - 1);
}
const state = EditorState.create({ doc, extensions: this.extensions });
this.editor = new EditorView({ parent: this.root(), state });
highlighter.addColor(this.editor, this.resolvableSegments);
this.getHighlighter()?.addColor(this.editor, this.resolvableSegments);
},
destroyed() {

View file

@ -18,6 +18,9 @@ export const theme = [
'.cm-cursor, .cm-dropCursor': {
borderLeftColor: 'var(--color-code-caret)',
},
'&.cm-editor.cm-focused': {
outline: '0',
},
'&.cm-focused .cm-selectionBackgroundm .cm-selectionBackground, .cm-content ::selection': {
backgroundColor: 'var(--color-code-selection)',
},
@ -30,6 +33,8 @@ export const theme = [
'.cm-gutters': {
backgroundColor: 'var(--color-code-gutterBackground)',
color: 'var(--color-code-gutterForeground)',
borderTopLeftRadius: 'var(--border-radius-base)',
borderBottomLeftRadius: 'var(--border-radius-base)',
},
'.cm-scroller': {
overflow: 'auto',

View file

@ -81,9 +81,11 @@
/>
<html-editor
v-else-if="getArgument('editor') === 'htmlEditor' && isHtmlNode(node)"
v-else-if="getArgument('editor') === 'htmlEditor'"
:html="node.parameters.html"
:isReadOnly="isReadOnly"
:rows="getArgument('rows')"
:disableExpressionColoring="!isHtmlNode(node)"
@valueChanged="valueChangedDebounced"
/>
@ -353,8 +355,8 @@ import { workflowHelpers } from '@/mixins/workflowHelpers';
import { hasExpressionMapping, isValueExpression, isResourceLocatorValue } from '@/utils';
import mixins from 'vue-typed-mixins';
import { CUSTOM_API_CALL_KEY } from '@/constants';
import { CODE_NODE_TYPE, HTML_NODE_TYPE } from '@/constants';
import { CUSTOM_API_CALL_KEY, HTML_NODE_TYPE } from '@/constants';
import { CODE_NODE_TYPE } from '@/constants';
import { PropType } from 'vue';
import { debounceHelper } from '@/mixins/debounce';
import { mapStores } from 'pinia';

View file

@ -28,9 +28,6 @@
import { NodeParameterValueType } from 'n8n-workflow';
import Vue, { PropType } from 'vue';
import { isValueExpression, isResourceLocatorValue } from '@/utils';
import { useNDVStore } from '@/stores/ndv';
import { mapStores } from 'pinia';
import { HTML_NODE_TYPE } from '@/constants';
export default Vue.extend({
name: 'parameter-options',
@ -54,13 +51,15 @@ export default Vue.extend({
},
},
computed: {
...mapStores(useNDVStore),
isDefault(): boolean {
return this.parameter.default === this.value;
},
isValueExpression(): boolean {
return isValueExpression(this.parameter, this.value);
},
isHtmlEditor(): boolean {
return this.getArgument('editor') === 'htmlEditor';
},
shouldShowOptions(): boolean {
if (this.isReadOnly === true) {
return false;
@ -95,13 +94,10 @@ export default Vue.extend({
return !!this.getArgument('loadOptionsMethod') || !!this.getArgument('loadOptions');
},
actions(): Array<{ label: string; value: string; disabled?: boolean }> {
if (
this.ndvStore.activeNode?.type === HTML_NODE_TYPE &&
this.ndvStore.activeNode?.parameters.operation === 'generateHtmlTemplate'
) {
if (this.isHtmlEditor && !this.isValueExpression) {
return [
{
label: 'Format HTML',
label: this.$locale.baseText('parameterInput.formatHtml'),
value: 'formatHtml',
},
];

View file

@ -878,6 +878,7 @@
"parameterInput.error": "ERROR",
"parameterInput.expression": "Expression",
"parameterInput.fixed": "Fixed",
"parameterInput.formatHtml": "Format HTML",
"parameterInput.issues": "Issues",
"parameterInput.loadingOptions": "Loading options...",
"parameterInput.openEditWindow": "Open Edit Window",

View file

@ -85,6 +85,7 @@ export class Mailgun implements INodeType {
type: 'string',
typeOptions: {
rows: 5,
editor: 'htmlEditor',
},
default: '',
description: 'HTML text message of email',