mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
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:
parent
3b5e1d127f
commit
8b09e98654
|
@ -36,11 +36,20 @@ export default mixins(expressionManager).extend({
|
||||||
props: {
|
props: {
|
||||||
html: {
|
html: {
|
||||||
type: String,
|
type: String,
|
||||||
|
required: true,
|
||||||
},
|
},
|
||||||
isReadOnly: {
|
isReadOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
rows: {
|
||||||
|
type: Number,
|
||||||
|
default: -1,
|
||||||
|
},
|
||||||
|
disableExpressionColoring: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -72,8 +81,8 @@ export default mixins(expressionManager).extend({
|
||||||
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
||||||
if (!viewUpdate.docChanged) return;
|
if (!viewUpdate.docChanged) return;
|
||||||
|
|
||||||
highlighter.removeColor(this.editor, this.htmlSegments);
|
this.getHighlighter()?.removeColor(this.editor, this.htmlSegments);
|
||||||
highlighter.addColor(this.editor, this.resolvableSegments);
|
this.getHighlighter()?.addColor(this.editor, this.resolvableSegments);
|
||||||
|
|
||||||
this.$emit('valueChanged', this.doc);
|
this.$emit('valueChanged', this.doc);
|
||||||
}),
|
}),
|
||||||
|
@ -144,7 +153,31 @@ export default mixins(expressionManager).extend({
|
||||||
return root;
|
return root;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isMissingHtmlTags() {
|
||||||
|
const zerothSection = this.sections.at(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
!zerothSection?.content.trim().startsWith('<html') &&
|
||||||
|
!zerothSection?.content.trim().endsWith('</html>')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
format() {
|
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 = [];
|
const formatted = [];
|
||||||
|
|
||||||
for (const { kind, content } of this.sections) {
|
for (const { kind, content } of this.sections) {
|
||||||
|
@ -185,20 +218,34 @@ export default mixins(expressionManager).extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (formatted.length === 0) return;
|
||||||
|
|
||||||
this.editor.dispatch({
|
this.editor.dispatch({
|
||||||
changes: { from: 0, to: this.doc.length, insert: formatted.join('\n\n') },
|
changes: { from: 0, to: this.doc.length, insert: formatted.join('\n\n') },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getHighlighter() {
|
||||||
|
if (this.disableExpressionColoring) return;
|
||||||
|
|
||||||
|
return highlighter;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
htmlEditorEventBus.$on('format-html', this.format);
|
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 });
|
this.editor = new EditorView({ parent: this.root(), state });
|
||||||
|
|
||||||
highlighter.addColor(this.editor, this.resolvableSegments);
|
this.getHighlighter()?.addColor(this.editor, this.resolvableSegments);
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyed() {
|
destroyed() {
|
||||||
|
|
|
@ -18,6 +18,9 @@ export const theme = [
|
||||||
'.cm-cursor, .cm-dropCursor': {
|
'.cm-cursor, .cm-dropCursor': {
|
||||||
borderLeftColor: 'var(--color-code-caret)',
|
borderLeftColor: 'var(--color-code-caret)',
|
||||||
},
|
},
|
||||||
|
'&.cm-editor.cm-focused': {
|
||||||
|
outline: '0',
|
||||||
|
},
|
||||||
'&.cm-focused .cm-selectionBackgroundm .cm-selectionBackground, .cm-content ::selection': {
|
'&.cm-focused .cm-selectionBackgroundm .cm-selectionBackground, .cm-content ::selection': {
|
||||||
backgroundColor: 'var(--color-code-selection)',
|
backgroundColor: 'var(--color-code-selection)',
|
||||||
},
|
},
|
||||||
|
@ -30,6 +33,8 @@ export const theme = [
|
||||||
'.cm-gutters': {
|
'.cm-gutters': {
|
||||||
backgroundColor: 'var(--color-code-gutterBackground)',
|
backgroundColor: 'var(--color-code-gutterBackground)',
|
||||||
color: 'var(--color-code-gutterForeground)',
|
color: 'var(--color-code-gutterForeground)',
|
||||||
|
borderTopLeftRadius: 'var(--border-radius-base)',
|
||||||
|
borderBottomLeftRadius: 'var(--border-radius-base)',
|
||||||
},
|
},
|
||||||
'.cm-scroller': {
|
'.cm-scroller': {
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
|
|
|
@ -81,9 +81,11 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<html-editor
|
<html-editor
|
||||||
v-else-if="getArgument('editor') === 'htmlEditor' && isHtmlNode(node)"
|
v-else-if="getArgument('editor') === 'htmlEditor'"
|
||||||
:html="node.parameters.html"
|
:html="node.parameters.html"
|
||||||
:isReadOnly="isReadOnly"
|
:isReadOnly="isReadOnly"
|
||||||
|
:rows="getArgument('rows')"
|
||||||
|
:disableExpressionColoring="!isHtmlNode(node)"
|
||||||
@valueChanged="valueChangedDebounced"
|
@valueChanged="valueChangedDebounced"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -353,8 +355,8 @@ import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||||
import { hasExpressionMapping, isValueExpression, isResourceLocatorValue } from '@/utils';
|
import { hasExpressionMapping, isValueExpression, isResourceLocatorValue } from '@/utils';
|
||||||
|
|
||||||
import mixins from 'vue-typed-mixins';
|
import mixins from 'vue-typed-mixins';
|
||||||
import { CUSTOM_API_CALL_KEY } from '@/constants';
|
import { CUSTOM_API_CALL_KEY, HTML_NODE_TYPE } from '@/constants';
|
||||||
import { CODE_NODE_TYPE, HTML_NODE_TYPE } from '@/constants';
|
import { CODE_NODE_TYPE } from '@/constants';
|
||||||
import { PropType } from 'vue';
|
import { PropType } from 'vue';
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
import { debounceHelper } from '@/mixins/debounce';
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
import { NodeParameterValueType } from 'n8n-workflow';
|
import { NodeParameterValueType } from 'n8n-workflow';
|
||||||
import Vue, { PropType } from 'vue';
|
import Vue, { PropType } from 'vue';
|
||||||
import { isValueExpression, isResourceLocatorValue } from '@/utils';
|
import { isValueExpression, isResourceLocatorValue } from '@/utils';
|
||||||
import { useNDVStore } from '@/stores/ndv';
|
|
||||||
import { mapStores } from 'pinia';
|
|
||||||
import { HTML_NODE_TYPE } from '@/constants';
|
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'parameter-options',
|
name: 'parameter-options',
|
||||||
|
@ -54,13 +51,15 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(useNDVStore),
|
|
||||||
isDefault(): boolean {
|
isDefault(): boolean {
|
||||||
return this.parameter.default === this.value;
|
return this.parameter.default === this.value;
|
||||||
},
|
},
|
||||||
isValueExpression(): boolean {
|
isValueExpression(): boolean {
|
||||||
return isValueExpression(this.parameter, this.value);
|
return isValueExpression(this.parameter, this.value);
|
||||||
},
|
},
|
||||||
|
isHtmlEditor(): boolean {
|
||||||
|
return this.getArgument('editor') === 'htmlEditor';
|
||||||
|
},
|
||||||
shouldShowOptions(): boolean {
|
shouldShowOptions(): boolean {
|
||||||
if (this.isReadOnly === true) {
|
if (this.isReadOnly === true) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -95,13 +94,10 @@ export default Vue.extend({
|
||||||
return !!this.getArgument('loadOptionsMethod') || !!this.getArgument('loadOptions');
|
return !!this.getArgument('loadOptionsMethod') || !!this.getArgument('loadOptions');
|
||||||
},
|
},
|
||||||
actions(): Array<{ label: string; value: string; disabled?: boolean }> {
|
actions(): Array<{ label: string; value: string; disabled?: boolean }> {
|
||||||
if (
|
if (this.isHtmlEditor && !this.isValueExpression) {
|
||||||
this.ndvStore.activeNode?.type === HTML_NODE_TYPE &&
|
|
||||||
this.ndvStore.activeNode?.parameters.operation === 'generateHtmlTemplate'
|
|
||||||
) {
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: 'Format HTML',
|
label: this.$locale.baseText('parameterInput.formatHtml'),
|
||||||
value: 'formatHtml',
|
value: 'formatHtml',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -878,6 +878,7 @@
|
||||||
"parameterInput.error": "ERROR",
|
"parameterInput.error": "ERROR",
|
||||||
"parameterInput.expression": "Expression",
|
"parameterInput.expression": "Expression",
|
||||||
"parameterInput.fixed": "Fixed",
|
"parameterInput.fixed": "Fixed",
|
||||||
|
"parameterInput.formatHtml": "Format HTML",
|
||||||
"parameterInput.issues": "Issues",
|
"parameterInput.issues": "Issues",
|
||||||
"parameterInput.loadingOptions": "Loading options...",
|
"parameterInput.loadingOptions": "Loading options...",
|
||||||
"parameterInput.openEditWindow": "Open Edit Window",
|
"parameterInput.openEditWindow": "Open Edit Window",
|
||||||
|
|
|
@ -85,6 +85,7 @@ export class Mailgun implements INodeType {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
typeOptions: {
|
typeOptions: {
|
||||||
rows: 5,
|
rows: 5,
|
||||||
|
editor: 'htmlEditor',
|
||||||
},
|
},
|
||||||
default: '',
|
default: '',
|
||||||
description: 'HTML text message of email',
|
description: 'HTML text message of email',
|
||||||
|
|
Loading…
Reference in a new issue