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,
107 getAutoCreate : function(){
109 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
113 cls: 'blog-masonary-wrapper ' + this.cls,
115 cls : 'mas-boxes masonary'
122 getChildContainer: function( )
128 this.boxesEl = this.el.select('.mas-boxes').first();
134 initEvents : function()
138 if(this.isAutoInitial){
139 Roo.log('hook children rendered');
140 this.on('childrenrendered', function() {
141 Roo.log('children rendered');
149 this.currentSize = this.el.getBox(true);
151 Roo.EventManager.onWindowResize(this.resize, this);
153 if(!this.isAutoInitial){
161 //this.layout.defer(500,this);
167 var cs = this.el.getBox(true);
170 this.currentSize.width == cs.width &&
171 this.currentSize.x == cs.x &&
172 this.currentSize.height == cs.height &&
173 this.currentSize.y == cs.y
175 Roo.log("no change in with or X or Y");
179 this.currentSize = cs;
189 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
191 this.layoutItems( isInstant );
193 this._isLayoutInited = true;
195 this.fireEvent('layout', this);
199 _resetLayout : function()
201 if(this.isHorizontal){
202 this.horizontalMeasureColumns();
206 this.verticalMeasureColumns();
210 verticalMeasureColumns : function()
212 this.getContainerWidth();
214 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
215 // this.colWidth = Math.floor(this.containerWidth * 0.8);
219 var boxWidth = this.boxWidth + this.padWidth;
221 if(this.containerWidth < this.boxWidth){
222 boxWidth = this.containerWidth
225 var containerWidth = this.containerWidth;
227 var cols = Math.floor(containerWidth / boxWidth);
229 this.cols = Math.max( cols, 1 );
231 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
233 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
235 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
237 this.colWidth = boxWidth + avail - this.padWidth;
239 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
240 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
243 horizontalMeasureColumns : function()
245 this.getContainerWidth();
247 var boxWidth = this.boxWidth;
249 if(this.containerWidth < boxWidth){
250 boxWidth = this.containerWidth;
253 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
255 this.el.setHeight(boxWidth);
259 getContainerWidth : function()
261 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
264 layoutItems : function( isInstant )
266 Roo.log(this.bricks);
268 var items = Roo.apply([], this.bricks);
270 if(this.isHorizontal){
271 this._horizontalLayoutItems( items , isInstant );
275 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
276 // this._verticalAlternativeLayoutItems( items , isInstant );
280 this._verticalLayoutItems( items , isInstant );
284 _verticalLayoutItems : function ( items , isInstant)
286 if ( !items || !items.length ) {
291 ['xs', 'xs', 'xs', 'tall'],
292 ['xs', 'xs', 'tall'],
304 ['tall', 'xs', 'xs', 'xs'],
305 ['tall', 'xs', 'xs'],
317 Roo.each(items, function(item, k){
320 // these layouts take up a full box,
354 var filterPattern = function(box, length)
362 var pattern = box.slice(0, length);
366 Roo.each(pattern, function(i){
370 Roo.each(standard, function(s){
372 if(String(s) != String(format)){
381 if(!match && length == 1){
386 filterPattern(box, length - 1);
392 box = box.slice(length, box.length);
394 filterPattern(box, 4);
400 Roo.each(boxes, function(box, k){
411 filterPattern(box, 4);
415 this._processVerticalLayoutQueue( queue, isInstant );
419 // _verticalAlternativeLayoutItems : function( items , isInstant )
421 // if ( !items || !items.length ) {
425 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
429 _horizontalLayoutItems : function ( items , isInstant)
431 if ( !items || !items.length || items.length < 3) {
437 var eItems = items.slice(0, 3);
439 items = items.slice(3, items.length);
442 ['xs', 'xs', 'xs', 'wide'],
443 ['xs', 'xs', 'wide'],
455 ['wide', 'xs', 'xs', 'xs'],
456 ['wide', 'xs', 'xs'],
469 Roo.each(items, function(item, k){
506 var filterPattern = function(box, length)
514 var pattern = box.slice(0, length);
518 Roo.each(pattern, function(i){
522 Roo.each(standard, function(s){
524 if(String(s) != String(format)){
533 if(!match && length == 1){
538 filterPattern(box, length - 1);
544 box = box.slice(length, box.length);
546 filterPattern(box, 4);
552 Roo.each(boxes, function(box, k){
563 filterPattern(box, 4);
570 var pos = this.el.getBox(true);
574 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
578 Roo.each(queue, function(box){
582 Roo.each(box, function(b){
584 b.el.setVisibilityMode(Roo.Element.DISPLAY);
594 Roo.each(box, function(b){
596 b.el.setVisibilityMode(Roo.Element.DISPLAY);
599 mx = Math.max(mx, b.x);
603 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
607 Roo.each(box, function(b){
609 b.el.setVisibilityMode(Roo.Element.DISPLAY);
623 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
626 /** Sets position of item in DOM
627 * @param {Element} item
628 * @param {Number} x - horizontal position
629 * @param {Number} y - vertical position
630 * @param {Boolean} isInstant - disables transitions
632 _processVerticalLayoutQueue : function( queue, isInstant )
634 var pos = this.el.getBox(true);
639 for (var i = 0; i < this.cols; i++){
643 Roo.each(queue, function(box, k){
645 var col = k % this.cols;
647 Roo.each(box, function(b,kk){
649 b.el.position('absolute');
651 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
652 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
654 if(b.size == 'md-left' || b.size == 'md-right'){
655 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
656 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
659 b.el.setWidth(width);
660 b.el.setHeight(height);
662 b.el.select('iframe',true).setSize(width,height);
666 for (var i = 0; i < this.cols; i++){
668 if(maxY[i] < maxY[col]){
673 col = Math.min(col, i);
677 x = pos.x + col * (this.colWidth + this.padWidth);
685 positions = this.getVerticalOneBoxColPositions(x, y, box);
688 positions = this.getVerticalTwoBoxColPositions(x, y, box);
691 positions = this.getVerticalThreeBoxColPositions(x, y, box);
694 positions = this.getVerticalFourBoxColPositions(x, y, box);
700 Roo.each(box, function(b,kk){
702 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
704 var sz = b.el.getSize();
706 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
714 for (var i = 0; i < this.cols; i++){
715 mY = Math.max(mY, maxY[i]);
718 this.el.setHeight(mY - pos.y);
722 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
724 // var pos = this.el.getBox(true);
727 // var maxX = pos.right;
729 // var maxHeight = 0;
731 // Roo.each(items, function(item, k){
735 // item.el.position('absolute');
737 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
739 // item.el.setWidth(width);
741 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
743 // item.el.setHeight(height);
746 // item.el.setXY([x, y], isInstant ? false : true);
748 // item.el.setXY([maxX - width, y], isInstant ? false : true);
751 // y = y + height + this.alternativePadWidth;
753 // maxHeight = maxHeight + height + this.alternativePadWidth;
757 // this.el.setHeight(maxHeight);
761 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
763 var pos = this.el.getBox(true);
768 var maxX = pos.right;
770 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
772 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
774 Roo.each(queue, function(box, k){
776 Roo.each(box, function(b, kk){
778 b.el.position('absolute');
780 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
781 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
783 if(b.size == 'md-left' || b.size == 'md-right'){
784 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
785 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
788 b.el.setWidth(width);
789 b.el.setHeight(height);
801 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
804 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
807 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
810 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
816 Roo.each(box, function(b,kk){
818 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
820 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
828 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
830 Roo.each(eItems, function(b,k){
832 b.size = (k == 0) ? 'sm' : 'xs';
833 b.x = (k == 0) ? 2 : 1;
834 b.y = (k == 0) ? 2 : 1;
836 b.el.position('absolute');
838 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
840 b.el.setWidth(width);
842 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
844 b.el.setHeight(height);
851 x : maxX - this.unitWidth * 2 - this.gutter,
856 x : maxX - this.unitWidth,
857 y : minY + (this.unitWidth + this.gutter) * 2
861 x : maxX - this.unitWidth * 3 - this.gutter * 2,
865 Roo.each(eItems, function(b,k){
867 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
873 getVerticalOneBoxColPositions : function(x, y, box)
877 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
879 if(box[0].size == 'md-left'){
883 if(box[0].size == 'md-right'){
888 x : x + (this.unitWidth + this.gutter) * rand,
895 getVerticalTwoBoxColPositions : function(x, y, box)
899 if(box[0].size == 'xs'){
903 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
907 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
921 x : x + (this.unitWidth + this.gutter) * 2,
922 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
929 getVerticalThreeBoxColPositions : function(x, y, box)
933 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
941 x : x + (this.unitWidth + this.gutter) * 1,
946 x : x + (this.unitWidth + this.gutter) * 2,
954 if(box[0].size == 'xs' && box[1].size == 'xs'){
963 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
967 x : x + (this.unitWidth + this.gutter) * 1,
981 x : x + (this.unitWidth + this.gutter) * 2,
986 x : x + (this.unitWidth + this.gutter) * 2,
987 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
994 getVerticalFourBoxColPositions : function(x, y, box)
998 if(box[0].size == 'xs'){
1007 y : y + (this.unitHeight + this.gutter) * 1
1012 y : y + (this.unitHeight + this.gutter) * 2
1016 x : x + (this.unitWidth + this.gutter) * 1,
1030 x : x + (this.unitWidth + this.gutter) * 2,
1035 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
1036 y : y + (this.unitHeight + this.gutter) * 1
1040 x : x + (this.unitWidth + this.gutter) * 2,
1041 y : y + (this.unitWidth + this.gutter) * 2
1048 getHorizontalOneBoxColPositions : function(maxX, minY, box)
1052 if(box[0].size == 'md-left'){
1054 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1061 if(box[0].size == 'md-right'){
1063 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1064 y : minY + (this.unitWidth + this.gutter) * 1
1070 var rand = Math.floor(Math.random() * (4 - box[0].y));
1073 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1074 y : minY + (this.unitWidth + this.gutter) * rand
1081 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
1085 if(box[0].size == 'xs'){
1088 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1093 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1094 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
1102 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1107 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1108 y : minY + (this.unitWidth + this.gutter) * 2
1115 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
1119 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
1122 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1127 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1128 y : minY + (this.unitWidth + this.gutter) * 1
1132 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1133 y : minY + (this.unitWidth + this.gutter) * 2
1140 if(box[0].size == 'xs' && box[1].size == 'xs'){
1143 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1148 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1153 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1154 y : minY + (this.unitWidth + this.gutter) * 1
1162 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1167 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1168 y : minY + (this.unitWidth + this.gutter) * 2
1172 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1173 y : minY + (this.unitWidth + this.gutter) * 2
1180 getHorizontalFourBoxColPositions : function(maxX, minY, box)
1184 if(box[0].size == 'xs'){
1187 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1192 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1197 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),
1202 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
1203 y : minY + (this.unitWidth + this.gutter) * 1
1211 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1216 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1217 y : minY + (this.unitWidth + this.gutter) * 2
1221 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1222 y : minY + (this.unitWidth + this.gutter) * 2
1226 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),
1227 y : minY + (this.unitWidth + this.gutter) * 2
1235 * adds a Masonry Brick
1236 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1238 addBrick : function(cfg)
1240 var cn = new Roo.bootstrap.MasonryBrick(cfg);
1241 //this.register(cn);
1242 cn.parentId = this.id;
1243 cn.onRender(this.el, null);
1248 * register a Masonry Brick
1249 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1252 register : function(brick)
1254 this.bricks.push(brick);
1255 brick.masonryId = this.id;
1259 * clear all the Masonry Brick
1261 clearAll : function()
1264 //this.getChildContainer().dom.innerHTML = "";
1265 this.el.dom.innerHTML = '';
1268 getSelected : function()
1270 for (var i=0; i<this.bricks.length; i++) {
1271 Roo.log(this.bricks[i]);
1276 Roo.apply(Roo.bootstrap.LayoutMasonry, {
1280 * register a Masonry Layout
1281 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
1284 register : function(layout)
1286 this.groups[layout.id] = layout;
1289 * fetch a Masonry Layout based on the masonry layout ID
1290 * @param {string} the masonry layout to add
1291 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
1294 get: function(layout_id) {
1295 if (typeof(this.groups[layout_id]) == 'undefined') {
1298 return this.groups[layout_id] ;