Draft-js: Remove all inline styles from current block

Created on 8 Apr 2016  路  9Comments  路  Source: facebook/draft-js

Hi there!

I did not find a Util function that allows to remove all inline styles from a block. Did I miss it?

Anyway I tried to do it myself, and I went to something like below ; but this seems to work only if there is a non-collapsed selection in the current block :disappointed:

const { Editor, EditorState, Modifier, RichUtils } = Draft;

// ...

function removeInlineStyles (editorState, inlineStyles) {
  const selection = editorState.getSelection();
  const nextContentState = Object.keys(inlineStyles)
  .reduce((contentState, style) => {
    return Modifier.removeInlineStyle(
      contentState,
      selection,
      style
    );
  }, editorState.getCurrentContent());

  return EditorState.push(
    editorState,
    nextContentState,
     'change-inline-style'
  );
}

class TestEditor extends React.Component {
  // ...
  _changeBlockType (type) {
    const nextEditorState = RichUtils.toggleBlockType(
      this.state.editorState,
      type
    );
    this.onChange(
      removeInlineStyles(nextEditorState, INLINE_STYLES)
    );
  }
}

If someone understand why, I would love to know :smile:

And could / should this be added to Draft as a Util / Modifier function?
I am needing it because in my case, each block type has its own inline styles basically. So we do not want that some inline styles from a "paragraphe" becomes applied to a "title" if the user change the block type from "paragraphe" to "title". To keep it simple, this implies that if user change it back to "paragraphe", inline styles are lost.
I think this could be usefull for many cases anyway.

PS: thanks for everybody's work on Draft and making this open source :)
BTW I am in holidays for 2 weeks starting tomorrow and probably won't be available (Vietnam) so do not take it bad if I do not reply for some days :)

question

Most helpful comment

For anyone looking in the future:

const clearInlineStyles = editorState => {
  const styles = [
    'BOLD',
    'ITALIC',
    'UNDERLINE',
    'STRIKETHROUGH',
    'CODE'
  ];

  const contentWithoutStyles = _.reduce(styles, (newContentState, style) => (
    Modifier.removeInlineStyle(
      newContentState,
      editorState.getSelection(),
      style
    )
  ), editorState.getCurrentContent());

  return EditorState.push(
    editorState,
    contentWithoutStyles,
    'change-inline-style'
  );
};

All 9 comments

Haven't tested this, but maybe try calling Modifier.replaceText passing in the string that already exists and null for inlineStyle param?

@heymath To be sure that all inline styles for the whole block get reset you could create a new SelectionState for the block which is changed, by using the anchorKey of the original selection, if it is collapsed. Then you can span from 0 to block.getLength() and have anchorKey and focusKey be the same block. Then you can use this selection to remove inline styles for all characters in the block.

In order to reset everything (inline styles AND entities) you can just set the block's CharacterList to new one without styles:

List(Repeat(CharacterMetadata.create(), textLength))

If you have entities which you want to keep, then you will have to loop over the character list and just reset the style prop of each character:

const characterList = block.getCharacterList();
const updatedCharacterList = characterList.map(c => (
  c.set('style', c.get('style').clear())
));

const updatedBlock = block.set('characterList', characterList);

Thank you very much guys! I will try this right after my holidays, that should be OK :)

Both suggestions here should work. :)

For anyone looking in the future:

const clearInlineStyles = editorState => {
  const styles = [
    'BOLD',
    'ITALIC',
    'UNDERLINE',
    'STRIKETHROUGH',
    'CODE'
  ];

  const contentWithoutStyles = _.reduce(styles, (newContentState, style) => (
    Modifier.removeInlineStyle(
      newContentState,
      editorState.getSelection(),
      style
    )
  ), editorState.getCurrentContent());

  return EditorState.push(
    editorState,
    contentWithoutStyles,
    'change-inline-style'
  );
};

@dictions - this should be in draft by default...plain and simple feature and clean code. I would suggest a PR...

@hellendag - why did you close the issue? Is this feature (a standard for any editor with text styling feature) already part of DraftJS???

In my project I don't want any of the inline stylings (and whitelisting the block elements that is allowed), I would presume this is pretty common in simplest use cases for the draft-js.

This leads to the question, what is performant way to do this? It's probably a difficult thing to answer and having a canonical and documented way to "disable" inline styles would be preferable.

There is now two, but I'm pretty sure there is some other ways too. @dictions approach seems to be relying on listing all the styles (which seems fragile), but is probably more performant. @johanneslumpe approach seems more generic since one does not need to list the different styles, but is looping characterList a slow process?

P.S. If there is "blockRenderMap" why not also "inlineRenderMap" where one could whitelist allowed inline styles also?

For anyone looking in the future. I created this logic based on the answer of @davidbyttow

const selectionState = editorState.getSelection();
const anchorKey = selectionState.getAnchorKey();
//Then based on the docs for SelectionState -
const currentContent = editorState.getCurrentContent();
const currentBlock = currentContent.getBlockForKey(anchorKey);
const start = selectionState.getStartOffset();
const end = selectionState.getEndOffset();
// Selected Text
const selectedText = currentBlock.getText().slice(start, end);

const contentWithoutStyles = Modifier.replaceText(
  editorState.getCurrentContent(),
  selectionState,
  selectedText,
  null,
);

const newstate = EditorState.push(
  editorState,
  contentWithoutStyles,
  'change-inline-style',
);

setEditorState(newstate);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

abeq picture abeq  路  3Comments

mvnnn picture mvnnn  路  3Comments

eessex picture eessex  路  3Comments

vierno picture vierno  路  3Comments

pklavins picture pklavins  路  3Comments