<!doctype html>
<html>
<head>
<script>
function do_something() {
var theBody = document.getElementsByTagName("body")[0];
var theImg = document.createElement("img");
theImg.src = "cat.png";
theBody.appendChild(theImg.cloneNode(true));
var count = 0;
for (var i = 0; i < 10; i++, count++) {
if (i == 5) continue;
if (count == 3) {
count = 0;
theBody.removeChild(theBody.lastChild);
} else {
theBody.appendChild(theImg.cloneNode(true));
}
if (i > 7) break;
}
}
</script>
</head>
<body onload="do_something()"></body>
</html>
I am supposed to tell how many images would a modern browser display.
I have two major doubts here:
When i=4, what is the value of count? I think it would be 0, but don't why I am confused about it.
As the code tells, when count = 0, an image will be removed from the body. Does the code append an image, and then remove an image? Or, does it simply remove one image? This is the part that is confusing because nothing is said about what happens when i=3.
According to the given answer, 6 images are added in the loop, and 2 are removed. So, a total number of 5 images are displayed.
When i=4, what is the value of count? I think it would be 0, but don't why I am confused about it.
When i == 3, count is set to 0. At the end of the for block, count++ is executed, so by the time i == 4, count == 1
As the code tells, when count = 0, an image will be removed from the
body. Does the code append an image, and then remove an image? Or,
does it simply remove one image? This is the part that is confusing
because nothing is said about what happens when i=3.
i == 0 append
i == 1 append
i == 2 append
i == 3 image from previous step removed
i == 4 append
etc.
Related
How can a row of inline-blocks be wrapped by a shrinking parent resulting in equal (or almost equal) rows?
So instead of wrapping like this:
wrap like this:
And if there's an uneven number of blocks, like this:
You can use CSS Grid grid-template-columns and #media (if you want to wrap by screen-width) or in JS with docment.getElementById('bottomblocks').style.gridTemplateColumns variable to achieve this. (If I understand correctly)
I wrote here an example with JS:
https://jsfiddle.net/Lhbqdt2z/
You can learn about it where I started with it: Coding Tech Talk
Or just from W3Schools
Moz://a has a good examples here
He is something fun I just wrote... Assuming you want an "enhanced wrap" behavior that wraps by the half of its childs, instead of the normal floating.
It's more an "essay" than a strong best practice answer. ;)
$(window).on("load resize",function(){
$(".container div").css({"clear":"initial"});
var wrapped = false;
var wrappedAt = 0;
var wrappedNtimes =0;
var pos = $(".container div").first().offset();
var n = $(".container div").length;
$(".container div").each(function(index){
if(!wrapped){
if( ($(this).offset().top != pos.top)){
console.log("Wrapped at "+index+" out of "+n);
wrapped = true;
wrappedAt = index;
wrappedNtimes++;
}
pos=$(this).offset();
}
});
if(wrapped){
// Force enhanced wrapping... .oO(lol)
console.log("--"+wrappedAt+"--");
var half = Math.ceil(n/(wrappedNtimes+1));
$(".container div").each(function(){
if( $(this).index() != 0 && ($(this).index())%half == 0){
$(this).css({"clear":"left"}); // zero-based.
}
});
}
});
CodePen demo
Here's a solution that inserts <br> elements at the ends of each row. This code can be placed into a function to run whenever you need to wrap the blocks.
// Make sure that the last row of blocks doesn't have 2 less blocks than all
// the previous rows. Assume that all blocks are equal size.
var blocks = sharing.find('.btn');
//what's the parent width
var parentWidth = blocks.parent().width();
//how many blocks can fit in such a width
var maxNumOfBlocksInOneRow = Math.floor(parentWidth / blocks.outerWidth(true));
//repeatable code
var calcNumOfBlocksInLastRow = function(){
var lastRowFull = blocks.length % maxNumOfBlocksInOneRow ? false : true;
if (lastRowFull) {
return maxNumOfBlocksInOneRow;
} else {
return blocks.length % maxNumOfBlocksInOneRow;
}
}
//do we have more blocks than row's maximum?
if (blocks.length > maxNumOfBlocksInOneRow) {
//how many blocks would the last row have
var numOfBlocksInLastRow = calcNumOfBlocksInLastRow();
//if the last row is missing more than 1 block, try with 1 less block in each row
while (numOfBlocksInLastRow < maxNumOfBlocksInOneRow - 1) {
maxNumOfBlocksInOneRow--;
numOfBlocksInLastRow = calcNumOfBlocksInLastRow();
}
//insert <br> at the end of each row
jQuery('<br>').insertAfter(blocks.filter(':nth-child(' + maxNumOfBlocksInOneRow + 'n)'));
}
I currently have a document, with help from StackOverflow users already, that randomly generates questions, adds it to the end of a document, and then has the ability to delete all the questions posted. This is based on deleting everything under a horizontal rule.
Link to GDrive containing example document & code: LINK TO GDRIVE
You can also see what it currently does here: https://imgur.com/QVrOZKu
However, I now want to only want to add content after a certain point in the document, as well as only delete content between two certain points. You can see the two horizontal rules in an image below in which I want to add/delete
content.
The first horizontal rule in the picture is the third horizontal rule in the document.
Has anyone got any ideas how I can delete and add content between those two points? I've tried using child index's but failed miserably.
This is similar to Deleting all content down from the second horizontal line in a document so I adapt the solutions. First function deletes the paragraphs between the 3rd and 4th line. It counts horizontal lines as we loop through paragraphs. When the count reaches 3, start deleting subsequent paragraphs. When it exceeds 3, stop the loop.
function deleteFrom3to4() {
var body = DocumentApp.getActiveDocument().getBody();
body.appendParagraph('');
var para = body.getParagraphs();
var ruleCount = 0;
for (var i = 0; i < para.length - 1; i++) {
if (para[i].findElement(DocumentApp.ElementType.HORIZONTAL_RULE)) {
ruleCount++;
}
else if (ruleCount == 3) {
body.removeChild(para[i]);
}
if (ruleCount > 3) {
break;
}
}
}
And this one inserts a paragraph after the 3rd horizontal line. Again, it loops until the 3rd line is found; inserts a paragraph after it (expressed by body.getChildIndex(para[i]) + 1 child index) and stops.
function insertAfter3() {
var body = DocumentApp.getActiveDocument().getBody();
body.appendParagraph('');
var para = body.getParagraphs();
var ruleCount = 0;
for (var i = 0; i < para.length - 1; i++) {
if (para[i].findElement(DocumentApp.ElementType.HORIZONTAL_RULE)) {
ruleCount++;
}
if (ruleCount == 3) {
body.insertParagraph(body.getChildIndex(para[i]) + 1, "Here is a new paragraph");
break;
}
}
}
When I click the "change lights" button I have to click it twice for the picture to change. What could be going wrong? Any ideas?
Here is my HTML:
<p>Click the button to change to the next light.</p>
<img id="starting_light" src="green.jpg">
<button type="button" onclick="nextLightClick()">Change</button>
And my JavaScript:
var gyr = new Array("green.jpg","yellow.jpg","red.jpg");
var index = 0;
var gyrLen = gyr.length;
function nextLightClick() {
if (index == gyrLen)
index = 0;
var image = document.getElementById('starting_light');
image.src = gyr[index];
index++;
}
I suspect the main problem to be in the JavaScript because once I started messing around with the variables the issue was introduced.
The first time this runs, the image is green.
It then sets the image to gyr[0], the green image, then index is incremented.
You can either increment the index before setting the image, or reorder the array to have green be last.
The first time you click the button, index is equal to 0, so nextLightClick() is setting image.src to "green.jpg", which is the same (assuming "1green.jpg" is a typo) as the starting image.
The solution is to move index++ to the first line of nextLightClick().
Your index is still 0 on the first time you enter the function and set the image.
Move the index++; to the start of the function, or initialize the index to value 1.
var index = 1;
If you want to initialize the index to 1, then you should rename the variable to something like nextIndex.
I don't think it is the case. Your code is working correctly. Your first image is green and the first time you click you are replacing it with the first image, that's the reason you don't see any difference.
You might consider doing it as:
var gyr = new Array("http://i.imgur.com/eucAMTA.jpg", "http://is2.mzstatic.com/image/thumb/Purple122/v4/be/9a/f0/be9af074-90f2-5894-99a0-17460783db6c/source/1200x630bf.jpg", "https://i0.wp.com/fusion.net/wp-content/uploads/2016/05/RED.jpg?resize=1600%2C900&quality=80&strip=all");
var index = 0;
var gyrLen = gyr.length;
function nextLightClick() {
index++;
// alert("hello" + index);
if (index == gyrLen)
index = 0;
var image = document.getElementById('starting_light');
image.src = gyr[index];
}
img {
width: 200px;
height: 200px;
}
p>Click the button to change to the next light.</p>
<img id="starting_light" src="http://i.imgur.com/eucAMTA.jpg">
<button type="button" onclick="nextLightClick()">Change</button>
Ah I seem to have found the answer thanks to Zac and American the problem was that index should have been at the first line of 'nexlightclick'
Fixed script below:
<p>Click the button to change to the next light.</p>
<img id="starting_light" src="green.jpg">
<button type="button" onclick="nextLightClick()">Change lights</button>
<script>
var gyr = new Array("green.jpg","yellow.jpg","red.jpg");
var index = 0;
var gyrLen = gyr.length;
function nextLightClick() {
index++;
if (index == gyrLen)
index = 0;
var image = document.getElementById('starting_light');
image.src = gyr[index];
}
</script>
</body>
</html>
There is a little problem with index update logic. You must evaluate its value and if it's less than gry.length add one else reinitialize to 0.
The inside script code:
var gyr = new Array("green.jpg","yellow.jpg","red.jpg");
var index = 0;
function nextLightClick() {
index = index + 1 < gyr.length ? index + 1 : 0;
document.getElementById('starting_light').alt = gyr[index];
}
I'm creating a script that takes two input dimensions, width, and height, and creates a scaled grid which is representative of how many blocks could fit in a box with the given dimensions with the following function:
function makeRow() {
for (var i = 1; i <= blocksTall; i++) {
var mb = document.createElement("div");
mb.setAttribute("class", "matrix-block mb-off");
mb.setAttribute("onClick", "select_mb('" + j + "," + i + "');");
placeBlocks.appendChild(mb);
if (i = blocksWide) {
placeBlocks.appendChild('br');
}
}
}
This function works fine to display the first row of blocks, and then inserts a break tag after the row has finished being rendered, which is exactly what I want to do. The problem is I need to generate 17 more rows, with the same number of blocks, each one under the previous row, so my first thought was, I'll just wrap another for loop around this first for loop and since there is a break there, it will render the new row below the previous one:
for (var j = 1; j <= blocksTall; j++) { // Vertical for loop.
for (var i = 1; i <= blocksWide; i++) { // Horizontal for loop.
var mb = document.createElement("div");
//mb.setAttribute("id", "matblock-" + i + "-" + j);
mb.setAttribute("class", "matrix-block mb-off");
mb.setAttribute("onClick", "select_mb('" + i + "," + j + "');");
placeBlocks.appendChild(mb);
}
if (j = blocksWide) {
placeBlocks.appendChild(brk);
}
}
Where blocksWide = 17. Here is a fiddle with the complete script. When I log the value for j in the console, it does in fact increment (which tells me that the for loop is working). What seems to be happening though is that it is for some reason rendering the row, and then either rendering the new row on top of it (seems unlikely since the break tag is rendered after each row completes) or, for some reason the children are destroyed each time a new "horizontal" for loop is run.
Does anybody know why this might be happening and how to properly get each row to be appended under the last row so it produces a grid of blocks instead of just one row?
Thanks in advance, any help is greatly appreciated.
So, I'm a bit confused about some aspects of your script, but I think you have two major issues.
Firstly, you only ever call document.createElement("br") once, which means you only ever create a single line-break; and a single line-break can only appear in one place in the DOM. This:
placeBlocks.appendChild(brk);
removes brk from its current position in the DOM and then puts it at the end of placeBlocks. You should change it to this:
placeBlocks.appendChild(document.createElement("br"));
Secondly, I don't think that if (j = blocksWide) { makes sense. Note that it's equivalent to this:
j = blocksWide;
if (blocksWide != 0) {
which means that it interferes with your for-loop by manipulating the value of j. I think the fix for that issue is simply to remove the whole if-check, and to perform its body unconditionally.
I really don't understand what you were trying to do with the remainder operators and the dividing, but blocksWide resolved to infinity causing an infinite loop, and blocksHigh was just 17. All of the other variables besides full weren't used.
You don't actually need two loops, although it is ok to do that. If you want to use just one loop you basically just need to know if i is a multiple of dispW.
So you divide i by dispW then you want to know if it is an integer, to find this you use the remainder operator for 1 and if it resolves to 0 it is an interger. It looks like this...
if ((i / dispW) % 1 === 0)
// if ( dispW=3 && ( i=3 || i=6 || i=9 || ... ) ) true;
This in a loop would look like
totalWidth = dispW * dispH; // total number of blocks
for (var i = 1; i <= totalWidth; i++) {
// do stuff;
if((i / dispW) % 1 === 0) {
// insert new line break;
}
}
The method you used for selecting the blocks was a round about way of doing it. First you shouldn't use inline javascript, second you shouldn't use javascript to embed inline javascript in a dynamically created element. Use element.onclick = function; instead.
Notice there is no braces after the function. This is because you are actually passing the function reference and not the returned value of the function.
element.onclick passes an event object to the function reference. You can use this to select the block that was clicked on like so.
for ( ... ) {
...
var element = document.createElement('div');
element.onclick = myFunction;
...
}
function myFunction(e) {
var clicked = e.target // this is the element that was clicked on
}
Also, you were creating one <br> element outside of the loop. Because appendChild moves elements and does not create elements it will just keep moving the line break until the loop finishes. It should look like this.
placeBox.appendChild(document.createElement('br'))
// append a newly created line break;
Then even if all the logic worked as intended and you create a new line break every time, floated blocks means no line breaks use display: inline-block; instead.
So in the end what you get is...
(Full difference)
window.onload = function () {
renderGrid();
};
function renderGrid() {
var blocksTall = document.getElementById('height-in').value;
var blocksWide = document.getElementById('width-in').value;
var blocksTotal = blocksWide * blocksTall;
var placeBlocks = document.getElementById('matrix-shell');
while (placeBlocks.firstChild) {
placeBlocks.firstChild.remove();
}
console.log(blocksWide + "/" + blocksTall);
for (var i = 1; i <= blocksTotal; i++) {
var mb = document.createElement("div");
mb.className = 'matrix-block mb-off';
mb.onclick = select_mb;
placeBlocks.appendChild(mb);
if (((i / blocksWide) % 1) === 0) {
var brk = document.createElement("br");
placeBlocks.appendChild(brk);
}
}
}
function select_mb(e) {
var cur_mb = e.target;
if (cur_mb.className == "matrix-block mb-off") {
// Turn cell on.
cur_mb.style.backgroundColor = "#00FF00";
cur_mb.className = "matrix-block mb-on";
} else {
//Turn cell off.
cur_mb.style.backgroundColor = "#000";
cur_mb.className = "matrix-block mb-off";
}
}
.matrix-block {
height: 10px;
width: 10px;
border: 1px solid #fff;
display: inline-block;
background-color: black;
}
.mb-off {
background-color: black;
}
#matrix-shell {
font-size: 0;
display: inline-block;
border: 1px solid red;
white-space: nowrap;}
<table>
<tr>
<td>Width:</td>
<td>
<input id="width-in" name="width-in" type="text" />
</td>
</tr>
<tr>
<td>Height:</td>
<td>
<input id="height-in" name="height-in" type="text" />
</td>
</tr>
<tr>
<td colspan="2">
<button onClick="renderGrid()">Compute</button>
</td>
</tr>
</table>
<br/>
<div id="matrix-shell"></div>
I have this image table that has two columns and 20 rows. When executing this for loop, all the rows are working okay except for the first row, which only displays the first image on the left. It's really weird; is there something wrong with the order of the execution?
var image= [];
var rows=5;
for (var i = 0; i < test.length; i++) {
var avatar = test[i].image; // The profile image
if(i % 2 === 0){
image[i]= Titanium.UI.createImageView({
top:row,
image:avatar
align:right
});
win.add(image[i]);
//trying to increase the image
row =row+200;
} else if(i % 2 === 1) {
image[i]= Titanium.UI.createImageView({
top:row,
image:avatar
align:left
});
win.add(image[i]);
}
}
i=0, i%2=0, show the image (supposed to be right), row+=200;
i=1, i%2=1, show the image (left side), row stays same
i=2, i%2=0, show the image (right side), row+=200
0%2 = 0, and that represents your right side image, and then it goes to the next line. Just need to play around with where you increment row and which side your loop starts with.