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(){
111 cls: 'blog-masonary-wrapper ' + this.cls,
113 cls : 'mas-boxes masonary'
120 getChildContainer: function( )
126 this.boxesEl = this.el.select('.mas-boxes').first();
132 initEvents : function()
136 if(this.isAutoInitial){
137 Roo.log('hook children rendered');
138 this.on('childrenrendered', function() {
139 Roo.log('children rendered');
147 this.currentSize = this.el.getBox(true);
149 Roo.EventManager.onWindowResize(this.resize, this);
151 if(!this.isAutoInitial){
159 //this.layout.defer(500,this);
165 var cs = this.el.getBox(true);
168 this.currentSize.width == cs.width &&
169 this.currentSize.x == cs.x &&
170 this.currentSize.height == cs.height &&
171 this.currentSize.y == cs.y
173 Roo.log("no change in with or X or Y");
177 this.currentSize = cs;
187 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
189 this.layoutItems( isInstant );
191 this._isLayoutInited = true;
193 this.fireEvent('layout', this);
197 _resetLayout : function()
199 if(this.isHorizontal){
200 this.horizontalMeasureColumns();
204 this.verticalMeasureColumns();
208 verticalMeasureColumns : function()
210 this.getContainerWidth();
212 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
213 // this.colWidth = Math.floor(this.containerWidth * 0.8);
217 var boxWidth = this.boxWidth + this.padWidth;
219 if(this.containerWidth < this.boxWidth){
220 boxWidth = this.containerWidth
223 var containerWidth = this.containerWidth;
225 var cols = Math.floor(containerWidth / boxWidth);
227 this.cols = Math.max( cols, 1 );
229 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
231 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
233 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
235 this.colWidth = boxWidth + avail - this.padWidth;
237 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
238 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
241 horizontalMeasureColumns : function()
243 this.getContainerWidth();
245 var boxWidth = this.boxWidth;
247 if(this.containerWidth < boxWidth){
248 boxWidth = this.containerWidth;
251 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
253 this.el.setHeight(boxWidth);
257 getContainerWidth : function()
259 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
262 layoutItems : function( isInstant )
264 Roo.log(this.bricks);
266 var items = Roo.apply([], this.bricks);
268 if(this.isHorizontal){
269 this._horizontalLayoutItems( items , isInstant );
273 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
274 // this._verticalAlternativeLayoutItems( items , isInstant );
278 this._verticalLayoutItems( items , isInstant );
282 _verticalLayoutItems : function ( items , isInstant)
284 if ( !items || !items.length ) {
289 ['xs', 'xs', 'xs', 'tall'],
290 ['xs', 'xs', 'tall'],
302 ['tall', 'xs', 'xs', 'xs'],
303 ['tall', 'xs', 'xs'],
315 Roo.each(items, function(item, k){
318 // these layouts take up a full box,
352 var filterPattern = function(box, length)
360 var pattern = box.slice(0, length);
364 Roo.each(pattern, function(i){
368 Roo.each(standard, function(s){
370 if(String(s) != String(format)){
379 if(!match && length == 1){
384 filterPattern(box, length - 1);
390 box = box.slice(length, box.length);
392 filterPattern(box, 4);
398 Roo.each(boxes, function(box, k){
409 filterPattern(box, 4);
413 this._processVerticalLayoutQueue( queue, isInstant );
417 // _verticalAlternativeLayoutItems : function( items , isInstant )
419 // if ( !items || !items.length ) {
423 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
427 _horizontalLayoutItems : function ( items , isInstant)
429 if ( !items || !items.length || items.length < 3) {
435 var eItems = items.slice(0, 3);
437 items = items.slice(3, items.length);
440 ['xs', 'xs', 'xs', 'wide'],
441 ['xs', 'xs', 'wide'],
453 ['wide', 'xs', 'xs', 'xs'],
454 ['wide', 'xs', 'xs'],
467 Roo.each(items, function(item, k){
504 var filterPattern = function(box, length)
512 var pattern = box.slice(0, length);
516 Roo.each(pattern, function(i){
520 Roo.each(standard, function(s){
522 if(String(s) != String(format)){
531 if(!match && length == 1){
536 filterPattern(box, length - 1);
542 box = box.slice(length, box.length);
544 filterPattern(box, 4);
550 Roo.each(boxes, function(box, k){
561 filterPattern(box, 4);
568 var pos = this.el.getBox(true);
572 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
576 Roo.each(queue, function(box){
580 Roo.each(box, function(b){
582 b.el.setVisibilityMode(Roo.Element.DISPLAY);
592 Roo.each(box, function(b){
594 b.el.setVisibilityMode(Roo.Element.DISPLAY);
597 mx = Math.max(mx, b.x);
601 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
605 Roo.each(box, function(b){
607 b.el.setVisibilityMode(Roo.Element.DISPLAY);
621 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
624 /** Sets position of item in DOM
625 * @param {Element} item
626 * @param {Number} x - horizontal position
627 * @param {Number} y - vertical position
628 * @param {Boolean} isInstant - disables transitions
630 _processVerticalLayoutQueue : function( queue, isInstant )
632 var pos = this.el.getBox(true);
637 for (var i = 0; i < this.cols; i++){
641 Roo.each(queue, function(box, k){
643 var col = k % this.cols;
645 Roo.each(box, function(b,kk){
647 b.el.position('absolute');
649 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
650 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
652 if(b.size == 'md-left' || b.size == 'md-right'){
653 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
654 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
657 b.el.setWidth(width);
658 b.el.setHeight(height);
660 b.el.select('iframe',true).setSize(width,height);
664 for (var i = 0; i < this.cols; i++){
666 if(maxY[i] < maxY[col]){
671 col = Math.min(col, i);
675 x = pos.x + col * (this.colWidth + this.padWidth);
683 positions = this.getVerticalOneBoxColPositions(x, y, box);
686 positions = this.getVerticalTwoBoxColPositions(x, y, box);
689 positions = this.getVerticalThreeBoxColPositions(x, y, box);
692 positions = this.getVerticalFourBoxColPositions(x, y, box);
698 Roo.each(box, function(b,kk){
700 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
702 var sz = b.el.getSize();
704 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
712 for (var i = 0; i < this.cols; i++){
713 mY = Math.max(mY, maxY[i]);
716 this.el.setHeight(mY - pos.y);
720 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
722 // var pos = this.el.getBox(true);
725 // var maxX = pos.right;
727 // var maxHeight = 0;
729 // Roo.each(items, function(item, k){
733 // item.el.position('absolute');
735 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
737 // item.el.setWidth(width);
739 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
741 // item.el.setHeight(height);
744 // item.el.setXY([x, y], isInstant ? false : true);
746 // item.el.setXY([maxX - width, y], isInstant ? false : true);
749 // y = y + height + this.alternativePadWidth;
751 // maxHeight = maxHeight + height + this.alternativePadWidth;
755 // this.el.setHeight(maxHeight);
759 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
761 var pos = this.el.getBox(true);
766 var maxX = pos.right;
768 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
770 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
772 Roo.each(queue, function(box, k){
774 Roo.each(box, function(b, kk){
776 b.el.position('absolute');
778 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
779 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
781 if(b.size == 'md-left' || b.size == 'md-right'){
782 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
783 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
786 b.el.setWidth(width);
787 b.el.setHeight(height);
799 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
802 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
805 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
808 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
814 Roo.each(box, function(b,kk){
816 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
818 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
826 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
828 Roo.each(eItems, function(b,k){
830 b.size = (k == 0) ? 'sm' : 'xs';
831 b.x = (k == 0) ? 2 : 1;
832 b.y = (k == 0) ? 2 : 1;
834 b.el.position('absolute');
836 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
838 b.el.setWidth(width);
840 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
842 b.el.setHeight(height);
849 x : maxX - this.unitWidth * 2 - this.gutter,
854 x : maxX - this.unitWidth,
855 y : minY + (this.unitWidth + this.gutter) * 2
859 x : maxX - this.unitWidth * 3 - this.gutter * 2,
863 Roo.each(eItems, function(b,k){
865 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
871 getVerticalOneBoxColPositions : function(x, y, box)
875 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
877 if(box[0].size == 'md-left'){
881 if(box[0].size == 'md-right'){
886 x : x + (this.unitWidth + this.gutter) * rand,
893 getVerticalTwoBoxColPositions : function(x, y, box)
897 if(box[0].size == 'xs'){
901 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
905 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
919 x : x + (this.unitWidth + this.gutter) * 2,
920 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
927 getVerticalThreeBoxColPositions : function(x, y, box)
931 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
939 x : x + (this.unitWidth + this.gutter) * 1,
944 x : x + (this.unitWidth + this.gutter) * 2,
952 if(box[0].size == 'xs' && box[1].size == 'xs'){
961 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
965 x : x + (this.unitWidth + this.gutter) * 1,
979 x : x + (this.unitWidth + this.gutter) * 2,
984 x : x + (this.unitWidth + this.gutter) * 2,
985 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
992 getVerticalFourBoxColPositions : function(x, y, box)
996 if(box[0].size == 'xs'){
1005 y : y + (this.unitHeight + this.gutter) * 1
1010 y : y + (this.unitHeight + this.gutter) * 2
1014 x : x + (this.unitWidth + this.gutter) * 1,
1028 x : x + (this.unitWidth + this.gutter) * 2,
1033 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
1034 y : y + (this.unitHeight + this.gutter) * 1
1038 x : x + (this.unitWidth + this.gutter) * 2,
1039 y : y + (this.unitWidth + this.gutter) * 2
1046 getHorizontalOneBoxColPositions : function(maxX, minY, box)
1050 if(box[0].size == 'md-left'){
1052 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1059 if(box[0].size == 'md-right'){
1061 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1062 y : minY + (this.unitWidth + this.gutter) * 1
1068 var rand = Math.floor(Math.random() * (4 - box[0].y));
1071 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1072 y : minY + (this.unitWidth + this.gutter) * rand
1079 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
1083 if(box[0].size == 'xs'){
1086 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1091 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1092 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
1100 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1105 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1106 y : minY + (this.unitWidth + this.gutter) * 2
1113 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
1117 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
1120 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1125 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1126 y : minY + (this.unitWidth + this.gutter) * 1
1130 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1131 y : minY + (this.unitWidth + this.gutter) * 2
1138 if(box[0].size == 'xs' && box[1].size == 'xs'){
1141 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1146 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1151 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1152 y : minY + (this.unitWidth + this.gutter) * 1
1160 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1165 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1166 y : minY + (this.unitWidth + this.gutter) * 2
1170 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1171 y : minY + (this.unitWidth + this.gutter) * 2
1178 getHorizontalFourBoxColPositions : function(maxX, minY, box)
1182 if(box[0].size == 'xs'){
1185 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1190 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1195 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),
1200 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
1201 y : minY + (this.unitWidth + this.gutter) * 1
1209 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1214 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1215 y : minY + (this.unitWidth + this.gutter) * 2
1219 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1220 y : minY + (this.unitWidth + this.gutter) * 2
1224 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),
1225 y : minY + (this.unitWidth + this.gutter) * 2
1233 * adds a Masonry Brick
1234 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1236 addBrick : function(cfg)
1238 var cn = new Roo.bootstrap.MasonryBrick(cfg);
1239 //this.register(cn);
1240 cn.parentId = this.id;
1241 cn.onRender(this.el, null);
1246 * register a Masonry Brick
1247 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1250 register : function(brick)
1252 this.bricks.push(brick);
1253 brick.masonryId = this.id;
1257 * clear all the Masonry Brick
1259 clearAll : function()
1262 //this.getChildContainer().dom.innerHTML = "";
1263 this.el.dom.innerHTML = '';
1266 getSelected : function()
1268 for (var i=0; i<this.bricks.length; i++) {
1269 Roo.log(this.bricks[i]);
1274 Roo.apply(Roo.bootstrap.LayoutMasonry, {
1278 * register a Masonry Layout
1279 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
1282 register : function(layout)
1284 this.groups[layout.id] = layout;
1287 * fetch a Masonry Layout based on the masonry layout ID
1288 * @param {string} the masonry layout to add
1289 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
1292 get: function(layout_id) {
1293 if (typeof(this.groups[layout_id]) == 'undefined') {
1296 return this.groups[layout_id] ;