I've got a product title which I'm splitting and inserting a linebreak using javascript like this:
<script>
function myFunction() {
var str = "How are you - doing today?";
var res = str.split("-").join('<br>');
document.getElementById("demo").innerHTML = res;
}
</script>
This works for most case scenarios, however in some cases I will need to remove the second line completely. So everything after the - will need to be removed. Only within that element though, so if I've got this for example
<h3>This is a product - title</h3>
the result should be
<h3>This is a product</h3>
Again this only needs to apply to elements with a certain class. Anybody got any idea ow to do this?
Why not us a simple replace,
string = string.replace(/-/g, '<br>');
or for complete deletion, take
string = string.replace(/-.*$/g, '');
Check className of the element:
function myFunction() {
const str = `How are you - doing today?`
const first = str.split(`-`)[0]
const all = str.split(`-`).join(`<br/>`)
const el = document.getElementById(`demo`)
const el.innerHTML = el.className === `any-name` ? first : all
}
Try this:
(function() {
// For splitted titles
var split = document.querySelectorAll(".dash-split");
var splits = [];
split.forEach(function(spl) {
splits.push(spl.innerHTML.split("-").join("<br>"));
});
console.log(splits); // Outputs ["This is <br> split!"]
// For removed titles
var removedEls = document.querySelectorAll(".dash-split");
var removed = [];
removedEls.forEach(function(rem) {
removed.push(rem.innerText.split("-")[0].trim());
});
console.log(removed); // Outputs ["This is"]
})();
<!DOCTYPE html>
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<div>
<h1 class="dash-split">This is - split!</h1>
<h1 class="dash-remove">This is - removed!</h1>
</div>
</body>
</html>
This should get you what you want, provided the script runs at the end of the document. For wrapping, it keys off of the class title-wrap.
<html>
<head></head>
<body>
<h3>This is a product - title</h3>
<h3 class="title title-wrap">This is a product - with a wrapped title</h3>
<h3>This is a product - with another title</h3>
<script>
(function() {
var titles = document.querySelectorAll('h3');
titles.forEach(function(o, i) {
var title = o.innerHTML;
if (/title-wrap/ig.test(o.className)) {
o.innerHTML = title.replace(/-/g, '<br />');
} else {
o.innerHTML = title.replace(/-.*$/g, '');
}
});
})();
</script>
</body>
</html>
Related
I've tried this
<html>
<head>
<title>None</title>
</head>
<body>
<p id="text">just some random text. random text</p>
<button type="button" onclick="strReplace();">Replace</button>
<script>
function strReplace(){
var myStr = document.getElementById("text");
var mySte = myStr.textContent;
console.log(mySte);
</script>
</body>
and I want this following outcome
just some random text
random text
You can use this regex to find and replace string without breaking html: /(?!<[^>]+)\.(?![^<]+>)/g
[myattr]
{
background-color: pink;
}
[myattr]:after
{
content: "this element's attribute is: " attr(myattr);
background-color: lightgreen;
margin: 1em;
}
p > span
{
background-color: lightblue;
}
<html>
<head>
<title>None</title>
</head>
<body>
<p id="text">just some. random text. <span myattr="text.with.dots">nested.html</span> end.
<span>i < 40. But i is also > 30. What are valid values of i?</span>
</p>
<button type="button" onclick="strReplace();">Replace</button>
<script>
function strReplace(){
var myStr = document.getElementById("text");
myStr.innerHTML = myStr.innerHTML.replace(/(?!<[^>]+)\.(?![^<]+>)/g, "<br>");
console.log(myStr.innerHTML);
}
</script>
</body>
To directly answer the question:
var outputHtml = inputText.replace(/\./g, '<br />');
The Javascript replace method will by default replace the first instance of something (the first . in this case), so the g regex modifier tells it to replace them all. The \. in the regex is because . is a special character in regexes. This will replace every dot in the text.
What about ellipsis?
This technique won't work well on text that contains literal ellipsis, like this:
Hello world...
If your text is likely to contain this, and you want that to be ignored, then the following regex is more appropriate:
/[^\.](\.)[^\.]/g
This'll match any . which is not surrounded by other .
var outputHtml = inputText.replace(/[^\.](\.)[^\.]/g, '<br />');
Handling HTML
In the question here, the input is actually coming from the DOM. We can't replace . on its innerHTML as it would replace content inside HTML tags as well. So, if your input text is coming from the DOM like this (and not, say, a textarea), then the safest route is to apply the replacement only to text nodes. That is done like this:
document.getElementById("start").addEventListener("click", () => {
var inputNode = document.getElementById("text");
replace(inputNode);
});
function replace(node) {
if(!node) {
return;
}
if (node.nodeName == '#text') {
// We've found a text node. Apply the regex to it now.
// Note that you can use either of the above regexes here.
var inputText = node.textContent;
var lines = inputText.split(/\./g);
if(lines.length > 1) {
// It had at least one dot in it.
// Swap in this new set, each with a <br /> between them.
var parent = node.parentNode;
var nextSibling = node.nextSibling;
parent.removeChild(node);
lines.forEach((line, i) => {
if(i != 0){
// insert the <br>
var br = document.createElement('br');
parent.insertBefore(br, nextSibling);
}
var textNode = document.createTextNode(line);
parent.insertBefore(textNode, nextSibling);
});
}
} else {
// Loop through each child node.
// We go backwards such that completed replacements don't affect the loop.
for(var i=node.childNodes.length - 1; i>=0; i--) {
replace(node.childNodes[i]);
}
}
}
<html>
<head>
<title>None</title>
</head>
<body>
<p id="text">just some random text. random text</p>
<button type="button" id="start">Replace</button>
</body>
</html>
If you're starting from a HTML string inside a browser, you can then use the above replace method and the browsers internal parsing to safely only affect the actual text:
function replaceHtmlString(html) {
var div = document.createElement('div');
div.innerHTML = html;
replace(div);
return div.innerHTML;
}
The script below is meant to find all html comments in the page (there are 4) and return them as one string. I ran the script below and received a "Too Much Recursion" error.
Have I created an infinite loop or did I do something else?
function findComment()
{
var olElement = document.getElementById("everything");//this is the id for my body element
var comments = new Array();
if (olElement.nodeType == 8)
{
comments[comments.length] = olElement;
} else if(olElement.childNodes.length>0)
{
for (var i = 0; i<olElement.childNodes.length; i++)
{
comments = comments.concat(findComment(olElement.childNodes[i]));
}
}
alert(comments);
}
//window.onload = countListItems;
//window.onload = countTagItems;
//window.onload = getElements;
window.onload = findComment;
This is a rough cut version of how you could do it with a recursion. It is not really elegant but will do the work:
function fico(el){
if (el.nodeType==8) return [el.textContent.trim()]
else return [...el.childNodes].map(fico);
}
console.log(fico(document.querySelector("#everything")).toString().replace(/,+/g,", "));
<body id="everything">
<div>something <!-- comment1 -->
<div>with something inside
<!-- comment2 -->
<div>and something further<div>
<span>inside
<!-- comment3 --></span>
it
</div>
more regular text
<!-- comment4 --> and enough.
</div></body>
Depending on the html input the function will return an array of subarrays with further levels of subarrays. To flatten it I used the Array-method toString() and then replace() with a regular expression to throw out the multiple commas in the result. There is still a superfluous one at the beginning ;-)
And here is an alternative version that uses a global comments array like you used in your code:
var comments=[];
function fico(el){
if (el.nodeType==8) comments.push(el.textContent.trim());
else [...el.childNodes].forEach(fico);
}
fico(document.querySelector("#everything")); // collect comments ...
console.log(comments.join(', ')); // ... and display them
<body id="everything">
<div>something <!-- comment1 -->
<div>with something inside
<!-- comment2 -->
<div>and something further<div>
<span>inside
<!-- comment3 --></span>
it
</div>
more regular text
<!-- comment4 --> and enough.
</div></body>
Move the olElements variable outside the function and pass in the element you want to search. The recursion you have is always starting with 'everything';
var comments = new Array();
function findComment(element)
{
if (element.nodeType == 8)
{
comments[comments.length] = element;
} else if(element.childNodes.length>0)
{
for (var i = 0; i<element.childNodes.length; i++)
{
comments = comments.concat(findComment(element.childNodes[i]));
}
}
return comments;
}
var olElement = document.getElementById("everything");//this is the id for my body element
alert(findComment(olElement));
Update: I tried both methods above and received error that either "element" or "el" is null. So...progress. I've pulled together my full code and html and posted below:
<!DOCTYPE html>
<html>
<head>
<title>A Simple Page</title>
<script>
var comments = new Array();
function findComment(element)
{
if (element.nodeType == 8)
{
comments[comments.length] = element;
} else if(element.childNodes.length>0)
{
for (var i = 0; i<element.childNodes.length; i++)
{
comments = comments.concat(findComment(element.childNodes[i]));
}
}
return comments;
}
//window.onload = countListItems;
//window.onload = countTagItems;
//window.onload = getElements;
var olElement = document.getElementById("everything");//this is the id for my body element
window.onload = alert(findComment(olElement));
</script>
</head>
<body>
<div id="everything">
<h1>Things to Do</h1><!--this is a title-->
<ol id="toDoList"><!--this is a list-->
<li>Mow the lawn</li><!--this is a list item-->
<li>Clean the windows</li>
<li>Answer your email</li>
</ol>
<p id="toDoNotes">Make sure all these things are done so you can get some rest.</p>
</div>
</body>
</html>
I am new to java and am trying to create a game that simulates hangman. I am trying to get the letters from the user after they input on keyboard. However, when I type something it doesn't make any difference, it doesn't output whether it is correct or incorrect. I think I may not be using the event in my guessLetter() function correctly, any help would be greatly appreciated.
window.addEventListener("DOMContentLoaded", function() {
var word = ['taco'];
let randNum = Math.floor(Math.random() * word.length);
let chosenWord = word[randNum];
let underScore = [];
let docUnderScore = document.getElementsByClassName('underScore');
let docRightGuess = document.getElementsByClassName('rightGuess');
let docWrongGuess = document.getElementsByClassName('wrongGuess');
console.log(chosenWord); //lets grader cheat
let generateUnderscore = () => {
for (let i = 0; i < chosenWord.length; i++) {
underScore.push('_');
}
return underScore;
}
document.onkeyup = function guessLetter(event) {
let letter = String.fromCharCode(event.keyCode || event.code).toLowerCase();
if (chosenWord.indexOf(letter) > -1) {
rightWord.push(letter);
underScore[chosenWord.indexOf(letter)] = letter;
docUnderScore[0].innerHTML = underScore.join(' ');
docRightGuess[0].innerHTML = rightWord;
if (underScore.join('') === chosenWord) {
alert('CONGRATS! YOU WIN!!!');
} else {
wrongWord.push(letter);
docWrongGuess[0].innerHTML = wrongWord;
}
}
underScore[0].innerHTML = generateUnderscore().join(' ');
}
});
<!DOCTYPE html>
<html>
<head>
<h1> Hangman </h1>
<div id="guesses">
<div class="letter" id="letter" </div>
</div>
</head>
<body>
</body>
<div class="container">
<div class="underScore">_ _ _ _</div>
<div class="rightGuess"> right guess </div>
<div class="wrongGuess"> wrong guess </div>
</div>
</html>
In the JS console, ReferenceErrors are being thrown as a result of the fact that the rightWord and wrongWord variables have not been defined.
You are writing the in head tag why ? it doesn't shown in your web page , place the html tags within body.
My aim is to use a single input to collect numbers and strings then use it to determine a math operation.
For example, I parse in values such as √64 intending to find the square root of 64. Knowing that this is no valid javascript, so I decided to get the first character with result[0]; which is "√" and then slice out the remaining values with result.slice(1); which is "64", then when the condition that result[0] == "√" is true then Math.sqrt(sliceVal) . This seems perfect and runs well in a mobile editor, but doesn't run in any web browser.
function actn() {
var input = document.getElementById("input").value;
var display = document.getElementById("display");
var result = input.toString();
var firstVal = result[0];
if (firstVal == "√") {
var sliceVal = result.slice(1);
display.innerHTML = Math.sqrt(sliceVal);
}
}
I do not know why It is not running at your end but It is working perfectly according to your requirement I tested above code :)
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
function actn() {
var input = document.getElementById("test").value;
var result = input.toString();
var firstVal = result[0];
if (firstVal == "√") {
var sliceVal = result.slice(1);
alert(Math.sqrt(sliceVal));
}
alert("No match found");
}
</script>
</head>
<body>
<input type="text" id="test" />
<button type="button" onclick="actn()">Test</button>
</body>
</html>
Checking ASCII value instead of character comparison should work.
<html>
<body>
<input type="text" id="input" />
<button type="button" id="sqrRoot">Square Root</button>
<h1 id="display"></h1>
<script>
function actn() {
var input = document.getElementById("input").value;
var display = document.getElementById("display");
var result = input.toString();
var firstVal = result[0];
/* Ascii value for √ is 8730 */
if (firstVal.charCodeAt(0) === 8730) {
var sliceVal = result.slice(1);
display.innerHTML = Math.sqrt(sliceVal);
}
}
document.getElementById("sqrRoot").addEventListener("click", function () {
actn();
});
</script>
</body>
</html>
I am very new to html and javascript. I have a textbox and am trying to count the number of words, then displaying the count in real time. I do not understand what I am doing wrong in this, or how to correct it. textContent does not make much sense to me.
<html>
<head>
<style>
input[type='text'] {width:50px;}
textarea {width:500px;height:300px;}
</style>
</head>
<body>
<div>
<h2>Test</h2>
<p>The number of words is <span id="wordCount"></span></p>
<textarea id="toCount"></textarea>
</div>
<script>
document.getElementById('toCount').addEventListener('input', function () {
var text = this.textContent,
count = text.trim().replace(/\s+/g, ' ').split(' ').length;
document.querySelector('.wordCount').textContent = count;
});
</script>
</body>
</html>
The error that I get right now says
Uncaught TypeError: Cannot set property 'textContent' of null
Your selector should be #wordCount, and the textarea content can be accessed using value:
<html>
<head>
<style>
input[type='text'] {width:50px;}
textarea {width:500px;height:300px;}
</style>
</head>
<body>
<div>
<h2>Test</h2>
<p>The number of words is <span id="wordCount"></span></p>
<textarea id="toCount"></textarea>
</div>
<script>
document.getElementById('toCount').addEventListener('input', function () {
var text = this.value,
count = text.trim().replace(/\s+/g, ' ').split(' ').length;
document.getElementById('wordCount').textContent = count;
});
</script>
</body>
</html>
The reason why you are getting null is: in selection, #wordCount is by Id, and .wordCount is by class. So document.querySelector('.wordCount') is returning null as there is no element with class wordCount.
The fix would be to simply change
document.querySelector('.wordCount').textContent = count;
to
document.querySelector('#wordCount').textContent = count;
Try this one.
document.getElementById('toCount').addEventListener('input', function () {
// var text = this.textContent,
var text = this.value,
count = text.trim().replace(/\s+/g, ' ').split(' ').length;
// document.querySelector('#wordCount').textContent = count;
document.querySelector('#wordCount').textContent = count;
});
try this.
document.getElementById('toCount').addEventListener('input', function () {
var text = this.value,
count = text.trim().split(' ').length;
document.querySelector('#wordCount').textContent = count;
});
Here is the jsfiddle