Draftjs replaceText 保存样式
Draftjs replaceText conserving style
我正在使用 Draftjs 和 draft-js-plugins-editor,我正在使用两个插件:draft-js-mathjax-plugin and draft-js-mention-plugin
当用户使用“@”提及元素时,我想稍后用值替换所有提及的内容。例如 "You have @A" 将替换为 "You have 300"。我发现并使用了 Draft-js building search and replace functionality ,它有详细的文档和解释。
我改变了一些功能,使它们更全球化:
function findWithRegex (regex, contentBlock, callback) {
const text = contentBlock.getText();
let matchArr, start, end;
while ((matchArr = regex.exec(text)) !== null) {
start = matchArr.index;
end = start + matchArr[0].length;
callback(start, end);
}
}
function Replace (editorState,search,replace) {
const regex = new RegExp(search, 'g');
const selectionsToReplace = [];
const blockMap = editorState.getCurrentContent().getBlockMap();
blockMap.forEach((contentBlock,i) => (
findWithRegex(regex, contentBlock, (start, end) => {
const blockKey = contentBlock.getKey();
const blockSelection = SelectionState
.createEmpty(blockKey)
.merge({
anchorOffset: start,
focusOffset: end,
});
selectionsToReplace.push(blockSelection)
})
));
let contentState = editorState.getCurrentContent();
selectionsToReplace.forEach((selectionState,i) => {
contentState = Modifier.replaceText(
contentState,
selectionState,
replace
)
});
return EditorState.push(
editorState,
contentState,
);
}
单独使用时效果很好,但是当我使用 mathjax-plugin 放置数学表达式,然后使用 Replace
函数时,所有数学内容都消失了...
我知道在 replaceText 函数的定义中我们可以插入 inlineStyle,但我没有找到 "extract" 样式的任何方法。
我尝试使用 getEntityAt
、findStyleRanges
、findEntityRanges
和其他函数,但我不能让它们做我想做的事...
这是我的反应组件:
import React, { Component } from 'react';
import {EditorState, SelectionState, Modifier, convertFromRaw, convertToRaw} from 'draft-js';
import Editor from 'draft-js-plugins-editor';
import createMathjaxPlugin from 'draft-js-mathjax-plugin';
import createMentionPlugin, { defaultSuggestionsFilter } from 'draft-js-mention-plugin';
export default class EditorRplace extends Component {
constructor(props) {
super(props);
this.mentionPlugin = createMentionPlugin({
entityMutability: 'IMMUTABLE',
mentionPrefix: '@'
});
//We recover the data from the props
let JSONContentState = JSON.parse(this.props.instruction);
let inputs = this.props.inputs;
let values = this.props.values;
this.state = {
editorState: EditorState.createWithContent(convertFromRaw(JSONContentState)),
plugins:[this.mentionPlugin,createMathjaxPlugin({setReadOnly:this.props.isReadOnly})],
trigger:this.props.trigger,
inputs:inputs,
values:values,
};
}
componentDidMount() {
this.setState({
editorState:onReplace(this.state.editorState,'A','B')
})
}
onChange = (editorState) => {
this.setState({
editorState:editorState,
})
};
render() {
return (
<div>
<Editor
readOnly={true}
editorState={this.state.editorState}
plugins={this.state.plugins}
onChange={this.onChange}
/>
</div>
);
}
}
如果我没有使用替换功能,一切都会按预期显示,提及的样式和数学表达式都正确。
找不到"proper"解决方案,直接在原始内容状态上手动编辑。
首先,我对所有 块 进行迭代,然后对这个块中的每个 entity 进行迭代。我正在手动替换 block[i].text 中的文本。然后我不得不比较前一个元素和新元素的长度,以更改下一个元素的偏移量。
我正在使用两个数组,一个称为输入,一个称为值。输入必须按长度排序(从高到低),因为如果我们有@AB 和@A 并且我们以@A 开头,我们可能会发生冲突。
然后输入数组中的每个元素都必须有一个 "index" 值,该值 link 到 values 数组才能用正确的值正确替换。
let instruction = {"blocks":[{"key":"ar0s","text":"Multiply @alpha by @beta \t\t ","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":9,"length":6,"key":0},{"offset":19,"length":5,"key":1},{"offset":26,"length":2,"key":2}],"data":{}}],"entityMap":{"0":{"type":"mention","mutability":"IMMUTABLE","data":{"mention":{"index":0,"type":"Integer","name":"alpha","min":0,"max":10}}},"1":{"type":"mention","mutability":"IMMUTABLE","data":{"mention":{"index":1,"type":"Integer","name":"beta","min":0,"max":10}}},"2":{"type":"INLINETEX","mutability":"IMMUTABLE","data":{"teX":"\frac{@alpha}{@beta}","displaystyle":false}}}}
let inputs = [{index:0,name:'alpha'},{index:1,name:'beta'}];
let values = [1,123456];
replace(instruction,inputs,values);
function replace(contentState,inputs,values)
{
instruction.blocks.forEach((block,i) => {
console.log('Block['+i+'] "' + block.text + '"');
let offsetChange = 0;
block.entityRanges.forEach((entity) => {
entity.offset+=offsetChange;
console.log('\n[Entity] offsetChange:' + offsetChange);
inputs.forEach(input => {
if(instruction.entityMap[entity.key].type === 'mention') {
if(input.name === instruction.entityMap[entity.key].data.mention.name)
{
console.log('replace ' + entity.offset + ' ' + entity.length + ' ' + block.text.toString().substr(entity.offset,entity.length));
block.text = block.text.toString().replace(block.text.toString().substr(entity.offset,entity.length),values[input.index])
let newLength = values[input.index].toString().length
console.log('newLength:' +newLength);
offsetChange+= (newLength-entity.length);
entity.length=newLength;
}
}
});
});
});
return instruction;
}
所以它可以满足我的需要。
我正在使用 Draftjs 和 draft-js-plugins-editor,我正在使用两个插件:draft-js-mathjax-plugin and draft-js-mention-plugin
当用户使用“@”提及元素时,我想稍后用值替换所有提及的内容。例如 "You have @A" 将替换为 "You have 300"。我发现并使用了 Draft-js building search and replace functionality ,它有详细的文档和解释。 我改变了一些功能,使它们更全球化:
function findWithRegex (regex, contentBlock, callback) {
const text = contentBlock.getText();
let matchArr, start, end;
while ((matchArr = regex.exec(text)) !== null) {
start = matchArr.index;
end = start + matchArr[0].length;
callback(start, end);
}
}
function Replace (editorState,search,replace) {
const regex = new RegExp(search, 'g');
const selectionsToReplace = [];
const blockMap = editorState.getCurrentContent().getBlockMap();
blockMap.forEach((contentBlock,i) => (
findWithRegex(regex, contentBlock, (start, end) => {
const blockKey = contentBlock.getKey();
const blockSelection = SelectionState
.createEmpty(blockKey)
.merge({
anchorOffset: start,
focusOffset: end,
});
selectionsToReplace.push(blockSelection)
})
));
let contentState = editorState.getCurrentContent();
selectionsToReplace.forEach((selectionState,i) => {
contentState = Modifier.replaceText(
contentState,
selectionState,
replace
)
});
return EditorState.push(
editorState,
contentState,
);
}
单独使用时效果很好,但是当我使用 mathjax-plugin 放置数学表达式,然后使用 Replace
函数时,所有数学内容都消失了...
我知道在 replaceText 函数的定义中我们可以插入 inlineStyle,但我没有找到 "extract" 样式的任何方法。
我尝试使用 getEntityAt
、findStyleRanges
、findEntityRanges
和其他函数,但我不能让它们做我想做的事...
这是我的反应组件:
import React, { Component } from 'react';
import {EditorState, SelectionState, Modifier, convertFromRaw, convertToRaw} from 'draft-js';
import Editor from 'draft-js-plugins-editor';
import createMathjaxPlugin from 'draft-js-mathjax-plugin';
import createMentionPlugin, { defaultSuggestionsFilter } from 'draft-js-mention-plugin';
export default class EditorRplace extends Component {
constructor(props) {
super(props);
this.mentionPlugin = createMentionPlugin({
entityMutability: 'IMMUTABLE',
mentionPrefix: '@'
});
//We recover the data from the props
let JSONContentState = JSON.parse(this.props.instruction);
let inputs = this.props.inputs;
let values = this.props.values;
this.state = {
editorState: EditorState.createWithContent(convertFromRaw(JSONContentState)),
plugins:[this.mentionPlugin,createMathjaxPlugin({setReadOnly:this.props.isReadOnly})],
trigger:this.props.trigger,
inputs:inputs,
values:values,
};
}
componentDidMount() {
this.setState({
editorState:onReplace(this.state.editorState,'A','B')
})
}
onChange = (editorState) => {
this.setState({
editorState:editorState,
})
};
render() {
return (
<div>
<Editor
readOnly={true}
editorState={this.state.editorState}
plugins={this.state.plugins}
onChange={this.onChange}
/>
</div>
);
}
}
如果我没有使用替换功能,一切都会按预期显示,提及的样式和数学表达式都正确。
找不到"proper"解决方案,直接在原始内容状态上手动编辑。
首先,我对所有 块 进行迭代,然后对这个块中的每个 entity 进行迭代。我正在手动替换 block[i].text 中的文本。然后我不得不比较前一个元素和新元素的长度,以更改下一个元素的偏移量。
我正在使用两个数组,一个称为输入,一个称为值。输入必须按长度排序(从高到低),因为如果我们有@AB 和@A 并且我们以@A 开头,我们可能会发生冲突。
然后输入数组中的每个元素都必须有一个 "index" 值,该值 link 到 values 数组才能用正确的值正确替换。
let instruction = {"blocks":[{"key":"ar0s","text":"Multiply @alpha by @beta \t\t ","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":9,"length":6,"key":0},{"offset":19,"length":5,"key":1},{"offset":26,"length":2,"key":2}],"data":{}}],"entityMap":{"0":{"type":"mention","mutability":"IMMUTABLE","data":{"mention":{"index":0,"type":"Integer","name":"alpha","min":0,"max":10}}},"1":{"type":"mention","mutability":"IMMUTABLE","data":{"mention":{"index":1,"type":"Integer","name":"beta","min":0,"max":10}}},"2":{"type":"INLINETEX","mutability":"IMMUTABLE","data":{"teX":"\frac{@alpha}{@beta}","displaystyle":false}}}}
let inputs = [{index:0,name:'alpha'},{index:1,name:'beta'}];
let values = [1,123456];
replace(instruction,inputs,values);
function replace(contentState,inputs,values)
{
instruction.blocks.forEach((block,i) => {
console.log('Block['+i+'] "' + block.text + '"');
let offsetChange = 0;
block.entityRanges.forEach((entity) => {
entity.offset+=offsetChange;
console.log('\n[Entity] offsetChange:' + offsetChange);
inputs.forEach(input => {
if(instruction.entityMap[entity.key].type === 'mention') {
if(input.name === instruction.entityMap[entity.key].data.mention.name)
{
console.log('replace ' + entity.offset + ' ' + entity.length + ' ' + block.text.toString().substr(entity.offset,entity.length));
block.text = block.text.toString().replace(block.text.toString().substr(entity.offset,entity.length),values[input.index])
let newLength = values[input.index].toString().length
console.log('newLength:' +newLength);
offsetChange+= (newLength-entity.length);
entity.length=newLength;
}
}
});
});
});
return instruction;
}
所以它可以满足我的需要。