[WIKI-481] refactor: editor parser #7261

This commit is contained in:
Aaryan Khandelwal 2025-06-27 16:05:38 +05:30 committed by GitHub
parent 25a6cd49fc
commit e09aeab5b8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 47 additions and 22 deletions

View file

@ -0,0 +1,19 @@
/**
* @description function to extract all additional assets from HTML content
* @param htmlContent
* @returns {string[]} array of additional asset sources
*/
export const extractAdditionalAssetsFromHTMLContent = (_htmlContent: string): string[] => [];
/**
* @description function to replace additional assets in HTML content with new IDs
* @param props
* @returns {string} HTML content with replaced additional assets
*/
export const replaceAdditionalAssetsInHTMLContent = (props: {
htmlContent: string;
assetMap: Record<string, string>;
}): string => {
const { htmlContent } = props;
return htmlContent;
};

View file

@ -1,40 +1,42 @@
// plane imports // plane imports
import { TDocumentPayload, TDuplicateAssetData, TDuplicateAssetResponse } from "@plane/types"; import { TDocumentPayload, TDuplicateAssetData, TDuplicateAssetResponse } from "@plane/types";
import { TEditorAssetType } from "@plane/types/src/enums"; import { TEditorAssetType } from "@plane/types/src/enums";
// plane web imports
import {
extractAdditionalAssetsFromHTMLContent,
replaceAdditionalAssetsInHTMLContent,
} from "@/plane-editor/helpers/parser";
// local imports // local imports
import { convertHTMLDocumentToAllFormats } from "./yjs-utils"; import { convertHTMLDocumentToAllFormats } from "./yjs-utils";
/** /**
* @description function to extract all image assets from HTML content * @description function to extract all assets from HTML content
* @param htmlContent * @param htmlContent
* @returns {string[]} array of image asset sources * @returns {string[]} array of asset sources
*/ */
export const extractImageAssetsFromHTMLContent = (htmlContent: string): string[] => { const extractAssetsFromHTMLContent = (htmlContent: string): string[] => {
// create a DOM parser // create a DOM parser
const parser = new DOMParser(); const parser = new DOMParser();
// parse the HTML string into a DOM document // parse the HTML string into a DOM document
const doc = parser.parseFromString(htmlContent, "text/html"); const doc = parser.parseFromString(htmlContent, "text/html");
// get all image components // collect all unique asset sources
const imageComponents = doc.querySelectorAll("image-component"); const assetSources = new Set<string>();
// collect all unique image sources
const imageSources = new Set<string>();
// extract sources from image components // extract sources from image components
const imageComponents = doc.querySelectorAll("image-component");
imageComponents.forEach((component) => { imageComponents.forEach((component) => {
const src = component.getAttribute("src"); const src = component.getAttribute("src");
if (src) imageSources.add(src); if (src) assetSources.add(src);
}); });
return Array.from(imageSources); const additionalAssetIds = extractAdditionalAssetsFromHTMLContent(htmlContent);
return [...Array.from(assetSources), ...additionalAssetIds];
}; };
/** /**
* @description function to replace image assets in HTML content with new IDs * @description function to replace assets in HTML content with new IDs
* @param props * @param props
* @returns {string} HTML content with replaced image assets * @returns {string} HTML content with replaced assets
*/ */
export const replaceImageAssetsInHTMLContent = (props: { const replaceAssetsInHTMLContent = (props: { htmlContent: string; assetMap: Record<string, string> }): string => {
htmlContent: string;
assetMap: Record<string, string>;
}): string => {
const { htmlContent, assetMap } = props; const { htmlContent, assetMap } = props;
// create a DOM parser // create a DOM parser
const parser = new DOMParser(); const parser = new DOMParser();
@ -48,11 +50,15 @@ export const replaceImageAssetsInHTMLContent = (props: {
component.setAttribute("src", assetMap[oldSrc]); component.setAttribute("src", assetMap[oldSrc]);
} }
}); });
// serialize the document back into a string // replace additional sources
return doc.body.innerHTML; const replacedHTMLContent = replaceAdditionalAssetsInHTMLContent({
htmlContent: doc.body.innerHTML,
assetMap,
});
return replacedHTMLContent;
}; };
export const getEditorContentWithReplacedImageAssets = async (props: { export const getEditorContentWithReplacedAssets = async (props: {
descriptionHTML: string; descriptionHTML: string;
entityId: string; entityId: string;
entityType: TEditorAssetType; entityType: TEditorAssetType;
@ -63,18 +69,18 @@ export const getEditorContentWithReplacedImageAssets = async (props: {
const { descriptionHTML, entityId, entityType, projectId, variant, duplicateAssetService } = props; const { descriptionHTML, entityId, entityType, projectId, variant, duplicateAssetService } = props;
let replacedDescription = descriptionHTML; let replacedDescription = descriptionHTML;
// step 1: extract image assets from the description // step 1: extract image assets from the description
const imageAssets = extractImageAssetsFromHTMLContent(descriptionHTML); const assetIds = extractAssetsFromHTMLContent(descriptionHTML);
if (imageAssets.length !== 0) { if (assetIds.length !== 0) {
// step 2: duplicate the image assets // step 2: duplicate the image assets
const duplicateAssetsResponse = await duplicateAssetService({ const duplicateAssetsResponse = await duplicateAssetService({
entity_id: entityId, entity_id: entityId,
entity_type: entityType, entity_type: entityType,
project_id: projectId, project_id: projectId,
asset_ids: imageAssets, asset_ids: assetIds,
}); });
if (Object.keys(duplicateAssetsResponse ?? {}).length > 0) { if (Object.keys(duplicateAssetsResponse ?? {}).length > 0) {
// step 3: replace the image assets in the description // step 3: replace the image assets in the description
replacedDescription = replaceImageAssetsInHTMLContent({ replacedDescription = replaceAssetsInHTMLContent({
htmlContent: descriptionHTML, htmlContent: descriptionHTML,
assetMap: duplicateAssetsResponse, assetMap: duplicateAssetsResponse,
}); });