Word count is wrong when adding new line in contenteditable - javascript

I count the words in a contenteditable. I split it using spaces. The problem comes when you enter a new line. It doesn’t count the word you’re currently writing on the new line until you add a space.
On top of that, in the following example if you split the example text into two lines, it will “eat up” one word when you do that:
http://jsfiddle.net/MrbUK/
I’m guessing this issue exists because between HTML elements there are no spaces:
<div>some things</div><div>are cool</div> its string would be “some thingsare cool”.
Here’s the code that I have:
function wordCount() {
var content_text = $('#post_content').text(),
char_count = content_text.length,
word_count = 0;
// if no characters, words = 0
if (char_count != 0)
word_count = content_text.replace(/[^\w ]/g, "").split(/\s+/).length;
$('.word_count').html(word_count + " words • " + char_count + " characters");
}
I tried replacing some HTML tags:
word_count = content_text.replace(/ /g, " ").replace(/<div>/g, "<p>").replace(/<\/div>/g, "</p>").replace(/<\/p><p>/g, " ").split(/\s+/).length;
without any luck. I need to discard whether it’s a <p> or <div> and some browsers add when merging lines together.
Any ideas? Thanks!
EDIT:
Thanks to Jefferson below for his clever method, I managed to solve this. For some reason I have to do -1 on the word_count to display the correct number of words:
function wordCount() {
var content_div = $('#post_content'),
content_text,
char_count = content_div.text().length,
word_count = 0;
// if no characters, words = 0
if (char_count != 0)
content_div.children().each(function(index, el) {
content_text += $(el).text()+"\n";
});
// if there is content, splits the text at spaces (else displays 0 words)
if (typeof content_text !== "undefined")
word_count = content_text.split(/\s+/).length - 1;
$('.word_count').html(word_count + " words • " + char_count + " characters");
}

You can use this:
$("#post_content").children().each(function(index, el){buffer += $(el).text()+"\n"})
This way you iterate by all elements inside your div and get only the text, put a "\n" between them.

Jefferson's answer was great, and it helped me with this exact same issue.
The problem I encountered was the contents of my contenteditable div was not entirely wrapped in HTML tags.
For example, my div contained the following HTML code:
This is my first line<div>This is my second line</div>
By using $.children(), it was ignoring the first line and only returning a word count of 5. To get round this I used $.contents() instead. Modified code is below:
$("#post_content").contents().each(function(index, el){buffer += $(el).text()+"\n"})
This returned a line count of 10.
Apologies for adding this as an answer and not as a comment to Jefferson's answer, however my reputation is too low to allow me to do that. I felt it was worth pointing the above out though.

Related

Adding space to fill array length

I am working with a javascript program that needs to be formatted a certain way. Basically, I need to have each section of information from an array be a set length, for example 12 characters long, and no more than that.
The problem I am running into comes when a value in the array is NOT 12 characters long. If I have a value that is less than the 12 characters the remaining character allotment needs to be filled with blank spaces.
The length of each section of information varies in size and is not always 12. How can I add X number of blank spaces, should the length not meet the maximum requirement, for each section?
This is where I am at with adding space:
str = str + new Array(str.length).join(' ');
I am pretty sure what I have above is wrong but I believe I am on the right track with the .join function. Any ideas?
EDIT: I was asked to show a wanted outcome. It is a bit complicated because this javascript is being run out of a web report tool and not out of something like Visual Studio so its not traditional JS.
The outcome expected should look something like:
Sample Image
So as shown above the data is in one line, cutting off longer strings of information or filling in blank spaces if its too short for the "column" to keep that nice even look.
try this code and leverage the wonders of the map function:
let say your array is:
var myArr = ["123456789012", "12345678901", "123"];
now just apply this function
myArr.map(function(item){ //evalueate each item inside the array
var strLength = item.length; //apply this function to each item
if (strLength < 12){
return item + ' '.repeat(12-item.length) //add the extra spaces as needed
} else {
return item; // return the item because it's length is 12 or +
}
})
What you are looking for is the ' '.repeat(x) - where x is the times you want to repeat the string you have set, it could be '*'.repeat(2) and you would get '**', if you want to understand more about it look at the docs
depending on which version of javascript, this might work:
if (str.length < 12) str += ' '.repeat(12 - str.length);
Not exactly sure how you're setup -- but something like the following will accept an array and return another array with all its values being 12 characters in length.
var array = ['Test', 'Testing', 'Tested', 'This is not a Test'];
var adjustedArray = correctLength(array, 12);
function correctLength(array, length) {
array.map(function(v, i) {
if (array[i].length < length) {
array[i] += Array((length+1) - array[i].length).join('_');
}
// might not need this if values are already no greater than 12
array[i] = array[i].substring(0, length);
});
return array;
}
console.log(adjustedArray);

How to fiil paragraph with content?

I want to create a paragraph that contains: name, cost (like "3.66$"). But the problem is that I want to fill the space in dots ("......") and I dont know how.
I take the values (name & cost) from database and each name is diffrent so I can not think about way that makes the space be filled with dots.
For instance, the rows:
"apple 20.58$"
"banana and ice cream 4.99$"
need to be:
"apple ...................... 20.58$"
"banana and ice cream ........ 4.99$"
this is the code:
for (var i = 0; i < data.d.length; i++) {
$(document).ready(function () {
$("#ShowMenu").append(
"<p style='text-align: left;margin: 0px;'>" +
"<span style='font-size: large;font-weight: bold;float:left;'>" + data.d[i].title + "</span>" +
"<span style='float:right;'>" + data.d[i].cost + "</span>" +
"</p>"
);
});
}
If you are replacing a value (and not a regular expression), only the
first instance of the value will be replaced. To replace all
occurrences of a specified value, use the global (g) modifier (see
"More Examples" below).
Souce.
The problem is that replace replaces the first found occurrence. You can do it like this:
function replaceAll(input, what, withWhat) {
while (input.indexOf(what) !== 0) {
input = input.replace(what, withWhat);
}
return input;
}
But this is not performant and not elegant. To improve it, you need to use regular expressions:
function replaceAll(input, what, withWhat) {
return input.replace(new RegExp(what, 'g'), withWhat);
}
and call replaceAll. If you want this to make it more general, you can do something like this:
String.prototype.replaceAll = replaceAll;
EDIT:
The answer above came from the assumption that the text is generated by Javascript. My assumption was wrong as can be seen from the comment section and the question edit. The real situation is that the spaces appear because of CSS styling with float.
A possible solution is to create an image of a dot character and another image with the desired background for the other contents. Set the background image of the paragraph to be the dot image with repeat and the background image of the span to be the colored image.
Another possible solution is not to use float, but to write the dots using javascript until the width is the desired one. This involves tag measuring and is slow.
You can use function like this:
function getReceiptItem(name, cost, maxLength) {
var dotsLength = maxLength - name.length - cost.length - '$'.length;
if (dotsLength < 0) {
name = name.substring(0, name.length + dotsLength);
dotsLength = 0;
}
return name + Array(dotsLength).join('.') + cost + '$';
}
Full example
Don`t forget set monospace font for receipt, like:
* {
font-family: 'monospace';
}

regexp looping and logic in javascript

Not certain if this can be done in regexp under javascript, but thought it would be interesting to see if it is possible.
So thought I would clean up a piece of html to remove most tags, literally just dropping them, so <H1><img><a href ....>. And that would be relatively simple (well, stole the basis from another post, thanks karim79 Remove HTML Tags in Javascript with Regex).
function(inString, maxlength, callback){
console.log("Sting is " + inString)
console.log("Its " + inString.length)
var regex = /(<([^>]+)>)/ig
var outString = inString.replace(regex, "");
console.log("No HTML sting " + outString);
if ( outString.length < maxlength){
callback(outString)
} else {
console.log("Lets cut first bit")
}
}
But then I started thinking, is there a way where I can control regex execution. So lets say that I want to keep certain tabs, like b,br,i and maybe change H1-6 to b. So in pseudo code, something like:
for ( var i in inString.regex.hits ) {
if ( hits[i] == H1 ) {
hits[i] = b;
}
}
The issue is that I want the text thats not HTML tags to stay as it is, and I want it to just cut out by default. One option would of course be to change the ones I want to keep. Say change <b> to [[b]], once that is done to all the ones of interest. Then put them back to <b> once all unknown have been removed. So like this (only for b, and not certain the code below would work):
function(inString, maxlength, callback){
console.log("Sting is " + inString)
console.log("Its " + inString.length)
var regex-remHTML = /(<([^>]+)>)/ig
var regex-hideB = /(<b>)/ig
var regex-showB = /([b])/ig
var outString = inString.replace(regex-hideB, "[b]");
outString = outString.replace(regex-remHTML, "");
outString = outString.replace(regex-showB, "<b>");
console.log("No HTML sting " + outString);
if ( outString.length < maxlength){
callback(outString)
} else {
console.log("Lets cut first bit")
}
}
But would it be possible to be smarter, writing cod ethat says here is a peice of HTML tag, run this code against the match.
As Tim Biegeleisen sai in its comment, maybe a better solution could be using a parser instead of a Regex...
By the way, if you want to control what is going to be changed by the regex you can pass a callback to the String.prototype.replace:
var input = "<div><h1>CIAO Bello</h1></div>";
var output = input.replace(/(<([^>]+)>)/gi, (val) => {
if(val.indexOf("div") > -1) {
return "";
}
return val;
})
;
console.log("output", output);

Cut off last characters from html paragraph with JS

How to cut off last 20 characters from a normal html paragraph with a classname which contains two words? For instance <p class="sentence slice">Last twenty characters have to be chopped off!!!</p>
I know there's a slice method in JS https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice but how to implement this onto the website?
If you are interested in using .slice, all you need to do is this:
JavaScript
$("#clickme").click(function () {
var text = $("p").text();
text = (text.length > 20) ? text.slice(0,-20) : text;
// important to check whether the text is longer than 20 characters
$("p").text(text); // update the text
})
HTML
<p>Lots and lots and lots and lots and lots of text12345678901234567890</p>
<button id="clickme">remove last 20 characters</button>
fiddle
You can do:
$("p.sentence.slice").text(function() {
var text = $(this).text(),
length = text.length;
if (length > 20)
return text.substr(0, (length - 20));
else return text;
});
Since you are mentioning the following, let's assume that you don't know the actual name of the classes; you just know that the paragraph tag that you want to modify, definitely contains two classes.
(...) with a classname which contains two words?
Using tymeJV's solution (using substr), the following will only modify a paragraph tag which contains exactly two classes, and its length (in characters) is greater than 20.
$('p').each(function () {
var classes = $.trim($(this).attr('class'));
var count = classes.split(' ');
var text = $(this).text();
if(count.length === 2 && text.length > 20) {
$(this).text(text.substr(0, (text.length - 20)));
}
});
Demo: http://jsfiddle.net/EP47z/

parse a textarea in substrings based on line breaks in Javascript

I have a text area that I need to parse. Each new line needs to be pulled out and an operation needs to be performed on it. After the operation is done the operation needs to be run on the next line. This is what I have at the moment. I know the indexOf search won't work because it's searching character by character.
function convertLines()
{
trueinput = document.getElementById(8).value; //get users input
length = trueinput.length; //getting the length of the user input
newinput=trueinput; //I know this looks silly but I'm using all of this later
userinput=newinput;
multiplelines=false; //this is a check to see if I should use the if statement later
for (var i = 0; i < length; i++) //loop threw each char in user input
{
teste=newinput.charAt(i); //gets the char at position i
if (teste.indexOf("<br />") != -1) //checks if the char is the same
{
//line break is found parse it out and run operation on it
userinput = newinput.substring(0,i+1);
submitinput(userinput);
newinput=newinput.substring(i+1);
multiplelines=true;
}
}
if (multiplelines==false)
submitinput(userinput);
}
So for the most part it is taking the userinput. If it has multiply lines it will run threw each line and seperatly and run submitinput. If you guys can help me I'd be eternally thankful. If you have any questions please ask
Line breaks within the value of a textarea are represented by line break characters (\r\n in most browsers, \n in IE and Opera) rather than an HTML <br> element, so you can get the individual lines by normalizing the line breaks to \n and then calling the split() method on the textarea's value. Here is a utility function that calls a function for every line of a textarea value:
function actOnEachLine(textarea, func) {
var lines = textarea.value.replace(/\r\n/g, "\n").split("\n");
var newLines, i;
// Use the map() method of Array where available
if (typeof lines.map != "undefined") {
newLines = lines.map(func);
} else {
newLines = [];
i = lines.length;
while (i--) {
newLines[i] = func(lines[i]);
}
}
textarea.value = newLines.join("\r\n");
}
var textarea = document.getElementById("your_textarea");
actOnEachLine(textarea, function(line) {
return "[START]" + line + "[END]";
});
If user is using enter key to go to next line in your text-area you can write,
var textAreaString = textarea.value;
textAreaString = textAreaString.replace(/\n\r/g,"<br />");
textAreaString = textAreaString.replace(/\n/g,"<br />");
textarea.value = textAreaString;
to simplify the answers, here is another approach..
var texta = document.getElementById('w3review');
function conv (el_id, dest_id){
var dest = document.getElementById(dest_id),
texta = document.getElementById(el_id),
val = texta.value.replace(/\n\r/g,"<br />").replace(/\n/g,"<br />");
dest.innerHTML = val;
}
<textarea id="targetted_textarea" rows="6" cols="50">
At https://www.a2z-eco-sys.com you will get more than what you need for your website, with less cost:
1) Advanced CMS (built on top of Wagtail-cms).
2) Multi-site management made easy.
3) Collectionized Media and file assets.
4) ...etc, to know more, visit: https://www.a2z-eco-sys.com
</textarea>
<button onclick="conv('targetted_textarea','destination')" id="convert">Convert</button>
<div id="destination">Had not been fetched yet click convert to fetch ..!</div>

Categories

Resources