4 * http://masonry.desandro.com
6 * The idea is to render all the bricks based on vertical width...
8 * The original code extends 'outlayer' - we might need to use that....
14 * @class Roo.bootstrap.LayoutMasonry
15 * @extends Roo.bootstrap.Component
16 * Bootstrap Layout Masonry class
19 * Create a new Element
20 * @param {Object} config The config object
23 Roo.bootstrap.LayoutMasonry = function(config){
24 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
32 * Fire after layout the items
33 * @param {Roo.bootstrap.LayoutMasonry} this
34 * @param {Roo.EventObject} e
41 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
44 * @cfg {Boolean} isLayoutInstant = no animation?
46 isLayoutInstant : false, // needed?
49 * @cfg {Number} boxWidth width of the columns
54 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
59 * @cfg {Number} padWidth padding below box..
64 * @cfg {Number} gutter gutter width..
69 * @cfg {Number} maxCols maximum number of columns
75 * @cfg {Boolean} isAutoInitial defalut true
82 * @cfg {Boolean} isHorizontal defalut false
92 bricks: null, //CompositeElement
96 _isLayoutInited : false,
98 // isAlternative : false, // only use for vertical layout...
101 * @cfg {Number} alternativePadWidth padding below box..
103 alternativePadWidth : 50,
105 getAutoCreate : function(){
109 cls: 'blog-masonary-wrapper ' + this.cls,
111 cls : 'mas-boxes masonary'
118 getChildContainer: function( )
124 this.boxesEl = this.el.select('.mas-boxes').first();
130 initEvents : function()
134 if(this.isAutoInitial){
135 Roo.log('hook children rendered');
136 this.on('childrenrendered', function() {
137 Roo.log('children rendered');
145 this.currentSize = this.el.getBox(true);
147 Roo.EventManager.onWindowResize(this.resize, this);
149 if(!this.isAutoInitial){
157 //this.layout.defer(500,this);
163 var cs = this.el.getBox(true);
166 this.currentSize.width == cs.width &&
167 this.currentSize.x == cs.x &&
168 this.currentSize.height == cs.height &&
169 this.currentSize.y == cs.y
171 Roo.log("no change in with or X or Y");
175 this.currentSize = cs;
185 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
187 this.layoutItems( isInstant );
189 this._isLayoutInited = true;
191 this.fireEvent('layout', this);
195 _resetLayout : function()
197 if(this.isHorizontal){
198 this.horizontalMeasureColumns();
202 this.verticalMeasureColumns();
206 verticalMeasureColumns : function()
208 this.getContainerWidth();
210 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
211 // this.colWidth = Math.floor(this.containerWidth * 0.8);
215 var boxWidth = this.boxWidth + this.padWidth;
217 if(this.containerWidth < this.boxWidth){
218 boxWidth = this.containerWidth
221 var containerWidth = this.containerWidth;
223 var cols = Math.floor(containerWidth / boxWidth);
225 this.cols = Math.max( cols, 1 );
227 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
229 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
231 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
233 this.colWidth = boxWidth + avail - this.padWidth;
235 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
236 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
239 horizontalMeasureColumns : function()
241 this.getContainerWidth();
243 var boxWidth = this.boxWidth;
245 if(this.containerWidth < boxWidth){
246 boxWidth = this.containerWidth;
249 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
251 this.el.setHeight(boxWidth);
255 getContainerWidth : function()
257 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
260 layoutItems : function( isInstant )
262 Roo.log(this.bricks);
264 var items = Roo.apply([], this.bricks);
266 if(this.isHorizontal){
267 this._horizontalLayoutItems( items , isInstant );
271 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
272 // this._verticalAlternativeLayoutItems( items , isInstant );
276 this._verticalLayoutItems( items , isInstant );
280 _verticalLayoutItems : function ( items , isInstant)
282 if ( !items || !items.length ) {
287 ['xs', 'xs', 'xs', 'tall'],
288 ['xs', 'xs', 'tall'],
300 ['tall', 'xs', 'xs', 'xs'],
301 ['tall', 'xs', 'xs'],
313 Roo.each(items, function(item, k){
316 // these layouts take up a full box,
350 var filterPattern = function(box, length)
358 var pattern = box.slice(0, length);
362 Roo.each(pattern, function(i){
366 Roo.each(standard, function(s){
368 if(String(s) != String(format)){
377 if(!match && length == 1){
382 filterPattern(box, length - 1);
388 box = box.slice(length, box.length);
390 filterPattern(box, 4);
396 Roo.each(boxes, function(box, k){
407 filterPattern(box, 4);
411 this._processVerticalLayoutQueue( queue, isInstant );
415 // _verticalAlternativeLayoutItems : function( items , isInstant )
417 // if ( !items || !items.length ) {
421 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
425 _horizontalLayoutItems : function ( items , isInstant)
427 if ( !items || !items.length || items.length < 3) {
433 var eItems = items.slice(0, 3);
435 items = items.slice(3, items.length);
438 ['xs', 'xs', 'xs', 'wide'],
439 ['xs', 'xs', 'wide'],
451 ['wide', 'xs', 'xs', 'xs'],
452 ['wide', 'xs', 'xs'],
465 Roo.each(items, function(item, k){
502 var filterPattern = function(box, length)
510 var pattern = box.slice(0, length);
514 Roo.each(pattern, function(i){
518 Roo.each(standard, function(s){
520 if(String(s) != String(format)){
529 if(!match && length == 1){
534 filterPattern(box, length - 1);
540 box = box.slice(length, box.length);
542 filterPattern(box, 4);
548 Roo.each(boxes, function(box, k){
559 filterPattern(box, 4);
566 var pos = this.el.getBox(true);
570 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
574 Roo.each(queue, function(box){
578 Roo.each(box, function(b){
580 b.el.setVisibilityMode(Roo.Element.DISPLAY);
590 Roo.each(box, function(b){
592 b.el.setVisibilityMode(Roo.Element.DISPLAY);
595 mx = Math.max(mx, b.x);
599 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
603 Roo.each(box, function(b){
605 b.el.setVisibilityMode(Roo.Element.DISPLAY);
619 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
622 /** Sets position of item in DOM
623 * @param {Element} item
624 * @param {Number} x - horizontal position
625 * @param {Number} y - vertical position
626 * @param {Boolean} isInstant - disables transitions
628 _processVerticalLayoutQueue : function( queue, isInstant )
630 var pos = this.el.getBox(true);
635 for (var i = 0; i < this.cols; i++){
639 Roo.each(queue, function(box, k){
641 var col = k % this.cols;
643 Roo.each(box, function(b,kk){
645 b.el.position('absolute');
647 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
648 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
650 if(b.size == 'md-left' || b.size == 'md-right'){
651 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
652 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
655 b.el.setWidth(width);
656 b.el.setHeight(height);
658 b.el.select('iframe',true).setSize(width,height);
662 for (var i = 0; i < this.cols; i++){
664 if(maxY[i] < maxY[col]){
669 col = Math.min(col, i);
673 x = pos.x + col * (this.colWidth + this.padWidth);
681 positions = this.getVerticalOneBoxColPositions(x, y, box);
684 positions = this.getVerticalTwoBoxColPositions(x, y, box);
687 positions = this.getVerticalThreeBoxColPositions(x, y, box);
690 positions = this.getVerticalFourBoxColPositions(x, y, box);
696 Roo.each(box, function(b,kk){
698 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
700 var sz = b.el.getSize();
702 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
710 for (var i = 0; i < this.cols; i++){
711 mY = Math.max(mY, maxY[i]);
714 this.el.setHeight(mY - pos.y);
718 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
720 // var pos = this.el.getBox(true);
723 // var maxX = pos.right;
725 // var maxHeight = 0;
727 // Roo.each(items, function(item, k){
731 // item.el.position('absolute');
733 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
735 // item.el.setWidth(width);
737 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
739 // item.el.setHeight(height);
742 // item.el.setXY([x, y], isInstant ? false : true);
744 // item.el.setXY([maxX - width, y], isInstant ? false : true);
747 // y = y + height + this.alternativePadWidth;
749 // maxHeight = maxHeight + height + this.alternativePadWidth;
753 // this.el.setHeight(maxHeight);
757 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
759 var pos = this.el.getBox(true);
764 var maxX = pos.right;
766 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
768 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
770 Roo.each(queue, function(box, k){
772 Roo.each(box, function(b, kk){
774 b.el.position('absolute');
776 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
777 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
779 if(b.size == 'md-left' || b.size == 'md-right'){
780 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
781 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
784 b.el.setWidth(width);
785 b.el.setHeight(height);
797 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
800 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
803 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
806 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
812 Roo.each(box, function(b,kk){
814 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
816 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
824 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
826 Roo.each(eItems, function(b,k){
828 b.size = (k == 0) ? 'sm' : 'xs';
829 b.x = (k == 0) ? 2 : 1;
830 b.y = (k == 0) ? 2 : 1;
832 b.el.position('absolute');
834 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
836 b.el.setWidth(width);
838 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
840 b.el.setHeight(height);
847 x : maxX - this.unitWidth * 2 - this.gutter,
852 x : maxX - this.unitWidth,
853 y : minY + (this.unitWidth + this.gutter) * 2
857 x : maxX - this.unitWidth * 3 - this.gutter * 2,
861 Roo.each(eItems, function(b,k){
863 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
869 getVerticalOneBoxColPositions : function(x, y, box)
873 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
875 if(box[0].size == 'md-left'){
879 if(box[0].size == 'md-right'){
884 x : x + (this.unitWidth + this.gutter) * rand,
891 getVerticalTwoBoxColPositions : function(x, y, box)
895 if(box[0].size == 'xs'){
899 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
903 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
917 x : x + (this.unitWidth + this.gutter) * 2,
918 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
925 getVerticalThreeBoxColPositions : function(x, y, box)
929 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
937 x : x + (this.unitWidth + this.gutter) * 1,
942 x : x + (this.unitWidth + this.gutter) * 2,
950 if(box[0].size == 'xs' && box[1].size == 'xs'){
959 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
963 x : x + (this.unitWidth + this.gutter) * 1,
977 x : x + (this.unitWidth + this.gutter) * 2,
982 x : x + (this.unitWidth + this.gutter) * 2,
983 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
990 getVerticalFourBoxColPositions : function(x, y, box)
994 if(box[0].size == 'xs'){
1003 y : y + (this.unitHeight + this.gutter) * 1
1008 y : y + (this.unitHeight + this.gutter) * 2
1012 x : x + (this.unitWidth + this.gutter) * 1,
1026 x : x + (this.unitWidth + this.gutter) * 2,
1031 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
1032 y : y + (this.unitHeight + this.gutter) * 1
1036 x : x + (this.unitWidth + this.gutter) * 2,
1037 y : y + (this.unitWidth + this.gutter) * 2
1044 getHorizontalOneBoxColPositions : function(maxX, minY, box)
1048 if(box[0].size == 'md-left'){
1050 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1057 if(box[0].size == 'md-right'){
1059 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1060 y : minY + (this.unitWidth + this.gutter) * 1
1066 var rand = Math.floor(Math.random() * (4 - box[0].y));
1069 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1070 y : minY + (this.unitWidth + this.gutter) * rand
1077 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
1081 if(box[0].size == 'xs'){
1084 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1089 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1090 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
1098 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1103 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1104 y : minY + (this.unitWidth + this.gutter) * 2
1111 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
1115 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
1118 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1123 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1124 y : minY + (this.unitWidth + this.gutter) * 1
1128 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1129 y : minY + (this.unitWidth + this.gutter) * 2
1136 if(box[0].size == 'xs' && box[1].size == 'xs'){
1139 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1144 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1149 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1150 y : minY + (this.unitWidth + this.gutter) * 1
1158 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1163 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1164 y : minY + (this.unitWidth + this.gutter) * 2
1168 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1169 y : minY + (this.unitWidth + this.gutter) * 2
1176 getHorizontalFourBoxColPositions : function(maxX, minY, box)
1180 if(box[0].size == 'xs'){
1183 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1188 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1193 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1198 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
1199 y : minY + (this.unitWidth + this.gutter) * 1
1207 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1212 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1213 y : minY + (this.unitWidth + this.gutter) * 2
1217 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1218 y : minY + (this.unitWidth + this.gutter) * 2
1222 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
1223 y : minY + (this.unitWidth + this.gutter) * 2
1231 * adds a Masonry Brick
1232 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1234 addItem : function(cfg)
1236 var cn = new Roo.bootstrap.MasonryBrick(cfg);
1238 cn.parentId = this.id;
1239 cn.onRender(this.el, null);
1243 * register a Masonry Brick
1244 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1246 register : function(brick)
1248 this.bricks.push(brick);
1249 brick.masonryId = this.id;
1253 * clear all the Masonry Brick
1255 clearAll : function()
1258 //this.getChildContainer().dom.innerHTML = "";
1259 this.el.dom.innerHTML = '';