Update editorState with two operations at once - draftjs

I am trying to split a word into two words when I enter the space bar. Every word in my text is an entity, so when I split a word in two, I need to update the text and create a new entity.
I am using the Modifier module for both updates.
const editorStateAfterText =
EditorState.push(
editorState,
Modifier.insertText(
contentState,
selectionState,
' ',
),
command,
);
const editorStateAfterEntity =
EditorState.push(
editorStateAfterText,
Modifier.applyEntity(
contentState,
newSelectionState,
newEntityKey
),
command,
);
this.setState({editorState: editorStateAfterEntity})
I am trying to update the editor state with two operations at once. They both work if the other one is not present. When the two are present, it only updates the last one.
Is there any way to update the text (split the word) and add the new entity to the entityMap?

As defined in the docs https://draftjs.org/docs/api-reference-editor-state.html#push, push is asking for 3 params: editorState, contentState and command.
I was doing it ok in editorStateAfterEntity passing the updated editorState parameter with editorStateAfterText, but I was ignoring the updated contentState.
So here is how it finally worked:
const contentAfterText = Modifier.insertText(
contentState,
selectionState,
' ',
);
const editorStateAfterText = EditorState.push(
editorState,
contentAfterText,
command,
);
const contentStateAfterTextAndEntity = Modifier.applyEntity(
contentAfterText,
newSelectionState,
newEntityKey
);
const editorStateAfterTextAndEntity = EditorState.push(
editorStateAfterText,
contentStateAfterTextAndEntity,
command,
);
this.setState({editorState: editorStateAfterTextAndEntity});

Related

how to delete auto closed brackets in VSCode extetnsion Completion?

I register [[ as the completion trigger word, VSCode will auto generate ]] for [[,
My completion want to delete the [[]].
For example:
when user type [[,
user may type some filter text,
the final result will be [xxx](/xxx)
I tried additionalTextEdits to delete [[]], but when user type some filter text, the position will be wrong.
item.insertText = `[${title}](/${relativePath})`;
const start = position.character - 2;
item.additionalTextEdits = [
vscode.TextEdit.delete(
new vscode.Range(position.line, start, position.line, start + 4)
),
];
Solve this by using command, completion can add a command param, which can do something when completion complete.
vscode.commands.registerCommand(
'foam-vscode.delete-wiki-link-end-brackets',
() => {
const editor = vscode.window.activeTextEditor;
if (editor) {
const current = editor.selection.active;
editor.edit(editBuilder => {
editBuilder.delete(
new vscode.Range(
current.line,
current.character,
current.line,
current.character + 2
)
);
});
return;
}
}
);

VS Code - Selection to multi cursor

Does anyone know how to turn an vscode editor selection range into a multi cursor selection?
for instance on this line:
"out of this line I'd like to select this|"
run the key bind
selection would turn into multi cursor like so
"out of this line I'd like to | select this |"
You can use the extension Select By v1.10
Execute the command: SelectBy: Create separate cursors for anchor and active position of the selection(s) , selectby.anchorAndActiveSeparate
It will create new cursors for every anchor and active position of all the current selections. Overlapping cursors are eliminated.
Assuming you are working with only a single selection:
const selection = vscode.window.activeTextEditor.selections[0];
const newSelection1 = new vscode.Selection(selection.start, selection.start);
const newSelection2 = new vscode.Selection(selection.end, selection.end);
vscode.window.activeTextEditor.selections = [newSelection1, newSelection2];
You will get the same result selecting left-to-right as right-to-left.
I made this into an extension: Convert Selection - it works on multiple selections.
Here is the entire code of the extension:
const vscode = require('vscode');
/**
* #param {vscode.ExtensionContext} context
*/
function activate(context) {
let disposable = vscode.commands.registerCommand('convert-selection.surround', function () {
const editor = vscode.window.activeTextEditor;
const selections = editor.selections;
const newSelections = [];
for (const selection of selections) {
const newSelection1 = new vscode.Selection(selection.start, selection.start);
const newSelection2 = new vscode.Selection(selection.end, selection.end);
newSelections.push(newSelection1, newSelection2);
}
editor.selections = newSelections;
});
context.subscriptions.push(disposable);
}
exports.activate = activate;

Draft.js Mention Plugin is not working after rendering contentState to the editor

I am using mentions with the draft.js (like this #yourname) and sending to the database to save and fetching it to render on the web page but things are not working as expected.
On Saving to the database ->
const contentState = editorState.getCurrentContent();
const currentStateData = convertToRaw(contentState);
const richStringifyValue = JSON.stringify(currentStateData);
// sending richStringifyValue to save in Mongo DB
On Fetch and set in editor ->
const [editorState, setEditorState] = React.useState(() => EditorState.createEmpty());
const parsedData = JSON.parse(post.contentStyled);
const fromRawData = convertFromRaw(parsedData );
EditorState.createWithContent(fromRawData);
// here is the view rendered part -
<Editor
readOnly={true}
editorState={editorState}
/>
But after setting in editor (after the data fetched from API) my mentions (#... #... #...) lost the CSS. What should we do?
On Using Edit ->
On fetch and setting again in Editor ->
I don't know why is that happening, please help to resolve this issue!
You should do the following:
const [editorState, setEditorState] = React.useState(() => {
const parsedData = JSON.parse(post.contentStyled);
const fromRawData = convertFromRaw(parsedData );
return EditorState.createWithContent(fromRawData);
});
// ...
<Editor
readOnly={true}
editorState={editorState}
/>
If you override the editorState with a new created state you are removing all the decorators which were added by the plugins.
Dominic's answer made me realize what was going on with the decorators, but his approach didn't work for me either.
What I ended up doing instead was to avoid mounting the editor altogether until I have the data inside the EditorState:
const [editorState, setEditorState] = React.useState(null);
useEffect(() => {
const parsedData = JSON.parse(post.contentStyled);
const fromRawData = convertFromRaw(parsedData );
setEditorState(() => EditorState.createWithContent(fromRawData));
}, []);
editorState && <Editor readOnly={true} editorState={editorState}/>
This way you insert your persisted data into the state before instantiating the component. And afterwards any other plugin adding decorators will work as intended.

Is it possible to set TextDocument as dirty programatically in VSCode?

Is it possible to set a TextDocument as dirty programatically in VSCode? Something like
openedDocument.setDirty()
There isn't a direct way to do it; TextDocument.isDirty is a read-only property.
However, I put together a workaround that sets isDirty by making an edit that has no effect (tested with VSCode 1.37.1):
// Set the dirty bit on 'textEditor'. This is meant to be called as a
// text editor command.
async function setDirty(textEditor: TextEditor, editBuilder: TextEditorEdit)
: Promise<void>
{
// The strategy here is to make a change that has no effect. If the
// document has text in it, we can replace some text with itself
// (simply inserting an empty string does not work). We prefer to
// edit text at the end of the file in order to minimize spurious
// recomputation by analyzers.
// Try to replace the last line.
if (textEditor.document.lineCount >= 2) {
const lineNumber = textEditor.document.lineCount-2;
const lastLineRange = new Range(
new Position(lineNumber, 0),
new Position(lineNumber+1, 0));
const lastLineText = textEditor.document.getText(lastLineRange);
editBuilder.replace(lastLineRange, lastLineText);
return;
}
// Try to replace the first character.
const range = new Range(new Position(0, 0), new Position(0, 1));
const text = textEditor.document.getText(range);
if (text.length > 0) {
editBuilder.replace(range, text);
return;
}
// With an empty file, we first add a character and then remove it.
// This has to be done as two edits, which can cause the cursor to
// visibly move and then return, but we can at least combine them
// into a single undo step.
await textEditor.edit(
(innerEditBuilder: TextEditorEdit) => {
innerEditBuilder.replace(range, " ");
},
{ undoStopBefore: true, undoStopAfter: false });
await textEditor.edit(
(innerEditBuilder: TextEditorEdit) => {
innerEditBuilder.replace(range, "");
},
{ undoStopBefore: false, undoStopAfter: true });
}
In your activate function, hook it up with something like:
context.subscriptions.push(
commands.registerTextEditorCommand("extension.setDirty", setDirty));

DraftJS: Reset blockType after return

I am currently building an editor like the one that is used on medium.com. For each unstyled block, I render a custom component that holds edit buttons to change the block type of that section.
However, when I for example change the section to a header-one and hit the return button the new block is also a header-one block. I like to see that the new block is unstyled instead of the same type of the previous block.
Any ideas on how to do this?
After some more searching and trying I found the solution myself! It appears that the best way to do this is by inserting a new block when the split-block keyCommand is fired.
For example:
createEmptyBlock(editorState: Draft.EditorState) {
const newBlock = new Draft.ContentBlock({
key: Draft.genKey(),
type: "unstyled",
text: "",
characterList: Immutable.List()
})
const contentState = editorState.getCurrentContent()
const newBlockMap = contentState.getBlockMap().set(newBlock.getKey(), newBlock)
return Draft.EditorState.push(
editorState,
Draft.ContentState
.createFromBlockArray(newBlockMap.toArray())
.set('selectionAfter', contentState.getSelectionAfter().merge({
anchorKey: newBlock.getKey(),
anchorOffset: 0,
focusKey: newBlock.getKey(),
focusOffset: 0,
isBackward: false,
})) as Draft.ContentState,
"split-block"
)
}
This answer was posted as an edit to the question DraftJS: Reset blockType after return by the OP n9iels under CC BY-SA 3.0.