Skip to content

Commit

Permalink
fix(Designer): Revert - Updated HTML Editor to support newline charac…
Browse files Browse the repository at this point in the history
…ters (#4807)

* Revert "fix(Designer): Updated HTML Editor to support newline characters (for dynamic content) (#4635)"

This reverts commit f4e1f8b.

* adding test

* adding another test
  • Loading branch information
Eric-B-Wu committed May 8, 2024
1 parent e5bc077 commit 4d2a984
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 43 deletions.
35 changes: 35 additions & 0 deletions libs/designer-ui/src/lib/editor/base/utils/__test__/helper.spec.ts
@@ -0,0 +1,35 @@
import { describe, expect, it } from 'vitest';
import { ValueSegmentType } from '../../../models/parameter';
import { createLiteralValueSegment, createEmptyLiteralValueSegment, removeFirstAndLast } from '../helper';

describe('Helper functions', () => {
it('creates a literal value segment', () => {
const segment = createLiteralValueSegment('test', '1');
expect(segment).toEqual({
id: '1',
type: ValueSegmentType.LITERAL,
value: 'test',
});
});

it('creates an empty literal value segment', () => {
const segment = createEmptyLiteralValueSegment();
expect(segment).toEqual({
id: expect.any(String), // The id is generated by guid(), so we can't know its exact value
type: ValueSegmentType.LITERAL,
value: '',
});
});

it('removes first and last characters from segments', () => {
const segments = [
{ id: '1', type: ValueSegmentType.LITERAL, value: 'test' },
{ id: '2', type: ValueSegmentType.LITERAL, value: 'example' },
];
const result = removeFirstAndLast(segments, 't', 'e');
expect(result).toEqual([
{ id: '1', type: ValueSegmentType.LITERAL, value: 'est' },
{ id: '2', type: ValueSegmentType.LITERAL, value: 'exampl' },
]);
});
});
30 changes: 2 additions & 28 deletions libs/designer-ui/src/lib/editor/base/utils/editorToSegment.ts
Expand Up @@ -37,8 +37,7 @@ const getChildrenNodesToSegments = (node: ElementNode, segments: ValueSegment[],
export const convertStringToSegments = (
value: string,
nodeMap: Map<string, ValueSegment>,
options?: SegmentParserOptions,
convertSpaceToNewline?: boolean
options?: SegmentParserOptions
): ValueSegment[] => {
if (!value) {
return [];
Expand Down Expand Up @@ -90,28 +89,7 @@ export const convertStringToSegments = (
segmentSoFar += currChar;

if (!isInQuotedString && currChar === '}' && currSegmentType === ValueSegmentType.TOKEN) {
let token: ValueSegment | undefined = undefined;

// removes formatting compatibility issues between nodemap and HTML text in the editor
// when opening an action with an HTML editor
if (convertSpaceToNewline) {
// modifiedSegmentSoFar -> in segmentSoFar, replace spaces with no space
const modifiedSegmentSoFar = removeNewlinesAndSpaces(segmentSoFar);
// for each key in nodeMap
for (const key of nodeMap.keys()) {
// keyNoNewline = key, but replace all newlines with no space
const keyNoNewline = removeNewlinesAndSpaces(key);
// if the nodemap key and modified HTML segment match,
// take the corresponding HTML node in the nodemap
if (keyNoNewline === modifiedSegmentSoFar) {
token = nodeMap.get(key);
break;
}
}
} else {
token = nodeMap.get(segmentSoFar);
}

const token = nodeMap.get(segmentSoFar);
if (token) {
// If remove quotes param is set, remove the quotes from previous and next segments if it's a single token
if (options?.removeSingleTokenQuotesWrapping && doubleQuotesStarted && returnSegments.length > 0) {
Expand Down Expand Up @@ -164,7 +142,3 @@ const collapseLiteralSegments = (segments: ValueSegment[]): void => {
index++;
}
};

const removeNewlinesAndSpaces = (inputStr: string): string => {
return inputStr.replace(/\s+/g, '').replaceAll(/\n/g, '');
};
Expand Up @@ -143,7 +143,7 @@ const appendChildrenNode = (
const childNodeFormat = childNode.getFormat();

if (tokensEnabled && nodeMap) {
const contentAsParameter = convertStringToSegments(decodedTextContent, nodeMap, options, true);
const contentAsParameter = convertStringToSegments(decodedTextContent, nodeMap, options);
contentAsParameter.forEach((segment) => {
const tokenNode = createTokenNodeFromSegment(segment, options, nodeMap);
if (tokenNode) {
Expand Down
Expand Up @@ -7,7 +7,6 @@ import {
encodeStringSegmentTokensInLexicalContext,
} from '../../../../editor/base/utils/parsesegments';
import {
canReplaceSpanWithId,
cleanHtmlString,
cleanStyleAttribute,
encodeSegmentValueInLexicalContext,
Expand All @@ -20,7 +19,7 @@ import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
import type { EditorState, LexicalEditor } from 'lexical';
import { $getRoot } from 'lexical';

interface HTMLChangePluginProps {
export interface HTMLChangePluginProps {
isValuePlaintext: boolean;
setIsSwitchFromPlaintextBlocked: (value: boolean) => void;
setIsValuePlaintext: (isValuePlaintext: boolean) => void;
Expand Down Expand Up @@ -75,7 +74,6 @@ export const convertEditorState = (
// Create a temporary DOM element to parse the HTML string
const tempElement = getDomFromHtmlEditorString(htmlEditorString, nodeMap);

let idValue = '';
// Loop through all elements and remove unwanted attributes
const elements = tempElement.querySelectorAll('*');
// biome-ignore lint/style/useForOf: Node List isn't iterable
Expand All @@ -89,7 +87,7 @@ export const convertEditorState = (
}
if (attribute.name === 'id' && !isValuePlaintext) {
// If we're in the rich HTML editor, encoding occurs at the element level since they are all wrapped in <span>.
idValue = element.getAttribute('id') ?? ''; // e.g., "@{concat('&lt;', '"')}"
const idValue = element.getAttribute('id') ?? ''; // e.g., "@{concat('&lt;', '"')}"
const encodedIdValue = encodeSegmentValueInLexicalContext(idValue); // e.g., "@{concat('%26lt;', '%22')}"
element.setAttribute('id', encodedIdValue);
continue;
Expand All @@ -108,11 +106,12 @@ export const convertEditorState = (

// Replace `<span id="..."></span>` with the captured `id` value if it is found in the viable IDs map.
const spanIdPattern = /<span id="(.*?)"><\/span>/g;
let noTokenSpansString = decodedLexicalString;
const decodedLexicalStringWithoutNewlines = decodedLexicalString.replace(/\n/g, '');
if (canReplaceSpanWithId(idValue, nodeMap)) {
noTokenSpansString = decodedLexicalStringWithoutNewlines.replace(spanIdPattern, idValue);
}
const noTokenSpansString = decodedLexicalString.replace(spanIdPattern, (match, idValue) => {
if (nodeMap.get(idValue)) {
return idValue;
}
return match;
});
const valueSegments: ValueSegment[] = convertStringToSegments(noTokenSpansString, nodeMap, { tokensEnabled: true });
resolve(valueSegments);
});
Expand Down
@@ -0,0 +1,17 @@
import { HTMLChangePlugin } from '../HTMLChangePlugin';
import { test } from 'vitest';

test('HTMLChangePlugin can be used', () => {
const mockProps = {
isValuePlaintext: false,
setIsSwitchFromPlaintextBlocked: () => {},
setIsValuePlaintext: () => {},
setValue: () => {},
};

try {
HTMLChangePlugin(mockProps);
} catch (e) {
throw new Error(`HTMLChangePlugin could not be used: ${e}`);
}
});
5 changes: 0 additions & 5 deletions libs/designer-ui/src/lib/html/plugins/toolbar/helper/util.ts
Expand Up @@ -65,11 +65,6 @@ export const cleanHtmlString = (html: string): string => {
return cleanedHtmlString;
};

// If we can find the id in the nodemap, return true.
export const canReplaceSpanWithId = (idValue: string, nodeMap: Map<string, ValueSegment>): boolean => {
return nodeMap.get(idValue) !== undefined;
};

export const cleanStyleAttribute = (styleAttributeValue: string): string | undefined => {
const newValue = styleAttributeValue.replace('white-space: pre-wrap;', '').trim();
return newValue.length ? newValue : undefined;
Expand Down

0 comments on commit 4d2a984

Please sign in to comment.