react-draft-wysiwyg icon indicating copy to clipboard operation
react-draft-wysiwyg copied to clipboard

Remove button should remove all styling

Open marchaos opened this issue 6 years ago • 5 comments

I kind of feel that the "remove" button should remove all styling, links, title styles and bullet points. This is how it works in gmail (remove styling button). Would it be possible to make this consistent with other editors?

marchaos avatar Feb 07 '19 16:02 marchaos

Hello @marchaos : in various other editor like this one https://www.froala.com/wysiwyg-editor Remove option only clears inline formatting.

jpuri avatar Feb 09 '19 09:02 jpuri

Nuke-all option (ignores selection). AFAIK just overriding the Remove component would not be enough, so a custom button is needed

import * as React from 'react';
import { EditorState, CharacterMetadata, ContentBlock, ContentState } from 'draft-js';

//NIH https://github.com/facebook/draft-js/issues/166#issuecomment-393488544
const removeInlineStyles = (
  editorState: EditorState,
  retainInlineStyles: string[] = []
) => {
  let blocks = editorState
      .getCurrentContent()
      .getBlocksAsArray()
      .map(singleBlock =>
          singleBlock.set(
              "characterList",
              singleBlock.getCharacterList().map(charMetaData => {
                  if (!charMetaData) {
                      return charMetaData;
                  }
                  let entity = charMetaData.getEntity();
                  let style = charMetaData.getStyle();
                  return CharacterMetadata.create({
                      entity: entity,
                      style: style.intersect(retainInlineStyles)
                  });
              })
          )
      ) as ContentBlock[];
  return EditorState.createWithContent(
      ContentState.createFromBlockArray(blocks)
  );
};

interface Props {
  editorState?: EditorState,
  onChange?: (editorState: EditorState) => void
}

const eraserIcon = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNSIgaGVpZ2h0PSIxNSIgdmlld0JveD0iMCAwIDE2IDE2Ij48cGF0aCBkPSJNOC4xIDE0bDYuNC03LjJjLjYtLjcuNi0xLjgtLjEtMi41bC0yLjctMi43Yy0uMy0uNC0uOC0uNi0xLjMtLjZIOC42Yy0uNSAwLTEgLjItMS40LjZMLjUgOS4yYy0uNi43LS42IDEuOS4xIDIuNWwyLjcgMi43Yy4zLjQuOC42IDEuMy42SDE2di0xSDguMXptLTEuMy0uMXMwLS4xIDAgMGwtMi43LTIuN2MtLjQtLjQtLjQtLjkgMC0xLjNMNy41IDZoLTFsLTMgMy4zYy0uNi43LS42IDEuNy4xIDIuNEw1LjkgMTRINC42Yy0uMiAwLS40LS4xLS42LS4yTDEuMiAxMWMtLjMtLjMtLjMtLjggMC0xLjFMNC43IDZoMS44TDEwIDJoMUw3LjUgNmwzLjEgMy43LTMuNSA0Yy0uMS4xLS4yLjEtLjMuMnoiLz48L3N2Zz4=';

export class RichTextCleaner extends React.Component<Props> {

  clean = () => {
    const { editorState, onChange } = this.props;
    onChange(removeInlineStyles(editorState));
  }
  
  render() {
    return (
      <div className="rdw-remove-wrapper" aria-label="rdw-remove-control"onClick={this.clean}>
        <div className="rdw-option-wrapper" title="Remove">
          <img
            src={eraserIcon}
            alt=""
          />
        </div>
      </div>
    );
  }
}

And then in your editor:

toolbarCustomButtons={[<RichTextCleaner />]}

gytisgreitai avatar Apr 19 '19 08:04 gytisgreitai

My First CSS Example

This is a paragraph.

manoharkumarsingh avatar Oct 05 '23 09:10 manoharkumarsingh

`

h1 { color: white; text-align: center; }

p { font-family: verdana; font-size: 20px; }

My First CSS Example

This is a paragraph.

`

manoharkumarsingh avatar Oct 05 '23 09:10 manoharkumarsingh

Updated @gytisgreitai solution to only format the selection.

const removeInlineStyles = (editorState: EditorState, retainInlineStyles: string[] = []) => {
    const contentState = editorState.getCurrentContent();
    const selectionState = editorState.getSelection();
    const startKey = selectionState.getStartKey();
    const endKey = selectionState.getEndKey();
    const startOffset = selectionState.getStartOffset();
    const endOffset = selectionState.getEndOffset();
    const blocks = contentState.getBlockMap();

    let newBlocks = blocks.map((block, blockKey) => {
        if (!blockKey) {
            return block;
        }

        let newCharList = block.getCharacterList().map((charMetaData, index) => {
            let isWithinSelection = false;

            if (blockKey === startKey && blockKey === endKey) {
                // Selection starts and ends within this block
                isWithinSelection = index >= startOffset && index < endOffset;
            } else if (blockKey === startKey) {
                // Selection starts in this block
                isWithinSelection = index >= startOffset;
            } else if (blockKey === endKey) {
                // Selection ends in this block
                isWithinSelection = index < endOffset;
            } else if (blockKey > startKey && blockKey < endKey) {
                // Selection spans across this entire block
                isWithinSelection = true;
            }

            if (!isWithinSelection || !charMetaData) {
                return charMetaData;
            }

            let style = charMetaData.getStyle().intersect(retainInlineStyles);
            return CharacterMetadata.create({ entity: charMetaData.getEntity(), style: style });
        });

        return block.set("characterList", newCharList);
    });

    return EditorState.push(editorState, ContentState.createFromBlockArray(newBlocks.toArray()), 'change-inline-style');
};

CryptITAustria avatar Dec 20 '23 21:12 CryptITAustria