Validate letters in real time and manipulate them - javascript

I've a div with contenteditable and I'm trying to manipulate the array of this div to check if each letter written inside it, is the same as the letter on another text, based on the index.
The validation is done, I can check it, my problem is that, I need to change the letter color to red, if the letter don't validate. And I'm having trouble inserting a span with the class that I want.
Anyone have a sugestion?
Code follows:
timer.addEventListener('secondsUpdated', function (e) {
$('#countdown .values').html(timer.getTimeValues().toString(['minutes', 'seconds']));
if ($('.true-textarea').contents().get(0)) {
var textResult = $(".true-textarea").contents().get(0).nodeValue;
var textSize = textResult().length - 1;
}
$(".true-textarea").on("keypress", function(e) {
var c = String.fromCharCode(e.which);
e.preventDefault();
$(".true-textarea").html("");
if (c != textFake[textSize]) {
$(".true-textarea").addClass("red-border");
cls = "color-red";
} else {
cls = "color-purple";
$(".true-textarea").removeClass("red-border");
}
console.log('result', textResult);
console.log('size', textSize)
res += "<span class='"+cls+"'>"+c+"</span>";
cls = "";
$(".true-textarea").html(res);
});
});

So after hours trying to figure this out I came up if this code.
Used some examples that I saw in around the internet, fixed some problems, and it's working with the following code:
function focusAtEnd(el) {
el.focus();
if (typeof window.getSelection != "undefined"
&& typeof document.createRange != "undefined") {
var range = document.createRange();
range.selectNodeContents(el);
range.collapse(false);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (typeof document.body.createTextRange != "undefined") {
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.collapse(false);
textRange.select();
}
}
$('.true-textarea').unbind();
$('.true-textarea').focus();
timer.start({countdown: true, startValues: {seconds: 60}});
$('#countdown .values').html(timer.getTimeValues().toString(['minutes', 'seconds']));
var res = "", cls = "";
textResult.on("keypress", function(e){
textResult.find('br').remove();
var c = String.fromCharCode(e.which);
e.preventDefault();
res = textResult.html();
textSize = textResult.text().length;
if (c === textFake[textSize]) {
cls = "color-purple";
} else {
cls = "color-red";
}
res += "<span class='"+cls+"'>"+c+"</span>";
var del = false;
var lastFocused;
cls = "";
textResult.html(res);
focusAtEnd($(this).get(0));
})

Related

Javascript - Prevent whole text selection on triple click and make selected only single word

When we double click on single word then browser select that word, when we triple click on single word then browser select that whole single line or whole paragraph.
Here, I want to prevent selecting all words on triple click and change to select only single word
I tried with this code
function clearSelection() {
if(document.selection && document.selection.empty) {
document.selection.empty();
} else if(window.getSelection) {
var sel = window.getSelection();
sel.removeAllRanges();
}
}
This works for you?jsfiddle
I edit your fiddle.
document.querySelector('div').addEventListener('click', function (evt) {
var o = this,
ot = this.textContent;
if (evt.detail >= 3) {
clearSelection();
}
});
function clearSelection() {
if(document.selection && document.selection.empty) {
document.selection.empty();
} else if(window.getSelection) {
var sel = window.getSelection();
sel.removeAllRanges();
}
}
Here's my fork: http://jsfiddle.net/kr2t0bpw/1/
It captures the selected word on the second click and saves the offsets. On third click it clears the selection and creates a new one with the previous saved offset.
var throttle = false;
var sel = window.getSelection();
var selStart = 0;
var selEnd = 0;
document.querySelector('div').addEventListener('click', function (evt) {
if (!throttle && evt.detail === 2) {
selStart = sel.anchorOffset;
selEnd = sel.focusOffset;
}
if (!throttle && evt.detail === 3) {
var node = this.firstChild;
sel.removeAllRanges();
throttle = true;
var range = document.createRange();
range.setStart(node, selStart);
range.setEnd(node, selEnd)
sel.removeAllRanges();
sel.addRange(range);
}
});
this is old and i cant add a comment, but for the answer of #kbariotis, you need to set throttle to false at the end or it will just work once.
var throttle = false;
var sel = window.getSelection();
var selStart = 0;
var selEnd = 0;
document.querySelector('div').addEventListener('click', function (evt) {
if (!throttle && evt.detail === 2) {
selStart = sel.anchorOffset;
selEnd = sel.focusOffset;
}
if (!throttle && evt.detail === 3) {
var node = this.firstChild;
sel.removeAllRanges();
throttle = true;
var range = document.createRange();
range.setStart(node, selStart);
range.setEnd(node, selEnd)
sel.removeAllRanges();
sel.addRange(range);
}
throttle = false;
});

Change selected text via javascript

window.addEventListener("keydown", function(e){
/*
keyCode: 8
keyIdentifier: "U+0008"
*/
if(e.keyCode === 16 && getSelectionText() != "") {
e.preventDefault();
replaceSelectedText(strcon(getSelectionText()));
}
});
function getSelectionText() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
return text;
}
function strcon(givenString) {
var b = '';
var a = givenString;
for (i = 0; i < a.length; i++) {
if (a.charCodeAt(i) >= 65 && a.charCodeAt(i) <= 90) {
b = b + a.charAt(i).toLowerCase();
}
else
b = b + a.charAt(i).toUpperCase();
}
return b;
}
function replaceSelectedText(replacementText) {
var sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(replacementText));
}
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
range.text = replacementText;
}
}
The code I have right now seems to change the appearance of the actual text instead of actually changing it. For example, when I'm on Facebook and I press the certain key, the text seems to have changed but then when I press enter, the text goes back to what it was before.
I believe the issue is with the function replaceSelectedText but I'm not sure how to fix it.
Any ideas?
No JQuery please.
https://jsfiddle.net/1rvz3696/
You have to get your textarea element to replace the value in it. This is how your replaceSelectedText function should look like,
function replaceSelectedText(text) {
var txtArea = document.getElementById('myTextArea');
if (txtArea.selectionStart != undefined) {
var startPos = txtArea.selectionStart;
var endPos = txtArea.selectionEnd;
selectedText = txtArea.value.substring(startPos, endPos);
txtArea.value = txtArea.value.slice(0, startPos) + text + txtArea.value.slice(endPos);
}
}
And here's the Fiddle.
Without specific id, you can replace txtArea to this.
var txtArea = document.activeElement;
And another Fiddle

Can I change the HTML of the selected text?

Can we change the HTML or its attributes of the selected part of the web page using javascript?
For example,
There is a random web page:(A part of it is shown)
with HTML as
...<p>Sample paragraph</p>..
It is possible to get the HTML of the selected text which has already been answered here.
But, is it possible for me change the html of the selected text? Like, add a class or id attribute to the paragraph tag.
The jQuery wrapselection plugin sounds like what you're looking for http://archive.plugins.jquery.com/project/wrapSelection . What you're asking for is not directly possible though, the plugin works by adding in extra nodes around the surrounding text which may not be 100% reliable (particularly in IE6-8)
Here is a working example without a plugin.
http://jsfiddle.net/9HTPw/2/
function getSel() {
var sel = null;
if (
typeof document.selection != "undefined" && document.selection
&& document.selection.type == "Text") {
sel = document.selection;
} else if (
window.getSelection && window.getSelection().rangeCount > 0) {
sel = window.getSelection();
}
return sel;
}
var getSelectionStart = (function () {
function createRangeFromSel(sel) {
var rng = null;
if (sel.createRange) {
rng = sel.createRange();
} else if (sel.getRangeAt) {
rng = sel.getRangeAt(0);
if (rng.toString() == "") rng = null;
}
return rng;
}
return function (el) {
var sel = getSel(),
rng, r2, i = -1;
if (sel) {
rng = createRangeFromSel(sel);
if (rng) {
if (rng.parentElement) {
if (rng.parentElement() == el) {
r2 = document.body.createTextRange();
r2.moveToElementText(el);
r2.collapse(true);
r2.setEndPoint("EndToStart", rng);
i = r2.text.length;
}
} else {
if ( rng.startContainer && rng.endContainer
&& rng.startContainer == rng.endContainer
&& rng.startContainer == rng.commonAncestorContainer
&& rng.commonAncestorContainer.parentNode == el) {
//make sure your DIV does not have any inner element,
//otherwise more code is required in order to filter
//text nodes and count chars
i = rng.startOffset;
}
}
}
}
return i;
};
})();
$("#content").on('mousedown', function () {
$("#content").html(content)
});
var content = $("#content").html();
$("#content").on('mouseup', function () {
var start = getSelectionStart(this);
var len = getSel().toString().length;
$(this).html(
content.substr(0, start) +
'<span style=\"background-color: yellow;\">' +
content.substr(start, len) +
'</span>' +
content.substr(Number(start) + Number(len), content.toString().length));
});
References:
http://bytes.com/topic/javascript/answers/153164-return-selectionstart-div

How to insert text into the textarea at the current cursor position?

I would like to create a simple function that adds text into a text area at the user's cursor position. It needs to be a clean function. Just the basics. I can figure out the rest.
Use selectionStart/selectionEnd properties of the input element (works for <textarea> as well)
function insertAtCursor(myField, myValue) {
//IE support
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
//MOZILLA and others
else if (myField.selectionStart || myField.selectionStart == '0') {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)
+ myValue
+ myField.value.substring(endPos, myField.value.length);
} else {
myField.value += myValue;
}
}
This snippet could help you with it in a few lines of jQuery 1.9+: http://jsfiddle.net/4MBUG/2/
$('input[type=button]').on('click', function() {
var cursorPos = $('#text').prop('selectionStart');
var v = $('#text').val();
var textBefore = v.substring(0, cursorPos);
var textAfter = v.substring(cursorPos, v.length);
$('#text').val(textBefore + $(this).val() + textAfter);
});
New answer:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setRangeText
I'm not sure about the browser support for this though.
Tested in Chrome 81.
function typeInTextarea(newText, el = document.activeElement) {
const [start, end] = [el.selectionStart, el.selectionEnd];
el.setRangeText(newText, start, end, 'select');
}
document.getElementById("input").onkeydown = e => {
if (e.key === "Enter") typeInTextarea("lol");
}
<input id="input" />
<br/><br/>
<div>Press Enter to insert "lol" at caret.</div>
<div>It'll replace a selection with the given text.</div>
Old answer:
A pure JS modification of Erik Pukinskis' answer:
function typeInTextarea(newText, el = document.activeElement) {
const start = el.selectionStart
const end = el.selectionEnd
const text = el.value
const before = text.substring(0, start)
const after = text.substring(end, text.length)
el.value = (before + newText + after)
el.selectionStart = el.selectionEnd = start + newText.length
el.focus()
}
document.getElementById("input").onkeydown = e => {
if (e.key === "Enter") typeInTextarea("lol");
}
<input id="input" />
<br/><br/>
<div>Press Enter to insert "lol" at caret.</div>
Tested in Chrome 47, 81, and Firefox 76.
If you want to change the value of the currently selected text while you're typing in the same field (for an autocomplete or similar effect), pass document.activeElement as the first parameter.
It's not the most elegant way to do this, but it's pretty simple.
Example usages:
typeInTextarea('hello');
typeInTextarea('haha', document.getElementById('some-id'));
For the sake of proper Javascript
HTMLTextAreaElement.prototype.insertAtCaret = function (text) {
text = text || '';
if (document.selection) {
// IE
this.focus();
var sel = document.selection.createRange();
sel.text = text;
} else if (this.selectionStart || this.selectionStart === 0) {
// Others
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
this.value = this.value.substring(0, startPos) +
text +
this.value.substring(endPos, this.value.length);
this.selectionStart = startPos + text.length;
this.selectionEnd = startPos + text.length;
} else {
this.value += text;
}
};
A simple solution that works on firefox, chrome, opera, safari and edge but probably won't work on old IE browsers.
var target = document.getElementById("mytextarea_id")
if (target.setRangeText) {
//if setRangeText function is supported by current browser
target.setRangeText(data)
} else {
target.focus()
document.execCommand('insertText', false /*no UI*/, data);
}
setRangeText function allow you to replace current selection with the provided text or if no selection then insert the text at cursor position. It's only supported by firefox as far as I know.
For other browsers there is "insertText" command which only affect the html element currently focused and has same behavior as setRangeText
Inspired partially by this article
I like simple javascript, and I usually have jQuery around. Here's what I came up with, based off mparkuk's:
function typeInTextarea(el, newText) {
var start = el.prop("selectionStart")
var end = el.prop("selectionEnd")
var text = el.val()
var before = text.substring(0, start)
var after = text.substring(end, text.length)
el.val(before + newText + after)
el[0].selectionStart = el[0].selectionEnd = start + newText.length
el.focus()
}
$("button").on("click", function() {
typeInTextarea($("textarea"), "some text")
return false
})
Here's a demo: http://codepen.io/erikpukinskis/pen/EjaaMY?editors=101
Rab's answer works great, but not for Microsoft Edge, so I added a small adaptation for Edge as well:
https://jsfiddle.net/et9borp4/
function insertAtCursor(myField, myValue) {
//IE support
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
// Microsoft Edge
else if(window.navigator.userAgent.indexOf("Edge") > -1) {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)+ myValue
+ myField.value.substring(endPos, myField.value.length);
var pos = startPos + myValue.length;
myField.focus();
myField.setSelectionRange(pos, pos);
}
//MOZILLA and others
else if (myField.selectionStart || myField.selectionStart == '0') {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)
+ myValue
+ myField.value.substring(endPos, myField.value.length);
} else {
myField.value += myValue;
}
}
function insertAtCaret(text) {
const textarea = document.querySelector('textarea')
textarea.setRangeText(
text,
textarea.selectionStart,
textarea.selectionEnd,
'end'
)
}
setInterval(() => insertAtCaret('Hello'), 3000)
<textarea cols="60">Stack Overflow Stack Exchange Starbucks Coffee</textarea>
If the user does not touch the input after text is inserted, the 'input' event is never triggered, and the value attribute will not reflect the change. Therefore it is important to trigger the input event after programmatically inserting text. Focusing the field is not enough.
The following is a copy of Snorvarg's answer with an input trigger at the end:
function insertAtCursor(myField, myValue) {
//IE support
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
// Microsoft Edge
else if(window.navigator.userAgent.indexOf("Edge") > -1) {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)+ myValue
+ myField.value.substring(endPos, myField.value.length);
var pos = startPos + myValue.length;
myField.focus();
myField.setSelectionRange(pos, pos);
}
//MOZILLA and others
else if (myField.selectionStart || myField.selectionStart == '0') {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)
+ myValue
+ myField.value.substring(endPos, myField.value.length);
} else {
myField.value += myValue;
}
triggerEvent(myField,'input');
}
function triggerEvent(el, type){
if ('createEvent' in document) {
// modern browsers, IE9+
var e = document.createEvent('HTMLEvents');
e.initEvent(type, false, true);
el.dispatchEvent(e);
} else {
// IE 8
var e = document.createEventObject();
e.eventType = type;
el.fireEvent('on'+e.eventType, e);
}
}
Credit to plainjs.com for the triggerEvent function
More about the oninput event at w3schools.com
I discovered this while creating an emoji-picker for a chat. If the user just select a few emojis and hit the "send" button, the input field is never touched by the user. When checking the value attribute it was always empty, even though the inserted emoji unicodes was visible in the input field. Turns out that if the user does not touch the field the 'input' event never fired and the solution was to trigger it like this. It took quite a while to figure this one out... hope it will save someone some time.
The code below is a TypeScript adaptation of the package https://github.com/grassator/insert-text-at-cursor by Dmitriy Kubyshkin.
/**
* Inserts the given text at the cursor. If the element contains a selection, the selection
* will be replaced by the text.
*/
export function insertText(input: HTMLTextAreaElement | HTMLInputElement, text: string) {
// Most of the used APIs only work with the field selected
input.focus();
// IE 8-10
if ((document as any).selection) {
const ieRange = (document as any).selection.createRange();
ieRange.text = text;
// Move cursor after the inserted text
ieRange.collapse(false /* to the end */);
ieRange.select();
return;
}
// Webkit + Edge
const isSuccess = document.execCommand("insertText", false, text);
if (!isSuccess) {
const start = input.selectionStart;
const end = input.selectionEnd;
// Firefox (non-standard method)
if (typeof (input as any).setRangeText === "function") {
(input as any).setRangeText(text);
} else {
if (canManipulateViaTextNodes(input)) {
const textNode = document.createTextNode(text);
let node = input.firstChild;
// If textarea is empty, just insert the text
if (!node) {
input.appendChild(textNode);
} else {
// Otherwise we need to find a nodes for start and end
let offset = 0;
let startNode = null;
let endNode = null;
// To make a change we just need a Range, not a Selection
const range = document.createRange();
while (node && (startNode === null || endNode === null)) {
const nodeLength = node.nodeValue.length;
// if start of the selection falls into current node
if (start >= offset && start <= offset + nodeLength) {
range.setStart((startNode = node), start - offset);
}
// if end of the selection falls into current node
if (end >= offset && end <= offset + nodeLength) {
range.setEnd((endNode = node), end - offset);
}
offset += nodeLength;
node = node.nextSibling;
}
// If there is some text selected, remove it as we should replace it
if (start !== end) {
range.deleteContents();
}
// Finally insert a new node. The browser will automatically
// split start and end nodes into two if necessary
range.insertNode(textNode);
}
} else {
// For the text input the only way is to replace the whole value :(
const value = input.value;
input.value = value.slice(0, start) + text + value.slice(end);
}
}
// Correct the cursor position to be at the end of the insertion
input.setSelectionRange(start + text.length, start + text.length);
// Notify any possible listeners of the change
const e = document.createEvent("UIEvent");
e.initEvent("input", true, false);
input.dispatchEvent(e);
}
}
function canManipulateViaTextNodes(input: HTMLTextAreaElement | HTMLInputElement) {
if (input.nodeName !== "TEXTAREA") {
return false;
}
let browserSupportsTextareaTextNodes;
if (typeof browserSupportsTextareaTextNodes === "undefined") {
const textarea = document.createElement("textarea");
textarea.value = "1";
browserSupportsTextareaTextNodes = !!textarea.firstChild;
}
return browserSupportsTextareaTextNodes;
}
Posting modified function for own reference. This example inserts a selected item from <select> object and puts the caret between the tags:
//Inserts a choicebox selected element into target by id
function insertTag(choicebox,id) {
var ta=document.getElementById(id)
ta.focus()
var ss=ta.selectionStart
var se=ta.selectionEnd
ta.value=ta.value.substring(0,ss)+'<'+choicebox.value+'>'+'</'+choicebox.value+'>'+ta.value.substring(se,ta.value.length)
ta.setSelectionRange(ss+choicebox.value.length+2,ss+choicebox.value.length+2)
}
/**
* Usage "foo baz".insertInside(4, 0, "bar ") ==> "foo bar baz"
*/
String.prototype.insertInside = function(start, delCount, newSubStr) {
return this.slice(0, start) + newSubStr + this.slice(start + Math.abs(delCount));
};
$('textarea').bind("keydown keypress", function (event) {
var val = $(this).val();
var indexOf = $(this).prop('selectionStart');
if(event.which === 13) {
val = val.insertInside(indexOf, 0, "<br>\n");
$(this).val(val);
$(this).focus();
}
});
Extending on Adriano's answer, we may also take cursor end into consideration which will make the "replace text" work
$('input[type=button]').on('click', function() {
var cursorStart = $('#text').prop('selectionStart');
var cursorEnd = $('#text').prop('selectionEnd');
var v = $('#text').val();
var textBefore = v.substring(0,cursorStart);
var textAfter = v.substring(cursorEnd);
$('#text').val(textBefore + $(this).val() + textAfter);
});
Changed it to getElementById(myField):
function insertAtCursor(myField, myValue) {
// IE support
if (document.selection) {
document.getElementById(myField).focus();
sel = document.selection.createRange();
sel.text = myValue;
}
// MOZILLA and others
else if (document.getElementById(myField).selectionStart || document.getElementById(myField).selectionStart == '0') {
var startPos = document.getElementById(myField).selectionStart;
var endPos = document.getElementById(myField).selectionEnd;
document.getElementById(myField).value =
document.getElementById(myField).value.substring(0, startPos)
+ myValue
+ document.getElementById(myField).value.substring(endPos, document.getElementById(myField).value.length);
} else {
document.getElementById(myField).value += myValue;
}
}

how to get selected text inside a textarea element by javascript?

I'm not familiar with such attributes,
can someone provide a simple demo?
I need it to be done without any libraries.
<script type="text/javascript">
function ShowSelectionInsideTextarea()
{
var textComponent = document.getElementById('mytextarea');
var selectedText;
// IE version
if (document.selection != undefined)
{
textComponent.focus();
var sel = document.selection.createRange();
selectedText = sel.text;
}
// Mozilla version
else if (textComponent.selectionStart != undefined)
{
var startPos = textComponent.selectionStart;
var endPos = textComponent.selectionEnd;
selectedText = textComponent.value.substring(startPos, endPos)
}
alert("You selected: " + selectedText);
}
</script>

Categories

Resources