Draft-js: Question: Insert Block with text is breaking pointer location

Created on 21 Nov 2016  路  8Comments  路  Source: facebook/draft-js

Hi All,
So i have been working on a custom button to insert product content into a draft editor but it is currently breaking the pointer location. I am assume this is because of the text characters I am inserting or the tag.
How can I make the text inside none selectable and treat this element like an image?
Do you think this is what is breaking my selection?

screen shot 2016-11-21 at 5 44 07 pm

for example if you tried to make a link in the blue block it would make a new line at max

Most helpful comment

@neove Its in the draft-js package but not exported
import DraftPasteProcessor from 'draft-js/lib/DraftPasteProcessor';

All 8 comments

Hey @stagfoo did you have any luck with this feature? Im current working on a component build on top of CKEditor so I can drag and drop 'isolated islands' all over the text. However integrating Ckeditor on my React UI is kinda hassle so I would love to use something like Draft.js to implement that. I think what you're doing is kind of similar even though you're not using drag'n drop for your custom-buttom. Maybe we can share some thoughts on it :)

This is how my component looks so far:
screen shot 2016-11-29 at 12 08 15 am

I did but I'm out of the office, next time I'm back I will post my solution.

so i did this as a decorator like so

    function findImageEntities(contentBlock, callback) {
      //get all text
      const text = contentBlock.getText();
      //find just []() 
      const IMG = /(\[.*?\]\()(.+?)(\))/g;
      let match;
      while ((match = IMG.exec(text)) !== null) {
        const start = match.index;
        const end = start + match[0].length;
        callback(start, end);
      }
    }

    const Image = (props) => {
      let height = 'auto';
      let width = 'auto';
      let src;
      //get the text found by the above function [image](imageUrl =100x100)
      let split = props.decoratedText.split('(')[1].split(')')[0];
      src = split.split('=')[0].trim();
      split = split.split('=')[1].split('x');
      height = split[1];
      width = split[0];
      // return fully customisable tag
      return (
          <span>
            <img alt="" src={src} height={height} width={width} />
          </span>
        );
    };

this is a simple example but you can do all your custom calls to product data inside the const Image function

const decorator = new CompositeDecorator([
      {
        strategy: findProductCode,
        component: productComp,
      },
      {
        strategy: findLinkEntities,
        component: Link,
      },
      {
        strategy: findImageEntities,
        component: Image,
      },
    ]);

Check the documentation on decorators in draft
https://facebook.github.io/draft-js/docs/advanced-topics-decorators.html#content

Drag and drop is also on draft-js-plugins.com

To insert the content into draft I use this function

function insertHtmlBlock(currentEditorState, html, state) {
  console.log(convertFromHTML(html));
  const rawObject = convertToRaw(currentEditorState.getCurrentContent());
  const enterObject = {};
  const processedHTML = DraftPasteProcessor.processHTML(html);
  enterObject.depth = processedHTML[0].depth;
  enterObject.key = processedHTML[0].key;
  enterObject.text = processedHTML[0].text;
  enterObject.type = processedHTML[0].type;
  enterObject.depth = processedHTML[0].depth;
  enterObject.data = processedHTML[0].data;
  enterObject.entityRanges = [];
  enterObject.inlineStyleRanges = [];
  rawObject.blocks.push(enterObject);
  const newContentState = convertFromRaw(rawObject);
  state.setState({ editorState: EditorState.push(currentEditorState, newContentState, 'insert-fragment') });
}

Example button

 this.confirmImage = () => {
      const { editorState } = this.state;
      insertHtmlBlock(editorState, `<p>![](https://unsplash.it/200/300 =200x200)</p>`, this);
    };

and this is be changed to the Image component.

Awesome answer @stagfoo! I will take a look on the documentation of it. Thank you so much!

@stagfoo could you please tell me how to get DraftPasteProcessor ? thank u

@neove Its in the draft-js package but not exported
import DraftPasteProcessor from 'draft-js/lib/DraftPasteProcessor';

for Images its actually better to use an Atomic Blocks.
Atomic blocks don't have selection issues and only take up one char and you pass in a custom component, which allows you to add a delete button.
https://github.com/facebook/draft-js/blob/master/examples/draft-0-9-1/media/media.html

I would say if you want to edit the text inside use decorators
If you don't want text inside use Atomic Block.

Was this page helpful?
0 / 5 - 0 ratings