4 * @class Roo.bootstrap.LayoutMasonry
5 * @extends Roo.bootstrap.Component
6 * @children Roo.bootstrap.Element Roo.bootstrap.Img Roo.bootstrap.MasonryBrick
7 * Bootstrap Layout Masonry class
10 * http://masonry.desandro.com
12 * The idea is to render all the bricks based on vertical width...
14 * The original code extends 'outlayer' - we might need to use that....
17 * Create a new Element
18 * @param {Object} config The config object
21 Roo.bootstrap.LayoutMasonry = function(config){
23 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
27 Roo.bootstrap.LayoutMasonry.register(this);
33 * Fire after layout the items
34 * @param {Roo.bootstrap.LayoutMasonry} this
35 * @param {Roo.EventObject} e
42 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
45 * @cfg {Boolean} isLayoutInstant = no animation?
47 isLayoutInstant : false, // needed?
50 * @cfg {Number} boxWidth width of the columns
55 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
60 * @cfg {Number} padWidth padding below box..
65 * @cfg {Number} gutter gutter width..
70 * @cfg {Number} maxCols maximum number of columns
76 * @cfg {Boolean} isAutoInitial defalut true
83 * @cfg {Boolean} isHorizontal defalut false
93 bricks: null, //CompositeElement
97 _isLayoutInited : false,
99 // isAlternative : false, // only use for vertical layout...
102 * @cfg {Number} alternativePadWidth padding below box..
104 alternativePadWidth : 50,
108 getAutoCreate : function(){
110 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
114 cls: 'blog-masonary-wrapper ' + this.cls,
116 cls : 'mas-boxes masonary'
123 getChildContainer: function( )
129 this.boxesEl = this.el.select('.mas-boxes').first();
135 initEvents : function()
139 if(this.isAutoInitial){
140 Roo.log('hook children rendered');
141 this.on('childrenrendered', function() {
142 Roo.log('children rendered');
150 this.selectedBrick = [];
152 this.currentSize = this.el.getBox(true);
154 Roo.EventManager.onWindowResize(this.resize, this);
156 if(!this.isAutoInitial){
164 //this.layout.defer(500,this);
170 var cs = this.el.getBox(true);
173 this.currentSize.width == cs.width &&
174 this.currentSize.x == cs.x &&
175 this.currentSize.height == cs.height &&
176 this.currentSize.y == cs.y
178 Roo.log("no change in with or X or Y");
182 this.currentSize = cs;
192 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
194 this.layoutItems( isInstant );
196 this._isLayoutInited = true;
198 this.fireEvent('layout', this);
202 _resetLayout : function()
204 if(this.isHorizontal){
205 this.horizontalMeasureColumns();
209 this.verticalMeasureColumns();
213 verticalMeasureColumns : function()
215 this.getContainerWidth();
217 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
218 // this.colWidth = Math.floor(this.containerWidth * 0.8);
222 var boxWidth = this.boxWidth + this.padWidth;
224 if(this.containerWidth < this.boxWidth){
225 boxWidth = this.containerWidth
228 var containerWidth = this.containerWidth;
230 var cols = Math.floor(containerWidth / boxWidth);
232 this.cols = Math.max( cols, 1 );
234 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
236 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
238 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
240 this.colWidth = boxWidth + avail - this.padWidth;
242 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
243 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
246 horizontalMeasureColumns : function()
248 this.getContainerWidth();
250 var boxWidth = this.boxWidth;
252 if(this.containerWidth < boxWidth){
253 boxWidth = this.containerWidth;
256 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
258 this.el.setHeight(boxWidth);
262 getContainerWidth : function()
264 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
267 layoutItems : function( isInstant )
269 Roo.log(this.bricks);
271 var items = Roo.apply([], this.bricks);
273 if(this.isHorizontal){
274 this._horizontalLayoutItems( items , isInstant );
278 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
279 // this._verticalAlternativeLayoutItems( items , isInstant );
283 this._verticalLayoutItems( items , isInstant );
287 _verticalLayoutItems : function ( items , isInstant)
289 if ( !items || !items.length ) {
294 ['xs', 'xs', 'xs', 'tall'],
295 ['xs', 'xs', 'tall'],
307 ['tall', 'xs', 'xs', 'xs'],
308 ['tall', 'xs', 'xs'],
320 Roo.each(items, function(item, k){
323 // these layouts take up a full box,
357 var filterPattern = function(box, length)
365 var pattern = box.slice(0, length);
369 Roo.each(pattern, function(i){
373 Roo.each(standard, function(s){
375 if(String(s) != String(format)){
384 if(!match && length == 1){
389 filterPattern(box, length - 1);
395 box = box.slice(length, box.length);
397 filterPattern(box, 4);
403 Roo.each(boxes, function(box, k){
414 filterPattern(box, 4);
418 this._processVerticalLayoutQueue( queue, isInstant );
422 // _verticalAlternativeLayoutItems : function( items , isInstant )
424 // if ( !items || !items.length ) {
428 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
432 _horizontalLayoutItems : function ( items , isInstant)
434 if ( !items || !items.length || items.length < 3) {
440 var eItems = items.slice(0, 3);
442 items = items.slice(3, items.length);
445 ['xs', 'xs', 'xs', 'wide'],
446 ['xs', 'xs', 'wide'],
458 ['wide', 'xs', 'xs', 'xs'],
459 ['wide', 'xs', 'xs'],
472 Roo.each(items, function(item, k){
509 var filterPattern = function(box, length)
517 var pattern = box.slice(0, length);
521 Roo.each(pattern, function(i){
525 Roo.each(standard, function(s){
527 if(String(s) != String(format)){
536 if(!match && length == 1){
541 filterPattern(box, length - 1);
547 box = box.slice(length, box.length);
549 filterPattern(box, 4);
555 Roo.each(boxes, function(box, k){
566 filterPattern(box, 4);
573 var pos = this.el.getBox(true);
577 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
581 Roo.each(queue, function(box){
585 Roo.each(box, function(b){
587 b.el.setVisibilityMode(Roo.Element.DISPLAY);
597 Roo.each(box, function(b){
599 b.el.setVisibilityMode(Roo.Element.DISPLAY);
602 mx = Math.max(mx, b.x);
606 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
610 Roo.each(box, function(b){
612 b.el.setVisibilityMode(Roo.Element.DISPLAY);
626 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
629 /** Sets position of item in DOM
630 * @param {Element} item
631 * @param {Number} x - horizontal position
632 * @param {Number} y - vertical position
633 * @param {Boolean} isInstant - disables transitions
635 _processVerticalLayoutQueue : function( queue, isInstant )
637 var pos = this.el.getBox(true);
642 for (var i = 0; i < this.cols; i++){
646 Roo.each(queue, function(box, k){
648 var col = k % this.cols;
650 Roo.each(box, function(b,kk){
652 b.el.position('absolute');
654 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
655 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
657 if(b.size == 'md-left' || b.size == 'md-right'){
658 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
659 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
662 b.el.setWidth(width);
663 b.el.setHeight(height);
665 b.el.select('iframe',true).setSize(width,height);
669 for (var i = 0; i < this.cols; i++){
671 if(maxY[i] < maxY[col]){
676 col = Math.min(col, i);
680 x = pos.x + col * (this.colWidth + this.padWidth);
688 positions = this.getVerticalOneBoxColPositions(x, y, box);
691 positions = this.getVerticalTwoBoxColPositions(x, y, box);
694 positions = this.getVerticalThreeBoxColPositions(x, y, box);
697 positions = this.getVerticalFourBoxColPositions(x, y, box);
703 Roo.each(box, function(b,kk){
705 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
707 var sz = b.el.getSize();
709 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
717 for (var i = 0; i < this.cols; i++){
718 mY = Math.max(mY, maxY[i]);
721 this.el.setHeight(mY - pos.y);
725 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
727 // var pos = this.el.getBox(true);
730 // var maxX = pos.right;
732 // var maxHeight = 0;
734 // Roo.each(items, function(item, k){
738 // item.el.position('absolute');
740 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
742 // item.el.setWidth(width);
744 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
746 // item.el.setHeight(height);
749 // item.el.setXY([x, y], isInstant ? false : true);
751 // item.el.setXY([maxX - width, y], isInstant ? false : true);
754 // y = y + height + this.alternativePadWidth;
756 // maxHeight = maxHeight + height + this.alternativePadWidth;
760 // this.el.setHeight(maxHeight);
764 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
766 var pos = this.el.getBox(true);
771 var maxX = pos.right;
773 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
775 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
777 Roo.each(queue, function(box, k){
779 Roo.each(box, function(b, kk){
781 b.el.position('absolute');
783 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
784 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
786 if(b.size == 'md-left' || b.size == 'md-right'){
787 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
788 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
791 b.el.setWidth(width);
792 b.el.setHeight(height);
804 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
807 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
810 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
813 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
819 Roo.each(box, function(b,kk){
821 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
823 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
831 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
833 Roo.each(eItems, function(b,k){
835 b.size = (k == 0) ? 'sm' : 'xs';
836 b.x = (k == 0) ? 2 : 1;
837 b.y = (k == 0) ? 2 : 1;
839 b.el.position('absolute');
841 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
843 b.el.setWidth(width);
845 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
847 b.el.setHeight(height);
854 x : maxX - this.unitWidth * 2 - this.gutter,
859 x : maxX - this.unitWidth,
860 y : minY + (this.unitWidth + this.gutter) * 2
864 x : maxX - this.unitWidth * 3 - this.gutter * 2,
868 Roo.each(eItems, function(b,k){
870 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
876 getVerticalOneBoxColPositions : function(x, y, box)
880 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
882 if(box[0].size == 'md-left'){
886 if(box[0].size == 'md-right'){
891 x : x + (this.unitWidth + this.gutter) * rand,
898 getVerticalTwoBoxColPositions : function(x, y, box)
902 if(box[0].size == 'xs'){
906 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
910 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
924 x : x + (this.unitWidth + this.gutter) * 2,
925 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
932 getVerticalThreeBoxColPositions : function(x, y, box)
936 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
944 x : x + (this.unitWidth + this.gutter) * 1,
949 x : x + (this.unitWidth + this.gutter) * 2,
957 if(box[0].size == 'xs' && box[1].size == 'xs'){
966 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
970 x : x + (this.unitWidth + this.gutter) * 1,
984 x : x + (this.unitWidth + this.gutter) * 2,
989 x : x + (this.unitWidth + this.gutter) * 2,
990 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
997 getVerticalFourBoxColPositions : function(x, y, box)
1001 if(box[0].size == 'xs'){
1010 y : y + (this.unitHeight + this.gutter) * 1
1015 y : y + (this.unitHeight + this.gutter) * 2
1019 x : x + (this.unitWidth + this.gutter) * 1,
1033 x : x + (this.unitWidth + this.gutter) * 2,
1038 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
1039 y : y + (this.unitHeight + this.gutter) * 1
1043 x : x + (this.unitWidth + this.gutter) * 2,
1044 y : y + (this.unitWidth + this.gutter) * 2
1051 getHorizontalOneBoxColPositions : function(maxX, minY, box)
1055 if(box[0].size == 'md-left'){
1057 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1064 if(box[0].size == 'md-right'){
1066 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1067 y : minY + (this.unitWidth + this.gutter) * 1
1073 var rand = Math.floor(Math.random() * (4 - box[0].y));
1076 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1077 y : minY + (this.unitWidth + this.gutter) * rand
1084 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
1088 if(box[0].size == 'xs'){
1091 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1096 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1097 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
1105 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1110 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1111 y : minY + (this.unitWidth + this.gutter) * 2
1118 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
1122 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
1125 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1130 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1131 y : minY + (this.unitWidth + this.gutter) * 1
1135 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1136 y : minY + (this.unitWidth + this.gutter) * 2
1143 if(box[0].size == 'xs' && box[1].size == 'xs'){
1146 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1151 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1156 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1157 y : minY + (this.unitWidth + this.gutter) * 1
1165 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1170 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1171 y : minY + (this.unitWidth + this.gutter) * 2
1175 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1176 y : minY + (this.unitWidth + this.gutter) * 2
1183 getHorizontalFourBoxColPositions : function(maxX, minY, box)
1187 if(box[0].size == 'xs'){
1190 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].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),
1200 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),
1205 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
1206 y : minY + (this.unitWidth + this.gutter) * 1
1214 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1219 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].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),
1225 y : minY + (this.unitWidth + this.gutter) * 2
1229 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),
1230 y : minY + (this.unitWidth + this.gutter) * 2
1238 * remove a Masonry Brick
1239 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
1241 removeBrick : function(brick_id)
1247 for (var i = 0; i<this.bricks.length; i++) {
1248 if (this.bricks[i].id == brick_id) {
1249 this.bricks.splice(i,1);
1250 this.el.dom.removeChild(Roo.get(brick_id).dom);
1257 * adds a Masonry Brick
1258 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1260 addBrick : function(cfg)
1262 var cn = new Roo.bootstrap.MasonryBrick(cfg);
1263 //this.register(cn);
1264 cn.parentId = this.id;
1270 * register a Masonry Brick
1271 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1274 register : function(brick)
1276 this.bricks.push(brick);
1277 brick.masonryId = this.id;
1281 * clear all the Masonry Brick
1283 clearAll : function()
1286 //this.getChildContainer().dom.innerHTML = "";
1287 this.el.dom.innerHTML = '';
1290 getSelected : function()
1292 if (!this.selectedBrick) {
1296 return this.selectedBrick;
1300 Roo.apply(Roo.bootstrap.LayoutMasonry, {
1304 * register a Masonry Layout
1305 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
1308 register : function(layout)
1310 this.groups[layout.id] = layout;
1313 * fetch a Masonry Layout based on the masonry layout ID
1314 * @param {string} the masonry layout to add
1315 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
1318 get: function(layout_id) {
1319 if (typeof(this.groups[layout_id]) == 'undefined') {
1322 return this.groups[layout_id] ;