First Image - Initial Text when typing something in Facebook Chat Box
Second Image - The moment you hit space it converts to this!
I have seen in developer console it is not the input box at all, they are using span and all with background-image to do it but how to actually combine it completely, to avoid any clutter whatsoever. I am attaching a link of codepen of what I did when pressing Enter key. But not able to do for the Space Bar. Codepen Link Anything you guys can help. Thanks in advance. NOTE :- No external libraries and would prefer Javascript answer.
var emojiContainer = {
":)" : "https://static.xx.fbcdn.net/images/emoji.php/v9/zeb/2/16/1f642.png",
"<3" : "https://static.xx.fbcdn.net/images/emoji.php/v9/zed/2/16/2764.png"
};
var chatDetailText = document.getElementById('chatDetailText');
chatDetailText.addEventListener("keypress", function (e) {
console.log("Inside keypress event")
var textEntered = chatDetailText.value;
var keyPressed = e.which || e.keyCode;
console.log(emojiContainer[this.value])
if (keyPressed === 13){
console.log("inside keypress 13")
if(emojiContainer[this.value]){
console.log("inside value found of enter")
var emojiImg = document.createElement("img");
emojiImg.src = emojiContainer[this.value];
document.getElementById('enterPressed').appendChild(emojiImg);
document.getElementById('chatDetailText').value = '';
}else{
console.log("value not found of enter")
var divChatDetail = document.createElement('div');
/*chatDetailSeperator.className = "aClassName";*/ //To add class name for div
divChatDetail.innerHTML = this.value;
document.getElementById('enterPressed').appendChild(divChatDetail);
document.getElementById('chatDetailText').value = '';
}
}
}, false);
You can use HTML5 ContentEditable attribute for div.
here is just an example. Take care of cert position etc.
var emojiContainer = {
":)" : "https://static.xx.fbcdn.net/images/emoji.php/v9/zeb/2/16/1f642.png",
"<3" : "https://static.xx.fbcdn.net/images/emoji.php/v9/zed/2/16/2764.png"
};
var chatDetailText = document.getElementById('chatDetailText');
chatDetailText.addEventListener("keypress", function (e) {
console.log("Inside keypress event")
var textEntered = chatDetailText.innerHTML;
var keyPressed = e.which || e.keyCode;
console.log(keyPressed)
if (keyPressed === 32){
var last_word = textEntered.split(" ");
last_word = last_word[last_word.length-1];
console.log(last_word);
if(emojiContainer[last_word]){
console.log("inside value found of enter")
var emojiImg = "<img src='"+emojiContainer[last_word]+"' >";
textEntered = textEntered.replace(last_word, emojiImg)
chatDetailText.innerHTML = textEntered;
}
}
}, false);
<div id="enterPressed"></div>
<div contenteditable="true" id="chatDetailText" >edit this</div>
I got it done, thanks to Zeeshan for helping me with contenteditable. Do update if you have any improvisations.
var emojiContainer = {
":)" : "https://static.xx.fbcdn.net/images/emoji.php/v9/zeb/2/16/1f642.png",
"<3" : "https://static.xx.fbcdn.net/images/emoji.php/v9/zed/2/16/2764.png"
};
var chatDetailText = document.getElementById('chatDetailText');
chatDetailText.addEventListener("keydown", function (e) {
//to perform the action based on pressing space bar (32) or enter (13).
var keydown = e.which || e.keyCode;
//to get the pointer location and modify to place to the end if needed
var selectionInfo = getSelectionTextInfo(this);
//to get the complete text extered by the user.
var input = chatDetailText.innerHTML;
//to cover the cases in which user enters <3 and gets interpreted as <
var textEntered = decodeHtml(input);
//To split the text entered and to get the location of the emoji for conversion
var last_word = textEntered.split(/\s{1}/);
//After splitting contains the emoji and now can be accessed.
last_word = last_word[last_word.length-1];
//space bar is pressed and the smiley is just inserted
if (keydown === 32 && selectionInfo.atEnd){
//if the emoji is available in our database, it'll replace the same using the Facebook url which is currently used.
if(emojiContainer[last_word]){
var emojiImg = "<img src='"+emojiContainer[last_word]+"' >";
textEntered = textEntered.replace(last_word, emojiImg);
chatDetailText.innerHTML = textEntered;
elemIterate = document.getElementById('chatDetailText');//This is the element to move the caret to the end of
setEndOfContenteditable(elemIterate);
}
//Enter key is pressed after typing the emoji
}else if (keydown === 13) {
// To avoid extra line insertion in div.
e.preventDefault();
//if the emoji is available in our database, it'll replace the same using the Facebook url which is currently used.
if(emojiContainer[last_word]){
var emojiImg = document.createElement("img");
emojiImg.src = emojiContainer[last_word];
var spanChatElement = document.createElement("span");
var precedingChatContent = textEntered.split(/\s{1}/);
precedingChatContent.pop(); //To pop the last smiley found
if(precedingChatContent.length !=0){
precedingChatContent = precedingChatContent.join(" ");
spanChatElement.innerHTML = precedingChatContent;
document.getElementById('enterPressed').appendChild(spanChatElement);
}
document.getElementById('enterPressed').appendChild(emojiImg);
document.getElementById('chatDetailText').innerHTML = '';
}else{
//If no Smiley found, just the plain text it'll automatically display the text in a div
var divChatElement = document.createElement('div');
//chatDetailSeperator.className = "aClassName"; To add class name for div
divChatElement.innerHTML = textEntered;
document.getElementById('enterPressed').appendChild(divChatElement);
document.getElementById('chatDetailText').innerHTML = '';
}
}
}, false);
function decodeHtml(html) {
var textAreaElement = document.createElement("textarea");
textAreaElement.innerHTML = html;
return textAreaElement.value;
}
//To send the pointer to the end of the div.
function setEndOfContenteditable(contentEditableElement){
var range,selection;
if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
{
range = document.createRange();//Create a range (a range is like the selection but invisible)
range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
selection = window.getSelection();//get the selection object (allows you to change selection)
selection.removeAllRanges();//remove any selections already made
selection.addRange(range);//make the range you have just created the visible selection
}
else if(document.selection)//IE 8 and lower
{
range = document.body.createTextRange();//Create a range (a range is like the selection but invisible)
range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
range.select();//Select the range (make it the visible selection
}
}
//To check if it is at the end.
function getSelectionTextInfo(contentEditableElement) {
var atEnd = false;
var selectionRange, testRange;
if (window.getSelection) {
var windowSelection = window.getSelection();
if (windowSelection.rangeCount) {
selectionRange = windowSelection.getRangeAt(0);
testRange = selectionRange.cloneRange();
testRange.selectNodeContents(contentEditableElement);
testRange.setStart(selectionRange.endContainer, selectionRange.endOffset);
atEnd = (testRange.toString() == "");
}
}else if (document.selection && document.selection.type != "Control") {
selectionRange = document.selection.createRange();
testRange = selectionRange.duplicate();
testRange.moveToElementText(contentEditableElement);
testRange.setEndPoint("StartToEnd", selectionRange);
atEnd = (testRange.text == "");
}
return { atEnd: atEnd };
}
You just need to change the line if (keyPressed === 13){ to if (keyPressed === 32){ in your codepen link. And to stop that from posting the comment, you just need to add another function for if (keypressed === 13).
Related
when my webpage load then on console array of id showing
But when the whole page load array of id disappear
enter code here1: https://i.stack.imgur.com/AsdWq.png
And my main problem in this image
[enter image description here][2][2]: https://i.stack.imgur.com/0Ci3I.png
that is my code
so how to save id in var $write = $(":input").on('focus').map((i, el) => el.id).get();
and when its save in the $write function so where the cursor the value go in it.
But in it typing in one input box gets text on all input box. I want typing in one and value get in one whyen cursor update
like when my mouse cursor in itemNo_1 so the value go in that input box and when itemNo_2 so the value go in that input box.
please help me.
$(function(){
var $write = $(":input").on('focus').map((i, el) => el.id).get();
shift = false,
capslock = false;
backspace = false;
console.log(Object.values($write));
$('#keyboard li').click(function(){
var $this = $(this),
character = $this.html();
// Shift keys
if ($this.hasClass('left-shift') || $this.hasClass('right-shift')) {
$('.letter').toggleClass('uppercase');
$('.symbol span').toggle();
shift = (shift === true) ? false : true;
capslock = false;
backspace = false;
return false;
}
// Caps lock
if ($this.hasClass('capslock')) {
$('.letter').toggleClass('uppercase');
capslock = true;
return false;
}
// backspace lock
if ($this.hasClass('backspace')) {
$('.letter').toggleClass('uppercase');
capslock = true;
return false;
}
// Delete
if ($this.hasClass('delete')) {
var html = $write.html(),
txt = html.substr(0, html.length - 1);
$write.html(txt);
$write.autocomplete("search", txt);
return false;
}
// Delete
// Special characters
if ($this.hasClass('symbol')) character = $('span:visible', $this).html();
if ($this.hasClass('space')) character = ' ';
if ($this.hasClass('tab')) character = "\t";
if ($this.hasClass('return')) character = "\n";
// Uppercase letter
if ($this.hasClass('uppercase')) character = character.toUpperCase();
// Remove shift once a key is clicked.
if (shift === true) {
$('.symbol span').toggle();
if (capslock === false) $('.letter').toggleClass('uppercase');
shift = false;
}
//console.log("DO IT ", character);
// Add the character
$write.val($write.val() + character);
$write.html(txt);
$write.autocomplete("search", txt);
});
});
rest code is
here
$(function () {
var write = write();
write.init("keyboard");
//first input focus
var $firstInput = $(":input").first().focus();
write.currentElement = $firstInput;
write.currentElementCursorPosition = 0;
});
An input field #chatInput needs to be be focused when clicking on a container element #text EXCEPT if text inside that element was (highlighted via either double click or mouse selection)
// what I got so far which is incomplete
$('#text').on('click', function (e) {
$('#chatInput').focus();
});
Fiddle: https://jsfiddle.net/xhykmtwy/4/
You may want to consider the solution below, which checks if some text is selected in the text element after the click event:
$('#text').click(function () {
var container = this;
setTimeout(function () {
var selectedElement = null;
var selectedText = null;
if (window.getSelection) {
// For modern browsers
var selection = window.getSelection();
if (selection) {
selectedText = selection.toString();
if (selection.anchorNode) {
selectedElement = selection.anchorNode.parentNode;
}
}
}
else if (document.selection && document.selection.type === "Text") {
// For IE < 9
var selection = document.selection;
selectedText = selection.createRange().text;
}
if (!(selectedText && selectedText.length > 0) || (selectedElement !== container && !$(container).has(selectedElement))) {
setTimeout(function () { $('#chatInput').focus(); }, 0);
}
}, 0);
});
According to my tests, it works in IE (including IE7), Firefox and Chrome. The only exception is the double-click in IE, which does not select the text. You can see the result in this jsfiddle.
The calls to setTimeout ensures that all the selection processing has been done, especially when clicking on the selected text to deselect it.
Credits:
I used the method proposed by Eineki in How can I get the element in which highlighted text is in? to check if the text element contains the selected text.
The code for processing the selection in IE < 9 was found in Tim Down's answer to the post Get the Highlighted/Selected text.
A bit longer than I initially thought a solution could be but here's what I got:
var mouseDownStart = 0,
lastKeyupTime = 0;
function processKeyDown() {
if (!mouseDownStart) {
mouseDownStart = Date.now();
}
}
function processKeyUp() {
var now = Date.now(),
isDoubleClick = lastKeyupTime && now - lastKeyupTime < 500;
isHighliting = now - mouseDownStart > 150
lastKeyupTime = now;
mouseDownStart = 0;
return {
isDoubleClick: isDoubleClick,
isHighliting: isHighliting
}
}
$('#text').on('mousedown', function (e) {
processKeyDown();
});
$('#text').on('mouseup', function (e) {
var data = processKeyUp();
if (data.isDoubleClick || data.isHighliting) return;
$('#chatInput').focus();
});
Updated fiddle: https://jsfiddle.net/xhykmtwy/1/
I have this in my contenteditable div. Whenever I type #something, then type space, I would like to bold that word instantly in that div.
E.g.
This is my message. #lol. I would like to bold the hashtag.
Below is the code I have
<div id="message" name="message" contenteditable="true"></div>
$('#message').keyup(function(e){
var len = $(this).val().length;
if ($(this).val().substring(length - 1, 1) == '#') {
}
//detect space
if(e.keyCode == 32){
}
});
I am using jquery. How do i go about doing so?
Using contenteditable = "true" may be tricky, but this is a possible solution:
The text is bold when a word is preceded by #
Example: hello #world, this is a #sample
HTML:
<div id="divEditable" contenteditable="true"></div>
JavaScript: jsbin.com/zisote
We are going to split the code, but actually it is wrapped in an IIFE
/*** Cached private variables ***/
var _break = /<br\s?\/?>$/g,
_rxword = /(#[\w]+)$/gm,
_rxboldDown = /<\/b>$/gm,
_rxboldUp = /<\/b>(?!<br\s?\/?>)([\w]+)(?:<br\s?\/?>)?$/,
_rxline = /(<br\s?\/?>)+(?!<b>)(<\/b>$)+/g;
/*** Handles the event when a key is pressed ***/
$(document).on("keydown.editable", '.divEditable', function (e) {
//fixes firefox NodeContent which ends with <br>
var html = this.innerHTML.replace(_break, ""),
key = (e.which || e.keyCode),
dom = $(this);
//space key was pressed
if (key == 32 || key == 13) {
//finds the # followed by a word
if (_rxword.test(dom.text()))
dom.data("_newText", html.replace(_rxword, "<b>$1</b> "));
//finds the end of bold text
if (_rxboldDown.test(html))
dom.data("_newText", html + " ");
}
//prevents the bold NodeContent to be cached
dom.attr("contenteditable", false).attr("contenteditable", true);
});
/*** Handles the event when the key is released ***/
$(document).on("keyup.editable", '.divEditable', function (e) {
var dom = $(this),
newText = dom.data("_newText"),
innerHtml = this.innerHTML,
html;
//resets the NodeContent
if (!dom.text().length || innerHtml == '<br>') {
dom.empty();
return false;
}
//fixes firefox issue when text must follow with bold
if (!newText && _rxboldUp.test(innerHtml))
newText = innerHtml.replace(_rxboldUp, "$1</b>");
//fixes firefox issue when space key is rendered as <br>
if (!newText && _rxline.test(innerHtml)) html = innerHtml;
else if (newText && _rxline.test(newText)) html = newText;
if (html) newText = html.replace(_rxline, "$2$1");
if (newText && newText.length) {
dom.html(newText).removeData("_newText");
placeCaretAtEnd(this);
}
});
/*** Sets the caret position at end of NodeContent ***/
function placeCaretAtEnd (dom) {
var range, sel;
dom.focus();
if (typeof window.getSelection != "undefined"
&& typeof document.createRange != "undefined") {
range = document.createRange();
range.selectNodeContents(dom);
range.collapse(false);
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (typeof document.body.createTextRange != "undefined") {
//this handles the text selection in IE
range = document.body.createTextRange();
range.moveToElementText(dom);
range.collapse(false);
range.select();
}
}
You can play with live code here: jsbin.com/zisote
Here is a sample. An editable div is not a good idea though. Try to change this. A textarea maybe is better...
http://jsfiddle.net/blackjim/h9dck/5/
function makeBold(match, p1, p2, p3, offset, string) {
return p1+'<b>' + p2 + '</b>'+p3;
};
$('#message').keyup(function (e) {
var $this = $(this);
//detect space
if (e.keyCode == 32) {
var innerHtml = $this.html();
innerHtml = innerHtml.replace(/(.*[\s|($nbsp;)])(#\w+)(.*)/g, makeBold);
if(innerHtml !== $this.html()){
$this.html(innerHtml)
.focus();
}
}
});
I would like to find out and keep track of the 'line number' (rows) of the cursor in a textarea. (The 'bigger picture' is to parse the text on the line every time a new line is created/modified/selected, if of course the text was not pasted in. This saves parsing the whole text un-necessarily at set intervals.)
There are a couple of posts on StackOverflow however none of them specifically answer my question, most questions are for cursor position in pixels or displaying lines numbers besides the textarea.
My attempt is below, it works fine when starting at line 1 and not leaving the textarea. It fails when clicking out of the textarea and back onto it on a different line. It also fails when pasting text into it because the starting line is not 1.
My JavaScript knowledge is pretty limited.
<html>
<head>
<title>DEVBug</title>
<script type="text/javascript">
var total_lines = 1; // total lines
var current_line = 1; // current line
var old_line_count;
// main editor function
function code(e) {
// declare some needed vars
var keypress_code = e.keyCode; // key press
var editor = document.getElementById('editor'); // the editor textarea
var source_code = editor.value; // contents of the editor
// work out how many lines we have used in total
var lines = source_code.split("\n");
var total_lines = lines.length;
// do stuff on key presses
if (keypress_code == '13') { // Enter
current_line += 1;
} else if (keypress_code == '8') { // Backspace
if (old_line_count > total_lines) { current_line -= 1; }
} else if (keypress_code == '38') { // Up
if (total_lines > 1 && current_line > 1) { current_line -= 1; }
} else if (keypress_code == '40') { // Down
if (total_lines > 1 && current_line < total_lines) { current_line += 1; }
} else {
//document.getElementById('keycodes').innerHTML += keypress_code;
}
// for some reason chrome doesn't enter a newline char on enter
// you have to press enter and then an additional key for \n to appear
// making the total_lines counter lag.
if (total_lines < current_line) { total_lines += 1 };
// putput the data
document.getElementById('total_lines').innerHTML = "Total lines: " + total_lines;
document.getElementById('current_line').innerHTML = "Current line: " + current_line;
// save the old line count for comparison on next run
old_line_count = total_lines;
}
</script>
</head>
<body>
<textarea id="editor" rows="30" cols="100" value="" onkeydown="code(event)"></textarea>
<div id="total_lines"></div>
<div id="current_line"></div>
</body>
</html>
You would want to use selectionStart to do this.
<textarea onkeyup="getLineNumber(this, document.getElementById('lineNo'));" onmouseup="this.onkeyup();"></textarea>
<div id="lineNo"></div>
<script>
function getLineNumber(textarea, indicator) {
indicator.innerHTML = textarea.value.substr(0, textarea.selectionStart).split("\n").length;
}
</script>
This works when you change the cursor position using the mouse as well.
This is tough because of word wrap. It's a very easy thing to count the number of line breaks present, but what happens when the new row is because of word wrap? To solve this problem, it's useful to create a mirror (credit: github.com/jevin). Here's the idea:
Create a mirror of the textarea
Send the content from the beginning of the textarea to the cursor to the mirror
Use the height of the mirror to extract the current row
On JSFiddle
jQuery.fn.trackRows = function() {
return this.each(function() {
var ininitalHeight, currentRow, firstIteration = true;
var createMirror = function(textarea) {
jQuery(textarea).after('<div class="autogrow-textarea-mirror"></div>');
return jQuery(textarea).next('.autogrow-textarea-mirror')[0];
}
var sendContentToMirror = function (textarea) {
mirror.innerHTML = String(textarea.value.substring(0,textarea.selectionStart-1)).replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br />') + '.<br/>.';
calculateRowNumber();
}
var growTextarea = function () {
sendContentToMirror(this);
}
var calculateRowNumber = function () {
if(firstIteration){
ininitalHeight = $(mirror).height();
currentHeight = ininitalHeight;
firstIteration = false;
} else {
currentHeight = $(mirror).height();
}
// Assume that textarea.rows = 2 initially
currentRow = currentHeight/(ininitalHeight/2) - 1;
//remove tracker in production
$('.tracker').html('Current row: ' + currentRow);
}
// Create a mirror
var mirror = createMirror(this);
// Style the mirror
mirror.style.display = 'none';
mirror.style.wordWrap = 'break-word';
mirror.style.whiteSpace = 'normal';
mirror.style.padding = jQuery(this).css('padding');
mirror.style.width = jQuery(this).css('width');
mirror.style.fontFamily = jQuery(this).css('font-family');
mirror.style.fontSize = jQuery(this).css('font-size');
mirror.style.lineHeight = jQuery(this).css('line-height');
// Style the textarea
this.style.overflow = "hidden";
this.style.minHeight = this.rows+"em";
var ininitalHeight = $(mirror).height();
// Bind the textarea's event
this.onkeyup = growTextarea;
// Fire the event for text already present
// sendContentToMirror(this);
});
};
$(function(){
$('textarea').trackRows();
});
This worked for me:
function getLineNumber(textarea) {
return textarea.value.substr(0, textarea.selectionStart) // get the substring of the textarea's value up to the cursor position
.split("\n") // split on explicit line breaks
.map((line) => 1 + Math.floor(line.length / textarea.cols)) // count the number of line wraps for each split and add 1 for the explicit line break
.reduce((a, b) => a + b, 0); // add all of these together
};
Inspired by colab's answer as a starting point, this includes the number of word wraps without having to introduce a mirror (as in bradbarbin's answer).
The trick is simply counting how many times the number of columns textarea.cols can divide the length of each segment between explicit line breaks \n.
Note: this starts counting at 1.
I have a function that displays a countdown next to a text field for the number of characters in the field (think twitter)
<script language="javascript" type="text/javascript">
function countDown(control, maxLen, counter, typeName) {
var len = control.value.length;
var txt = control.value;
var span = document.getElementById(counter);
span.style.display = '';
span.innerHTML = (maxLen - len);
if (len >= (maxLen - 10)) {
span.style.color = 'red';
} else {
span.style.color = '';
}
}
</script>
And the next field down takes a comma separated value. Example:
tomato, apple, orange, pear
and I'd like to limit that list to 5 things (and 4 separating commas).
How can I make a similar function that counts down for the number of commas in the input.
I got this started, but it's not changing the value in the span.
my Javascript
<script language="javascript" type="text/javascript">
var max = 5;
function commaDown(area,ticker){
// our text in the textarea element
var txt = area.val();
// how many commas we have?
var commas = txt.split(",").length;
var span = document.getElementById(ticker);
//var commas ++;
if(commas > max) {
// grab last comma position
var lastComma = txt.lastIndexOf(",");
// delete all after last comma position
area.val(txt.substring(0, lastComma));
//it was count with + 1, so let's take that down
commas--;
}
if (txt == '') {
commas = 0;
}
// show message
span.innerHTML = (max-commas);
}
</script>
and my html (I think the problem lies here)
<input id="choices" type="text" name="choices" class="text medium" onkeyup="commaDown('choices','limit');"/> <span id="limit">5</span><br/>
Any ideas?
Something like this (assuming you have a text field with id csv)
document.getElementById('csv').onkeydown = function(e){
if (!e) var e = window.event;
var list = this.value.split(',');
if (list.length == 5 && e.keyCode == '188' )
{
// what to do if more than 5 commas(,) are entered
// i put a red border and make it go after 1 second
this.style.borderColor ='red';
var _this = this;
setTimeout(function(){
_this.style.borderColor='';
_this.disabled=false;
},1000);
// return false to forbid the surplus comma to be entered in the field
return false;
}
}
example at http://www.jsfiddle.net/gaby/YEHXf/2/
Updated Answer
You seem to have mixed parts of jQuery in your code and that causes the script to fail
var max = 5;
function commaDown(_area, _ticker){
var area = document.getElementById(_area);
// our text in the textarea element
var txt = area.value;
// how many commas we have?
var commas = txt.split(",").length;
var span = document.getElementById(_ticker);
//var commas ++;
if(commas > max) {
// grab last comma position
var lastComma = txt.lastIndexOf(",");
// delete all after last comma position
area.value = txt.substring(0, lastComma);
//it was count with + 1, so let's take that down
commas--;
}
if (txt == '') {
commas = 0;
}
// show message
span.innerHTML = (max-commas);
}
live example at http://jsfiddle.net/z4KRd/
here is a solution:
test: http://jsbin.com/ulobu3
code: http://jsbin.com/ulobu3/edit
if you never used jsBin before, it is very easy, on the left side you have the javascript code (like if it was in your HTML code, and in your right side you have the html code.
and you just need to add /edit to the end of a jsbin url to edit that code, and save any new revisions to that code.
I added jQuery framework to make the example faster to code.