When I'm clicking on the button the text from the clipboard is pasted without style, but keeps the current style inline, but that's not what I need.
My code
async function getClipboardContents() {
try {
const textFromClipboard = await navigator.clipboard.readText();
const newContentState = Modifier.replaceText(
editorState.getCurrentContent(),
editorState.getSelection(),
textFromClipboard,
editorState.getCurrentInlineStyle(),
);
const newPushState = Draft.EditorState.push(editorState, newContentState, 'change-block-data');
handleOnChange(newPushState);
} catch (err) {
console.error('error', err);
}
}
What needs to be done so that the text is inserted with formatting?
Text formatting loses after using clipboard.readText(). You should use clipboard.read() instead. It will return array of ClipBoardItem.
You can read your initial formatting from this object that way:
const [clipboardItem] = await navigator.clipboard.read();
const blob = await clipboardItem.getType('text/html');
// Here's your formmated text
const formattedText = await new Response(blob).text();
Related
In my extension I want to edit the document on a few specific document edits.
My actual use case is a bit complicated so I have created a minimal example. The code below listens for any document edit. If the word "hello" exists in the edit (i.e. the user pasted some code that contains the word "hello") then we replace the change range with the pasted text but just make it upper case.
We also console.log if the edit was successful, and any potential reason the edit was rejected.
vscode.workspace.onDidChangeTextDocument(event => {
for (const change of event.contentChanges) {
if (change.text.includes("hello")) {
activeEditor.edit(editBuilder => {
editBuilder.replace(change.range, change.text.toUpperCase());
}).then(
value => console.log("SUCCESS: "+value),
reason => console.log("FAIL REASON: "+reason),
);
}
}
});
A working example would be selecting some text in a document and pasting in the text const hello = 5;. As expected, the extension replaces the text with CONST HELLO = 5; and logs SUCCESS: true.
But when I paste in some text that automatically get formatted I run into problems. If I were to paste in:
const hello = 5;
const lol = 10;
const lmao = 20;
Including all the whitespaces/tabs, then vscode wants to "format" or correct my lines, i.e. remove the whitespace. So the resulting text will be:
const hello = 5;
const lol = 10;
const lmao = 20;
The extension tries to make it uppercase still but only prints SUCCESS: false. No reason is logged at all; the reject function is not executed.
Why does the edit not succeed? Should I await the other edits somehow or keep re-trying the edit until it succeeds? Am I logging the rejection incorrectly?
In case it helps, here is code I use - I found it better to have the editBuilder outside the loop. I think you can adapt it for your purposes:
editor.edit( (editBuilder) => {
// put your for (const change of event.contentChanges) {} here
for (const match of matches) {
resolvedReplace = variables.buildReplace(args, "replace", match, editor.selection, null, index);
const matchStartPos = document.positionAt(match.index);
const matchEndPos = document.positionAt(match.index + match[0].length);
const matchRange = new vscode.Range(matchStartPos, matchEndPos);
editBuilder.replace(matchRange, resolvedReplace);
}
}).then(success => {
if (!success) {
return;
}
if (success) { ... do something here if you need to }
});
One solution is just to "keep trying again". I do not like this solution, but it is a solution nevertheless, and it currently works for my use-case.
async function makeReplaceEdit(range: vscode.Range, text: string, maxRetries = 10) {
for (let i = 0; i <= maxRetries; i++) {
const editor = vscode.window.activeTextEditor;
if (!editor) return;
const success = await editor.edit(editBuilder => {
editBuilder.replace(
range,
text
);
}, { undoStopBefore: false, undoStopAfter: false });
if (success) break;
}
};
vscode.workspace.onDidChangeTextDocument((event) => {
// See if any change contained "hello"
let foundHello = false;
for (const change of event.contentChanges) {
if (change.text.includes("hello")) {
foundHello = true;
}
}
if (foundHello) {
console.log("inside1");
const editor = vscode.window.activeTextEditor;
if (!editor) return;
makeReplaceEdit(editor.document.lineAt(0).range, "Change");
}
});
I'm trying to replicate the code in this article:
https://depth-first.com/articles/2020/08/24/smiles-validation-in-the-browser/
What I'm trying to do different is that I'm using a textarea instead of input to take multi-line input. In addition to displaying an error message, I also want to display the entry which doesn't pass the validation.
The original validation script is this:
const path = '/target/wasm32-unknown-unknown/release/smival.wasm';
const read_smiles = instance => {
return smiles => {
const encoder = new TextEncoder();
const encoded = encoder.encode(`${smiles}\0`);
const length = encoded.length;
const pString = instance.exports.alloc(length);
const view = new Uint8Array(
instance.exports.memory.buffer, pString, length
);
view.set(encoded);
return instance.exports.read_smiles(pString);
};
};
const watch = instance => {
const read = read_smiles(instance);
document.querySelector('input').addEventListener('input', e => {
const { target } = e;
if (read(target.value) === 0) {
target.classList.remove('invalid');
} else {
target.classList.add('invalid');
}
});
}
(async () => {
const response = await fetch(path);
const bytes = await response.arrayBuffer();
const wasm = await WebAssembly.instantiate(bytes, { });
watch(wasm.instance);
})();
For working with a textarea, I've changed the watch function to this and added a <p id="indicator"> element to the html to display an error:
const watch = instance => {
const read = read_smiles(instance);
document.querySelector("textarea").addEventListener('input', e => {
const { target } = e;
var lines_array = target.value.split('/n');
var p = document.getElementById("indicator");
p.style.display = "block";
p.innerHTML = "The size of the input is : " + lines_array.length;
if (read(target.value) === 0) {
target.classList.remove('invalid');
} else {
target.classList.add('invalid');
}
});
}
I'm not even able to get a count of entries that fail the validation. I believe this is async js and I'm just a beginner in JavaScript so it's hard to follow what is happening here, especially the part where the function e is referencing itself.
document.querySelector("textarea").addEventListener('input', e => {
const { target } = e;
Can someone please help me in understanding this complicated code and figuring out how to get a count of entries that fail the validation and also printing the string/index of the same for helping the user?
There is a mistake in you code to count entries in the textarea:
var lines_array = target.value.split('\n'); // replace /n with \n
You are asking about the function e is referencing itself:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. You can find more informations Mdn web docs - Destructuring object
Trying to clear my search result after I submit a new API call. Tried implementing gallery.remove(galleryItems); at different points but to no avail.
A bit disappointed I couldn't figure it out but happy I was able to get a few async functions going. Anyway, here's the code:
'use strict';
const form = document.querySelector('#searchForm');
const gallery = document.querySelector('.flexbox-container');
const galleryItems = document.getElementsByClassName('flexbox-item');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const userSearch = form.elements.query.value; // grab user input
const res = await getRequest(userSearch); // async func that returns a fully parsed Promise
tvShowMatches(res.data); // looks for matches, creates and appends name + image;
form.elements.query.value = '';
});
const getRequest = async (search) => {
const config = { params: { q: search } };
const res = await axios.get('http://api.tvmaze.com/search/shows', config);
return res;
};
const tvShowMatches = async (shows) => {
for (let result of shows) {
if (result.show.image) {
// new div w/ flexbox-item class + append to gallery
const tvShowMatch = document.createElement('DIV')
tvShowMatch.classList.add('flexbox-item');
gallery.append(tvShowMatch);
// create, fill & append tvShowName to tvShowMatch
const tvShowName = document.createElement('P');
tvShowName.textContent = result.show.name;
tvShowMatch.append(tvShowName);
// create, fill & append tvShowImg to tvShowMatch
const tvShowImg = document.createElement('IMG');
tvShowImg.src = result.show.image.medium;
tvShowMatch.append(tvShowImg);
}
}
};
Thanks
Instead of gallery.remove(galleryItems); consider resetting gallery.innerHTML to an empty string whenever a submit event occurs
Like this:
form.addEventListener('submit', async (e) => {
e.preventDefault();
gallery.innerHTML = ''; // Reset here
const userSearch = form.elements.query.value; // grab user input
const res = await getRequest(userSearch); // async func that returns a fully parsed Promise
tvShowMatches(res.data); // looks for matches, creates and appends name + image;
form.elements.query.value = '';
});
I believe this will do it.. you were close.
const galleryItems = document.getElementsByClassName('flexbox-item');
// to remove
galleryItems.forEach(elem => elem.remove() );
I have a problem with this piece of code.
I import input data from a file formated like so and store it in const input:
aabcccccaaa
aaccb
shsudbud
There are no spaces or any other white characters except from '\n' newline.
I get inputs in this way: (LiveServer inside VS Code)
const getData = async () => {
const resp = await fetch("./inputs.txt");
const data = await resp.text();
return data;
};
Then I call:
const myFunc = async () => {
const input = await getData();
const rows = input.split("\n").map(row => row);
rows.forEach(row => {
const charArr = [...row];
console.log(charArr);
});
};
After logging to console first and second row it seems like there is "" (empty string) attached to the end of each of them. The third element is fine so I guess its somehow connected with newline character.
I have also tried creating charArr by doing:
const charArr = Array.from(row);
Or
const charArr = row.split("");
But the outcome was the same.
Later I found this topic: Remove empty elements from an array in Javascript
So I tried:
const charArr = [...row].filter(Boolean);
But the "" is still at the end of charArr created from 1st and 2nd row.
const input = `aabcccccaaa
aaccb
shsudbud`;
const rows = input.split("\n").map(row => row);
rows.forEach(row => {
const charArr = [...row];
console.log(charArr);
});
In this snippet everything works fine. So here is where my questions start:
Why does .filter() method not work properly in this case?
Could this problem browser specific?
Thanks in advance.
i want to autofill a form with puppeteer.
I fill out the first input, then click on a button that then creates a new input field that has focus.
How can i select this input? Can i use document.activeElement and how?
let newActivity = 'button.new_activity'
await page.waitForSelector(newActivity)
await page.click(newActivity)
// find active/focused input
await page.type(focusedInput, 'message')
You can use evaluateHandle to get the element handle, and then call the type function on that element.
const el = await page.evaluateHandle(() => document.activeElement);
await el.type('message');
function findFocusedNode(node) {
if (node.focused) {
return node;
}
for (const child of node.children || []) {
const focusedNode = findFocusedNode(child);
if (focusedNode) {
return focusedNode;
}
}
}
const snapshot = await page.accessibility.snapshot();
const focusedNode = findFocusedNode(snapshot);
console.log('focusedNode', focusedNode);
https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-accessibility