Building JavaScript objects representing a tree - javascript

function createObjects(element, depth){
element.label = element.getElementsByTagName("label")[0].firstChild.nodeValue;
element.url = element.getElementsByTagName("url")[0].firstChild.nodeValue;
element.depth = depth;
if(treeWidths[depth] == undefined){
treeWidths[depth] = 1;
} else {
treeWidths[depth]++;
}
element.children = new Array();
allNodes.push(element);
var children = element.getElementsByTagName("children")[0].childNodes;
for(var i=0; i<children.length; i++){
if(children[i].nodeType != 3 && children[i].tagName == "node"){
element.children.push(createObjects(children[i], depth+1));
}
}
element.expanded = false;
element.visible = false;
element.moved = false;
element.x = 0;
element.y = 0;
if (getNodeWidth() < element.label.length * 10)
element.width = element.label.length * 10;
else
element.width = getNodeWidth();
element.height = getNodeHeight();
return element; }
Having problems with Firefox, it says that 'element.children.push' is not a function but works (only) in Google Chrome...
Any clue?

element.children = new Array();
I wouldn't add an array as a property of an element. If you want to add children to an element, this is not the right way. Also if you want to just use an array to manage data, this is not the right way either.
If you want to add child elements use:
element.appendChild(createObjects(children[i], depth + 1));

Related

Looping error in Javascript with eventHandler

I have the following Javascript code within and HTML page. Its function is to display elements on the form based on the user pressing a + button and if the element is not needed then it removes it via the user pressing the - button. Currently its throwing an error "TypeError: docs[n]" is undefined after the following sequence of events:
Select button to add elements
Remove elements not needed
Add elements back (Error Thrown)
Any help would be most appreciated
`<script language="JavaScript">`
var idx = 0;
var d;
//Make getElementsByClassName work for all of IE revs
if (!document.getElementsByClassName) {
document.getElementsByClassName = function (cn) {
var rx = new RegExp("(?:^|\\s)" + cn+ "(?:$|\\s)");
var allT = document.getElementsByTagName("*"), allCN = [],ac="", i = 0, a;
while (a = allT[i=i+1]) {
ac=a.className;
if ( ac && ac.indexOf(cn) !==-1) {
if(ac===cn){ allCN[allCN.length] = a; continue; }
rx.test(ac) ? (allCN[allCN.length] = a) : 0;
}
}
return allCN;
}
}
function add_fields(e) {
// for some reason, adding the new fields wipes out existing values, so save and restore
var docs = document.getElementsByClassName("doc");
var revs = document.getElementsByClassName("rev");
++idx;
/* console.log("test " + idx); */
var saveDocs = new Array(idx);
var saveRevs = new Array(idx);
for (n=0; n < idx; n++) {
saveDocs[n] = docs[n].value; **//Error is thrown here**
saveRevs[n] = revs[n].value;
}
node = document.getElementById("content");
theNewRow = document.createElement("tr");
theNewCell = theNewRow.insertCell(0);
theNewCell.innerHTML = "Approver Name";
theNewCell.setAttribute("style","font-size: 12pt");
theNewCell1 = theNewRow.insertCell(1);
theNewCell1.innerHTML = "<input type='text' class='doc' style='width:180px;' id='docNum0'/>";
theNewCell1.setAttribute("style","padding-left: 10px");
theNewCell2 = theNewRow.insertCell(2);
theNewCell2.innerHTML = "Approver Email";
theNewCell2.setAttribute("style","font-size: 12pt");
theNewCell2.setAttribute("style","padding-left: 10px");
theNewCell3 = theNewRow.insertCell(3);
theNewCell3.innerHTML = "<input type='text' class='rev' style='width:180px;' id='rev0'/> <input class='minusThing' type='button' style='font-size:10px' value='- '/>";
theNewCell3.setAttribute("style","padding-left: 0px");
node.appendChild( theNewRow );
// restore old arrays and add the id tags to the fields just added
docs = document.getElementsByClassName("doc");
revs = document.getElementsByClassName("rev");
for (n=0; n < idx; n++) {
docs[n].value = saveDocs[n];
revs[n].value = saveRevs[n];
}
docs[idx].id = "docNum" + idx;
revs[idx].id = "rev" + idx;
}
//for Loop the entries
function myfunction() {
alert('Inside Function')
var values = "";
for (n=0; n <= idx; n++)
{
var doc = document.getElementById("docNum"+n).value;
var rev = document.getElementById("rev"+n).value;
//alert(doc+rev);
//Call VbScript Sub and pass value
PassValues(doc,rev);
```
If you've removed all the docs, document.getElementsByClassName("doc"); is going to return an empty array. If you're incrementing idx before your loop, the loop will execute once and try to access docs[0], which is undefined.

Reset values Issue

Building a dice game and you get 3 rolls. Once you finish your turn i'm trying to have a "reset" button that will reset the values back to the original spot so the "next person" can play. The values reset as I expected but when I "roll" none of the functions are taking place and i'm pretty new in js so i'm not sure what the problem is.
var playerScore = document.getElementById('firstPlayerScore');
var rollButton = document.getElementById('roll_button');
var dice1 = new dice(1);
var dice2 = new dice(2);
var dice3 = new dice(3);
var dice4 = new dice(4);
var dice5 = new dice(5);
var diceArray = [dice1, dice2, dice3, dice4, dice5];
var cargo = 0;
var numOfRolls = 0;
var cargoButton = document.getElementById('cargo');
var canHaveCargo = false;
function restart(){
dice1 = new dice(1);
dice2 = new dice(2);
dice3 = new dice(3);
dice4 = new dice(4);
dice5 = new dice(5);
diceArray = [dice1, dice2, dice3, dice4, dice5];
cargo = 0;
numOfRolls = 0;
canHaveCargo = false;
addGlow();
updateDiceImageUrl();
document.getElementById("dice1").classList.remove('glowing');
document.getElementById("dice2").classList.remove('glowing');
document.getElementById("dice3").classList.remove('glowing');
document.getElementById("dice4").classList.remove('glowing');
document.getElementById("dice5").classList.remove('glowing');
}
//dice object
function dice(id){
this.id = id;
this.currentRoll = 1;
this.previousRoll = 1;
this.isSelected = false;
this.diceImageUrl = "img/dice/dice1.png";
this.roll = function(){
this.previousRoll = this.currentRoll;
this.currentRoll = getRandomRoll(1, 6);
}
}
//returns an array of all dice that are not currently selected so they can be rolled.
function getRollableDiceList(){
var tempDiceList = [];
for(var i = 0; i < diceArray.length; i++){
if(!diceArray[i].isSelected){
tempDiceList.push(diceArray[i]);
}
}
return tempDiceList;
}
// gets a random number between min and max (including min and max)
function getRandomRoll(min,max){
return Math.floor(Math.random() * (max-min + 1) + min);
}
// calls the roll function on each dice
function rollDice(rollableDiceList){
for(var i = 0; i < rollableDiceList.length; i++){
rollableDiceList[i].roll();
}
}
// updates each dice with the new url for the image that corresponds to what their current roll is
function updateDiceImageUrl(){
for(var i = 0; i < diceArray.length; i++){
var currentDice = diceArray[i];
currentDice.diceImageUrl = "http://boomersplayground.com/img/dice/dice" + currentDice.currentRoll + ".png";
//update div image with img that cooresponds to their current roll
updateDiceDivImage(currentDice);
}
}
//Displays the image that matches the roll on each dice
function updateDiceDivImage(currentDice) {
document.getElementById("dice"+currentDice.id).style.backgroundImage = "url('" + currentDice.diceImageUrl +"')";
}
// returns an array of all
function getNonSelectedDice(){
var tempArray = [];
for(var i = 0; i < diceArray.length; i++){
if(!diceArray[i].isSelected){
tempArray.push(diceArray[i]);
}
tempArray.sort(function(a, b){
return b.currentRoll - a.currentRoll;
});
}
return tempArray;
}
function getSelectedDice(){
var selectedDice = [];
for(var i = 0; i < diceArray.length; i++){
if(diceArray[i].isSelected){
selectedDice.push(diceArray[i]);
}
}
return selectedDice;
}
//boolean variables
var shipExist = false;
var captExist = false;
var crewExist = false;
//checks each dice for ship captain and crew. Auto select the first 6, 5 , 4.
function checkForShipCaptCrew(){
//array of dice that are not marked selected
var nonSelectedDice = getNonSelectedDice();
for(var i = 0; i < nonSelectedDice.length; i++){
//temp variable that represents the current dice in the list
currentDice = nonSelectedDice[i];
if (!shipExist) {
if (currentDice.currentRoll == 6) {
shipExist = true;
currentDice.isSelected = true;
}
}
if (shipExist && !captExist) {
if (currentDice.currentRoll == 5) {
captExist = true;
currentDice.isSelected = true;
}
}
if (shipExist && captExist && !crewExist) {
if (currentDice.currentRoll == 4) {
crewExist = true;
currentDice.isSelected = true;
canHaveCargo = true;
}
}
}
}
function addGlow(){
var selectedDice = getSelectedDice();
for (var i = 0; i < selectedDice.length; i++){
var addGlowDice = selectedDice[i];
var element = document.getElementById('dice' + addGlowDice.id);
element.className = element.className + " glowing";
}
}
function getCargo(){
var cargo = 0;
var moreDice = getNonSelectedDice();
if (canHaveCargo){
for(var i=0; i < moreDice.length; i++){
cargo += moreDice[i].currentRoll;
playerScore.innerHTML = 'You have got ' + cargo + ' in ' + numOfRolls + ' rolls!';
}
} else {
alert("You don't have Ship Captain and the Crew yet!");
}
}
rollButton.addEventListener('click', function(){
//generate rollable dice list
if (numOfRolls < 3) {
var rollableDiceList = getRollableDiceList();
//roll each dice
rollDice(rollableDiceList);
//update dice images
updateDiceImageUrl();
getNonSelectedDice();
// //auto select first 6, 5, 4 (in that order)
checkForShipCaptCrew();
addGlow();
// //adds a red glow to each dice that is selected
numOfRolls++;
}
});
cargoButton.addEventListener('click', getCargo);
var startButton = document.getElementById('restart');
startButton.addEventListener('click', restart);
http://boomer1204.github.io/shipCaptainCrew/
Here is a link to the live game since it's the only way I can describe the problem since I don't know what's not working. If you roll the dice a couple times the dice will get a blue border and be "saved" according to the rules. Now after you hit th restart button that doesn't happen anymore.
Thanks for the help in advance guys
Just add this to your restart()
function restart(){
...
shipExist = false;
capExist = false;
crewExist = false;
...
}
It's hard to replicate without a fiddle, but it seems that you are adding and removing the 'glowing' class using separate processes. Have you tried adding the glowing class the same way you are removing it?
element.classList.add("glowing")
See an example within a fiddle: https://jsfiddle.net/5tstf2f8/

Using jspdf.debug.js Wrap table head in pdf when

I am using jspdf.debug.js for generation html table in pdf format.
The table heading is not wrapping properly, shown like this:
image of the distorted heading jspdf.debug.js
below is the code that prints out the thead. though it doesn't wrap long text in next line
jsPDFAPI.printHeaderRow = function (lineNumber, new_page) {
if (!this.tableHeaderRow) {
throw 'Property tableHeaderRow does not exist.';
}
var tableHeaderCell,
tmpArray,
i,
ln;
this.printingHeaderRow = true;
if (headerFunction !== undefined) {
var position = headerFunction(this, pages);
setLastCellPosition(position[0], position[1], position[2], position[3], -1);
}
this.setFontStyle('bold');
var tempHeaderConf = [];
for (i = 0, ln = this.tableHeaderRow.length; i < ln; i += 1) {
this.setFillColor(248,218,194);
//this.maxWidth(10);
//this.setWidth(10);
// console.log("width"+this.width);
/*changed neeraj color of table heading*/
//this.setFillColor(200,200,200);
tableHeaderCell = this.tableHeaderRow[i];
if (new_page) {
tableHeaderCell[1] = this.margins && this.margins.top || 0;
tempHeaderConf.push(tableHeaderCell);
}
tmpArray = [].concat(tableHeaderCell);
this.cell.apply(this, tmpArray.concat(lineNumber));
}
if (tempHeaderConf.length > 0){
this.setTableHeaderRow(tempHeaderConf);
}
this.setFontStyle('normal');
this.printingHeaderRow = false;
};
})(jsPDF.API);
code for the same if fiddle
https://jsfiddle.net/neerajsonar/afas07Lf/
I am using jsPDF version 1.0.272
In jsPDFAPI.table = function (x,y, data, headers, config) (Around line 2833)
after if (printHeaders) {
clause, I added true as the last parameter to the call to calculateLineHeight():
var lineHeight = this.calculateLineHeight(headerNames, columnWidths, headerPrompts.length?headerPrompts:headerNames,true);
Next, in the for loop, I removed the String() from the last parameter:
tableHeaderConfigs.push([x, y, columnWidths[header], lineHeight, (headerPrompts.length ? headerPrompts[i] : header)]);
In the for loop after the //Construct the data rows comment, I added false as the last parameter to calculateLineHeight():
lineHeight = this.calculateLineHeight(headerNames, columnWidths, model,false);
I added another parameter, isHeader, to the calculateLineHeight function:
jsPDFAPI.calculateLineHeight = function (headerNames, columnWidths, model, isHeader)
Then I modified the function:
jsPDFAPI.calculateLineHeight = function (headerNames, columnWidths, model, isHeader) {
var header, lineHeight = 0;
for (var j = 0; j < headerNames.length; j++) {
header = headerNames[j];
if(isHeader){
model[j] = this.splitTextToSize(String(model[j]), columnWidths[model[j].toLowerCase().replace(/\s+/g, '')] - padding);
var h = this.internal.getLineHeight() * model[j].length + padding;
}else{
model[header] = this.splitTextToSize(String(model[header]), columnWidths[header] - padding);
var h = this.internal.getLineHeight() * model[header].length + padding;
}
if (h > lineHeight)
lineHeight = h;
}
return lineHeight;
};
And if you want to unbold the table headings, go to function
jsPDFAPI.printHeaderRow = function (lineNumber, new_page) and comment the line this.setFontStyle('bold');

What is the plain Javascript equivalent of .each and $(this) when used together like in this example?

What is the plain Javascript equivalent of .each and $(this).find when used together in this example?
$(document).ready(function(){
$('.rows').each(function(){
var textfield = $(this).find(".textfield");
var colorbox = $(this).find(".box");
function colorchange() {
if (textfield.val() <100 || textfield.val() == null) {
colorbox.css("background-color","red");
colorbox.html("Too Low");
}
else if (textfield.val() >300) {
colorbox.css("background-color","red");
colorbox.html("Too High");
}
else {
colorbox.css("background-color","green");
colorbox.html("Just Right");
}
}
textfield.keyup(colorchange);
}
)});
Here's a fiddle with basically what I'm trying to accomplish, I know I need to use a loop I'm just not sure exactly how to set it up. I don't want to use jquery just for this simple functionality if I don't have to
http://jsfiddle.net/8u5dj/
I deleted the code I already tried because it changed every instance of the colorbox so I'm not sure what I did wrong.
This is how to do what you want in plain javascript:
http://jsfiddle.net/johnboker/6A5WS/4/
var rows = document.getElementsByClassName('rows');
for(var i = 0; i < rows.length; i++)
{
var textfield = rows[i].getElementsByClassName('textfield')[0];
var colorbox = rows[i].getElementsByClassName('box')[0];
var colorchange = function(tf, cb)
{
return function()
{
if (tf.value < 100 || tf.value == null)
{
cb.style.backgroundColor = 'red';
cb.innerText = "Too Low";
}
else if (tf.value > 300)
{
cb.style.backgroundColor = 'red';
cb.innerText = "Too High";
}
else
{
cb.style.backgroundColor = 'green';
cb.innerText = "Just Right";
}
};
}(textfield, colorbox);
textfield.onkeyup = colorchange;
}
var rows = document.querySelectorAll('.rows');
for (var i=0; i<rows.length; i++) {
var row = rows[i];
var textfield = row.querySelector('.textfield');
var colorbox = row.querySelector('.box');
// ...
}
Note that you must use a for loop to iterate the rows because querySelectorAll() does not return an array, despite appearances. In particular, that means that .forEach() isn't valid on the returned list.

Javascript Dynamically added HTML

Please Look at the following code only the last image moves.
http://jsfiddle.net/u8Bg3/
But second one works
http://jsfiddle.net/u8Bg3/1/
As pointed by the Er144 even this works with jquery
http://jsfiddle.net/u8Bg3/14/
I also found out appendchild works but not innerhtml
The difference between two is that in first one html exits in second one it's dynamically created
HTML
<body>
<div class="racetrack" id="racetrack"></div>
<div id="track-tmpl" class="hide">
<div class="track"><div id="player{{ x }}" class="runner"></div></div>
</div>
</body>
JS
var position = [0,40,80,120,80],
racetrack = document.getElementById('racetrack');
track_tmpl = document.getElementById('track-tmpl').innerHTML;
function Players(ele, ptimeout)
{
this.el = ele;
this.i = 0;
this.iterations = 0;
this.stop = 0;
this.timeout = ptimeout;
this.position = 0;
this.animate = function(){
if(this.i !== 0){
this.move((this.position + 5), this.i);
}
if(!this.stop){
if(this.i < 5){
setTimeout(function(_this){
_this.i++;
_this.animate();
},this.timeout,this);
}
if(this.i==5){
this.iterations ++;
if(this.iterations < 50){
this.i = 0;
this.animate();
}
else{
this.el.style.backgroundPosition = '120px 0px';
}
}
}
};
this.start = function(){
this.stop = 0;
this.animate();
};
this.move = function(to,positionIndex){
this.position = to;
this.el.style.backgroundPosition = '-'+position[positionIndex]+'px 0px';
this.el.style.webkitTransform = 'translate('+to+'px)';
this.el.style.mozTransform = 'translate('+to+'px)';
}
}
function Game(noOfPlayers){
this.noOfPlayers = noOfPlayers;
this.players = new Array();
for (var i = 0; i < this.noOfPlayers ; i++){
racetrack.innerHTML = racetrack.innerHTML + track_tmpl.replace('{{ x }}', i);
this.players.push(new Players(document.getElementById('player' + i), (120 + i)));
/* issue here with dynamic added content*/
}
this.start = function(){
for (var i = 0; i < this.noOfPlayers; i++){
this.players[i].start();
}
};
}
var game = new Game(3);
game.start();
Why is that in dynamically added html only the last one moves
The issue is with creating the player(n) object inside the for loop along with the assignments to innerHTML using `+='. The modified fiddle: http://jsfiddle.net/u8Bg3/15/ works fine. Cheers for a good question!
var finalized_tracks= "" ;
for (var i = 0; i < this.noOfPlayers ; i++){
finalized_tracks += track_tmpl.replace('{{ x }}', i);
}
racetrack.innerHTML = racetrack.innerHTML + finalized_tracks;
for (var i = 0; i < this.noOfPlayers ; i++){
this.players.push(new Players(document.getElementById('player'+ i),(120+i)));
}
If you use the jquery:
var element = track_tmpl.replace('{{ x }}', i);
$(racetrack).append(element);
instead of the line where you change the innerHtml of racetrack div, all elements are moving.
However, I'm not sure, why...
theCoder has pretty much nailed the issue with your code there.
Just as an additional thought, you could manually build the necessary divs using javascript instead, it's more long winded however...
for (var i = 0; i < this.noOfPlayers ; i++){
var newTrack = document.createElement("div");
newTrack.id = "track"+i;
newTrack.className = "track";
var newPlayer = document.createElement("div");
newPlayer.id = "player"+i;
newPlayer.className = "runner";
newTrack.appendChild(newPlayer);
racetrack.appendChild(newTrack);
this.players.push(new Players(document.getElementById('player' + i), (120 + i)));
}

Categories

Resources