(function(window, factory){
if(typeof define=='function'&&define.amd){
define(factory);
}else if(typeof module=='object'&&module.exports){
module.exports=factory();
}else{
window.Colcade=factory();
}}(window, function factory(){
function Colcade(element, options){
element=getQueryElement(element);
if(element&&element.colcadeGUID){
var instance=instances[ element.colcadeGUID ];
instance.option(options);
return instance;
}
this.element=element;
this.options={};
this.option(options);
this.lastAppend=[];
this.lastColumnHeights=[];
this.create();
element.classList.add('cr-colcade-loaded');
}
var proto=Colcade.prototype;
proto.option=function(options){
this.options=extend(this.options, options);
};
var GUID=0;
var instances={};
proto.create=function(){
this.errorCheck();
var guid=this.guid=++GUID;
this.element.colcadeGUID=guid;
instances[ guid ]=this;
this.reload();
this._windowResizeHandler=this.onWindowResize.bind(this);
this._loadHandler=this.onLoad.bind(this);
window.addEventListener('resize', this._windowResizeHandler);
this.element.addEventListener('load', this._loadHandler, true);
};
proto.errorCheck=function(){
var errors=[];
if(!this.element){
errors.push('Bad element: ' + this.element);
}
if(!this.options.columns){
errors.push('columns option required: ' + this.options.columns);
}
if(!this.options.items){
errors.push('items option required: ' + this.options.items);
}
if(errors.length){
throw new Error('[Colcade error] ' + errors.join('. '));
}};
proto.reload=function(){
this.updateColumns();
this.updateItems();
this.layout();
};
proto.updateColumns=function(){
this.columns=querySelect(this.options.columns, this.element);
};
proto.updateItems=function(){
this.items=querySelect(this.options.items, this.element);
};
proto.getActiveColumns=function(){
return this.columns.filter(function(column){
var style=getComputedStyle(column);
return style.display!='none';
});
};
proto.layout=function(){
this.activeColumns=this.getActiveColumns();
this._layout();
};
proto._layout=function(){
this.columnHeights=this.activeColumns.map(function(){
return 0;
});
this.layoutItems(this.items);
};
proto.layoutItems=function(items){
items.forEach(this.layoutItem, this);
};
proto.layoutItem=function(item){
var minHeight=Math.min.apply(Math, this.columnHeights);
var index=this.columnHeights.indexOf(minHeight);
this.activeColumns[ index ].appendChild(item);
this.columnHeights[ index ] +=item.offsetHeight||1;
};
proto.append=function(elems){
var items=this.getQueryItems(elems);
this.items=this.items.concat(items);
this.lastAppend.length=0;
this.lastAppend=items.slice();
this.lastColumnHeights.length=0;
this.lastColumnHeights=this.columnHeights.slice();
this.layoutItems(items);
};
proto.prepend=function(elems){
var items=this.getQueryItems(elems);
this.items=items.concat(this.items);
this._layout();
};
proto.getQueryItems=function(elems){
elems=makeArray(elems);
var fragment=document.createDocumentFragment();
elems.forEach(function(elem){
fragment.appendChild(elem);
});
return querySelect(this.options.items, fragment);
};
proto.empty=function(){
this.lastAppend.length=0;
this.lastColumnHeights.length=0;
this.items.forEach(function(item){
item.remove();
}, this);
this.items.length=0;
this._layout();
};
proto.measureColumnHeight=function(elem){
var boundingRect=this.element.getBoundingClientRect();
this.activeColumns.forEach(function(column, i){
if(!elem||column.contains(elem) ){
var lastChildRect=column.lastElementChild.getBoundingClientRect();
this.columnHeights[ i ]=lastChildRect.bottom - boundingRect.top;
}}, this);
};
proto.onWindowResize=function(){
clearTimeout(this.resizeTimeout);
this.resizeTimeout=setTimeout(function(){
this.onDebouncedResize();
}.bind(this), 100);
};
proto.onDebouncedResize=function(){
var activeColumns=this.getActiveColumns();
var isSameLength=activeColumns.length==this.activeColumns.length;
var isSameColumns=true;
this.activeColumns.forEach(function(column, i){
isSameColumns=isSameColumns&&column==activeColumns[i];
});
if(isSameLength&&isSameColumns){
return;
}
this.activeColumns=activeColumns;
this._layout();
};
proto.onLoad=function(event){
this.measureColumnHeight(event.target);
if(0 < this.lastColumnHeights.length&&0 < this.lastAppend.length){
this.columnHeights.length=0;
this.columnHeights=this.lastColumnHeights.slice();
this.layoutItems(this.lastAppend);
}};
proto.destroy=function(){
this.items.forEach(function(item){
this.element.appendChild(item);
}, this);
window.removeEventListener('resize', this._windowResizeHandler);
this.element.removeEventListener('load', this._loadHandler, true);
delete this.element.colcadeGUID;
delete instances[ this.guid ];
};
docReady(function(){
var dataElems=querySelect('[data-colcade]');
dataElems.forEach(htmlInit);
});
function htmlInit(elem){
var attr=elem.getAttribute('data-colcade');
var attrParts=attr.split(',');
var options={};
attrParts.forEach(function(part){
var pair=part.split(':');
var key=pair[0].trim();
var value=pair[1].trim();
options[ key ]=value;
});
new Colcade(elem, options);
}
Colcade.data=function(elem){
elem=getQueryElement(elem);
var id=elem&&elem.colcadeGUID;
return id&&instances[ id ];
};
Colcade.makeJQueryPlugin=function($){
$=$||window.jQuery;
if(!$){
return;
}
$.fn.colcade=function(arg0){
if(typeof arg0=='string'){
var args=Array.prototype.slice.call(arguments, 1);
return methodCall(this, arg0, args);
}
plainCall(this, arg0);
return this;
};
function methodCall($elems, methodName, args){
var returnValue;
$elems.each(function(i, elem){
var colcade=$.data(elem, 'colcade');
if(!colcade){
return;
}
var value=colcade[ methodName ].apply(colcade, args);
returnValue=returnValue===undefined ? value:returnValue;
});
return returnValue!==undefined ? returnValue:$elems;
}
function plainCall($elems, options){
$elems.each(function(i, elem){
var colcade=$.data(elem, 'colcade');
if(colcade){
colcade.option(options);
colcade.layout();
}else{
colcade=new Colcade(elem, options);
$.data(elem, 'colcade', colcade);
}});
}};
Colcade.makeJQueryPlugin();
function extend(a, b){
for(var prop in b){
a[ prop ]=b[ prop ];
}
return a;
}
function makeArray(obj){
var ary=[];
if(Array.isArray(obj) ){
ary=obj;
}else if(obj&&typeof obj.length=='number'){
for(var i=0; i < obj.length; i++){
ary.push(obj[i]);
}}else{
ary.push(obj);
}
return ary;
}
function querySelect(selector, elem){
elem=elem||document;
var elems=elem.querySelectorAll(selector);
return makeArray(elems);
}
function getQueryElement(elem){
if(typeof elem=='string'){
elem=document.querySelector(elem);
}
return elem;
}
function docReady(onReady){
if(document.readyState=='complete'){
onReady();
return;
}
document.addEventListener('DOMContentLoaded', onReady);
}
return Colcade;
}));