I am trying to put three elements that contain text on one line using only HTML tags and the style property. One of the elements is a counter that is counting up. Unfortunately the elements are too far from each other in my solution as I am trying to get them to stick together seamlessly. Cold you please help me out?
FYI: I have read several posts here on SO before posting and tried my best to make a solution below.
<span style="display: flex; justify-content: space-between;">
<span> There is </span>
<strong><span class="counter" style="font-family:Courier New; style:bold" data-target="100">0</span></strong>
<span>kg spam.</span>
</span>
<script>
const counters = document.querySelectorAll('.counter');
for(let n of counters) {
const updateCount = () => {
const target = + n.getAttribute('data-target');
const count = + n.innerText;
const speed = 5000; // change animation speed here
const inc = target / speed;
if(count < target) {
n.innerText = Math.ceil(count + inc);
setTimeout(updateCount, 1);
} else {
n.innerText = target;
}
}
updateCount();
}
</script>
Removing justify-content: space-between; and adding padding to the left and right of the counter should work:
<span style="display: flex;">
<span>There is </span>
<strong><span class="counter" style="font-family: Courier New; style: bold; padding: 0 0.2em" data-target="100">0</span></strong>
<span> kg spam.</span>
</span>
<script>
const counters = document.querySelectorAll('.counter');
for(let n of counters) {
const updateCount = () => {
const target = + n.getAttribute('data-target');
const count = + n.innerText;
const speed = 5000; // change animation speed here
const inc = target / speed;
if(count < target) {
n.innerText = Math.ceil(count + inc);
setTimeout(updateCount, 1);
} else {
n.innerText = target;
}
}
updateCount();
}
</script>
You might need to tweak the margin size, but this is the best idea I came up with.
If your goal is to form a sentence then you don't need these many spans they are all inline elements. I think one span is enough:
<style>
.counter {
style="font-family:Courier New;"
}
</style>
<span>
There is <em class="counter" data-target="100">0</em>kg spam.
And <em class="counter" data-target="200">0</em> buns.
</span>
<script>
const counters = document.querySelectorAll('.counter');
for (let n of counters) {
const updateCount = () => {
const target = +n.getAttribute('data-target');
const count = +n.innerText;
const speed = 5000; // change animation speed here
const inc = target / speed;
if (count < target) {
n.innerText = Math.ceil(count + inc);
setTimeout(updateCount, 15);
} else {
n.innerText = target;
}
}
updateCount();
}
</script>
If screen width reduces the line will wrap automatically. Same text with 100px wide box wraps perfectly. You don't have to do anything:
<style>
.counter {
style="font-family:Courier New;"
}
div{
width: 100px;
border: 1px solid gray;
}
</style>
<div><span>
There is <em class="counter" data-target="100">0</em>kg spam.
And <em class="counter" data-target="200">0</em> buns.
</span></div>
<script>
const counters = document.querySelectorAll('.counter');
for (let n of counters) {
const updateCount = () => {
const target = +n.getAttribute('data-target');
const count = +n.innerText;
const speed = 5000; // change animation speed here
const inc = target / speed;
if (count < target) {
n.innerText = Math.ceil(count + inc);
setTimeout(updateCount, 15);
} else {
n.innerText = target;
}
}
updateCount();
}
</script>
Related
I have been unsuccessful in trying to add two seperate maximum character fields to a form. I have tried renaming the element ids and changing the var i and c but to no avail. Thanks
Fiddle http://jsfiddle.net/rLkcy0t4/
Here is the code.
var maxchar = 160;
var i = document.getElementById("textinput");
var c = document.getElementById("count");
c.innerHTML = maxchar;
i.addEventListener("keydown", count);
function count(e) {
var len = i.value.length;
if (len >= maxchar) {
e.preventDefault();
} else {
c.innerHTML = maxchar - len - 1;
}
}
textarea {
display: block;
width: 200 px;
height: 100 px;
}
Remaining characters: <span id="count"></span>
<textarea id="textinput">
</textarea>
Delegation and data attributes will help
window.addEventListener("load", function() {
const container = document.getElementById("container")
container.querySelectorAll("textarea").forEach(ta => ta.dataset.max = ta.dataset.cnt); // save
container.addEventListener("input", function(e) {
const tgt = e.target;
if (tgt.matches("textarea")) {
const maxchar = +tgt.dataset.max;
let cnt = +tgt.dataset.cnt;
const c = tgt.previousElementSibling;
cnt = maxchar - tgt.value.length;
if (cnt < 0) {
tgt.value = tgt.value.slice(0, maxchar);
cnt = 0;
}
tgt.dataset.cnt = cnt;
c.textContent = cnt;
}
})
})
textarea {
display: block;
width: 200 px;
height: 100 px;
}
<div id="container">
Remaining characters: <span class="count"></span><textarea id="textinput1" data-cnt="160"></textarea>
<hr/> Remaining characters: <span class="count"></span><textarea id="textinput2" data-cnt="100"></textarea>
</div>
The problem in your fiddle is you are declaring multiple variable with the same name. You declare i and c twice. You also declare the function count twice. Rename half of those variables to something unique and it should work how you expect it to.
You can see a working example in this fiddle.
As you know the data will be changeable. So, I would like to know how can I change the color of all last digits of a number only if there is a zero in the end or more.
for Example: 0.50 will be 0.50. 10.00 = 10.00. 10,000.00 = 10,000.00. 100,050.00 = 100,050.00 and so on. Thanks and any help would be greatly appreciated.
.num{
color: black;
font-size: 22px;
font-family: sans-serif;
}
<div class="num">0.50</div>
<div class="num">10.00</div>
<div class="num">10,000.00</div>
<div class="num">100,050.00</div>
You have to do some kind of DOM manipulation to make the styling. You can try the following way:
var nums = document.querySelectorAll('.num');
nums.forEach(function(n){
var s = n.textContent.split(/[,.0]+$/);
var m = n.textContent.match(/[,.0]+$/);
if(s && m && s.length > 0 && m.length > 0){
n.innerHTML = s[0] + '<span class=numStyle>'+m[0]+'</span>';
}
});
.num{
color: black;
font-size: 22px;
font-family: sans-serif;
}
.numStyle{
font-weight: bold;
opacity: 0.5;
color: red;
}
<div class="num">1.5</div>
<div class="num">0.50</div>
<div class="num">10.00</div>
<div class="num">10,000.00</div>
<div class="num">100,050.00</div>
USING REGEX
function zeroHighligherWithRegex(str) {
var res = str.split(/(0(?:\n|\t|\s|0|,|\.)*)$/);
return res[0] + `<span class="highlight">${res[1]}</span>`;
}
WITHOUT USING REGEX
Find the last repeating zero list including . and ,
wrapping zero list in span
return the required number
zero highligher function
function zeroHighligher(textContent) {
let num = textContent;
let charList = num.split('');
let isContinuos = true;
let nonZeroNumList = [];
let zeroList = charList.reverse().map(num => {
if(isContinuos && (num === '0' || num === '.' || num === ',')) {
return num;
} else {
isContinuos = false;
nonZeroNumList.push(num);
}
});
let zeroNumString = zeroList.reverse().join('');
let nonZeroNumString = nonZeroNumList.reverse().join('');
const outputString = nonZeroNumString + `<span class="highlight">${zeroNumString}</span>`
return outputString;
}
to loop all the div elements
document.querySelectorAll('.num').forEach(elm => {
elm.innerHTML = zeroHighligherWithRegex(elm.textContent)
})
CSS
span.highlight {
font-weight: bolder;
}
Outputs
0.50
10.00
10,000.00
100,050.00
Demo
Using JS and the power of IIFE's you can do as follows:
(() => {
// Get all items
const items = document.getElementsByClassName('num');
// Iterate over those items to get text of each one
for (const item of items) {
const length = item.innerText.length;
const text = item.innerText;
let digits = 0;
// Iterate from end to start, you can access strings characters as it
// were an array, so if it finds anything that's not a
// comma, dot or zero, it will break the loop
for (var i = (length - 1); i >= 0; i--) {
if (text[i] === '0'
|| text[i] === '.'
|| text[i] === ','
) {
// Increment digits so you know hoy many yo have to change
digits++;
} else {
break;
}
}
// innerHTML to each one of your items
// the first part is to print normal substring
// second part prints from where you stopped to the end
item.innerHTML = `${text.substring(0, length-digits)}<b>${text.substring(length-digits, length)}</b>`
}
})();
<div class="num">0.50</div>
<div class="num">10.00</div>
<div class="num">10,000.00</div>
<div class="num">100,050.00</div>
I gave two solutions, using method forEach(). With wrapping in a span tag with a class and in a strong tag.
I tried not to use variables inside the loop, in order for you to better understand how my code works.
let num = document.querySelectorAll(".num");
num.forEach(function(num_curr) {
num_curr.innerHTML = num_curr.textContent.replace(/.$/, '<span class="last-letter">' + num_curr.textContent[num_curr.textContent.length - 1] + "</span>");
});
.num {
color: black;
font-size: 22px;
font-family: sans-serif;
}
.last-letter {
font-weight: bold;
color: green;
}
<div class="num">0.50</div>
<div class="num">10.00</div>
<div class="num">10,000.00</div>
<div class="num">100,050.00</div>
This is a solution without a span tag with a class. The last character is wrapped in a strong tag, which makes the character bold.
let num = document.querySelectorAll(".num");
num.forEach(function(num_curr) {
num_curr.innerHTML = num_curr.textContent.replace(/.$/, '<strong>' + num_curr.textContent[num_curr.textContent.length - 1] + "</strong>");
});
.num {
color: black;
font-size: 22px;
font-family: sans-serif;
}
<div class="num">0.50</div>
<div class="num">10.00</div>
<div class="num">10,000.00</div>
<div class="num">100,050.00</div>
I'm learning React and JavaScript generally via writing chess game and got to some intersting issue with elements changing position depending on whether content is empty or not.
I create simple CodePen to illustrate problem - https://codepen.io/anon/pen/KbGKrX?editors=0010
Clicking on each square will change it content.
Problem is that this square will change position, unless all squares in the same row have same content (null or text). Tried with empty strings and spaces instead null and got the same behaviour.
Inspecting in Dev Tools I see no change of CSS so I am puzzled and not sure whether its is some strange behaviour because of React or something else.
I would appreciate any help on this one.
JS part:
const BoardSquare = (props) => {
return (
<button
className={`board-square board-square-${props.squareColor}`}
onClick={props.onClick}
>
{props.piece}
</button>
);
};
const squares = new Array(8);
for (let i = 0; i < 8; i++) {
let row = new Array(8);
for (let j = 0; j < 8; j++) {
row[j] = {
rowIndex: i,
colIndex: j,
key: (j + 10).toString(36) + (8 - i).toString(),
color: (i + j) % 2 === 0 ? "light" : "dark",
piece: i === 1 ? j : null
};
}
squares[i] = row;
}
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: squares,
whiteMove: true
};
}
handleClickSquare(i, j) {
//alert("clicked:" + i + " " + j);
const squares = this.state.squares.slice();
squares[i][j].piece = squares[i][j].piece !== null ? null : j;
this.setState({ squares: squares, whiteMove: !this.state.whiteMove });
}
handleClickNewGame() {
const squares = this.state.squares.slice();
for (let i = 0; i < 8; i++) {
squares[1][i].piece = i;
squares[6][i].piece = i;
}
this.setState({ squares: squares, whiteMove: true });
}
render() {
return (
<div id="board">
{this.state.squares.map((row, rowIndex) => {
return (
<div>{
row.map((square, colIndex) => {
return (
<BoardSquare
key={square.key}
squareColor={square.color}
id={square.key}
piece={square.piece}
onClick={() => this.handleClickSquare(rowIndex, colIndex)}
/>
);
})}
</div>)
})}
</div>
)
}
}
// ========================================
ReactDOM.render(
<Game />,
document.getElementById('root')
);
CSS:
#board {
font-size: 0;
}
.board-square {
text-align: center;
align-items: center;
justify-content: center;
height: 20px;
width: 20px;
line-height: 20px;
font-size: 10px;
margin: 0;
padding: 0;
border: 0;
}
.board-square-dark {
background-color: green;
}
.board-square-light {
background-color: #E0AB76;
}
The reason for this behavior is because of the default baseline vertical alignment. Already well explained in this answer: https://stackoverflow.com/a/13550706/1790728
By changing the display to inline-block and setting vertical-align to top, the squares will be aligned without using a white-space.
Working example: https://codepen.io/anon/pen/MZLZYj
in chrome, space-around doesn't center items if its single column.
but in Firefox, it works.
how to make it behave like firefox?
also, keep in mind that text is aligned to the right
.flex-cont {
display: flex;
justify-content: flex-start;
flex-flow: column wrap;
align-content: space-around;
align-content: space-evenly;
align-items: flex-end;
}
.flex-item {
/* display: inline-block; */
flex: 0 1 auto;
width: fit-content;
}
http://jsfiddle.net/f6k7xoe0/1/
edit: also I can do this but this messes up text aligning to right :
.flex-cont{
align-items: center;
}
edit: honestly I wouldn't care so much if it was as a hobby, but I added cefsharp(chrome) in my application. will be in production. there is no other way. i have to get that render in the cefsharp.
edit:
this is not a duplicate.
I dont ask WHY it doesn't work. I want a solution
my output is different. output in the other questions is not even multi-column.
edit2: I solved it via js getboundrect compare get max-width of each item them apply margin if wrap happens. but its messy don't wanna use it. but I have to.
I cleaned up the code to make it apply the all flex-container, flex item if you give appropriate CssSelector in the doit() function. it will work. but this is for columns.
http://jsfiddle.net/yeaqrh48/1203/
var debug = true;
class ertTimer {
constructor(funcName ,intervalms=3500, maxRunDuration=20000 , StopIfReturnsTrue=true ) {
this.intervalObj = setInterval(function(){
console.log("interval - funcName:" + funcName.name);
try{
var res = funcName();
if(StopIfReturnsTrue)
if(res == true)
clearInterval(intervalObj);
} catch(exx){console.warn(exx.message, exx.stack);}
}, intervalms);
// after 15 sec delete interval
setTimeout( function(){ clearInterval( intervalObj ); },maxRunDuration);
this.intervalms = intervalms;
this.maxRunDuration = maxRunDuration;
}
get getter_intervalms() { return this.intervalms; }
calcRepeatTimes() {
return this.maxRunDuration / this.intervalms;
}
}
var center_ONsingleCol_nonFF = function(contNode, itemSelector) {
var items = contNode.querySelectorAll(itemSelector);
//arr.count shoud be 1 element // items[0].style.alignItems = "center";
var parItem = items[0].parentNode;
var parItemR = parItem.getBoundingClientRect();
var parWidth = parItemR.width;
var maxItemWidth = 0;
for (var k = 0; k < items.length; k++) {
var currItem = items[k].getBoundingClientRect();
if (currItem.width > maxItemWidth)
maxItemWidth = currItem.width;
//console.log(parWidth, itemWidth);
}
var alignItemsVal = getComputedStyle_propValue(parItem , "align-items");
var flexDirVal = getComputedStyle_propValue(parItem , "flex-direction");
var iswrapped = isWrapped(contNode ,itemSelector );
for (var k = 0; k < items.length; k++) {
if(iswrapped && flexDirVal == "column" ){
if(alignItemsVal == "flex-end"){
items[k].style.marginRight = "" + ((parWidth - maxItemWidth) * 0.5) + "px";
items[k].style.marginLeft = "";
}
else if(alignItemsVal == "flex-start"){
items[k].style.marginRight = "";
items[k].style.marginLeft = "" + ((parWidth - maxItemWidth) * 0.5) + "px";
}else
{
items[k].style.marginRight = "";
items[k].style.marginLeft = "";
}
}
else{
items[k].style.marginRight = "";
items[k].style.marginLeft = "";
}
}
};
var getComputedStyle_propValue = function(element , CssPropName){
//var element = document.querySelector( selector );
var compStyles = window.getComputedStyle(element);
var comStyle_xxx = compStyles.getPropertyValue(CssPropName);
return comStyle_xxx;
};
var colorizeItem = function(items) {
for (var k = 0; k < items.length; k++) {
items[k].style += ";background:Red;";
}
};
var detectWrap = function(contNode, item_selector) {
var wrappedItems = [];
var prevItem = {};
var currItem = {};
var items = contNode.querySelectorAll(item_selector);
//console.log("wrapped item arrrat::",items);
for (var i = 0; i < items.length; i++) {
currItem = items[i].getBoundingClientRect();
if (prevItem && prevItem.top > currItem.top) {
wrappedItems.push(items[i]);
}
prevItem = currItem;
}
return wrappedItems;
};
var isFirefox = function() {
var _isFF = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
return _isFF;
};
var isWrapped = function(contNode, item_selector){
var wrappedItems = detectWrap(contNode, item_selector);
//colorizeItem(wrappedItems);
if (wrappedItems == null || wrappedItems.length == 0)
return true;
else
return false;
};
var isWired_listenContResize = false;
var doit = function() {
if (isFirefox()) {
console.log("ff already works Right. ");
return;
} else {
console.log("not ff. script will run. ");
}
/* flexItem_selector must be relative to flexCont*/
var flexContainer_selector = ".flex-cont.cont-resize"; /*specific flex-cont */
var flexItem_selector = ".flex-item";
var contList = document.querySelectorAll(flexContainer_selector);
for (var i = 0; i < contList.length; i++) {
//no such event //there is external lib..
// call doit after you change size in the code;
if (!isWired_listenContResize) {
contList[i].onresize = function() { doit(); };
}
center_ONsingleCol_nonFF(contList[i], flexItem_selector);
}
isWired_listenContResize = true;
};
window.onresize = function(event) { doit(); };
window.onload = function(event) {
doit();
const et1_ = new ertTimer(doit , 500, 320000,true );
};
I am having some really weird issues with my static GridView Header. The lines in IE aren't lining up properly; some of them do, and others do not. Can some one help me out? It works perfectly in Chrome, just not IE.
Chrome:
IE:
Here is my relevant code.
<script type="text/javascript">
function MakeStaticHeader(gridId, height, width, headerHeight, isFooter) {
var tbl = document.getElementById(gridId);
if (tbl) {
var DivHR = document.getElementById('DivHeaderRow');
var DivMC = document.getElementById('DivMainContent');
var DivFR = document.getElementById('DivFooterRow');
//*** Set divheaderRow Properties ****
DivHR.style.height = headerHeight + 'px';
DivHR.style.width = (parseInt(width) - 50) + 'px';
DivHR.style.position = 'relative';
DivHR.style.top = '0px';
DivHR.style.left = (tbl.clientLeft-25) +'px';
DivHR.style.zIndex = '10';
DivHR.style.verticalAlign = 'top';
DivHR.style.alignContent = 'center';
//*** Set divMainContent Properties ****
DivMC.style.width = width + 'px';
DivMC.style.height = height + 'px';
DivMC.style.position = 'relative';
DivMC.style.top = -headerHeight + 'px';
DivMC.style.zIndex = '1';
//****Copy Header in divHeaderRow****
DivHR.appendChild(tbl.cloneNode(true));
}
}
function OnScrollDiv(Scrollablediv) {
document.getElementById('DivHeaderRow').scrollLeft = Scrollablediv.scrollLeft;
//if (document.getElementById('DivHeaderRow').scrollLeft >= 300) {
// document.getElementById('DivHeaderRow').scrollLeft = 300;
//}
}
</script>
CSS
html, body {
margin:0px;
padding:0px;
width: 100%;
box-sizing: border-box;
}
CSS Header Style
.GVFixedHeader
{
font-weight: bold;
background-color: Green;
position: relative;
font-size: 12px;
text-align: left;
}
It has to do with how IE renders a GridView. I would custom change my formating on one cell of the table, but that would mess with IE and change the default settings. Chrome would correctly identify that I only wanted to add style not change completely.
for (int i = 0; i < e.Row.Cells.Count; i++)
{
if (e.Row.RowType == DataControlRowType.Header)
{
e.Row.Cells[i].Attributes.Add("style", "white-space: inital;");
e.Row.Cells[i].Attributes.Add("style", "text-align: left;");//THIS IS WHAT I ADDED + some altering of the width of the JS
if (i == 1)
{
e.Row.Cells[i].Text = "Make Inactive?";
}
if (i == 9)
{
e.Row.Cells[i].Text = "Total Invoice YTD";
e.Row.Cells[i].Attributes.Add("style", "white-space: normal;");
}
if (i == 13)
{
e.Row.Cells[i].Attributes.Add("style", "white-space: normal;");
}
}
if (e.Row.RowType == DataControlRowType.DataRow) { e.Row.Cells[i].Attributes.Add("style", "white-space: nowrap;"); } //ALWAYS makes sure there is no wrapping of text
}