├── images └── milo.png ├── example ├── main.js ├── style.css ├── index.html └── bundle.js ├── .gitignore ├── package.json ├── lib └── debounce.js ├── README.md ├── .jshintrc ├── milo.min.js └── milo.js /images/milo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidchase/milo/master/images/milo.png -------------------------------------------------------------------------------- /example/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var Milo = require('../milo'); 3 | 4 | var milo = new Milo({ 5 | container: '.grid' 6 | }); 7 | 8 | window.addEventListener('load', milo.buildGrid); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Node ### 2 | # Logs 3 | logs 4 | *.log 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | node_modules 18 | 19 | *.DS_Store -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "milo-grid", 3 | "version": "1.0.1", 4 | "description": "Javascript Grid fallback for browsers that dont support column-count", 5 | "main": "milo.js", 6 | "directories": { 7 | "example": "example" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/davidchase/milo.git" 12 | }, 13 | "keywords": [ 14 | "grid", 15 | "columns", 16 | "grid-support" 17 | ], 18 | "author": "David Chase", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/davidchase/milo/issues" 22 | }, 23 | "homepage": "https://github.com/davidchase/milo#readme" 24 | } 25 | -------------------------------------------------------------------------------- /lib/debounce.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function debounce(fn, threshold, isAsap) { 3 | var timeout, result; 4 | 5 | var debounced = function() { 6 | var args = arguments; 7 | var context = this; 8 | 9 | var delayed = function() { 10 | if (!isAsap) { 11 | result = fn.apply(context, args); 12 | } 13 | timeout = null; 14 | }; 15 | if (timeout) { 16 | clearTimeout(timeout); 17 | } else if (isAsap) { 18 | result = fn.apply(context, args); 19 | } 20 | timeout = setTimeout(delayed, threshold); 21 | return result; 22 | }; 23 | debounced.cancel = function() { 24 | clearTimeout(timeout); 25 | }; 26 | return debounced; 27 | }; -------------------------------------------------------------------------------- /example/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | body { 7 | background: #f6f4f2; 8 | font-family:'Helvetica Neue', Helvetica, sans-serif; 9 | margin: 13px; 10 | } 11 | h1 { 12 | text-align: center; 13 | margin-bottom: 26px; 14 | color: #3e3e3e; 15 | } 16 | .grid { 17 | margin: 0 auto; 18 | position: relative; 19 | width: 100%; 20 | } 21 | .grid-item { 22 | font-size: 13px; 23 | padding: 0px 0px 32px 0px; 24 | position: absolute; 25 | background: #fff; 26 | box-sizing: border-box; 27 | box-shadow: 0px 2px 5px 1px #ccc; 28 | width:auto; 29 | height: auto; 30 | } 31 | 32 | img { 33 | max-width: 100%; 34 | height:auto; 35 | display: inline-block; 36 | vertical-align: middle; 37 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Milo 2 | ====== 3 | 4 | ![Milo](images/milo.png) 5 | 6 | A small pure javascript grid that provides as a nice fallback to browsers 7 | that don't currently support column-count such as IE8, IE9 8 | 9 | Simple usage: 10 | ------------- 11 | 12 | Check out the [**demo**](https://rawgit.com/davidchase/milo/master/example/index.html) 13 | 14 | Use [browserify](http://browserify.org) for client commonjs `require` 15 | 16 | `npm install -g browserify` 17 | 18 | ```js 19 | var Milo = require('./milo'); 20 | 21 | var milo = new Milo({ 22 | container: '.grid' 23 | }); 24 | 25 | window.addEventListener('load', milo.buildGrid); 26 | ``` 27 | 28 | HTML can be formatted like so: 29 | 30 | ```html 31 |
32 |
...
33 |
...
34 |
...
35 |
...
36 | ... 37 |
38 | ``` -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "nonew": true, // Prohibit use of constructors for side-effects. 3 | "curly": true, // Require {} for every new block or scope. 4 | "noarg": true, // Prohibit use of `arguments.caller` and `arguments.callee`. 5 | "forin": true, // Tolerate `for in` loops without `hasOwnPrototype`. 6 | "noempty": true, // Prohibit use of empty blocks. 7 | "node": true, // Enable globals available when code is running inside of the NodeJS runtime environment. 8 | "eqeqeq": true, // Require triple equals i.e. `===`. 9 | "strict": true, // Require `use strict` pragma in every file. 10 | "undef": true, // Require all non-global variables be declared before they are used. 11 | "newcap": true, // Require capitalization of all constructor functions e.g. `new F()`. 12 | "immed": true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` 13 | "browser": true, // Standard browser globals e.g. `window`, `document`. 14 | "freeze": true, // Prohibits overwriting prototypes of native objects e.g. Array, Data, etc 15 | "multistr": true, // Tolerate multi-line strings. 16 | "predef": [ "test", "setup", "teardown", "require" ], 17 | "sub": true 18 | } -------------------------------------------------------------------------------- /milo.min.js: -------------------------------------------------------------------------------- 1 | "use strict";var debounce=require("./lib/debounce"),qs=document.querySelector.bind(document),MiloGrid=function(i){if(!i||"object"!=typeof i)throw new Error("Need to add at least a container");this.containerEl=qs(i.container),this.children=this.containerEl.children,this.gridItemMargin=i.margin||10,this.gridItemWidth=i.width||210,this._resizeBind()},MiloGridProto=MiloGrid.prototype;MiloGridProto._calcTopPosition=function(i){return i>=this.gridColumns?this.topOffset[i-this.gridColumns]:0},MiloGridProto._calcGridColumns=function(){this.containerWidth=this.containerEl.clientWidth,this.gridColumns=Math.floor(this.containerWidth/(this.gridItemWidth+this.gridItemMargin))},MiloGridProto.buildGrid=function(){var i=0,t=this.children.length;for(this.topOffset=[],this._calcGridColumns(),i;t>i;i++)this.children[i].style.cssText="margin:"+this.gridItemMargin/2+";top:"+this._calcTopPosition(i)+";left:"+(this.gridItemWidth+this.gridItemMargin)*Math.round(i%this.gridColumns)+";width:"+this.gridItemWidth+";",this.topOffset.push(this.children[i].offsetHeight+this.gridItemMargin+this.children[i].offsetTop)},MiloGridProto._destroyGrid=function(){var i=0,t=this.children.length;for(i;t>i;i++)this.children[i].style.cssText=""},MiloGridProto._resizeBind=function(){var i=function(){this.buildGrid()}.bind(this);window.addEventListener("resize",debounce(i,600))};var Milo=function(i){var t=new MiloGrid(i);this.buildGrid=t.buildGrid.bind(t)};module.exports=Milo; -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The Grid 5 | 6 | 7 | 8 |

The Milo Project

9 |

with special guest Bill Murray

10 | Images courtesy of http://fillmurray.com 11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /milo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var debounce = require('./lib/debounce'); 4 | var qs = document.querySelector.bind(document); 5 | var MiloGrid = function(options) { 6 | if (!options || typeof options !== 'object') { 7 | throw new Error('Need to add at least a container'); 8 | } 9 | this.containerEl = qs(options.container); 10 | this.children = this.containerEl.children; 11 | this.gridItemMargin = options.margin || 10; 12 | this.gridItemWidth = options.width || 210; 13 | 14 | this._resizeBind(); 15 | }; 16 | var MiloGridProto = MiloGrid.prototype; 17 | 18 | MiloGridProto._calcTopPosition = function(index) { 19 | return index >= this.gridColumns ? this.topOffset[index - this.gridColumns] : 0; 20 | }; 21 | 22 | // to calculate the columns 23 | // get the current available width 24 | // then divide it by gridItem width + gridItem margin 25 | // we are using Math.floor to get the most possible 26 | // amount of columns to fit into the area allocated 27 | MiloGridProto._calcGridColumns = function() { 28 | this.containerWidth = this.containerEl.clientWidth; 29 | this.gridColumns = Math.floor((this.containerWidth / (this.gridItemWidth + this.gridItemMargin))); 30 | }; 31 | 32 | MiloGridProto.buildGrid = function() { 33 | var idx = 0; 34 | var length = this.children.length; 35 | // clean array before each build 36 | this.topOffset = []; 37 | 38 | this._calcGridColumns(); 39 | 40 | for (idx; idx < length; idx++) { 41 | this.children[idx].style.cssText = 42 | 'margin:' + this.gridItemMargin / 2 + 'px;' + 43 | 'top:' + this._calcTopPosition(idx) + 'px;' + 44 | 'left:' + (this.gridItemWidth + this.gridItemMargin) * Math.round(idx % this.gridColumns) + 'px;' + 45 | 'width:' + this.gridItemWidth + 'px;'; 46 | 47 | this.topOffset.push(this.children[idx].offsetHeight + this.gridItemMargin + this.children[idx].offsetTop); 48 | } 49 | }; 50 | 51 | MiloGridProto._destroyGrid = function() { 52 | var idx = 0; 53 | var length = this.children.length; 54 | for (idx; idx < length; idx++) { 55 | this.children[idx].style.cssText = ''; 56 | } 57 | }; 58 | 59 | MiloGridProto._resizeBind = function() { 60 | var rebuildGrid = function() { 61 | this.buildGrid(); 62 | }.bind(this); 63 | 64 | // debounce the window resize 65 | // to minimize the amount of rebuild calls 66 | window.addEventListener('resize', debounce(rebuildGrid, 600)); 67 | }; 68 | 69 | // expose a public api 70 | var Milo = function(options) { 71 | var miloGrid = new MiloGrid(options); 72 | this.buildGrid = miloGrid.buildGrid.bind(miloGrid); 73 | }; 74 | 75 | module.exports = Milo; -------------------------------------------------------------------------------- /example/bundle.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= this.gridColumns ? this.topOffset[index - this.gridColumns] : 0; 58 | }; 59 | 60 | // to calculate the columns 61 | // get the current available width 62 | // then divide it by gridItem width + gridItem margin 63 | // we are using Math.floor to get the most possible 64 | // amount of columns to fit into the area allocated 65 | MiloGridProto._calcGridColumns = function() { 66 | this.containerWidth = this.containerEl.clientWidth; 67 | this.gridColumns = Math.floor((this.containerWidth / (this.gridItemWidth + this.gridItemMargin))); 68 | }; 69 | 70 | MiloGridProto.buildGrid = function() { 71 | var idx = 0; 72 | var length = this.children.length; 73 | // clean array before each build 74 | this.topOffset = []; 75 | 76 | this._calcGridColumns(); 77 | 78 | for (idx; idx < length; idx++) { 79 | this.children[idx].style.cssText = 80 | 'margin:' + this.gridItemMargin / 2 + 'px;' + 81 | 'top:' + this._calcTopPosition(idx) + 'px;' + 82 | 'left:' + (this.gridItemWidth + this.gridItemMargin) * Math.round(idx % this.gridColumns) + 'px;' + 83 | 'width:' + this.gridItemWidth + 'px;'; 84 | 85 | this.topOffset.push(this.children[idx].offsetHeight + this.gridItemMargin + this.children[idx].offsetTop); 86 | } 87 | }; 88 | 89 | MiloGridProto._destroyGrid = function() { 90 | var idx = 0; 91 | var length = this.children.length; 92 | for (idx; idx < length; idx++) { 93 | this.children[idx].style.cssText = ''; 94 | } 95 | }; 96 | 97 | MiloGridProto._resizeBind = function() { 98 | var rebuildGrid = function() { 99 | this.buildGrid(); 100 | }.bind(this); 101 | 102 | // debounce the window resize 103 | // to minimize the amount of rebuild calls 104 | window.addEventListener('resize', debounce(rebuildGrid, 600)); 105 | }; 106 | 107 | // expose a public api 108 | var Milo = function(options) { 109 | var miloGrid = new MiloGrid(options); 110 | this.buildGrid = miloGrid.buildGrid.bind(miloGrid); 111 | }; 112 | 113 | module.exports = Milo; 114 | },{"./lib/debounce":2}]},{},[1]); 115 | --------------------------------------------------------------------------------