Как программно добавлять упоминания с помощью draft-js-упоминания-плагина?

Проблема:

Я пытаюсь создать интерфейс редактирования для содержимого, созданного с помощью draft-js + draft-js-mention-plugin. Однако editorState не сохранилось, только обычный текст. Упоминания сохранялись в виде массива объектов. Теперь мне нужно воссоздать editorState с этими данными.


Пример:

У меня есть такой простой текст:

const content = '@marcello we need to add spell check'

И массив mentions с такими объектами:

const mentions = [{
  length: 8,
  offset: 0,
  user: 'user:59441f5c37b1e209c300547d',
}]

Чтобы создать editorState с простым текстом, я использую следующие строки:

const contentState = ContentState.createFromText(content)
EditorState.createWithContent(contentState)

Это хорошо работает. Обычный текст устанавливается как исходное состояние, но без упоминаний.

Теперь мне нужен способ добавления упоминаний на основе mentions объектов.

Я пытаюсь прочитать код библиотеки, чтобы понять это, но пока безуспешно.


person Diego Haz    schedule 15.11.2017    source источник


Ответы (3)


С "draft-js": "^0.11.6" и "draft-js-mention-plugin": "^3.1.5" вы можете делать

const stateWithEntity = editorState.getCurrentContent().createEntity(
  'mention',
  'IMMUTABLE',
  {
    mention: {id: 'foobar', name: 'foobar', link: 'https://www.facebook.com/foobar'},
  },
)
const entityKey = stateWithEntity.getLastCreatedEntityKey()
const stateWithText = Modifier.insertText(stateWithEntity, editorState.getSelection(), 'foobar', null, entityKey)
EditorState.push(editorState, stateWithText)

Вы можете найти этот https://github.com/draft-js-plugins/draft-js-plugins/issues/915#issuecomment-386579249 и https://github.com/draft-js-plugins/draft-js-plugins./issues/983#issuecomment-382150332 полезно

person mcjlnrtwcz    schedule 02.11.2020
comment
Вы легенда. - person nomad; 18.11.2020

Как я "взломал" для этого свое решение:

// Imports
import { EditorState,convertToRaw, ContentState, convertFromRaw, genKey, ContentBlock  } from 'draft-js';
// Init some kind of block with a mention
let exampleState = {
  blocks: [
        {
          key: genKey(), //Use the genKey function from draft
          text: 'Some text with mention',
          type: 'unstyled',
          inlineStyleRanges: [],
          data: {},
          depth: 0,
          entityRanges: [
            { offset: 15, length: 7, key: 0 }
          ]
        }
  ],
  entityMap: [
    "0": {
      "type": "mention",
      "mutability": "SEGMENTED",
      "data": {
        "mention": {
          "name": "<name>",
          "link": "<link>",
          "avatar": "<avatar-url>"
        }
      }
    }
  ]
};
this.state.editorState = EditorState.createWithContent(convertFromRaw(exampleState));

Здесь вы можете создать некоторую функцию для ввода текста и вывода entityRange, чтобы вернуть смещение / длину упоминания и заменить массив «entityRanges» на ваш выделенный материал!

В этом примере слово «упоминание» будет выделено любым стилем, который вы используете с плагином упоминания.

Примечание:

Вы можете использовать класс ContentBlock из черновика или создать свою собственную реализацию, чтобы сделать это более красивым.

person geb12    schedule 15.02.2018

Это решение, которое мне удалось применить для добавления упоминания (#) (с entityMap, в новый блок в конце состояния). Его можно использовать как упоминание и так далее ... Конечно, это можно упростить, но для меня это работает так, как ожидалось.

 // import {....} from 'draft-js';
 import Immutable, {List, Repeat} from 'immutable' ;

  const addMentionLast = (editorState, mentionData) => {
   
    if(!mentionData.id) return;

    // debugger;
    const contentState = editorState.getCurrentContent();
    const oldBlockMap = contentState.getBlockMap();
    const lastKey = lastNonEmptyKey(contentState);
    const charData = CharacterMetadata.create();
    
    //new state with mention
    const selection = editorState.getSelection();
    const entityKey = Entity.create('#mention', 'SEGMENTED', {"mention":{...mentionData }} );
    //add text 
    const textWithEntity = Modifier.insertText(contentState, selection , `#${mentionData.name}` , null,  entityKey); 
    const _editorState = EditorState.push(editorState,  textWithEntity ,  'insert-characters');
    
    //create new block
    const _newBlock = new ContentBlock({
      key:  genKey(),
      type: 'unstyled',
      depth: 0,
      text: mentionData.name,
      characterList: List(Repeat(charData, mentionData.name.length)),
    });

    //set the entity
    const __newBlock =  applyEntityToContentBlock(_newBlock,0, mentionData.name.length, entityKey)

    //set new block in order..
    const blocksMap =
      Immutable.OrderedMap().withMutations(map => {
        if (lastKey) {
          //after the last non empty:
          for (let [k, v] of oldBlockMap.entries()) {
            map.set(k, v);
            if (lastKey === k) {
              map.set(k, v);
              map.set(__newBlock.key, __newBlock);
            }
          }
        }
        else {
          // first line:
          map.set(__newBlock.key, __newBlock);
        }
      });
   
    return EditorState.push(
      _editorState,
          ContentState
            .createFromBlockArray(Array.from(blocksMap.values()))
            .set('selectionBefore', contentState.getSelectionBefore())
            .set('selectionAfter', contentState.getSelectionAfter())
    )

  }

  function lastNonEmptyKey (content){
    const lastNonEmpty = content.getBlockMap().reverse().skipUntil((block, _) => block.getLength()).first();
 if (lastNonEmpty) return lastNonEmpty.getKey();
}

Спасибо всем за то, что поделились!

person Vlad    schedule 21.07.2020