I need help with optimizing this small system that takes in a string and looks for any words that match the words stored in an array. The system should reprint the same string with the new words every time there was a match. However, it only changes after the first match currently.
Sample text:
his de is good
but his en is worse then nl
The result for the above is currently:
his Dutch is good
but his English is worse then nl
But the result I want to get is:
his Dutch is good
but his English is worse then Danish
So how can I fix the system to print the second result?
Here is my system in JSFIDDLE.
function check(string, wrapper) {
var terms = ['de', 'en', 'nl'];
var match = false;
for(var i=0;i<terms.length && !match;i++) {
if(string.indexOf(terms[i]) > -1) {
match = true;
var newString='';
wrapper.css("background", "#a1e4ff");
var matchString = string.substring(string.indexOf(terms[i]), (string.indexOf(terms[i])+terms[i].length));
var rx = RegExp("\\b" + matchString + "\\b", "g");
switch(matchString) {
case 'de':
newString = string.replace(rx, "Dutch");
break;
case 'en':
newString = string.replace(rx, "English");
break;
case 'nl':
newString = string.replace(rx, "Danish");
break;
default:
alert('no matches');
}
$(".corrections").append("<li>" + newString + "</li>");
}
}
}
$(document).ready(function() {
$('textarea').focusout(function() {
var x = $(this).val();
$('.orig-list').html(x.replace(/\n(?!>)/g, '<li>'));
});
$('#down').click(function() {
$('.orig-list li').each(function() {
var phrase = $(this).text();
var matchHighlight = $(this);
check(phrase, matchHighlight);
});
});
});
The main point is that you did not add <li> tag before the first item, and that is why you $('.orig-list li').each did not select it and that is why the string consisting of one line did not work. Change the $('.orig-list').html() code to
$('.orig-list').html("<li>" + x.replace(/\n(?!>)/g, '<li>'));
Besides, it will be much easier if you put the terms with replacements into a dictionary, and use it like
if (/en|de|nl/.test(string)) {
wrapper.css("background", "#a1e4ff");
newString = string.replace(/en|de|nl/g, function(x) {
return terms[x] || "";
});
$(".corrections").append("<li>" + newString + "</li>");
}
See the updated snippet below.
function check(string, wrapper) {
var terms = {'de':'German', 'en':'English', 'nl':'Dutch'};
if (/en|de|nl/.test(string)) {
wrapper.css("background", "#a1e4ff");
newString = string.replace(/en|de|nl/g, function(x) {
return terms[x] || "";
});
$(".corrections").append("<li>" + newString + "</li>");
}
}
$(document).ready(function() {
$('textarea').focusout(function() {
var x = $(this).val();
$('.orig-list').html("<li>" + x.replace(/\n(?!>)/g, '<li>'));
});
$('#down').click(function() {
$('.orig-list li').each(function() {
var phrase = $(this).text();
var matchHighlight = $(this);
check(phrase, matchHighlight);
});
});
});
span#down {
background: #4f5152;
width: 100px;
color: #fff;
display: block;
margin-top: 20px;
padding: 9px;
border-radius: 4px;
line-height: 1;
font-weight: 600;
cursor:pointer;
margin-bottom: 50px;
}
.receiver div {
border: 1px solid red;
width: 40%;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="content-wrapper">
<div class="receiver">
<textarea></textarea>
<span id="down">Generate List</span>
<div>
<h4>Generated List with unicode errors</h4>
<ol class="orig-list"></ol>
</div>
<div class="corrections-wrapper">
<h4>Corrected Names</h4>
<ol class="corrections"></ol>
</div>
</div>
</div>
Related
I am attempting to wrap every 20 chars in a new div container. I keep getting undefined I assume from the array results that do not exist yet. How can I wrap every 20 chars as the user types and reaches char 20, 40, 60,and 80 and place it into a div container with the max allowed chars being 80, and is there a better way of doing this than writing out the array groups manually by 20's.
function creaeTextField(clicked_id) {
var dropArea = document.getElementById('headarea');
var myArea = document.createElement('div');
var myAreaOuter = document.createElement('div');
myArea.className = "areaClass";
myAreaOuter.className = "areaClassOuter";
myArea.id = "areaClass";
myAreaOuter.id = "areaClassOuter";
myArea.contentEditable = "true";
if (clicked_id == 'text') {
myAreaOuter.appendChild(myArea);
dropArea.appendChild(myAreaOuter);
myArea.addEventListener("keydown", findLimitb);
myArea.addEventListener("keyup", findLimitb);
var style = window.getComputedStyle(myArea, null).getPropertyValue('font-size');
var fontSize = parseFloat(style);
function findLimitb() {
if (myArea.offsetHeight <= fontSize * 4) {
myArea.addEventListener("keydown", breaker);
} else {
if (event.keyCode === 8 || event.keyCode === 46 || event.keyCode === 37 || event.keyCode === 38 || event.keyCode === 39 || event.keyCode === 40) {
myArea.focus();
} else {
myArea.removeEventListener("keydown", breaker);
event.preventDefault();
myArea.style.height = fontSize * 4 + "px";
}
}
}
function breaker() {
var myAr = myArea.innerHTML.split("");
var divCon = document.createElement('div');
myArea.appendChild(divCon);
if (myArea.innerHTML.length > 20) {
divCon.innerHTML = myAr[0] + myAr[1] + myAr[2] + myAr[3] + myAr[4] + myAr[5] + myAr[6] + myAr[7] + myAr[8] + myAr[9] + myAr[10] + myAr[11] + myAr[12] + myAr[13] + myAr[14] + myAr[15] + myAr[16] + myAr[17] + myAr[18] + myAr[19] + myAr[20];
}
}
}
}
.headarea {
width: 100%;
height: 130px;
float: left;
}
.buttonStyle {
width: 60px;
height: 25px;
float: left;
}
.areaClassOuter {
float: left;
padding: 10px;
position: relative;
z-index: 29;
border: 1px #000000 solid;
}
.areaClass {
min-width: 100px;
max-width: 310px;
min-height: 60px;
max-height: 100px;
float: left;
padding: 7px;
position: relative;
z-index: 30;
border: 1px #000000 solid;
overflow: hidden;
white-space: pre-wrap;
word-wrap: break-word;
font-size: 24pt;
text-align: center;
}
<div class="headarea" id="headarea"></div>
<button class="buttonStyle" id="text" type="button" onclick="creaeTextField(this.id)"></button>
You could just listen for the keydown-event like you did in your question and then work with substring to get and remove the first part of the string. The first part can then be appended to an container and the rest of the string (in most cases only 1 char) can be set as content of the input-element.
you should also consider using textContent instead of innerHtml, so that the user is able input safely characters that are used by html.
let textOutput = document.getElementById('textOutput');
let textInput = document.getElementById('textInput');
let maxInputLength = 20;
let maxOutputElement = 4; // 4*20 = 80 Chars
textInput.addEventListener('keydown', function(event) {
if (textOutput.children.length >= maxOutputElement) {
event.preventDefault();
textInput.textContent = '';
}
let textChanged = false;
let text = textInput.textContent;
while (text.length >= maxInputLength) {
let firstPart = text.substring(0, maxInputLength);
let textElement = document.createElement('div');
textElement.textContent = firstPart;
textElement.contentEditable = true;
textElement.addEventListener('keyup', function(event) {
let editText = event.currentTarget.textContent;
if (editText.length >= maxInputLength) {
event.currentTarget.textContent = editText.substring(0, maxInputLength);
}
});
textOutput.appendChild(textElement);
text = text.substring(maxInputLength);
textChanged = true;
}
if (textChanged) textInput.textContent = text;
});
#textOutput div {
display: inline-block;
margin: 5px;
background-color: #EEE;
}
#textInput {
display: block;
width: 160px;
height: 20px;
background: #EEE;
border: 1px dashed #CCC;
}
<div id="textOutput"></div>
<div id="textInput" contenteditable="true"></div>
You could split the string into spaces and use a modulus to see when 20 items have been reached.
This makes the code independent and allows you to change the number of words allowed in each string.
We split on the space and then iterate over the words, we reconstruct the string but push the results into an array when we reach the 'paragraphlength'. You then end up with an array of strings that are 20 words long.
There are some edge cases that aren't covered here and may not be an issue depending on your use case. For example, what if a user just puts illegible characters in, ect
//The wording as a string
const words = "this is a really long set of words that need to be broken down into a paragraphs array that has lots of words that need to be broken down into a nicer structure for users to easier consume. We split on the space and then iterate over the words, we reconstruct the string but push the results into an array when we reach the 'paragraphlength'";
const getParagraphs = (words, paragraphLength) => {
let paragraphs =[];
words.split(" ").reduce((memo, word, index) => {
if(index > 0 && index % paragraphLength === 0)
{
paragraphs.push(memo);
memo = "";
}
return memo + " " + word;
}, "");
return paragraphs
}
const paragraphs = getParagraphs(words, 20);
console.log("original string ===>", words);
console.log("paragraphs array ===>", paragraphs);
//below is for display purposes only
let results = document.getElementById('results');
paragraphs.forEach(paragraph => {
const para = document.createElement("p");
const node = document.createTextNode(paragraph);
para.appendChild(node);
results.appendChild(para);
});
<div id="results">
</div>
I'm trying to write a function that changes the color of a student grades strings according to a number inside of this string.
How to ask JavaScript to look for a number inside a string and also implement an if statement?
// courses grades function
function passStudentInfo(studentID) {
$.get("https://college.com/api/getCourses/" + studentID, function (data) {
if (!data || !data.length) {
console.log = 'not getting courses';
return;
}
data.forEach(function(element) {
document.getElementById('grade').innerHTML += element.courseName + ": " + element.examMark + "<br />" + "<hr>";
//this is the function I'm trying to write
function colors() {
let allGrades = document.getElementById('grade');
for (i = 0; i < allGrades.length; i++ ) {
if ( ?? < 60) {
allGrades[i].innerHTML.style.color = 'red';
} else if ( ?? >= 60 && x < 80 ) {
allGrades[i].innerHTML.style.color = 'yellow';
}
else {
allGrades[i].innerHTML.style.color = 'green';
}
}
}
colors()
//this is my html page
<h1 class="green">Your Grades</h1>
<h2>A summary of Your achievements</h2>
<div class="container achieve">
<p id="grade"></p>
</div>
.achieve {
border: 2px solid #3d3e5b;
margin-bottom: 2rem;
padding-top: 1rem;
}
.achieve p {
font-weight: 600;
font-size: 1.5;
}
I expect the output of red color string for a sentence containing a grade less than 60, yellow for 60-80 and green for above 80.
Example of one way to get it done, checking the examMark within the forEach and applying an appropriate class to a surrounding element in each row.
var data = [
{courseName: 'Math', examMark: 76.4},
{courseName: 'Science', examMark: 66.3},
{courseName: 'Spanish', examMark: 98.6}
];
data.forEach(function(element) {
// figure out what color the grade gives
var gradeColor = 'red';
if (element.examMark >= 80) {
gradeColor = 'green';
} else if (element.examMark >= 60) {
gradeColor = 'yellow';
}
document.getElementById('grade').innerHTML += "<div class='" + gradeColor + "'>" + element.courseName + ": " + element.examMark + "</div>";
});
.red {
color: red;
}
.yellow {
color: yellow;
}
.green {
color: green;
}
<div id='grade'></div>
for your If statements, try using >= or <=. it worked for me when my if statements weren't working correctly. Replace all of your < with <= or >=.
I have been trying to figure out the issue with using regular expressions to ignore lines starting with double hyphens and count the single lines as separate and double hyphenated lines counted as separately and display outside the text area.
I have tried and got success with counting the each line but ignoring hyphens and counting I have no idea on how can I do that using regular expressions.
On another side, I want to append the code inside of a span Item buts it's removing the text of item element.
Here is my code and sample Image.
$(document).ready(function(){
var items = $('#items');
var groups = $('#groups');
$('#ingredients_list').keydown(function(e) {
newLines = $(this).val().split("\n").length;
items.text(newLines);
});
});
.ingredients__section {
padding: 20px;
width: 100%;
box-sizing: border-box;
}
.ingredients__section textarea {
width: 100%;
}
.ingredients__section h2 {
color:#0433a7;
margin-bottom: 20px;
}
.ingredients__header {
display: table;
width: 100%;
table-layout:fixed;
}
.ingredients__title { display: table-cell; }
.ingredients__countinfo { display: table-cell; text-align:right; }
.item-count,
.group-count { padding: 5px 15px; background-color:#e4ebef; margin-left: 5px; font-size: 14px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="ingredients__section">
<div class="ingredients__header">
<div class="ingredients__title"><h2>INGREDIENTS</h2></div>
<div class="ingredients__countinfo">
<span class="group-count" id="groups">Groups:</span>
<span class="item-count" id="items">Items:</span>
</div>
</div>
<form>
<textarea id="ingredients_list" rows="15"></textarea><br />
</form>
</div>
Initialize counters
var groupsCount = 0;
var itemsCount = 0;
Get array of entered text
var arrayOfItems = $(this).val().split("\n");
Run for all elements in array and check first two symbols. If it is -- then groupsCount++ else itemsCount++
for (var i=0; i<arrayOfItems.length; i++) {
if (arrayOfItems[i][0] === '-' && arrayOfItems[i][1] === '-') {
groupsCount += 1;
itemsCount -= 1;
groups.text("Groups: " + groupsCount);
} else {
itemsCount += 1;
items.text("Items: " + itemsCount);
}
}
$(document).ready(function(){
var items = $('#items');
var groups = $('#groups');
$('#ingredients_list').keypress(function(e) {
var groupsCount = 0;
var itemsCount = 0;
var arrayOfItems = $(this).val().split("\n");
for (var i=0; i<arrayOfItems.length; i++) {
if (arrayOfItems[i] != '') {
if (arrayOfItems[i][0] === '-' && arrayOfItems[i][1] === '-') {
groupsCount += 1;
groups.text("Groups: " + groupsCount);
} else {
itemsCount += 1;
items.text("Items: " + itemsCount);
}
} else {
groups.text("Groups: " + groupsCount);
items.text("Items: " + itemsCount);
}
}
});
$(document).mousedown(function (e) {
var groupsCount = 0;
var itemsCount = 0;
var arrayOfItems = $('#ingredients_list').val().split("\n");
for (var i=0; i<arrayOfItems.length; i++) {
if (arrayOfItems[i] != '') {
if (arrayOfItems[i][0] === '-' && arrayOfItems[i][1] === '-') {
groupsCount += 1;
groups.text("Groups: " + groupsCount);
} else {
itemsCount += 1;
items.text("Items: " + itemsCount);
}
} else {
groups.text("Groups: " + groupsCount);
items.text("Items: " + itemsCount);
}
}
});
});
.ingredients__section {
padding: 20px;
width: 100%;
box-sizing: border-box;
}
.ingredients__section textarea {
width: 100%;
}
.ingredients__section h2 {
color:#0433a7;
margin-bottom: 20px;
}
.ingredients__header {
display: table;
width: 100%;
table-layout:fixed;
}
.ingredients__title { display: table-cell; }
.ingredients__countinfo { display: table-cell; text-align:right; }
.item-count,
.group-count { padding: 5px 15px; background-color:#e4ebef; margin-left: 5px; font-size: 14px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="ingredients__section">
<div class="ingredients__header">
<div class="ingredients__title"><h2>INGREDIENTS</h2></div>
<div class="ingredients__countinfo">
<span class="group-count" id="groups">Groups:</span>
<span class="item-count" id="items">Items:</span>
</div>
</div>
<form>
<textarea id="ingredients_list" rows="15"></textarea><br />
</form>
</div>
Its good, But I have seen that if you type a word with double hyphens -- or without the same --, it is adding +1 to both groupItems and listItems which are not what you are looking for.
It means if you start group name with -- it should add +1 to groups instead of items, so here is the small change in your code that might help you to fix.
$(document).ready(function(){
var items = $('#items');
var groups = $('#groups');
$('#ingredients_list').keypress(function(e) {
var groupsCount = 0;
var itemsCount = 0;
var arrayOfItems = $(this).val().split("\n");
console.log(arrayOfItems);
for (var i=0; i<arrayOfItems.length; i++) {
if (arrayOfItems[i][0] === '-' && arrayOfItems[i][1] === '-') {
groupsCount += 1;
groups.text("Groups: " + groupsCount);
} if (arrayOfItems[i][0] === '.'){ // I have given '.' here in single quote, you can add regex what you are looking for like numbers, letters, or expressions that start with.
itemsCount += 1;
items.text("Items: " + itemsCount);
}
}
});
});
I'm using a word count textarea jquery script and I'm trying to work out how to update the word count onload to e.g. 2 from the preset text area "this example" to start with.
(it currently shows 0)
I can set the focus on it and move the cursor but I don't know how to update it initially, any ideas?
HTML
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="text/javascript" src="js/jQuery.textareaCounter.c.js"></script>
<textarea id="txtarea" name="text" rows="7" cols="120">this example</textarea>
<script type="text/javascript">
$("textarea").textareaCounter();
document.getElementById('txtarea').focus();
var val = document.getElementById('txtarea').value; //store the value of the element
document.getElementById('txtarea').value = ''; //clear the value of the element
document.getElementById('txtarea').value = val; //set that value back. so cursor is at end.
</script>
jquery.min.js contains:-
(function(a){a.fn.textareaCounter=function(b){var c={limit:10};var b=a.extend(c,b);return this.each(function(){var c,d,e,f;c=a(this);c.after('<span style="font-size: 11px; clear: both; margin-top: 3px; display: block;" id="counter-text">Max. '+b.limit+" words</span>");c.keyup(function(){d=c.val();if(d===""){e=0}else{e=a.trim(d).split(" ").length}if(e>b.limit){a("#counter-text").html('<span style="color: #DD0000;">0 words left</span>');f=a.trim(d).split(" ",b.limit);f=f.join(" ");a(this).val(f)}else{a("#counter-text").html(b.limit-e+" words left")}})})}})(jQuery)
jQuery.textareaCounter.c.js contains:-
(function(a) {
a.fn.textareaCounter = function(b) {
var c = {
limit: 10
};
var b = a.extend(c, b);
return this.each(function() {
var c, d, e, f;
c = a(this);
c.after('<span style="font-size: 11px; clear: both; margin-top: 3px; display: block;" id="counter-text">' + "0 words</span>");
c.keyup(function() {
d = c.val();
if (d === "") {
e = 0
} else {
e = d.replace(/^[\s,.;]+/, "").replace(/[\s,.;]+$/, "").split(/[\s,.;]+/).length;
}
if (e > b.limit) {
// a("#counter-text").html('<span style="color: #DD0000;">0 words left</span>');
// f=a.trim(d).split(" ",b.limit);
// f=f.join(" ");
// a(this).val(f)
a("#counter-text").html(e + " words ")
document.myform.numwords.value = e;
} else {
a("#counter-text").html(e + " words ")
document.myform.numwords.value = e;
}
});
});
}
})
(jQuery)
This is what I changed in jQuery.textareaCounter.c.js:
var initCount = c.text().split(" ").length;
if(initCount < 2){initCount=0;}
c.after('<span style="font-size: 11px; clear: both; margin-top: 3px; display: block;" id="counter-text">' + initCount +" words</span>");
Here is the JSFiddle demo
You can fire a keyup event during initialization to trigger the update:
<script type="text/javascript">
$("textarea").textareaCounter();
document.getElementById('txtarea').focus();
var val = document.getElementById('txtarea').value; //store the value of the element
document.getElementById('txtarea').value = ''; //clear the value of the element
document.getElementById('txtarea').value = val; //set that value back. so cursor is at end.
// init word count
$("textarea")[0].dispatchEvent(new Event('keyup'));
</script>
//Function to show maxlength of Textarea
document.getElementById("textArea").addEventListener("keyup",function(){
var textAreaValue = document.getElementById("textArea").value;
var show = (250 - (textAreaValue.length));
document.getElementById('count').innerHTML = show + " characters remaining";
});
I'm making a syntax highlighter in Javascript and HTML. It works fine at the moment but I think it's really inefficient because I have an interval with a time of 0 which runs a function that loops through all of the characters in the text area and then inserts them into a div behind the text area to provide the syntax highlighting.
I think my lexer is really bad too, but at the moment I'm more concerned with the function running like a million times a second that loops through every character in the text area each time.
Can anyone please think of a more efficient way to do this?
There doesn't seem to be any performance problems but I'm not sure if it will work on a lower-powered machine because I don't want it to crash the browser tab because I want to have several on a page so I need it to be as efficient as possible.
I understand that its annoying to be given loads of code and asked to help, but I thought for the problem to be easiest to debug you'd need the entire code.
Here you code:
<html>
<head>
<title>My Syntax Highlighter</title>
<style type="text/css">
#container {
width: 100%;
height: 100%;
position: relative;
padding: 0px;
}
#code {
width: 100%;
height: 100%;
outline:none;
position: absolute;
background-color: transparent;
border: none;
font-family: Courier;
font-size: 22px;
color: rgba(0,0,0,.2) !important;
}
#codeb {
width: 100%;
height: 100%;
position: absolute;
font-family: Courier;
font-size: 22px;
padding: 2px 2px;
color: #000;
}
.keyword {
/*font-weight: bold;*/
color: #E42D82;
}
.string {
/*font-weight: bold;*/
color: #0086b3;
}
</style>
<script type="text/javascript">
function u() {
var code = document.getElementById("code");
var codeb = document.getElementById("codeb");
var c = "";
var tok = "";
var cc = 0;
var t = "";
var takeaway = 0;
var stringStarted = false;
var string = "";
for (var i = 0; i < code.value.length; i++) {
tok += code.value[i];
c += code.value[i];
cc++;
if (tok == "print") {
t = "<span class=\"keyword\">print</span>";
takeaway += 5;
c = c.substring(0, cc - takeaway) + t + c.substring(cc + t.length);
cc += t.length;
tok = "";
} else if (tok == "var") {
t = "<span class=\"keyword\">var</span>";
takeaway += 3;
c = c.substring(0, cc-takeaway) + t + c.substring(cc + t.length);
cc += t.length;
tok = "";
} else if (tok == "\"") {
tok = "";
if (stringStarted == false) {
stringStarted = true;
string += "\"";
} else {
stringStarted = false;
string += "\"";
t = "<span class=\"string\">" + string + "</span>";
takeaway += string.length;
c = c.substring(0, cc-takeaway) + t + c.substring(cc + t.length);
cc += t.length;
tok = "";
string = "";
}
tok = "";
} else if (tok == " ") {
if (stringStarted == true) {
string += " ";
}
c+= "";
tok = "";
} else {
if (stringStarted == true) {
string += code.value[i];
tok = "";
}
}
codeb.innerHTML = c;
//console.log("test");
};
//alert(string);
if (code.value == "") {
codeb.innerHTML = "";
}
clearI(setInterval(function(){ u(); }, 0));
}
function clearI(interval) {
clearInterval(interval);
}
var interval = setInterval(function(){ u(); }, 0);
</script>
</head>
<body>
<div id="container">
<div id="codeb"></div>
<textarea id="code" autofocus></textarea>
</div>
</body>
</html>