I am learning JS, but still have some troubles. I managed to edit a WYSIWYG editor to allow users to click a button "footnote" that inserts the following HTML:
<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span>
With some CSS I can place a number inside the element which counts upwards:
body {
counter-reset: footnotecounter;
}
span.footnote:before {
counter-increment: footnotecounter;
content: counter(footnotecounter);
position: relative;
top: -0.4em;
visibility: visible;
}
span.footnote {
color: #0389b9;
font-size: 0.875rem;
}
And example of some HTML:
Here is a text with a note.<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span> And there will be a second one too!<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span>
I actually use Popper and Twitter Bootstrap to show the content of the 'footnote' in a tooltip.
Now what I try to do, is to remove [FN] from all the span elements that have the class footnote with the following javascript:
footnotes = document.getElementsByClassName('footnote');
for (var i = 0; i < length; i++){
footnotes[i].replace("[FN]", " ");
}
This does not seem to work, but I don't know where my mistake is. Also, I guess, that since I am going to use JS to alter the footnotes, I might as well leave the CSS out of it altogether and use JS to create an increasing number in all elements, right?
Here is a JSFiddle to show a live example.
You have to check the length property of footnotes node list. You are trying to replace the element itself not the text inside of it. You have to replace the textContent or innerText property of the element.
Try the following way:
var footnotes = document.getElementsByClassName('footnote');
for (var i = 0; i < footnotes.length; i++){
footnotes[i].textContent = footnotes[i].textContent.replace("[FN]", " ");
}
body {
counter-reset: footnotecounter;
}
span.footnote:before {
counter-increment: footnotecounter;
content: counter(footnotecounter);
position: relative;
top: -0.4em;
visibility: visible;
}
span.footnote {
color: #0389b9;
font-size: 0.875rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>
Here is a text with a note.<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span> And there will be a second one too!<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span>
</p>
Update: As per the discussion in the comments
var footnotes = document.getElementsByClassName('footnote');
for (var i = 0; i < footnotes.length; i++){
footnotes[i].innerHTML = footnotes[i].textContent.replace("[FN]", "<span class='new'>"+ (i+1) +"</span> ");
}
body {
counter-reset: footnotecounter;
}
span.new{
position: relative;
top: -0.4em;
visibility: visible;
}
span.footnote {
color: #0389b9;
font-size: 0.875rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>
Here is a text with a note.<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span> And there will be a second one too!<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span>
Here's the number 3 thanks to CSS: <span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span> and number 4 <span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span>. All of this thanks to the CSS counter
</p>
Related
This question already has answers here:
How do I target elements with an attribute that has any value in CSS?
(3 answers)
Closed 2 years ago.
I need to get a display none the above span by attribute "data-email".
<span contenteditable="false" id="signature1596021675154" tabindex="1" data-role="test" data-email="qwerty" title="qwerty" data-name="name" style="z-index: 600; margin-right: 0px; visibility: visible;" class="index signature-container editor-elements valid_button"> </span>
The [attribute] selector is used to select elements with a specified attribute.
in your css you can do that:
span[data-mail] {
display: none;
}
or
span[data-mail="qwerty"] {
display: none;
}
span[data-email]{
color: red
}
span[data-email="test"]{
color: blue
}
<span contenteditable="false" id="signature1596021675154" tabindex="1" data-role="test" data-email="qwerty" title="qwerty" data-name="name" style="z-index: 600; margin-right: 0px; visibility: visible;" class="index signature-container editor-elements valid_button">hello </span>
<span data-email="test">world</span>
Just select element by attribute and apply CSS.
$('span[data-email="qwerty"]').css({
display: "none"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span contenteditable="false" id="signature1596021675154" tabindex="1" data-role="test" data-email="qwerty" title="qwerty" data-name="name" style="z-index: 600; margin-right: 0px; visibility: visible;" class="index signature-container editor-elements valid_button">Some text</span>
Because its HTML data attribute you can do the following in javascript
email_condition = "qwerty"; //you can set whatever condition you need
console.log(document.querySelector(`span[data-email="${email_condition}"]`));
document
.querySelector(`span[data-email="${email_condition}"]`)
.classList.add("display_none");
display_none is a class defined in css whose definition looks like
.display_none {
display: none;
}
You can refer my [codepen link]:https://codepen.io/ankitt8/pen/pogXJJV
References:
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*
https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
As mentioned in the comment if you want to make the code work for multiple span tags with same email condition you can do as below
email_condition = "qwerty";
let allSpanEmailTag = document.querySelectorAll(
`span[data-email="${email_condition}"]`
);
// note its querySelectorAll previously it was querySelector only
// querySelectorAll returns a list of node based on specified condition.
for (let i = 0; i < allSpanEmailTag.length; ++i) {
allSpanEmailTag[i].classList.add("display_none");
}
The codepen link has been updated so you can refer that!
I want to know if it's possible to change the text size and color incrementally on the same line, like this:
I want to use CSS only if possible. Any other solution, that at least doesn't force me to put each letter in its own span, is welcome, too.
body {
font-family:monospace;
}
<span style="font-size:50px;">L</span><span style="font-size:45px;opacity:0.7">o</span><span style="font-size:38px;opacity:0.5">r</span>...
What about some transformation and gradient without all these markup:
body {
perspective: 250px;
perspective-origin: bottom;
}
div {
font-size: 70px;
background: linear-gradient(to right, black,rgba(0,0,0,0.3),rgba(0,0,0,0.2));
display: inline-block;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
transform: rotateY(70deg);
transform-origin: left;
}
<div>
Lorem Ipsum Lorem
</div>
That really depends on your HTML markup. You can't do this with plain text "Lorem ipsum", but you can do it if each letter is wrapped in its own separate element pretty simply:
body > span {
font-size: 72px;
}
span > span {
font-size: 85%;
opacity: 0.8;
}
<span>
L<span>
o<span>
r<span>
e<span>
m <span>
i<span>
p<span>
s<span>
u<span>
m
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
You likely won't be able to do this without modifying your existing markup or introducing some JavaScript to do this for you, however.
As for the colour, you can change the opacity of each letter with this approach (as per the above example), but I'm not sure if this is possible as easily without having to apply styling to each letter individually.
Using James Donnelly answer with a bit of JS:
format = ([head, ...tail]) => {
if(tail.length == 0)
return "<span>" + head + "</span>";
return "<span>" + head + format(tail) + "</span>";
}
var el = document.querySelector(".test");
el.innerHTML = format(el.innerText)
.test > span {
font-size: 72px;
}
span > span {
font-size: 85%;
opacity: 0.8;
}
<div class="test">
Lorem ipsum
</div>
inspired from #James Donnelly's answer
this solution more dynamic , spans will be generated using javascript
checkout the code
document.addEventListener('DOMContentLoaded', function()
{
var fooDiv = document.getElementsByClassName("foo")[0];
var text = fooDiv.innerHTML.trim();
var textToSpans = "";
var textLength = text.length;
for(var i=0;i<textLength;i++){
textToSpans += "<span>" + text[i];
}
for(i=0;i<textLength;i++){
textToSpans += "</span>";
}
fooDiv.innerHTML = textToSpans;
//change the class so if this code run again this div will not effected
fooDiv.className = "bar";
}, false);
.bar > span {
font-size: 72px;
}
span > span {
font-size: 85%;
opacity: 0.8;
}
<div class="foo">
Lorem ips
</div>
var GradientLetters = class {
constructor(id, fontSizeStep) {
this.element = document.getElementById(id);
this.fontSizeStep = fontSizeStep;
this.letters = document.getElementById(id).innerText.split("");
document.getElementById(id).innerText = "";
this.makeGradient();
}
makeGradient() {
this.letters.forEach((currentValue, index) => {
let span = document.createElement("SPAN");
span.innerText = currentValue;
span.style.color = "rgba(0, 0, 0, " + (1 / index) + ")";
span.style.fontSize = 60 - (index * 2) + "px";
this.element.appendChild(span);
});
}
}
let gradientLetters = new GradientLetters("gradient-letters", 10);
p {
font-family: Arial;
}
<p id="gradient-letters">Lorem ip</p>
Impossible. Without wrapping the letters inside HTML tags simply You can't change CSS properties of the single letters.
The only thing that I've found is the ::first-letter selector, for the first letter, not the following.
Explanation in the CSS context
CSS font-size Property and CSS color Property are properties that you can define in the context of selectors.
Selectors are patterns that match against elements in a tree, and as
such form one of several technologies that can be used to select nodes
in a document.
So, defining CSS properties without pointing to elements (in this case, HTML element) seems to be not possible.
Using JavaScript
Using JavaScript is possible to split a string (In this case the innerText of an HTML Element like a paragraph) in letters, wrapping those letters in HTML Elements and then, style those Elements with CSS in several ways. In this case should be better to set CSS programmatically.
I have the following code on a Wordpress Woocommerce website which outputs "From £189.00"
I am trying to remove the word "From". I'm sure there must be a simple way using something like .price:pre {display:none;}.
<p class="price">From: <span class="woocommerce-Price-amount amount"><span class="woocommerce-Price-currencySymbol">£</span>189.00</span></p>
How can I hide the word "From" from this code, ideally using CSS? I am open to javascript in the functions.php as an alternative.
Due to the restrictive nature of Wordpress and the code it outputs, I'm unable to edit the snippet above. I have to manipulate the above code in CSS or in the functions.php
You can use font-size to hide the text, then overwrite it for the child span elements like so:
.price {
font-size: 0px;
}
.price span {
font-size: 16px;
}
<p class="price">From: <span class="woocommerce-Price-amount amount"><span class="woocommerce-Price-currencySymbol">£</span>189.00</span>
</p>
Since this is already said to be impossible, have a look at https://stackoverflow.com/a/23247837/1587329. Short answer:
.price>.woocommerce-Price-amount
{
visibility: visible;
}
.price
{
visibility: hidden;
width: 0;
height: 0;
margin: 0;
padding: 0;
}
jsfiddle thanks to #Anthony's comment.
Like this:
.price {display:none;}
<p class="price">From: </p>
<span class="woocommerce-Price-amount amount">
<span class="woocommerce-Price-currencySymbol">
£
</span>189.00
</span>
change the format of your html
<p class="price"><span class="from">From:</span> <span class="woocommerce-Price-amount amount"><span class="woocommerce-Price-currencySymbol">£</span>189.00</span></p>
and apply css like
.price .from {display:none;}
Pretty simple problem, but I can't find a solution. This plugin claims to do it, but I can't get it to work on my site at all, not as a called script, not inline, nothing. So, I have two columns of divs, the ones on one side larger than the other. I have set it up so the second column container will match the height of the first (which is determined elsewhere and thus varies) and set it to overflow:hidden, but what I want to do do is to remove the overflowing divs entirely so it always ends on the last complete div. Here's the fiddle: https://jsfiddle.net/bw2v39ru/2/
This is the JS to equalize the heights $('.row2').css('height', $('.row1').height()+'px');
In that example, only two of he block2 spans should be visible and the overflowing ones removed completely instead of leaving half a block.
Try this: https://jsfiddle.net/bw2v39ru/9/
Besides the code below - you will have to e.g. insert a <br style="clear:both;" /> in the parent DIV since the children has float: left
$('.row2').css('height', $('.row1').height());
var maxHeight = $("#main").outerHeight();
$("#main span").each(function() {
var elm = $(this);
if (elm.offset().top + elm.height() > maxHeight)
elm.remove();
});
as promised, here is my answer. Custom build jsfiddle from pure JavaScript.
https://jsfiddle.net/www139/vjgnsrpg/
Here is a code snippit for you. It assumes that all of your block2 elements have a fixed height. Also I changed the .row1 and .row2 classes to ids to make the solution easier to create. Feel free to change it back but remember to use document.getElementsByClassName('class')[i] instead.
//make sure you execute this script onload inside a jquery document ready or window.onload
//get the rendered height of both rows
//enter margin for blocks here
//this also assumes that the height of your block1 and block2 elements are fixed
var margin = 5;
var rowOneHeight = document.getElementById('row1').offsetHeight;
//get height of block2 element including vertical margin (multiplied twice)
var blockTwoHeight = document.getElementById('row2').getElementsByClassName('block2')[0].offsetHeight + 2 * margin;
var howManyBlocksCanFit = Math.floor(rowOneHeight / blockTwoHeight);
var numberOfBlocks = document.getElementById('row2').getElementsByClassName('block2').length;
for (var i = 0; i != numberOfBlocks - howManyBlocksCanFit; i++) {
document.getElementById('row2').removeChild(document.getElementById('row2').lastElementChild);
}
#main {
width: 240px;
}
#row1 {
float: left;
}
#row2 {
float: right;
overflow: hidden;
}
.block1 {
display: block;
margin: 5px;
width: 100px;
height: 50px;
border: 1px solid red;
}
.block2 {
display: block;
margin: 5px;
width: 100px;
height: 100px;
border: 1px solid red;
}
<div id="main">
<div id="row1">
<span class="block1"></span>
<span class="block1"></span>
<span class="block1"></span>
<span class="block1"></span>
<span class="block1"></span>
</div>
<div id="row2">
<span class="block2"></span>
<span class="block2"></span>
<span class="block2"></span>
<span class="block2"></span>
<span class="block2"></span>
</div>
</div>
Hope this helps you, please tell me if there was something I didn't understand in your question to improve my answer.
I programmed it for you, this works after your existing JS code line:
var row2 = $('div.row2'),
block2elements = row2.children('span.block2');
// Function to use also for other situations
function calculateElementsHeight(elements) {
var height = 0;
$.each(elements, function(i, elementRaw ){
height += $(elementRaw).height();
})
return height;
}
for(var i = 0; block2elements.length > i; i++) {
block2elements = row2.children('span.block2'); // Get new state of the block2 elements
if(row2.height() < calculateElementsHeight(block2elements)) {
block2elements.last().remove();
}
}
I have been working with some JavaScript to change display properties for my website. it works fine for Firefox and IE, but Chrome and Safari do not respond at all. I am trying to change the display from "none" to "block", or the reverse. Here is the code:
function setStyleClass (classesOff,classesOn) {
var classOn;
if (document.all) {
for (var s = 0; s < document.styleSheets.length; s++) {
for (var r = 0; r < document.styleSheets[s].rules.length; r++){
if (document.styleSheets[s].rules[r].selectorText.indexOf(classesOff,0) > -1) {
document.styleSheets[s].rules[r].style.display = "none";
}
for(var j = 0; j < classesOn.length; j++){
classOn = classesOn[j];
if (document.styleSheets[s].rules[r].selectorText == '.' + classOn) {
document.styleSheets[s].rules[r].style.display = "block";
}
}
}
}
}
else if (document.getElementById) {
for (var s = 0; s < document.styleSheets.length; s++) {
for (var r = 0; r < document.styleSheets[s].cssRules.length; r++) {
if (document.styleSheets[s].cssRules[r].selectorText.indexOf(classesOff,0) > -1) {
document.styleSheets[s].cssRules[r].style.display = "none";
}
for(var j = 0; j < classesOn.length; j++){
classOn = classesOn[j];
if (document.styleSheets[s].cssRules[r].selectorText == '.' + classOn) {
document.styleSheets[s].cssRules[r].style.display = "block";
}
}
}
}
}
}
When this is called, it is given a list of style id's to turn off, and styles to turn "on".
Here is the call:
onClick="setStyleClass('book','book2_nl','book3_nl','book4_nl','B1_List_01_20','B1_Link_21_40']);
The way this works is to turn "off" any styles with "book" in the name, as well as, book2_nl, book3_nl, and book4_nl. The last two styles get turned "on". So I am replacing one "list of links to pages" with another, different list. The code above works fine in IE and FF, but does nothing at all that I can see in Chrome and Safari.
the styles all look like this coming in:
.B4_Link_21_40 {
display: none;
color: #f8fb24;
font : 90% Book Antiqua;
}
.B4_List_21_40 {
display: none;
color: #f8fb24;
font : 90% Book Antiqua;
}
I want to get these styles to turn on when I click the appropriate link. Are there any obvious errors in my code that could be causing this?
OK, you have seen the above question, now I have figured out how to go back and add html to this for your benefit :)
<html>
<head></head>
<title></title>
<script> //the script posted above </script>
<style>
.book1 {
position: absolute;
left:0px;
top:410px;
width:200px;
height:40px;
display: block;
}
.book2 {
position:absolute;
left:0px;
top:450px;
width:200px;
height:40px;
}
.B1_Link_01_20 {
display: none;
color: #f8fb24;
font : 90% Book Antiqua;
}
.B1_List_01_20 {
display: block;
color: #f8fb24;
font : 90% Book Antiqua;
}
.B1_Link_21_40 {
display: block;
color: #f8fb24;
font : 90% Book Antiqua;
}
.B1_List_21_40 {
display: none;
color: #f8fb24;
font : 90% Book Antiqua;
}
</style>
<div align="justify" align="center" class="mainBody"
<p>Here's some content...</p>
</div>
<div class="book1">
<a href="#" target="_self"
onClick="setStyleClass('book',['B1_List_01_20','B1_Link_21_40']);
switchStyleClass('B2_Li');
onMouseOut="window.status=''; return true;">
</a>
</div>
<div class="book2">
<a href="#" target="_self"
onClick="setStyleClass('book',['B2_List_01_20','B2_Link_21_40']);
switchStyleClass('B1_Li');
onMouseOut="window.status=''; return true;">
</a>
</div>
<div class="B1_List_01_20">
<a href=Link To Page 1.shtml>1. Link To Page 1</a><br>
<a href=Link To Page 2.shtml>2. Link To Page 2</a><br>
<br></div>
<div class="B1_List_21_40">
<a href=Link To Page 21.shtml>21. Link To Page 21</a><br>
<a href=Link To Page 22.shtml>22. Link To Page 22</a><br>
<br></div>
<div class="B1_Link_01_20">
<a ONCLICK="setStyleClass('B1_Li',['B1_List_01_20','B1_Link_21_40']);" href="#">List of Links 1 - 20</a><br><br>
</div>
<div class="B1_Link_21_40">
<a ONCLICK="setStyleClass('B1_Li',['B1_List_21_40','B1_Link_01_20','B1_Link_41_60']);" href="#">List of Links 21 - 40</a><br><br>
</div>
</html>
First if your just trying to change links then I would put the different links in 2 containers positioned in the same place via position: absolute then I would have one with a default style none. When the button is clicked then you don't even have to pass anything to your method since your only dealing with 2 containers and you know both their id's.
Then instead of going though the style sheets, just use document.getElementById('container_1').style.display = 'block';
document.getElementById('container_2').style.display = 'none';
As long as your container is a block level, such as a div, then this will change their display property in every browser.
if you want to do it through changing their class names then you could do this.
function changeStyles(){
document.getElementById('container_1').className = 'classOn';
document.getElementById('container_2').className = 'classOff';
//rest of your javascript
}
*This is still assuming you go with two containers instead of trying to change every link's individual style
Edit:
So not knowing what html you actually have makes it harder to answer your comment but here goes.
Your html could look something like this:
<div class='classOn' id='container_1'>
<a href='some_link'>some link</a>
<a href='some_link2'>some link2</a>
<a href='some_link3'>some link3</a>
<a href='some_link4'>some link4</a>
</div>
<div class='classOff' id='container_2'>
<a href='different_link'>different link</a>
<a href='different_link2'>different link2</a>
<a href='different_link3'>different link3</a>
<a href='different_link4'>different link4</a>
</div>
<button onclick='changeStyles()>See new Links!</button>
Then your css:
.classOn{
display: block;
position:absolute;
margin: 10px 10px 10px 10px;
//rest of your css
}
.classOff{
display: none;
position: absolute;
margin: 10px 10px 10px 10px;
//rest of your css
}
Notice how both classes have the exact same margin, they can have this because of the absolute position attribute. It effectively takes the space they would be using out of the page. now when the function changeStyles() is called by pressing the button the first div is hidden and the second div shows up with the new links in the exact same position. hope that helps.
Ok so my example above works fine with what you have just make class='classOn' your class='B1_List_01_20' and make class='classOff' your class='B1_Link_21_40' and use the function above and it should switch between them just fine.