I've made a JavaScript dropdown menu. Everything works fine, except the background image. I have the image set to change when the dropdown menu is expanded, which also works fine.
The issue is with the headers. Unless the header is set to display inline-block or inline, the menu won't expand. When set to inline-block or inline everything expands when you click on the box. But if you click on the header itself, it adds the padding and border around the header and ads in the background image from the div. How do you prevent this from happening?
<div class="panel">
<div class="collapse"><h2>Features</h2></div>
<div class="elements">
text<br>text<br>text
</div>
</div>
<style>
h2 {/*display: inline-block;*/
/*display: inline;*/
margin: 0px;
padding: 0px 0px 0px 0px;
color: #ffffff;
text-align: center;
text-transform: uppercase;}
.expand,
.collapse {cursor: pointer;
background-position: center right;
background-repeat: no-repeat;
background-color: #000033;
border: 2px solid #990044;
color: #ffffff;
padding: 10px 0px;
text-align: center;}
.collapse {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAABHUlEQVRIS+3USw6CMBAA0BYNutOjcAQ9iXHjhoXhBt4AEmwwbvQm6g04ii4hCLaNNRUp/dDgQllRPvMy05lC0PMFe/bAH7Re8R8qaYySTZGPoyBYXm3WMQwP04Gbhfd8FJDYtKTxNjkCCBf4Ni3y0dwWSrChm51wXI/FhjHaRXix5rKygtYwGr4C1QUitPdKUJ7xemILbcJw7JsDnBktqU20DfP9VfoaCxuoDCPJvc1hF1QF+wBNy6uKNYK6qA4mBFVRXawVlKHkPTfUbKJo65NuFJ1W0sNb1EjPgOQEUcakGbJIApRPQpoZ+1iaoQKqjCln2IJqYdpgrZGArEGaGke5pPzPZE/Juq0bjbtU9KPpc6MMTTGjPeyCfQV8AK4c2lwJRjQ3AAAAAElFTkSuQmCC);}
.expand {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAABD0lEQVRIS+3Wyw2CQBAG4F1Q8KadSAnYgR0YL164SCWYKDHxonZgB1ICdiI3QR6yCgSVXXaAkGDkwgXyZf6dYcCo5Qu37KFugIaxH5FkdH1+hSYErpBgPck9E8j35AkUBYE5TEkqs6EoN1iApWmCUC6QgYHRUpCCOYk0zDUNV6VMkIYJSFAJFKLQim8glAqyME1b2AQ0zZ0CRQtBHiyNEop+gRCsCvoGVsGgaAbWwSDoE2wC40VxkxgPiteb7QFhPMsNsEPmLG196DZgolF0fFXYd614M47jhxvBCtEIXfy7rGZnKEq3k4jEZd3KPhMhcxqgYBV4gylZZaXf0qqR0t77g00n2pG/tjpl/37TPACe/d8VUJ3+EgAAAABJRU5ErkJggg==);}
.elements {background-color: #ccd9ff;
overflow: hidden;}
</style>
<script>
function aaManageEvent (eventObj, event, eventHandler) {
if (eventObj.addEventListener) {eventObj.addEventListener (event, eventHandler, false);}
else if (eventObj.attachEvent) {event = "on" + event; eventObj.attachEvent (event, eventHandler);}
}
window.onload = function () {
var divs = document.getElementsByTagName ("div");
for (var i = 0; i < divs.length; i++) {
if (divs[i].className == "collapse") {
aaManageEvent (divs [i], "click", spring.expandOrCollapse);
}
else if (divs[i].className == "elements") {
var height = divs [i].offsetHeight;
divs [i] .height = height;
if (divs [i] .id == "") divs [i].id = "div" + i;
divs [i].style.height = "0";
}
}
}
var spring = {
// adjust height
adjustItem : function (val, newItem) {
document.getElementById (newItem).style.height = val + "px";
},
// check if expand or collapse
expandOrCollapse : function (evnt) {
evnt = evnt ? evnt : window.event;
var target = evnt.target ? evnt.target : evnt.srcElement;
if (target.className == "collapse") spring.expand (target);
else spring.collapse (target);
},
// Expand Panel
expand : function (target) {
target.className = 'expand';
var children = target.parentNode.childNodes, panel;
for (var i = 0; i < children.length; i++) {
if (children [i].className == "elements") {
panel = children [i]; break;
}
}
var height = panel.height, incr = height / 20;
for (var i=0; i < 20; i++) {
var val = (i + 1) * incr;
var func = "spring.adjustItem (" + val + ", '" + panel.id + "')";
setTimeout (func, (i + 1) * 30);
}
},
// Collapse Panel
collapse : function (target) {
target.className = "collapse";
var children = target.parentNode.childNodes, panel;
for (var i = 0; i < children.length; i++) {
if (children [i].className == "elements") {
panel = children [i]; break;
}
}
var height = panel.height, decr = height / 20;
for (var i = 0; i < 20; i++) {
var val = height - (decr * (i + 1));;
var func = "spring.adjustItem (" + val + ", '" + panel.id + "')";
setTimeout (func, (i + 1) * 30);
}
}
};
</script>
When I click on the div, the dropdown works. But when I click on the header, I see an error in the browser console.
I think because when clicking on the <h2>Features</h2> element, the click event bubbles up to the <div class="collapse">, making the var target in this line not the <div class="collapse"> but the <h2>:
var target = evnt.target ? evnt.target : evnt.srcElement;
A possible solution to fix this is for example to add an id to this line:
<div id="header" class="collapse"><h2>Features</h2></div>
Then you can directly get that div by id and change the classname.
I've adjusted your expandOrCollapse function to make it toggle based on the classname from the div with id="header".
For example:
function aaManageEvent (eventObj, event, eventHandler) {
if (eventObj.addEventListener) {eventObj.addEventListener (event, eventHandler, false);}
else if (eventObj.attachEvent) {event = "on" + event; eventObj.attachEvent (event, eventHandler);}
}
window.onload = function () {
var divs = document.getElementsByTagName ("div");
for (var i = 0; i < divs.length; i++) {
if (divs[i].className == "collapse") {
aaManageEvent (divs [i], "click", spring.expandOrCollapse);
}
else if (divs[i].className == "elements") {
var height = divs [i].offsetHeight;
divs [i] .height = height;
if (divs [i] .id == "") divs [i].id = "div" + i;
divs [i].style.height = "0";
}
}
}
var spring = {
// adjust height
adjustItem : function (val, newItem) {
document.getElementById (newItem).style.height = val + "px";
},
// check if expand or collapse
expandOrCollapse : function (evnt) {
var header = document.getElementById('header');
if (header.className === "collapse") {
spring.expand(header);
} else {
spring.collapse(header);
}
},
// Expand Panel
expand : function (target) {
target.className = 'expand';
var children = target.parentNode.childNodes, panel;
for (var i = 0; i < children.length; i++) {
if (children [i].className == "elements") {
panel = children [i]; break;
}
}
var height = panel.height, incr = height / 20;
for (var i=0; i < 20; i++) {
var val = (i + 1) * incr;
var func = "spring.adjustItem (" + val + ", '" + panel.id + "')";
setTimeout (func, (i + 1) * 30);
}
},
// Collapse Panel
collapse : function (target) {
target.className = "collapse";
var children = target.parentNode.childNodes, panel;
for (var i = 0; i < children.length; i++) {
if (children [i].className == "elements") {
panel = children [i]; break;
}
}
var height = panel.height, decr = height / 20;
for (var i = 0; i < 20; i++) {
var val = height - (decr * (i + 1));;
var func = "spring.adjustItem (" + val + ", '" + panel.id + "')";
setTimeout (func, (i + 1) * 30);
}
}
};
h2 {/*display: inline-block;*/
/*display: inline;*/
margin: 0px;
padding: 0px 0px 0px 0px;
color: #ffffff;
text-align: center;
text-transform: uppercase;}
.expand,
.collapse {cursor: pointer;
background-position: center right;
background-repeat: no-repeat;
background-color: #000033;
border: 2px solid #990044;
color: #ffffff;
padding: 10px 0px;
text-align: center;}
.collapse {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAABHUlEQVRIS+3USw6CMBAA0BYNutOjcAQ9iXHjhoXhBt4AEmwwbvQm6g04ii4hCLaNNRUp/dDgQllRPvMy05lC0PMFe/bAH7Re8R8qaYySTZGPoyBYXm3WMQwP04Gbhfd8FJDYtKTxNjkCCBf4Ni3y0dwWSrChm51wXI/FhjHaRXix5rKygtYwGr4C1QUitPdKUJ7xemILbcJw7JsDnBktqU20DfP9VfoaCxuoDCPJvc1hF1QF+wBNy6uKNYK6qA4mBFVRXawVlKHkPTfUbKJo65NuFJ1W0sNb1EjPgOQEUcakGbJIApRPQpoZ+1iaoQKqjCln2IJqYdpgrZGArEGaGke5pPzPZE/Juq0bjbtU9KPpc6MMTTGjPeyCfQV8AK4c2lwJRjQ3AAAAAElFTkSuQmCC);}
.expand {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAABD0lEQVRIS+3Wyw2CQBAG4F1Q8KadSAnYgR0YL164SCWYKDHxonZgB1ICdiI3QR6yCgSVXXaAkGDkwgXyZf6dYcCo5Qu37KFugIaxH5FkdH1+hSYErpBgPck9E8j35AkUBYE5TEkqs6EoN1iApWmCUC6QgYHRUpCCOYk0zDUNV6VMkIYJSFAJFKLQim8glAqyME1b2AQ0zZ0CRQtBHiyNEop+gRCsCvoGVsGgaAbWwSDoE2wC40VxkxgPiteb7QFhPMsNsEPmLG196DZgolF0fFXYd614M47jhxvBCtEIXfy7rGZnKEq3k4jEZd3KPhMhcxqgYBV4gylZZaXf0qqR0t77g00n2pG/tjpl/37TPACe/d8VUJ3+EgAAAABJRU5ErkJggg==);}
.elements {background-color: #ccd9ff;
overflow: hidden;}
<div class="panel">
<div id="header" class="collapse"><h2>Features</h2></div>
<div class="elements">
text<br>text<br>text
</div>
</div>
Edit your declaration block of h2 as shown below. This will solve your problem.
h2 {
display: inline-block;
margin: 0px;
padding: 0px 0px 0px 0px;
color: #ffffff;
text-align: center;
text-transform: uppercase;
pointer-events: none; // this line solves your problem.
}
CSS property pointer-events let you control under what circumstances an element can become the target of mouse events. when you set it to none, the element will never be the target of mouse events. So, the click event passed on to its descendant elements (here the box).
Related
I have the following html structure:
<div id="pixel_1" class="pixelarea"></div>
<div id="pixel_2" class="pixelarea"></div>
<div id="pixel_3" class="pixelarea"></div>
each div is 10px wide and 10px high. The whole surface is 102 divs wide and 200 divs high.(1020 pixel wide and 2000pixel high)
This is my jquery function:
var getNumericPart = function(id) {
var num = id.replace(/[^\d]+/, '');
return num;
};
$('body').on('click','.pixelarea',function(e) {
e.preventDefault();
var id = getNumericPart($(this).attr('id')); //get only the number from the id
var count = parseInt($("#selectedpixelsum").text());
if($('#pixel_' +id).hasClass('selected')){
$('#pixel_' +id).removeClass('selected');
count--;
$('#selectedpixelsum').html(count);
}else{
$('#pixel_' +id).addClass('selected');
count++;
$('#selectedpixelsum').html(count);
}
});
How can I make sure that only adjacent divs can be selected?
By this I mean the divs below, above and to the right and left of the selected divs.
Because you know the number of items per row (102), it is simple to use the elements index to allow or disallow selection.
Left of centre is index - 1
Right of centre is index + 1
Above centre is index - 102
Below centre is index + 102
Assumes that only neighbours of the first pixel selected may be selected:
/*
* Create pixel grid
*/
const $pixelsContainer = $('.pixels');
for (let i = 0; i < (102 * 5); i++) {
$pixelsContainer.append('<div class="pixelarea" />');
}
/* END Create pixel grid */
let selectedIndex = -1;
$('.pixelarea').on('click', function() {
const clickedIndex = $(this).index();
if (clickedIndex === selectedIndex) {
/*
* Primary selected element was clicked. Remove all selections;
*/
$('.pixelarea.selected').removeClass('selected');
selectedIndex = -1;
return;
}
if (selectedIndex === -1) {
/*
* This is the primary selection
*/
selectedIndex = clickedIndex;
$(this).addClass('selected');
}
if (clickedIndex === selectedIndex - 1 || /* Left of primary */
clickedIndex === selectedIndex + 1 || /* Right of primary */
clickedIndex === selectedIndex - 102 || /* Above primary */
clickedIndex === selectedIndex + 102) { /* Below primary */
/*
* Select / Deselect this element
*/
$(this).toggleClass('selected');
}
});
.pixels {
display: flex;
flex-wrap: wrap;
width: 1020px;
}
.pixelarea {
box-sizing: border-box;
background: #f2f2f2;
border: 1px solid #e6e6e6;
width: 10px;
height: 10px;
}
.pixelarea:hover {
background: orange;
}
.pixelarea.selected {
background: limegreen;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="pixels"></div>
Assumes neighbours of the last pixel selected can be selected:
/*
* Create pixel grid
*/
const $pixelsContainer = $('.pixels');
const columnCount = 102;
const rowCount = 5;
for (let i = 0; i < (columnCount * rowCount); i++) {
$pixelsContainer.append('<div class="pixelarea" />');
}
/* END Create pixel grid */
let selectedIndex = -1;
$('.pixelarea').on('click', function() {
const clickedIndex = $(this).index();
if (selectedIndex === -1) {
/*
* This is the first selection
*/
selectedIndex = clickedIndex;
$(this).addClass('selected');
return;
}
if (clickedIndex === selectedIndex - 1 ||
clickedIndex === selectedIndex + 1 ||
clickedIndex === selectedIndex - columnCount ||
clickedIndex === selectedIndex + columnCount) {
selectedIndex = $(this).index();
$(this).addClass('selected');
}
});
.pixels {
display: flex;
flex-wrap: wrap;
width: 1020px;
}
.pixelarea {
box-sizing: border-box;
background: #f2f2f2;
border: 1px solid #e6e6e6;
width: 10px;
height: 10px;
}
.pixelarea:hover {
background: orange;
}
.pixelarea.selected {
background: limegreen;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="pixels"></div>
Assumes neighbours of any selected pixel can be selected:
(Fixes selectable pixels from flowing on to incorrect rows)
/*
* Create pixel grid
*/
const $pixelsContainer = $('.pixels');
const columnCount = 102;
const rowCount = 5;
for (let i = 0; i < (columnCount * rowCount); i++) {
$pixelsContainer.append('<div class="pixelarea" />');
}
/* END Create pixel grid */
let selectedIndex = -1;
$('.pixelarea').on('click', function() {
const clickedIndex = $(this).index();
if (selectedIndex === -1) {
/*
* This is the first selection
*/
selectedIndex = clickedIndex;
$(this).addClass('selected');
markAllowed();
return;
}
if ($(this).hasClass('allowed')) {
selectedIndex = $(this).index();
$(this).addClass('selected');
markAllowed();
}
});
function markAllowed() {
const row = Math.floor(selectedIndex / columnCount) + 1;
// Allow left if we haven't clicked the first element in the row
if (selectedIndex - 1 > 0) {
$('.pixelarea').eq(selectedIndex - 1).addClass('allowed');
}
/*
* Allow right if we haven't clicked the last element in the row
*/
if (((selectedIndex + 1) / row) < columnCount) {
$('.pixelarea').eq(selectedIndex + 1).addClass('allowed');
}
// Allow above if we haven't clicked in the first row
if (row > 1) {
$('.pixelarea').eq(selectedIndex - columnCount).addClass('allowed');
}
// Allow below
$('.pixelarea').eq(selectedIndex + columnCount).addClass('allowed');
}
.pixels {
display: flex;
flex-wrap: wrap;
width: 1020px;
}
.pixelarea {
box-sizing: border-box;
background: #f2f2f2;
border: 1px solid #e6e6e6;
width: 10px;
height: 10px;
}
.pixelarea:hover {
background: orange;
}
.pixelarea.selected {
background: limegreen;
}
.allowed {
background: lightGreen;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="pixels"></div>
I have a graph that is rendering its values as a div inside the body element with a class according to their number values. This is working fine. But next I need to sort the divs according to their number values or background color. BUT, it needs to start on the lower left corner of the page and fan out upwards to towards the right as the numbers increase. Basically just like a line graph.
I'd like to stay away from libraries if at all possible.
How would I approach this? Thank you all.
let interval = setInterval(makeDivs, 5);
function makeDivs(){
let cont = checkHeight();
if(cont){
let div = document.createElement('div');
let randNum = Math.random() * 100;
if(randNum < 20) { div.classList.add('blue') }
if(randNum >= 20 && randNum < 40) { div.classList.add('green') }
if(randNum >= 40 && randNum < 60) { div.classList.add('yellow') }
if(randNum >= 60 && randNum < 80) { div.classList.add('orange') }
if(randNum >= 80 && randNum < 101) { div.classList.add('red') }
div.textContent = randNum.toFixed(2);
document.querySelector('body').appendChild(div);
} else {
alert('done');
clearInterval(interval);
sortDivs(); // Begin sorting divs
}
}
function checkHeight(){
let w = window.innerHeight;
let b = document.querySelector('body').offsetHeight;
if(b < w) {
return true;
} else {
return false;
}
}
function sortDivs(){
document.querySelector("body div:last-child").remove();
alert('sorting now...')
}
* { box-sizing: border-box;}
body { width: 100vw; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: end;}
body div { width: calc(10% + 1px); text-align: center; border: 1px solid #ddd; margin: -1px 0 0 -1px; padding: 10px;}
body div.blue { background: aqua; }
body div.green { background: green; }
body div.yellow { background: yellow; }
body div.orange { background: orange; }
body div.red { background: red; }
UPDATE!!!
So I have this so far based on the feed back down below. The problem now is the sorting is only happening laterally and not on an angle (spreading right and to the top).
let interval = setInterval(makeDivs, 10);
function makeDivs(){
let cont = checkHeight();
if(cont){
let div = document.createElement('div');
let randNum = Math.random() * 100;
if(randNum < 20) { div.classList.add('blue') }
if(randNum >= 20 && randNum < 40) { div.classList.add('green') }
if(randNum >= 40 && randNum < 60) { div.classList.add('yellow') }
if(randNum >= 60 && randNum < 80) { div.classList.add('orange') }
if(randNum >= 80 && randNum < 101) { div.classList.add('red') }
div.textContent = randNum.toFixed(2);
document.querySelector('.outPut').appendChild(div);
} else {
clearInterval(interval);
document.querySelector(".outPut div:last-child").remove();
compileArrays(); // Begin sorting divs
}
}
function checkHeight(){
let w = window.innerHeight;
let b = document.querySelector('.outPut').offsetHeight;
if(b < w) {
return true;
} else {
return false;
}
}
function compileArrays(){
let divs = document.querySelectorAll('.outPut div');
let bArr = [], gArr = [], yArr = [], oArr = [], rArr = [];
divs.forEach( (d) => {
if( d.classList.contains('blue') ){ bArr.push(d) }
if( d.classList.contains('green') ){ gArr.push(d) }
if( d.classList.contains('yellow') ){ yArr.push(d) }
if( d.classList.contains('orange') ){ oArr.push(d) }
if( d.classList.contains('red') ){ rArr.push(d) }
});
let finalArr = sortArray(bArr).concat(sortArray(gArr)).concat(sortArray(yArr)).concat(sortArray(oArr)).concat(sortArray(rArr));
newDom(finalArr);
}
function sortArray(arr){
let newArr = arr;
newArr.sort( (a, b) => {
return a.innerText - b.innerText;
});
return newArr;
}
function newDom(arr){
let b = document.querySelector('.outPut');
b.innerHTML = '';
arr.reverse();
arr.forEach((a) => {
b.appendChild(a);
});
}
* { box-sizing: border-box;}
body { width: 100vw; height: 100vh; margin: 0; padding: 0; display: flex; align-items: flex-end;}
body .outPut { flex: 1; display: flex; flex-wrap: wrap; flex-direction:row-reverse; }
body .outPut div { width: calc(10% + 1px); text-align: center; border: 1px solid #ddd; margin: -1px 0 0 -1px; padding: 10px;}
body .outPut div.blue { background: aqua; }
body .outPut div.green { background: #44df15; }
body .outPut div.yellow { background: yellow; }
body .outPut div.orange { background: orange; }
body .outPut div.red { background: red; }
<div class="outPut"></div>
Supposed you already have a mechanism to organise such DIVs in a grid as shown, the following should give you what you are looking for:
var items = divList.filter((div) => div.nodeType == 1); // get rid of the whitespace text nodes
items.sort(function(a, b) {
return a.innerHTML == b.innerHTML
? 0
: (a.innerHTML > b.innerHTML ? 1 : -1);
});
Then, place them back in the DOM as needed, example:
for (i = 0; i < items.length; ++i) {
divList.appendChild(items[i]);
}
This worked with the first code example!!!
try this sortDivs function:
function sortDivs() {
document.querySelector("body div:last-child").remove();
alert('sorting now...')
let toSort = document.getElementsByTagName("div")
toSort = Array.prototype.slice.call(toSort, 0)
toSort.sort((a, b) => {
let aord = parseFloat(a.textContent);
let bord = parseFloat(b.textContent);
return bord - aord;
})
document.body.innerHTML = ""
for(var i = 0, l = toSort.length; i < l; i++) {
document.querySelector('body').appendChild(toSort[i]);
}
}
and in the css file set flex-wrap to wrap-reverse. Hope I could help :)
PS: please, implement some else if instead of doing only if
Here is a small fiddle with my sample code demonstrating a simple solution in pure JavaScript and absolute CSS positioning for what you are trying to achieve. Link
As some pointed out already, there might be a library, that already provides a better and complete solution for this - I did not research if it is so.
Code:
file.js
var container = document.getElementById("container")
var results = [1,2,3,4,5,6,7,8]
//you can pre-calculate the order of the distances
//here already orderdered array [distanec][X-axis][Y-axis]
var distances =[[0,0,0],
[1,1,0],
[1,0,1],
[1.414, 1,1],
[2,0,2],
[2,2,0],
[2.234, 2,1],
[2.234, 1,2]]
for (i = 0; i < results.length; i++){
var newDiv = document.createElement("div")
newDiv.className = "result"
newDiv.innerHTML = results[i]
newDiv.style.left = distances[i][1]*20 + "px"
newDiv.style.bottom = distances[i][2]*20 + "px"
container.appendChild(newDiv)
}
function setColor(element){
// set class based on value - you already have this part
}
style.css
#container {
border: 4px;
border-color: red;
border-style: solid;
height: 200px;
width: 200px;
position: relative;
}
.result{
border: 2px;
width: 20px;
height: 20px;
position: absolute;
border-color: blue;
border-style: solid;
text-align: center;
}
site.html
<div id="container">
</div>
Output:
I have a vertical navbar. When the client is on the website and viewing a section of the page that corresponds to the navbar button, that button should have a white border around it. When the client leaves that section for another section, that button should have a border around it and the last buttons border should disappear.
Unfortunately, only half of this works. I don't know why but when I scroll to another section the last sections corresponding button doesn't lose it's border, even though the debug messages state that the border color has been computed to be 'transparent'.
I've tried setting all faces of the border to transparent (top, bottom, left, right) and I've tried setting the style is jquery.
$(document).ready(() => {
$('.page').css('height', $(window).height());
$('.navbar').css('height', $(window).height());
})
let currentActiveButton = null;
document.addEventListener("scroll", () => {
let ids = calculateVisiblePages();
console.log(ids.join(", ") + "\n");
let heights = getVisibleHeights(ids);
let entry;
let highest = -1;
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
if (highest == -1) {
highest = heights[id];
entry = id;
continue;
}
let height = heights[id];
if (highest < height) {
highest = height;
entry = id;
}
}
// console.log(`Highest: ${entry}`);
if (currentActiveButton === entry) return;
if (currentActiveButton != null) {
console.log(
`Attempting to set current active button, id is ${currentActiveButton}, to transparent.`
);
let activeButton = document.getElementById(currentActiveButton);
activeButton.style.borderColor = 'transparent';
let computedStyle = window.getComputedStyle(activeButton);
console.log(`Computes style border color: ${computedStyle.borderTopColor}`);
}
currentActiveButton = entry;
let buttons = document.getElementsByClassName("navbar_button");
switch (entry) {
case "projects": {
console.log("Case is projects.");
borderButton("portfolioButton");
return;
}
case "previousComms": {
borderButton("previousCommsButton");
return;
}
case "aboutMe": {
borderButton("aboutMeButton");
return;
}
}
});
// function getCurrentActiveButton() {
// let buttons = document.getElementsByClassName("navbar_button");
// for (let i = 0; i < buttons.length; i++) {
// const button = buttons[i];
// let computed = window.getComputedStyle(button);
// if (computed.borderTopColor.startsWith("rgba(255, 255, 255")) {
// return button;
// }
// }
// }
function borderButton(id) {
let button = document.getElementById(id);
let computedStyle = window.getComputedStyle(button);
button.style.borderColor = "white";
}
function calculateVisiblePages() {
let pages = document.getElementsByClassName("page");
let visible = [];
for (let i = 0; i < pages.length; i++) {
const page = pages[i];
if (isVisible(page)) visible.push(page.id);
}
return visible;
}
function isVisible(element) {
let elementTop = element.offsetTop;
let elementBottom =
elementTop + Number(element.style.height.replace("px", ""));
let viewportTop = window.scrollY;
let viewportBottom = viewportTop + window.innerHeight;
return elementBottom > viewportTop && elementTop < viewportBottom;
}
function getVisibleHeights(ids) {
let cache = {};
for (let i = 0; i < ids.length; i++) {
// console.log(`Iterating on element: ${ids[i]}`);
const element = document.getElementById(ids[i]);
let elementTop = element.offsetTop;
let elementBottom =
elementTop + Number(element.style.height.replace("px", ""));
let viewportBottom = window.scrollY + window.innerHeight;
let bottom = elementBottom - viewportBottom;
if (bottom < 0) bottom = elementBottom;
if (bottom < viewportBottom && viewportBottom < elementBottom)
bottom = viewportBottom;
let top = elementTop > window.scrollY ? elementTop : window.scrollY;
cache[element.id] = bottom - top;
// for (let i = elementTop; i < elementBottom; i++) {
// //Check if pixel is in element and in the viewport.
// // console.log(`Iteration: ${i}`);
// if (i < window.scrollY) continue;
// if (i > window.scrollY && i < elementBottom && i < viewportBottom) {
// cache[element.id] = i - window.scrollY;
// }
// }
}
return cache;
}
The CSS:
#import url(https://fonts.googleapis.com/css?family=Roboto:500&display=swap);
.root {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 95% 5%
}
.pages {
display: grid;
grid-template-rows: auto auto auto
}
.page {
height: 100%;
width: 100%
}
#projects {
background: #00f
}
#previousComms {
background: #ff0
}
#aboutMe {
background: red
}
.navbar_buttons_wrapper {
height: 100%;
width: 5%;
position: fixed;
top: 0;
right: 0
}
.navbar_buttons {
height: 100%;
display: flex;
align-items: center;
justify-content: center
}
.navbar_buttons ul {
height: auto;
list-style: none;
color: #fff;
padding: 0;
display: grid;
grid-template-columns: auto auto auto;
transform: rotate(-90deg)
}
.navbar_buttons ul li {
width: max-content;
margin-left: 30px;
margin-right: 30px;
font-size: 1.2rem;
text-transform: uppercase;
border-style: solid;
border-color: transparent;
transition: .7s;
padding: 7px
}
html body {
font-family: Roboto, sans-serif;
margin: 0;
border: 0;
padding: 0;
background: #2c2c2c
}
The HTML:
<html>
<head>
<link rel="stylesheet" type="text/css" href="./styles/main.css" />
<script type="text/javascript" src="./scripts/main-min.js"></script>
</head>
<body>
<div class="root">
<div class="pages">
<div class="page" id="projects"></div>
<div class="page" id="previousComms"></div>
<div class="page" id="aboutMe"></div>
</div>
<div class="navbar">
<div class="navbar_buttons_wrapper">
<div class="navbar_buttons">
<ul>
<li class="navbar_button" id="portfolioButton">Portfolio</li>
<li class="navbar_button" id="previousCommsButton">Previous Commissioners</li>
<li class="navbar_button" id="aboutMeButton">About Me</li>
</ul>
</div>
</div>
</div>
</div>
</body>
</html>
I had expected the border to change from white to transparent. However, all I got was no change to the color of the border of the button of the section I had previously been looking at on the website:
Before Movement: https://gyazo.com/77171adefe255973709f11e305bfb030
After Movement: https://gyazo.com/b121d1d33b4f5f205df1468cd936352b
Source Before Movement: https://gyazo.com/92359267cf06cbe3b7c4942f04dbf9ea
Source After Movement: https://gyazo.com/7cc03865e17fc42382774747fb30052a
Github Project File: https://github.com/TheMasteredPanda/Portfolio-Website/blob/master/src/scripts/src/navbarBorderManagement.js#L32
Your problem is inconsistent naming conventions between your ID's and it's causing your element objects to get obfuscated, so if for example you were to breakpoint where you're setting your borderColor to reset it back to transparent, you'd see you're hitting a page HTMLDivElement and not the li you're aiming for. See changes below and have a great weekend, cheers!
$(document).ready(() => {
$('.page').css('height', $(window).height());
$('.navbar').css('height', $(window).height());
})
let currentActiveButton = null;
document.addEventListener("scroll", () => {
let ids = calculateVisiblePages();
console.log(ids.join(", ") + "\n");
let heights = getVisibleHeights(ids);
let entry;
let highest = -1;
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
if (highest == -1) {
highest = heights[id];
entry = id;
continue;
}
let height = heights[id];
if (highest < height) {
highest = height;
entry = id;
}
}
// console.log(`Highest: ${entry}`);
if (currentActiveButton === entry) return;
if (currentActiveButton != null) {
console.log(
`Attempting to set current active button, id is ${currentActiveButton}, to transparent.`
);
let activeButton = document.getElementById(currentActiveButton + 'Button');
activeButton.style.borderColor = 'transparent';
let computedStyle = window.getComputedStyle(activeButton);
console.log(`Computes style border color: ${computedStyle.borderTopColor}`);
}
currentActiveButton = entry;
let buttons = document.getElementsByClassName("navbar_button");
switch (entry) {
case "projects": {
console.log("Case is projects.");
borderButton("projectsButton");
return;
}
case "previousComms": {
borderButton("previousCommsButton");
return;
}
case "aboutMe": {
borderButton("aboutMeButton");
return;
}
}
});
// function getCurrentActiveButton() {
// let buttons = document.getElementsByClassName("navbar_button");
// for (let i = 0; i < buttons.length; i++) {
// const button = buttons[i];
// let computed = window.getComputedStyle(button);
// if (computed.borderTopColor.startsWith("rgba(255, 255, 255")) {
// return button;
// }
// }
// }
function borderButton(id) {
let button = document.getElementById(id);
let computedStyle = window.getComputedStyle(button);
button.style.borderColor = "white";
}
function calculateVisiblePages() {
let pages = document.getElementsByClassName("page");
let visible = [];
for (let i = 0; i < pages.length; i++) {
const page = pages[i];
if (isVisible(page)) visible.push(page.id);
}
return visible;
}
function isVisible(element) {
let elementTop = element.offsetTop;
let elementBottom =
elementTop + Number(element.style.height.replace("px", ""));
let viewportTop = window.scrollY;
let viewportBottom = viewportTop + window.innerHeight;
return elementBottom > viewportTop && elementTop < viewportBottom;
}
function getVisibleHeights(ids) {
let cache = {};
for (let i = 0; i < ids.length; i++) {
// console.log(`Iterating on element: ${ids[i]}`);
const element = document.getElementById(ids[i]);
let elementTop = element.offsetTop;
let elementBottom =
elementTop + Number(element.style.height.replace("px", ""));
let viewportBottom = window.scrollY + window.innerHeight;
let bottom = elementBottom - viewportBottom;
if (bottom < 0) bottom = elementBottom;
if (bottom < viewportBottom && viewportBottom < elementBottom)
bottom = viewportBottom;
let top = elementTop > window.scrollY ? elementTop : window.scrollY;
cache[element.id] = bottom - top;
// for (let i = elementTop; i < elementBottom; i++) {
// //Check if pixel is in element and in the viewport.
// // console.log(`Iteration: ${i}`);
// if (i < window.scrollY) continue;
// if (i > window.scrollY && i < elementBottom && i < viewportBottom) {
// cache[element.id] = i - window.scrollY;
// }
// }
}
return cache;
}
#import url(https://fonts.googleapis.com/css?family=Roboto:500&display=swap);
.root {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 95% 5%
}
.pages {
display: grid;
grid-template-rows: auto auto auto
}
.page {
height: 100%;
width: 100%
}
#projects {
background: #00f
}
#previousComms {
background: #ff0
}
#aboutMe {
background: red
}
.navbar_buttons_wrapper {
height: 100%;
width: 5%;
position: fixed;
top: 0;
right: 0
}
.navbar_buttons {
height: 100%;
display: flex;
align-items: center;
justify-content: center
}
.navbar_buttons ul {
height: auto;
list-style: none;
color: #fff;
padding: 0;
display: grid;
grid-template-columns: auto auto auto;
transform: rotate(-90deg)
}
.navbar_buttons ul li {
width: max-content;
margin-left: 30px;
margin-right: 30px;
font-size: 1.2rem;
text-transform: uppercase;
border-style: solid;
border-color: transparent;
transition: .7s;
padding: 7px
}
html body {
font-family: Roboto, sans-serif;
margin: 0;
border: 0;
padding: 0;
background: #2c2c2c
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<link rel="stylesheet" type="text/css" href="./styles/main.css" />
<script type="text/javascript" src="./scripts/main-min.js"></script>
</head>
<body>
<div class="root">
<div class="pages">
<div class="page" id="projects"></div>
<div class="page" id="previousComms"></div>
<div class="page" id="aboutMe"></div>
</div>
<div class="navbar">
<div class="navbar_buttons_wrapper">
<div class="navbar_buttons">
<ul>
<li class="navbar_button" id="projectsButton">Portfolio</li>
<li class="navbar_button" id="previousCommsButton">Previous Commissioners</li>
<li class="navbar_button" id="aboutMeButton">About Me</li>
</ul>
</div>
</div>
</div>
</div>
</body>
</html>
I want to add 10 points when blue box goes into brown box.
I tried to set score = 0 and points to add = 10 but it doesn't work.
I alert '+10 points' and it shows me the alert so I guess the problem is the DOM ?!?
Any suggestions ?
Thanks !
let moveCounter = 0;
let score = 0;
let obs = 10;
document.getElementById('score').textContent = '0';
var grid = document.getElementById("grid-box");
for (var i = 1; i <= 49; i++) {
var square = document.createElement("div");
square.className = 'square';
square.id = 'square' + i;
grid.appendChild(square);
}
var obstacles = [];
while (obstacles.length < 10) {
var randomIndex = parseInt(49 * Math.random());
if (obstacles.indexOf(randomIndex) === -1) {
obstacles.push(randomIndex);
var drawObstacle = document.getElementById('square' + randomIndex);
$(drawObstacle).addClass("ob")
}
}
var playerOne = [];
while (playerOne.length < 1) {
var randomIndex = parseInt(49 * Math.random());
if (playerOne.indexOf(randomIndex) === -1) {
playerOne.push(randomIndex);
var drawPone = document.getElementById('square' + randomIndex);
$(drawPone).addClass("p-0")
}
}
var addPoints = $('#score');
$('#button_right').on('click', function() {
if ($(".p-0").hasClass("ob")) {
alert('add +10 points !!!')
addPoints.text( parseInt(addPoints.text()) + obs );
}
moveCounter += 1;
if ($(".p-0").hasClass("ob")) {
}
$pOne = $('.p-0')
$pOneNext = $pOne.next();
$pOne.removeClass('p-0');
$pOneNext.addClass('p-0');
});
#grid-box {
width: 400px;
height: 400px;
margin: 0 auto;
font-size: 0;
position: relative;
}
#grid-box>div.square {
font-size: 1rem;
vertical-align: top;
display: inline-block;
width: 10%;
height: 10%;
box-sizing: border-box;
border: 1px solid #000;
}
.ob {
background-color: brown;
}
.p-0 {
background-color: blue;
}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<div id="grid-box">
</div>
<div class="move">
<button id="button_right">right</button><br>
</div>
<div id="score">
</div>
Thank you very much! I am new to JavaScript/ JQuery
Thank you very much!
You are trying to change the HTML inside of the div with id "score".
Selecting the css element using $("#id") retrieves the DOM element and not its contents so adding the score directly to it has no consequences.
What you want to do is: update the score variable and then set the HTML inside the div to the score value.
So instead of just:
addPoints += obs
you should
score += obs
addPoints.html(score)
Could anyone give me a hint on how to generate a chess board (8x8) using JavaScript, using a table tags or ?
I've got the following so far:
<DOCTYPE html>
<html>
<head>
<style>
div
{
border:1px solid black;
width:20px;
height:20px;
}
</style>
</head>
<body>
<script type="text/javascript">
// create a chess table 8x8.
var count = 0;
while (count < 64)
{
if (count % 2 == 0)
{
if (count % 8 == 0 && count !=0)
{
document.write('<br/><div style="background-color:#000000;float:left;"> </div>');
}
else
{
document.write('<div style="background-color:#000000;float:left;"> </div>');
}
}
else
{
document.write('<div style="background-color:#FFFFFF;float:left;"> </div>');
}
/*
*/
count++;
}
</script>
</body>
</html>
I tried to assign black and white to each odd and even number respectively, but it doesn't work this way.
Thank you in advance.
I can not test it at this moment but this should work. This code creates a 8x8 table in which black cells are tagged with "black" class and white cells are tagged with "white" class. Use CSS to give them color. I hope it helps.
var table = document.createElement("table");
for (var i = 1; i < 9; i++) {
var tr = document.createElement('tr');
for (var j = 1; j < 9; j++) {
var td = document.createElement('td');
if (i%2 == j%2) {
td.className = "white";
} else {
td.className = "black";
}
tr.appendChild(td);
}
table.appendChild(tr);
}
document.body.appendChild(table);
At some point for me, this became code golf:
http://jsfiddle.net/4Ap4M/
JS:
for (var i=0; i< 64; i++){
document.getElementById("mainChessBoard").appendChild(document.createElement("div")).style.backgroundColor = parseInt((i / 8) + i) % 2 == 0 ? '#ababab' : 'white';
}
HTML:
<div id="mainChessBoard">
</div>
CSS:
#mainChessBoard
{
width:160px;
height:160px;
border:1px solid black;
}
div
{
width:20px;
height:20px;
float:left;
}
This is the basic foundation to build your chess board.
You can check out the chess board pattern in the console.
var chessBoard = function(size){
var hash = '#'
var space = '_'
for (var i = 0; i < size; i++)
{
hash += '\n'
for (var j = 0; j < size; j++)
{
if((i +j) % 2 == 0)
{
hash += space
}
else
{
hash += "#"
}
};
};
console.log(hash)
}(8)
You can generate boards of any size you want, and this way is pretty easy to change the size of the squares and the colors. you don't need to change anything else.
It is good practice to keep appearance on the stylesheet.
Also don't use document.write
http://jsfiddle.net/YEJ9A/1/
Javascript
var x=8;
var y=8;
var chessBoard = document.getElementById("chessBoard");
for (var i=0; i<y; i++){
var row = chessBoard.appendChild(document.createElement("div"));
for (var j=0; j<x; j++){
row.appendChild(document.createElement("span"));
}
}
CSS
#chessBoard span{
display: inline-block;
width: 32px;
height: 32px;
}
#chessBoard div:nth-child(odd) span:nth-child(even),
#chessBoard div:nth-child(even) span:nth-child(odd){
background-color: black;
}
#chessBoard div:nth-child(even) span:nth-child(even),
#chessBoard div:nth-child(odd) span:nth-child(odd){
background-color: silver;
}
May be you want to do it with divs, not with the table. So here is the solution for it.
$(document).ready(function() {
for (var i = 1; i <= 8; i++) {
var divRow = $("<div>", {
class: "row",
});
for (var j = 1; j <= 8; j++) {
var div = $("<div>", {
class: "square"
});
if (i % 2 == j % 2) {
$(div).addClass("white");
} else {
$(div).addClass("black");
}
divRow.append(div);
}
$("#board").append(divRow);
}
});
#board {
margin: 0;
width: 256px;
height: 256px;
border: solid 1px #333;
}
#board .row {
margin: 0;
}
.square {
height: 32px;
width: 32px;
background: #efefef;
float: left;
}
.square.white {
background: #fff;
}
.square.black {
background: #333;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="board"></div>
A little modernization, using css variables, css attr() and dataset attributes.
This allows to tweak themes, and keep stuffs simple.
const cols = {0:"A", 1:"B", 2:"C", 3:"D", 4:"E", 5:"F", 6:"G", 7:"H"}
const table = document.createElement("table");
table.className = "board";
for (let i = 1; i < 9; i++) {
let tr = document.createElement('tr');
tr.dataset.line = i
for (let j = 1; j < 9; j++) {
let td = document.createElement('td');
td.dataset.col = cols[j-1];
td.dataset.line = i;
td.className = (i%2 === j%2) ? "white square" : "black square";
tr.appendChild(td);
}
table.appendChild(tr);
}
document.querySelector("div").appendChild(table);
:root {
--size: 640px;
--backcolor: darkslategray;
--dark: grey;
--light: white;
--legend: azure;
--hover: lightgreen
}
.board {
width: var(--size);
height: var(--size);
border: 32px solid;
border-color: var(--backcolor);
border-radius: 0.2rem;
}
.square {
border: 1px black solid;
}
.white{
background: var(--light);
}
.black{
background: var(--dark)
}
.board tr::before {
content: attr(data-line);
position: absolute;
margin: 1.8rem 0 0rem -1.5rem;
font-size: larger;
color: var(--legend);
}
.board tr::after {
content: attr(data-line);
position: absolute;
margin: 1.8rem 0 0rem 0.8rem;
font-size: larger;
color: var(--legend);
}
.board tr:first-child > td::before {
content: attr(data-col);
position: absolute;
margin: -4rem 0 0rem 1.6rem;
font-size: larger;
color: var(--legend);
}
.board tr:last-child > td::after {
content: attr(data-col);
position: absolute;
margin: 2.6rem 0 0rem 1.6rem;
font-size: larger;
color: var(--legend);
}
td:hover {
background: var(--hover);
cursor: pointer
}
<div></div>
The following code will print chess board using only HTML and JavaScript.
<script>
document.write("<table border='1' width='200' height='200'>");
for(var i=1; i<=8; i++)
{
document.write("<tr>");
for(var j=1; j<=8; j++)
{
if((i+j)%2!=0)
{
document.write("<td bgcolor='white'></td>");
}
else
{
document.write("<td bgcolor='black'></td>");
}
}
document.write("</tr>");
}
document.write("</table>");
</script>
You should try this one this will really work
<DOCTYPE html>
<html>
<head>
<style>
.chessBoard {
display: inline-block;
border: 2px solid lightGray;
}
.chessBoard div {
line-height: 1px;
}
.chessBoard span {
display: inline-block;
width: 32px;
height: 32px;
background-color: snow;
}
</style>
</head>
<body>
<div class="chessBoard" id="chessBoardNormal"></div>
<div class="chessBoard" id="chessBoardRandom"></div>
<script>
function colorNormal(x, y, color) {
var chessBoard = document.getElementById("chessBoardNormal");
for (var i = 0; i < x; i++) {
var row = chessBoard.appendChild(document.createElement("div"));
for (var j = 0; j < y; j++) {
var span = document.createElement('span');
if (i & 1) { // odd
if (j & 1) { // white
} else { // black
span.style.backgroundColor = color;
}
} else { // even
if (j & 1) { // black
span.style.backgroundColor = color;
}
}
row.appendChild(span);
}
}
}
function colorRandom(x, y) {
colorNormal(8, 8, Math.random() > .5 ? 'black' : '#CFD65C');
}
function getRandomHexColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16);
}
colorNormal(8, 8, 'black');
</script>
</body>
</html>
My idea is simple, if row is even then start with white piece otherwise start with black piece.
HTML:
<div id="mainChessBoard"></div>
Javascript:
const fragment = document.createDocumentFragment();
const board = document.getElementById("mainChessBoard");
const size = 8;
for (let i = 0; i < size; i++) {
let start = i % 2 === 0 ? 0 : 1; // if row is even then start with white otherwise start with black;
for (let j = 0; j < size; j++) {
const div = document.createElement('div');
div.classList.add(start === 1 ? "black" : "white");
fragment.appendChild(div);
start = start === 1 ? 0 : 1;
}
}
board.appendChild(fragment);
Here's a plain JS copy-paste solution. I know it's not that clean in terms of conditioning but it does the job comprehensibly and it's quite straight forward. Field size is easily adjustable as well.
const fieldSize = 50;
const whiteField = document.createElement("div");
whiteField.style = `height:${fieldSize}px;width:${fieldSize}px;background-color:white;display:inline-block`;
const blackField = document.createElement("div");
blackField.style = `height:${fieldSize}px;width:${fieldSize}px;background-color:black;display:inline-block`;
for (let i = 0; i < 8; i++) {
for (let j = 0; j < 8; j++)
i % 2 === 0 ?
j % 2 === 0 ?
document.body.appendChild(blackField.cloneNode(true)) :
document.body.appendChild(whiteField.cloneNode(true)) :
j % 2 === 0 ?
document.body.appendChild(whiteField.cloneNode(true)) :
document.body.appendChild(blackField.cloneNode(true));
document.body.appendChild(document.createElement("br"));
}
We can always think of a better performance, here's the DOM optimized solution using documentFragments -
// main container
let container = document.querySelector("#main");
// a fragment object to store a 2-D mesh of rows and columns
let fragment = new DocumentFragment();
for (let i = 0; i < 8; i++) {
// a fragment object to store a single row with 8 columns
let rowFragment = new DocumentFragment();
for (let j = 0; j < 8; j++) {
// div element for a column
let col = document.createElement("div");
col.style.border = "1px solid";
if ((i + j) % 2 == 0) col.style.background = "black";
else col.style.background = "white";
// adding column in a document fragment
rowFragment.appendChild(col);
}
// adding row in a main fragment
fragment.appendChild(rowFragment);
}
// adding fragment to a DOM one time - this will update the DOM only once
container.appendChild(fragment);
.container {
display: flex;
width: 416px; /* width + horizontal border of each cell ((50 + 2) * 8) */
height: 416px; /* height + vertical border of each cell ((50 + 2) * 8) */
}
div {
flex-wrap: wrap; /* to fit 8 cells in a row as per the width */
width: 50px;
height: 50px;
}
<div class="container" id="main"></div>
Here, the DocumentFragment creates an object of elements we add, but it isn't a part of the active document tree unless we append it to any other DOM node.
Javascript:
var i, j, clas;
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
clas = '';
if (j === 0) clas = 'first ';
else if (j === 7) clas = 'last ';
clas += (i % 2 == j % 2) ? 'white' : 'black';
var field = document.createElement('div');
field.className = clas;
document.body.appendChild(field);
}
}
CSS:
div {
float: left;
width: 20px;
height: 20px;
}
.first {
clear: left;
}
.black {
background: black;
}
.white {
background: red;
}
Sample: http://jsfiddle.net/YJnXG/2/
You mean like this?
.... html.....
<table>
<tr>
<script language='javascript'>
<!--
alternate();
//-->
</script>
</tr>
</table>
....more html.....
function alternate()
{
var numOfCells = 6;
var num = 0;
for (i = 0; i < numOfCells ; i++)
{
txt = "<td bgColor='";
txt += (num % 2 == 0) ? 'red' : 'black';
txt += "'>"
document.write(txt);
num++;
}
}
The % sign is mod; it returns the remainder of a division. the "(...) ? ... : ...;" construction is like an if/else. If the condition is true, the first option -- else the second.