<head>
<meta charset="UTF-8">
<!-- <script src="detect-element-resize.js"></script> <!-- NOTE: This Script in the JavaScript Tab -->
<!-- <script src="jquery.min.js"></script> <!-- No jQuery needed -->
<style>
.flex{ display: flex; display: flexbox; display: flex; }
.wrap{ flex-wrap: wrap; flex-wrap: wrap; flex-wrap: wrap;}
.cont {
border: 1px solid grey;
margin: auto;
width: 448px;
padding-right: 0;
padding-bottom: 0;
/*flex-direction: column;height: 225px;align-content: flex-start;*/
}
.controls{
width: 500px;
margin: auto;
justify-content: space-around;
text-align: center;
}
.elem {
border: 1px solid blue;
text-align:center;
/* float: left; /* Can Float it, or use Flexbox, either way */
}
input{
width: 25px; color: blue;
}
#resizableBorder{
resize: horizontal;
overflow: auto;
}
</style>
<style id="jsManipulated">
.elem {
height: 100px;
width: 100px;
line-height: 100px;
margin-right: 10px;
margin-bottom: 10px;
}
.cont {
padding-top: 10px;
padding-left: 10px;
}
</style>
</head>
<body>
<br>
<div class="flex controls">
<a target="_blank" href="https://stackoverflow.com/questions/29125444/equal-number-of-element-per-row-with-flexbox">StackOverflow</a>
<button id="adder">(+) add item</button>
<button id="remover">(-) remove item</button>
<span> Box Size:
<input id="sizer" type="text" value="100" boxCountlength="3" onkeypress='return event.charCode > 47 && event.charCode < 58'>
</span>
<span> Padding:
<input id="padder" type="text" value="10" boxCountlength="3" >
</div>
<br><hr><br>
<div id="resizableBorder" class="cont flex wrap">
<div class="elem"> 1</div><div class="elem"> 2</div><div class="elem"> 3</div>
<div class="elem"> 4</div><div class="elem"> 5</div><div class="elem"> 6</div>
<div class="elem"> 7</div><div class="elem"> 8</div><div class="elem"> 9</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function(){
var boxCount = 9;
var boxWidth = 100;
var boxBorderWidth = 10;
var adder = document.getElementById('adder');
var remover = document.getElementById('remover');
var sizer = document.getElementById('sizer');
var padder = document.getElementById('padder');
var flexParent = document.getElementsByClassName('cont')[0];
var styleEle = document.getElementById('jsManipulated');
var resizableBorder = document.getElementById('resizableBorder');
function addItem(){
console.log("add");
var newItem = document.createElement('div');
newItem.className += 'elem';
newItem.innerHTML = ++boxCount;
flexParent.appendChild( newItem );
repaint();
}
function removeItem(){
console.log("remove");
if(boxCount != 0){
--boxCount;
//flexParent.removeChild(flexParent.lastChild);
var position = flexParent.children.length -1;
if( flexParent.children[position].className == "resize-triggers"){ --position; } //ignore resize-triggers div.
flexParent.removeChild( flexParent.children[ position ] );
repaint();
}
}
function resizeBoxes(event) {
if( event.keyCode > 47 && event.keyCode < 58){ boxWidth = this.value; }
else if( event.keyCode == 40 ){ boxWidth = --this.value; }
else if( event.keyCode == 38 ){ boxWidth = ++this.value; }
else {
console.log('non-numeric keypress ignored: '+event.keyCode);
return;
}
updateBoxStyles( boxWidth, boxBorderWidth);
}
function repadBoxes(event) {
if( event.keyCode > 47 && event.keyCode < 58){ boxBorderWidth= this.value; }
else if( event.keyCode == 40 ){ boxBorderWidth = --this.value; }
else if( event.keyCode == 38 ){ boxBorderWidth = ++this.value;}
else {
console.log('non-numeric keypress ignored: '+event.keyCode);
return;
}
updateBoxStyles( boxWidth, boxBorderWidth);
}
function updateBoxStyles( size, edge ){
styleEle.innerHTML =
".elem { height: "
+size+"px; width: "
+size+"px; line-height: "
+size+"px; margin-right: "
+edge+"px; margin-bottom: "
+edge+"px;} .cont { padding-top: "
+edge+"px; padding-left: "
+edge+"px;}"
repaint();
}
/* LISTENERS */
window.onresize = repaint; //Only needed if 'width' of container is a percentage ex: '.cont{width:60%}'
adder.addEventListener('click', addItem );
remover.addEventListener('click', removeItem );
sizer.addEventListener('keyup', resizeBoxes );
padder.addEventListener('keyup', repadBoxes );
addResizeListener( resizableBorder, repaint); //using the 'detect-element-resize.js library'
/** Most Important Function Called Everytime Anything Changes, in order to keep elements to the left using 'margin-right' **/
repaint(); //initial resize on pageload;
function repaint() {
console.log('repaint');
var elementWidth = 2- -boxWidth- -boxBorderWidth; // 2 because: border is 1px*2, '- -' because '+' causes string concatination.
var elements = document.getElementsByClassName('elem');
var count = elements.length;
var parentWidth = parseInt( window.getComputedStyle( flexParent).getPropertyValue('width') );
var rowsCount = Math.ceil( count / Math.floor(parentWidth/elementWidth) );
var perRow = Math.floor( count / rowsCount);
var extra = count % rowsCount;
for (var i=0, ele; ele = elements[i]; i++) {
ele.style["margin-right"] = "";
}
if( rowsCount == Infinity || rowsCount == 0){ return; }//when elementWidth < parentWidth or Zero Boxes
var allPrevRowsTotal = 0;
for (var i = 1; i <= rowsCount && rowsCount > 1; i++) {
var perThisRow = perRow;
if( extra != 0){ --extra; perThisRow++; }
elements[ allPrevRowsTotal + perThisRow - 1 ].style["margin-right"] = parentWidth - (perThisRow * elementWidth) +"px";
allPrevRowsTotal += perThisRow;
}
}
});
</script>
</body>
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |