0

所以我一直在尝试获取convertFromHTML将图像转换为原子块的方法,以便它可以与 兼容,draft-js-image-plugin因为它需要类型的块atomic

给定一个简单的 HTML 结构,其中包含一些文本和开箱即用的图像,convertFromHTML会产生以下内容contentState

{
  "blocks": [
    {
      "key": "82k8",
      "text": "‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐",
      "type": "unstyled",
      "depth": 0,
      "inlineStyleRanges": [],
      "entityRanges": [],
      "data": {}
    },
    {
      "key": "9jbor",
      "text": "On December 29, 2020, 5:20 PM EST  txwbi.nrjrtn@gmail.com wrote:",
      "type": "unstyled",
      "depth": 0,
      "inlineStyleRanges": [],
      "entityRanges": [{ "offset": 34, "length": 23, "key": 0 }],
      "data": {}
    },
    {
      "key": "anq8o",
      "text": "A bunch of text here to test out the body",
      "type": "unstyled",
      "depth": 0,
      "inlineStyleRanges": [
        { "offset": 3, "length": 13, "style": "ITALIC" },
        { "offset": 3, "length": 13, "style": "UNDERLINE" },
        { "offset": 38, "length": 4, "style": "BOLD" }
      ],
      "entityRanges": [{ "offset": 0, "length": 1, "key": 1 }],
      "data": {}
    }
  ],
  "entityMap": {
    "0": {
      "type": "LINK",
      "mutability": "MUTABLE",
      "data": {
        "href": "mailto:txwbi.nrjrtn@gmail.com",
        "rel": "noreferrer nofollow noopener",
        "target": "_blank",
        "url": "mailto:txwbi.nrjrtn@gmail.com"
      }
    },
    "1": {
      "type": "IMAGE",
      "mutability": "IMMUTABLE",
      "data": {
        "alt": "cory_emoji.png",
        "height": "210",
        "src": "data:image/png;base64, ...BASE64ENCODEDIMAGE WOULD BE HERE I REMOVED BECAUSE OF CHAR LIMITS",
        "width": "173"
      }
    }
  }
}

我们可以看到img标签占据了一个unstyled我不想要的块。因此,我创建了以下函数来扩展默认块渲染映射以考虑img标签:

const {
  EditorState,
  convertToRaw,
  DefaultDraftBlockRenderMap,
  ContentState,
  convertFromHTML,
  getSafeBodyFromHTML
} = require('draft-js');

const Immutable = require('immutable');

module.exports.editorStateFromHTML = htmlBody => {
  console.log('HTML ---> EDITOR ::: RAW BODY', htmlBody);
  const blockRenderMap = Immutable.Map({
    atomic: {
      element: 'figure',
      aliasedElements: ['img']
    }
  });

  const extendedBlockRenderMap = DefaultDraftBlockRenderMap.merge(
    blockRenderMap
  );

  const blocksFromHTML = convertFromHTML(
    htmlBody,
    getSafeBodyFromHTML,
    extendedBlockRenderMap
  );

  console.log(blocksFromHTML);
  const state = ContentState.createFromBlockArray(
    blocksFromHTML.contentBlocks,
    blocksFromHTML.entityMap
  );
  console.log(JSON.stringify(convertToRaw(state)));
  const newEditor = EditorState.createWithContent(state);
  return newEditor;
};

导致此内容状态:

{
  "blocks": [
    {
      "key": "fhgqd",
      "text": "‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐",
      "type": "unstyled",
      "depth": 0,
      "inlineStyleRanges": [],
      "entityRanges": [],
      "data": {}
    },
    {
      "key": "2nsnk",
      "text": "On December 29, 2020, 5:20 PM EST  txwbi.nrjrtn@gmail.com wrote:",
      "type": "unstyled",
      "depth": 0,
      "inlineStyleRanges": [],
      "entityRanges": [{ "offset": 34, "length": 23, "key": 0 }],
      "data": {}
    },
    {
      "key": "7c7cu",
      "text": "A bunch of text here to test out the body",
      "type": "unstyled",
      "depth": 0,
      "inlineStyleRanges": [
        { "offset": 2, "length": 13, "style": "UNDERLINE" },
        { "offset": 2, "length": 13, "style": "ITALIC" },
        { "offset": 37, "length": 4, "style": "BOLD" }
      ],
      "entityRanges": [],
      "data": {}
    },
    {
      "key": "f84vb",
      "text": "",
      "type": "atomic",
      "depth": 0,
      "inlineStyleRanges": [],
      "entityRanges": [],
      "data": {}
    }
  ],
  "entityMap": {
    "0": {
      "type": "LINK",
      "mutability": "MUTABLE",
      "data": {
        "href": "mailto:txwbi.nrjrtn@gmail.com",
        "rel": "noreferrer nofollow noopener",
        "target": "_blank",
        "url": "mailto:txwbi.nrjrtn@gmail.com"
      }
    }
  }
}

如您所见,entityMap现在只有一个键,并且图像的所有数据都不再存在。如何在 entityMap 中img创建实体的同时使标签成为原子块???IMAGE

4

2 回答 2

0

AtomicBlockUtils.insertAtomicBlock用原子块和前后的无样式分隔符替换选定块。因此它足以设置EditorState.selection到相应的块,然后使用insertAtomicBlock方法:

if (value) {
    const blocksFromHTML = convertFromHTML(value);
    const contentState = ContentState.createFromBlockArray(
        blocksFromHTML.contentBlocks,
        blocksFromHTML.entityMap
    );

    let resultEditorState = EditorState.createWithContent(contentState, decorator);

    contentState.getBlocksAsArray().forEach(block => {

        //searching blocks with images. There may be other strategy, but this suited me
        const entityKey = contentState.getBlockForKey(block.key).getEntityAt(0);
        const hasImage =
            entityKey &&
            contentState
                .getEntityMap()
                .get(entityKey)
                .getType() === 'IMAGE';

        //replacing blocks with image with atomic
        if (hasImage) {
            resultEditorState = EditorState.acceptSelection(
                resultEditorState,
                SelectionState.createEmpty(block.key)
            );
            resultEditorState = AtomicBlockUtils.insertAtomicBlock(resultEditorState, entityKey, ' ');
        }
    });

    return resultEditorState;
}

return EditorState.createEmpty(decorator);
于 2022-01-11T09:34:14.160 回答
0

我的工作是遵循它有点难看,但它可以工作并给我正确的输出:

const {
  EditorState,
  convertToRaw,
  convertFromRaw,
  DefaultDraftBlockRenderMap,
  ContentState,
  convertFromHTML,
  getSafeBodyFromHTML
} = require('draft-js');

const Immutable = require('immutable');
const clone = require('rfdc')();

module.exports.editorStateFromHTML = htmlBody => {
  console.log('HTML ---> EDITOR ::: RAW BODY', htmlBody);
  const blockRenderMap = Immutable.Map({
    image: {
      element: 'img'
    }
  });

  const extendedBlockRenderMap = DefaultDraftBlockRenderMap.merge(
    blockRenderMap
  );

  const blocksFromHTML = convertFromHTML(
    htmlBody,
    getSafeBodyFromHTML,
    extendedBlockRenderMap
  );

  const state = ContentState.createFromBlockArray(
    blocksFromHTML.contentBlocks,
    blocksFromHTML.entityMap
  );
  const { blocks, entityMap } = convertToRaw(state);
  const imgCount = blocks.filter(b => b.type === 'image').length;

  if (imgCount > 0) {
    const fixedEntityMap = clone(entityMap);
    let arrKeys = Object.keys(fixedEntityMap);
    arrKeys = arrKeys.map(k => parseInt(k, 10));
    const lastKey = Math.max(...arrKeys);
    let blockCounter = lastKey;

    const fixedContentBlocks = blocks.map(blck => {
      if (blck.type === 'image') {
        blockCounter += 1;
        return {
          ...blck,
          text: ' ',
          type: 'atomic',
          entityRanges: [{ offset: 0, length: 1, key: blockCounter }]
        };
      }
      return blck;
    });

    const blocksFromHTML2 = convertFromHTML(htmlBody);
    const state2 = ContentState.createFromBlockArray(
      blocksFromHTML2.contentBlocks,
      blocksFromHTML2.entityMap
    );
    const { entityMap: imgEntities } = convertToRaw(state2);

    let entityCounter = lastKey;
    // eslint-disable-next-line no-restricted-syntax
    for (const [key, value] of Object.entries(imgEntities)) {
      if (value.type === 'IMAGE') {
        entityCounter += 1;
        fixedEntityMap[entityCounter] = value;
      }
    }

    const editorDefaultValue = {
      blocks: fixedContentBlocks,
      entityMap: fixedEntityMap
    };
    return EditorState.createWithContent(convertFromRaw(editorDefaultValue));
  }

  return EditorState.createWithContent(state);
};

如果有人有更好的解决方案,我会全力以赴。

于 2020-12-30T16:03:32.393 回答