Using javascript to select text and the containing element using createRange - javascript

I'm rolling my own generic wysiwyg editor but Im stuck selecting some text. I'm using a div with contenteditable set to true to enter the text into. The problem is I'm using a <var> tag to highlight some text that the user is supposed to delete and rewrite in their own words. When the text inside the <var> tag is clicked it highlights it as I expect but when you hit backspace it only deletes the text and not the tags (<var>). How can I tell the selection to grab a few more characters on each end of the selection so it also deletes the <var> tags? I'm using the following to make the selection happen.
var range = document.createRange();
range.selectNodeContents(elem);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);

Placed function on the div's click event.
Selected the <var> tag.
Used .selectNode rather than .selectNodeContents.
Browsers handle it differently though. Some will add <i></i> tags when you enter more text, others don't, but this does remove the <var> tag completely....
var myDiv = document.getElementById("myDiv");
var elem = document.getElementById("myVar");
myDiv.addEventListener("click", function() {
var range = document.createRange();
range.selectNode(elem);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
});
<div contenteditable="true" id="myDiv">
Hello, this<var id="myVar"> is a test</var> of the editor
</div>

Related

How can I select part of the sentence in playwright?

In my automation script I have a sentence - "when will my account be ready?". From this sentence I want to select the word "account". So basically I want to highlight that text and then right click on it. I am stuck at highlighting the text "account" using automation tool playwright.
Page element looks like this.
<div class="line-text">when will may account be ready</div>
After trying many things, below code worked for me. Basically the word I was trying to select, didn't have any tag around it so was hard to select that word. I used JavaScript first to select the text and then right clicked using playwright.
// element handle of a complete sentence
const elementHandle = await this.getMessageByText(messageText);
// below code selects the given word from the line. text is the word I want to //select
await elementHandle.evaluate((element, text) => {
const selection = window.getSelection();
const content = element.innerText;
const range = document.createRange();
range.setStart(element.childNodes[0], content.indexOf(text));
range.setEnd(element.childNodes[0], content.indexOf(text) + text.length);
selection.removeAllRanges();
selection.addRange(range);
}, textToMask);
await this.click(SELECTORS.messageBodyTextelementHandle, { button: 'right' });

Selecting element of an contenteditable div when Enter Key is pressed

I want to get the element where the event occured. This snippet only logs the parent element
eg. .
How to log the current element where the key is being pressed
eg. 1st or 2nd
document.getElementById('text').addEventListener('keypress', event => {
console.clear();
console.log(event.target)})
<body>
<div id="text" contenteditable="true">
<div>1st</div>
<div>2nd</div>
</div>
</body>
UPDATE: This should do the trick:
<div id="text" contenteditable="true">
<div>1st</div>
<div>2nd</div>
</div>
<script>
document.getElementById('text').addEventListener('keypress', function(ev) {
var selection = window.getSelection();
var range = selection.getRangeAt(0);
var container = range.commonAncestorContainer;
var nodeParent = container.parentNode;
console.log(nodeParent);
});
</script>
It checks the current selection (the text that is selected by the cursor from start to beginning). In your case, i.e. at keypress, the selection will be the same from start the end, being the actual position of the cursor.
The Selection can contain multiple ranges (all kinds of nodes, including text nodes), depending on what the user selected on the page. Here we are only interested in the first one, where the cursor is, so we do getRangeAt(0).
It then looks at the common ancestor container, being the text that is currently being edited. The commonAncestorContainer is the node in which the Range is situated. In this case it is either the text node with the text "1st" or the text node with the text "2nd".
Now that we have the Text Node that contains the first Range of the current Selection, we can see its parentNode, being the current div.
Does that do the trick?

Javascript - insert copied text without containing box

I'm currently learning Javascript and face the following problem. I want to copy the text of a readonly html textarea and use the following code:
function copy_text ()
{
var text = document.getElementById("textbox");
var range = document.createRange();
range.selectNode(text);
window.getSelection().addRange(range);
document.execCommand("copy");
}
Actually it works, but there is a little quirk. If I insert the copied text to another input field, for example like the input line of a webbrowser, then the text appears perfectly fine as text. However, if I paste the text into Microsoft Word, the text appears in a box with two slides, one at the bottom and one at the left side. What is going on here?
You're selecting the entire node, which is a textarea, so that's what gets copied to the clipboard. Word is then pasting a textarea into the document.
If you just want the text of the textarea, just use its select method:
function copy_text() {
var text = document.getElementById("textbox");
text.select();
document.execCommand("copy");
}
document.getElementById("btn").addEventListener("click", copy_text, false);
<textarea id="textbox" readonly>Some example text</textarea>
<br><input type="button" id="btn" value="Copy">
select selects the contents of the textarea, not the textarea itself.

Set window selection from a previously saved selection object

If I have a selection object from a textarea (with a class of my-text-area) using window.getSelection(), if this selection loses focus (say if the user clicks on another input field), is there a way I can set this selection again programmatically?
I've tried doing something like this:
When I have focus:
var currentSelection = window.getSelection();
After I lose focus and want to set the selection again:
var range = currentSelection.getRangeAt(0);
range.selectNode($('.my-text-area')[0]);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
This seems to select everything in my textarea though, not just the small selected area initially.
Just found the excellent Rangy library, that contains a Selection Save and Restore module that does exactly this: https://github.com/timdown/rangy/wiki/Selection-Save-Restore-Module

How to set the cursor in the child of a contentEditable element?

I want to know how to set the cursor in the child of an editable element. I have a content editable DIV with a SPAN inside and I want to set the cursor in the SPAN when the DIV is clicked to prevent someone typing in the DIV.
<div class="custom-input" spellcheck="true" contenteditable="true">
"NOT HERE"
<span data-type="text">
"TYPE HERE"
<br>
</span>
</div>
I have tried to do this with .focus() in jQuery, and it works but it just highlights the SPAN and the cursor remains in the DIV.
I'm trying to make something like Facebook chat does. Facebook chat uses contenteditable elements for the chat input, and if you click anywhere in the chat box the cursor always is focused in a SPAN label that is used for the input.
I had to do this recently and the below is what I ended up with.
NOTE: This will not appear to work here or on jsFiddle due the sandboxing and whatnot. Run the code on your localhost or hosted server and you'll see it works.
$(document).ready(function() {
var $element = $('.type-here');
createCaretPlacer($element, false); // set cursor and select text
createCaretPlacer($element, true, true); // set cursor at start
createCaretPlacer($element, true, false); // set cursor at end
});
function createCaretPlacer($element, collapse, atStart) {
var el = $element[0]; // get the dom node of the given element
el.focus(); // focus to the element
// feature test to see which methods to use for given browser
if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") {
// handle real browsers (not IE)
var range = document.createRange(); // create a new range object
range.selectNodeContents(el); // add the contents of the given element to the range
if(collapse) range.collapse(atStart); // collapse the rage to either the first or last index based on "atStart" param
var sel = window.getSelection(); // Returns a Selection object representing the range of text selected by the user or the current position of the caret.
sel.removeAllRanges(); // removes all ranges from the selection, leaving the anchorNode and focusNode properties equal to null and leaving nothing selected.
sel.addRange(range); // add the range we created to the selection effectively setting the cursor position
}
else if (typeof document.body.createTextRange != "undefined") {
// handle IE
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
if(collapse) textRange.collapse(atStart);
textRange.select();
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="custom-input" spellcheck="true" contenteditable="true">
"NOT HERE"
<span data-type="text" class="type-here">
"TYPE HERE"
<br>
</span>
</div>

Categories