Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

convertFromHTML tag <img /> problem #3

Open
Zhurbin opened this issue Jul 22, 2016 · 9 comments
Open

convertFromHTML tag <img /> problem #3

Zhurbin opened this issue Jul 22, 2016 · 9 comments

Comments

@Zhurbin
Copy link

Zhurbin commented Jul 22, 2016

Hi! In convertFromHTML for links i can do this:

    htmlToEntity: (nodeName, node) => {
        if (nodeName === 'a') {
            return Entity.create(
                'LINK',
                'MUTABLE',
                {url: node.href}
            )
        }
    }

For images ( tag) I trying:

    htmlToEntity: (nodeName, node) => {
        if (nodeName === 'img') {
            return Entity.create(
                'IMAGE',
                'MUTABLE',
                {src: node.src}
            )
        }
    }

But it doesn't work. In draft-js editor img not showed.

@benbriggs
Copy link
Contributor

benbriggs commented Aug 1, 2016

Images get a bit more complicated because they're not strict decorations of text. An additional atomic block type is used to have a custom block renderer, then the entity can be used to store metadata within that block. In our internal image plugin our conversion options look something like this:

const ENTITY_TYPE = 'IMAGE';
const BLOCK_TYPE = 'atomic';

export default createPlugin({
  htmlToBlock: (nodeName, node) => {
    if (nodeName === 'figure') {
      return BLOCK_TYPE;
    }
  },
  htmlToEntity: (nodeName, node) => {
    if (nodeName === 'img') {
      return Entity.create(ENTITY_TYPE, ...)
    }
  },
  blockRendererFn: (block) => {
    if (block.getType() === 'atomic' && block.length > 0 && Entity.get(block.getEntityAt(0)).getType() === ENTITY_TYPE) {
      return {
        component: ({block}) => {
          const {src} = Entity.get(block.getEntityAt(0)).getData();
          return <img src={src} />;
        },
        editable: false
      };
    }
  },
  blockToHTML: {
    'atomic': {
      start: '<figure>',
      end: '</figure>'
    }
  },
  entityToHTML: (entity, originalText) => {
    if (entity.type === ENTITY_TYPE) {
      return `<img src="${entity.data.src}" />`;
    }
  }
 });

This way your HTML output looking like this:

<figure>
  <img src="..." />
</figure>

If you need to deal with any incoming <img> tags that don't have wrapping <figures> you can add the block type by changing htmlToBlock to add the atomic block type around any tags without it:

htmlToBlock: (nodeName, node, lastList, inBlock) => {
  if (nodeName === 'figure' && node.firstChild.nodeName === 'IMG' || (nodeName === 'img' && inBlock !== BLOCK_TYPE) {
  return BLOCK_TYPE;
  }
}

Let me know if this works @Zhurbin!

@tianjianchn
Copy link

I'm using draft-js-image-plugin and with these codes:

htmlToEntity: (nodeName, node) => {
  if(nodeName==='img'){
    return Entity.create('block-image', 'IMMUTABLE', {url: node.src})
  }
},
htmlToBlock: (nodeName, node, lastList, inBlock)=>{
  if(nodeName==='img'){
    return 'block-image';
  }
},

No image displayed. The result content state has no entity info in the entityMap and blocks.

After checking the code, I find that the chunk constructed has some problems so that it can't find the entity info when creating the content state. See codes below(convertFromHTML.js#L503):

      textBlock = sanitizeDraftText(textBlock);
      var end = start + textBlock.length;
      var inlines = nullthrows(chunk).inlines.slice(start, end);
      var entities = nullthrows(chunk).entities.slice(start, end);
      var characterList = List(
        inlines.map((style, ii) => {
          var data = {style, entity: null};
          if (entities[ii]) {
            data.entity = entities[ii];
          }
          return CharacterMetadata.create(data);
        })
      );

The textBlock is always empty, so start is always equal to end, then empty array will be returned by slice(start, end)

@benbriggs
Copy link
Contributor

@kiliwalk thanks for investigating - i had run into this issue as well and addressed it here for atomic blocks since that seemed to be the block type provided by Draft for these sorts of things. the image plugin clearly uses a different block type, though, so the character doesn't get added.

I can add a config option that allows you to specify other "atomic" block types that this hack should apply to, though I should note that the real answer here is both draft-convert and draft-js-image-plugin updating to support block metadata so that no text or entity is necessary.

@vm
Copy link

vm commented Oct 13, 2017

Hey @benbriggs! I am hitting this issue as well with using the current versions of draft-js, draft-convert and draft-js-image-plugin. Is there a current way to solve this issue?

If the solution is to avoid using that image plugin and use a HubSpot version of it instead (or build my own), let me know. The HTML converter is super useful for us so I'd love the use it if possible.

@benbriggs
Copy link
Contributor

@vm what issues are you running into specifically? depending on what you're looking for (e.g. images as inline entities, or just getting images parsed as block-level elements) the issue might be a problem with any of those three packages in play.

I think it would be worth considering for draft-js-image-plugin to use block metadata since it gets you some nice things like proper render tree updates when metadata changes, so it might be worth either the team integrating that (at the cost of compatibility with early versions) or to just fork their version and change the backing implementation. Unfortunately our internal implementation is pretty deeply tied into our internal UI components so we haven't open sourced it 😞

@racmathafidz
Copy link

racmathafidz commented Nov 30, 2021

i know its too late but i'm just trying to help those who have this issue in the future.
just have this issue today for showing <img> tag and im using 'entityToHTML' and its fix the problem for me.

const currentContentAsHTML = convertToHTML({
      entityToHTML: (entity, originalText) => {
        if (entity.type === 'IMAGE') {          
          return `<img src="${entity.data.src}" />`;
        }
        return originalText;
      },
    })(editorState.getCurrentContent());

@moconchobhair
Copy link

Thank you @racmathafidz! You just made my day!

@alx4329
Copy link

alx4329 commented Jan 31, 2023

Never too late @racmathafidz, you made my day too!

@basannofal
Copy link

@racmathafidz
than a lot for helping

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants