Replace string with spans containing each character - html

I would like to replace the content of an h1 element containing a character chain with the same chain but each character should be wrapped in a span.
That seemed easy enough to me, but I maybe underestimated it.
Here's what I tried (css only for debug purposes) :
var titleLen = $("#title").length - 1;
for (i=0; i<titleLen; i++) {
letter = $("#title").charAt(i);
$("#title").append("<span>" + letter + "</span>");
};
h1 span {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 id=title>
Hello World !
</h1>
It isn't working but I can't find the problem. Any help ?

Part of the reason your current code isn't working is that you're calling length and charAt on the DOM element instead of on its contents -- but even with that corrected you're modifying the contents of the div at each step of the iteration, so the second charAt would wind up reaching part of the span you just inserted instead of the second character of the original string. (Edit: I've just realize this description isn't quite right; you would wind up with a span-wrapped copy after the original text, because you append instead of replacing.)
Here are a couple of different ways you could use your original algorithm:
// keep a copy of the original string and work from that:
var title = $("#title").html();
$('#title').html('');
for (i = 0; i < title.length; i++) {
letter = title.charAt(i);
$("#title").append("<span>" + letter + "</span>");
};
// Alternatively, build a string and dump it into the DOM all at once:
/*
let output = '';
for (i = 0; i < $('#title').html().length; i++) {
letter = $('#title').html().charAt(i);
output +="<span>" + letter + "</span>";
};
$('#title').html(output);
*/
h1 span {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 id=title>
Hello World !
</h1>
Or a simpler way to do this is to split the string into an array for each character, then use 'join' to include the span tags:
$('#title').html(
'<span>' +
$('#title').html().split('').join('</span><span>') +
'</span>'
)
h1 span {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 id=title>
Hello World !
</h1>

Related

Break word at specific character

I realise that similar questions have been asked, but none quite like this.
I have a situation where I am using BEM to display some classes in code tags. Below is an example:
Obviously the default behaviour is to break words at a hyphen, as we can see is happening in the example. Is there a way that I can control what characters the line-break occurs at? I would like to be able to have class name integrity maintained so that the line break occurs before each period . if necessary.
I have another solution using jquery,
$('.mypara').each(function () {
var str = $(this).html();
var htmlfoo = str.split('.').join('</br>');
$(this).html(htmlfoo);
});
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<code class="mypara">
This is-the HTML if its - characters exceed 50. characters it should go-to next line
</code>
<code class="mypara">
This is the HTM-if its. characters exceed 50 - characters it should. go-to next-line
</code>
Unfortunately I don't think there is a way to do everything you want with pure CSS.
UPDATE: removed spaces before periods in JS solution.
If you are able to use JavaScript you could process the code tag's contents to disable wrapping for words with hyphens and you could wrap each block starting with a period in an inline-block span.
The following code breaks the contents of each code tag into a list of blocks that start with either space or period. Each block is wrapped with a span that prevents wrapping, and blocks that begin with a period are additionally marked as display: inline-block;. This should give the behaviour you are looking for, and additionally preserve all content when copy-pasting text.
CSS:
.no-wrap-hyphen {
white-space: nowrap;
}
.wrap-period {
display: inline-block;
}
JavaScript (run this function on window load and resize):
function wrapPeriodsNotHyphens() { // run on window load or resize
var codes = document.getElementsByTagName( "code" );
for ( var i = 0; i < codes.length; i++ ) {
currentCode = codes[ i ].innerHTML.split(/(?=[ .])/); // split by spaces and periods
for ( var c = 0; c < currentCode.length; c++ ) {
// surround each item with nowrap span
currentCode[ c ] = '<span class="no-wrap-hyphen">' + currentCode[ c ] + '</span>';
if ( currentCode[ c ].indexOf( '.' ) > -1 ) {
// add a zero size space at the start for periods
currentCode[ c ] = '<span class="wrap-period">' + currentCode[ c ] + '</span>';
}
}
codes[ i ].innerHTML = currentCode.join('');
}
}

CSS to bold a varying length section of a paragraph up to a delimiter like a colon or hyphen

Is there a way to apply a bold style to the beginning of a paragraph up to a delimiter character--like a colon or hyphen? The value before the delimiter can be any length.
So a string like this:
Definition item: description or definition of the item....
would look like:
Definition item: description or definition of the item....
I get this result in javascript but its impossible to make in css :
( updated and added while loop )
function myFunction(str) {
var res = str.split(":");
var mynewres = "<b>" + res[0] + ": " + "</b>" + res[1];
var i = 2;
var newres = mynewres;
while (typeof res[i] !== 'undefined') {
newres = newres + ":" + res[i];
i++;
}
return newres;
}
var newtxt = myFunction("Note: This Function Don't Work Correctly If No Colones Are Used! That Means : You Must Use One Colone At Least!");
document.getElementById("LookHere").innerHTML = newtxt;
#LookHere {
font-size: 30px;
}
<span id="LookHere">
to add to my earlier comment :
CSS only offers the pseudo class :first-letter and :first-line to style text partially. To bold a text to emphase it, you can use the <em> or <strong> tag. <b> is also avalaible but that is HTML to structure your text.
For what it seems, there is an HTML structure to use that will describe itself these text content: the definition list(W3C) <dl><dt><dd>
The <dl> element represents a description list.
dt {font-weight:bold;}
<dl>
<dt>Definition item:</dt>
<dd>description or definition of the item....</dd>
</dl>
add some styles to set it on a line
dt {
font-weight: bold;
}
dt,
dd {
margin: 0;
display: inline;
}
<dl>
<dt>Definition item:</dt>
<dd>description or definition of the item....</dd>
</dl>
Wrap your title with <b></b>
<span><b>Definition item:</b> description or definition of the item....<span>
Also, you can use JS to handle this. (not recommended)
Just because this can be done does not mean that you should do this.
Manipulating the DOM just to change display is very bad practice.
Concern should be given to how the info is being generated in the first place.
That said here is a solution using jquery
$('p').each(function(e){
var title = this.innerText.substring(0, this.innerText.indexOf(':'))
var definition = this.innerText.substring(this.innerText.indexOf(':')).replace(":","").trim()
console.log("title:"+title);
console.log("definition:"+definition);
$(this).html("<strong>"+title+":</strong> "+definition)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Definition item: description or definition of the item....</p>
<p>another item: description or definition of the item....</p>
<p>new item: description or definition of the item....</p>
Allthough you should just edit it directly in the html. Here a jQuery free and flexible javascript solution:
var definitions = document.querySelectorAll('.definition');
for (var i = 0; i < definitions.length; i++) {
definitions[i].innerHTML = definitions[i].innerText.replace(/^[^:]+:/, '<b>$&</b>');
}
<p class=definition>Definition: This is something.</p>
<p class=definition>Example: Also allows : after definition.</p>
For the regex. ^ is the beginning of the string, [^:] matches everything not a colon +, for more than one match and ending with matching the colon itself, $& substitutes the match back in.
export const boldStringInAnotherString = (mainString, boldString) => {
const splitted = mainString.split(boldString)
return !mainString.includes(boldString) ? (<span>mainString</span>)
: (<span>{splitted[0]}<b>{boldString}</b>{splitted[1]}</span>)
}

Add a border only to the bottom of wrapped text

I'm trying to achieve an underline on some wrapped text that fits to the width of the bottom row of text whilst only appearing underneath that bottom line. Figure 1 illustrates the desired effect
Figure 1
Using this HTML:
<h2><span class="inline-block">optatur, volendit inum simolor</span></h2>
and setting the span to display:inline; I can get the underline to fit perfectly with the width of the text but it underlines all of the text.
Or, setting the span to display:inline-block; I can get the underline to only appear under the bottom line but it then fills the whole width of the parent.
See this JSfiddle for the above examples: http://jsfiddle.net/PWDV7/1/
Is there any way to achieve the result of figure 1?
With a good leg up from this answer to a questions about finding line wraps, I managed to come up with this solution (in short, it involves using JS to find where a line wrap has occurred and wraps a span around all the text that sits on the last line):
function underLineText () {
$underlined_text.each(function(){
var $this = $(this);
var text = $this.text();
var originalText = text;
var breakWords = new Array();
//split the words into individual strings
var words = text.split(' ');
//find the height of the first word
$this.text(words[0]);
var height = $this.height();
//if there is more than one word
if (words.length > 1) {
//loop through all the words
for(var i = 1; i < words.length; i++){
$this.text($this.text() + ' ' + words[i]);
//check if the current word has a different height from the previous word
//if this is true, we have witnessed a word wrap!
if($this.height() > height){
height = $this.height();
//add the first word after the wrap to a predefined array
breakWords.push(words[i]);
}
//on the last iteration on the loop...
if (i === words.length - 1) {
if (breakWords.length > 0) {
//select the last word of the breakWords array
//(this is to handle cases where there there are more than one line or word wraps)
var breakStartAt = breakWords[breakWords.length - 1];
//add a span before the last word
var withSpan = '<span>'+breakStartAt;
//replace the last occurrence of this word with the span wrapped version
//(this is to handle cases where there are more than one occurrences of the last word)
originalText = originalText.replaceLast(breakStartAt,withSpan);
//close the last line with a span
originalText += "</span>";
}
}
}
}
//if there are no word wraps, wrap the whole text in spans
else {
originalText = '<span>'+originalText+'</span>';
}
//replace the original text with the span-wrapped mod
$(this).html(originalText);
});
}
You can see it working here: http://jsfiddle.net/PWDV7/5/
Change the code like so:
HTML
<h2>optatur, volendit <span>inum simolor</span></h2>
CSS
h2 {
width:200px;
text-align:center;
}
h2 span {
border-bottom:3px solid black;
width:100%;
}
All I changed was the position of the <span> to wrap the text that you want the border on.
JsFiddle

Placing words directly under or above other words

I wish to do the following within div tags:
The words will be coloured differently using spans.
I will be given some text in a text box and via JavaScript I will need to dynamically update to div to show something like the above.
What is the best way to do this?
Will it involve a monospaced font?
Will it involve writing "hidden" text?
I wish to do entire paragraphs in this manner.
This might seem weird but the research I'm doing requires me present certain words from a given text with multiple colours and I think this might be a nice way of conveying this information.
Updating the text in the text box will update the following variables, and in turn I will need to convert these two variables into something like the image above.
text = "I am under the text above me and there is lots more text to come./n I am even moving onto a new line since I have more text"
color_per_word_position = {0:green, 1: red, 2: cyan, 4: yellow, 5: red, ...}
You will have to use a monospaced font for this.*
I basically see two options: 1. use whitespace 2. margins.
Option 1
Your text will look like
I•am•under•the•text•above
••am•under•••••text•above
where • denotes a space character. Pretty straight-forward in terms of CSS, since you don't have to worry about the spacing. The browser does it all for you. Example: http://jsfiddle.net/PYXdr/
*well, it may be possible with any font, using a lot of JS, but I guess it's not worth it.
Option 2
Since you probably don't want whitespace in between your spans, you may prefer this:
I•am•under•the•text•above
am•under text•above
Now, the spacing needs to be taken care of manually. Each span should get a margin-left that pushes it to the desired position. But before we can do that, we need to know the width of one character (using JS, since CSS does not provide that). Okay, pretty easy:
var el = document.createElement('pre');
el.style.display = 'inline-block';
el.innerHTML = ' ';
document.body.appendChild(el);
var width = parseFloat(getComputedStyle(el).width);
document.body.removeChild(el);
Now let's go ahead and move the spans:
span1.style.marginLeft = (2 * width) + 'px';
span2.style.marginLeft = (5 * width) + 'px';
Example: http://jsfiddle.net/JC3Sc/
Putting it all together
Now here's a basic example of how this might work:
var text = "I am under the text above me and there is lots more text to come.\nI am even moving onto a new line since I have more text"
var highlightBorders = [[2, 3, 4, 6], [6, 7]]; // YOUR TASK: implement the logic to display the following lines
var color_per_word_position = {0:'lime', 1: 'red', 2: 'cyan', 3:'orange', 4: 'yellow', 5: 'red'}
/* generate CSS */
var style = document.createElement('style');
for (var i in color_per_word_position) {
style.innerHTML += '.hl' + i + '{background:' + color_per_word_position[i] + '}';
}
document.head.appendChild(style);
/* generating the text */
text = text.split('\n');
var pre = document.createElement('pre');
text.forEach(function (line, i) {
var div = document.createElement('div');
var words = line.split(' ');
var result = [];
highlightBorders[i].forEach(function (len, j) {
var span = document.createElement('span');
span.innerHTML = words.splice(0, len).join(' ');
span.className = 'hl' + j;
if (j) {
span.style.marginLeft = width + 'px' // YOUR TASK: implement the logic
}
div.appendChild(span);
});
pre.appendChild(div);
});
document.body.appendChild(pre);
This is not a complete solution, since a) I don't really see which parts exactly you want to highlight and b) I don't want to spoil all the fun. But you get the idea.
Example: http://jsfiddle.net/tNyqL/
Using padding this is possible but also have absolute control by assigning text to a selector such as "p" for the class: fiddle http://jsfiddle.net/3NDs3/1/
.one {
width:200px;
}
.one p {
font: normal 14px Futura, sans-serif;
text-align:left;
padding-left:130px;
}
.two {
width:200px;
}
.two p {
text-align:center;
font: normal 14px Futura, sans-serif;
}
.three {
width:200px
}
.three p {
text-align:left;
font: normal 14px Futura, sans-serif;
padding-left:35px;
}
<div class="one">
<p>above me</p>
</div>
<div class="two">
<p>i am under the text above me</p>
</div>
<div class="three">
<p>under</p>
</div>

Farsi/Arabic number to be outputted properly

You have a file that outputs as such:
<div id="first">1</div>
2
<div id="third">
<? $i = 3; echo(i) ?>
</div>
Which outputs:
1
2
3
Now if I want to have an output as below:
?
?
?
Well, I was hoping I could output the Arabic/Farsi version of 1,2,3 instead of '?'. How can I use HTML/CSS convert to numbers to Arabic/Farsi?
And why does everything change except numbers when I change my language (Windows XP)?
If you want to number a list, you could use an ol element and change the list-style-type of it like:
ol {
list-style: arabic-indic;
}
Expanding on ShirzITCo and Kirk Woll's answer above -- which saved my but when client decided all the content in a WordPress CMS should use Eastern-Arabic numerals instead of the Western Arabic they started with:
function recursiveReplace(node) {
if (node.nodeType === 3) { // text node
node.nodeValue = node.nodeValue
.replace(/0/g,'۰')
.replace(/1/g,'۱')
.replace(/2/g,'۲')
.replace(/3/g,'۳')
.replace(/4/g,'۴')
.replace(/5/g,'۵')
.replace(/6/g,'۶')
.replace(/7/g,'۷')
.replace(/8/g,'۸')
.replace(/9/g,'۹');
} else if (node.nodeType === 1) { // element
$(node).contents().each(function () {
recursiveReplace(this);
});
}
}
recursiveReplace(document.body);
There is no automated way to change numbers, or even digits. Set up a mapping between then and convert manually.
Numbers are never localized, because unlike natural language words, Arabic numerals are understood across most of the world.
Simply use CSS:
ol {
list-style-type: persian
}
Use the following JavaScript code. This will replace numbers:
function recursiveReplace(node) {
if (node.nodeType == 3) { // text node
node.nodeValue = node.nodeValue.replace("1", "۱");
} else if (node.nodeType == 1) { // element
$(node).contents().each(function () {
recursiveReplace(this);
});
}
}
recursiveReplace(document.body);