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){
25 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29 Roo.bootstrap.LayoutMasonry.register(this);
35 * Fire after layout the items
36 * @param {Roo.bootstrap.LayoutMasonry} this
37 * @param {Roo.EventObject} e
44 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
47 * @cfg {Boolean} isLayoutInstant = no animation?
49 isLayoutInstant : false, // needed?
52 * @cfg {Number} boxWidth width of the columns
57 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
62 * @cfg {Number} padWidth padding below box..
67 * @cfg {Number} gutter gutter width..
72 * @cfg {Number} maxCols maximum number of columns
78 * @cfg {Boolean} isAutoInitial defalut true
85 * @cfg {Boolean} isHorizontal defalut false
95 bricks: null, //CompositeElement
99 _isLayoutInited : false,
101 // isAlternative : false, // only use for vertical layout...
104 * @cfg {Number} alternativePadWidth padding below box..
106 alternativePadWidth : 50,
110 getAutoCreate : function(){
112 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
116 cls: 'blog-masonary-wrapper ' + this.cls,
118 cls : 'mas-boxes masonary'
125 getChildContainer: function( )
131 this.boxesEl = this.el.select('.mas-boxes').first();
137 initEvents : function()
141 if(this.isAutoInitial){
142 Roo.log('hook children rendered');
143 this.on('childrenrendered', function() {
144 Roo.log('children rendered');
152 this.selectedBrick = [];
154 this.currentSize = this.el.getBox(true);
156 Roo.EventManager.onWindowResize(this.resize, this);
158 if(!this.isAutoInitial){
166 //this.layout.defer(500,this);
172 var cs = this.el.getBox(true);
175 this.currentSize.width == cs.width &&
176 this.currentSize.x == cs.x &&
177 this.currentSize.height == cs.height &&
178 this.currentSize.y == cs.y
180 Roo.log("no change in with or X or Y");
184 this.currentSize = cs;
194 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
196 this.layoutItems( isInstant );
198 this._isLayoutInited = true;
200 this.fireEvent('layout', this);
204 _resetLayout : function()
206 if(this.isHorizontal){
207 this.horizontalMeasureColumns();
211 this.verticalMeasureColumns();
215 verticalMeasureColumns : function()
217 this.getContainerWidth();
219 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
220 // this.colWidth = Math.floor(this.containerWidth * 0.8);
224 var boxWidth = this.boxWidth + this.padWidth;
226 if(this.containerWidth < this.boxWidth){
227 boxWidth = this.containerWidth
230 var containerWidth = this.containerWidth;
232 var cols = Math.floor(containerWidth / boxWidth);
234 this.cols = Math.max( cols, 1 );
236 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
238 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
240 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
242 this.colWidth = boxWidth + avail - this.padWidth;
244 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
245 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
248 horizontalMeasureColumns : function()
250 this.getContainerWidth();
252 Roo.log('this.containerWidth : ' + this.containerWidth);
254 var boxWidth = this.boxWidth;
256 Roo.log('this.boxWidth : ' + this.boxWidth);
258 if(this.containerWidth < boxWidth){
259 boxWidth = this.containerWidth;
262 Roo.log('boxWidth : ' + boxWidth);
264 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
266 Roo.log('this.unitWidth : ' + this.unitWidth);
268 this.el.setHeight(boxWidth);
272 getContainerWidth : function()
275 Roo.log(this.el.getBox(true));
276 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
279 layoutItems : function( isInstant )
281 Roo.log(this.bricks);
283 var items = Roo.apply([], this.bricks);
285 if(this.isHorizontal){
286 this._horizontalLayoutItems( items , isInstant );
290 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
291 // this._verticalAlternativeLayoutItems( items , isInstant );
295 this._verticalLayoutItems( items , isInstant );
299 _verticalLayoutItems : function ( items , isInstant)
301 if ( !items || !items.length ) {
306 ['xs', 'xs', 'xs', 'tall'],
307 ['xs', 'xs', 'tall'],
319 ['tall', 'xs', 'xs', 'xs'],
320 ['tall', 'xs', 'xs'],
332 Roo.each(items, function(item, k){
335 // these layouts take up a full box,
369 var filterPattern = function(box, length)
377 var pattern = box.slice(0, length);
381 Roo.each(pattern, function(i){
385 Roo.each(standard, function(s){
387 if(String(s) != String(format)){
396 if(!match && length == 1){
401 filterPattern(box, length - 1);
407 box = box.slice(length, box.length);
409 filterPattern(box, 4);
415 Roo.each(boxes, function(box, k){
426 filterPattern(box, 4);
430 this._processVerticalLayoutQueue( queue, isInstant );
434 // _verticalAlternativeLayoutItems : function( items , isInstant )
436 // if ( !items || !items.length ) {
440 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
444 _horizontalLayoutItems : function ( items , isInstant)
446 if ( !items || !items.length || items.length < 3) {
452 var eItems = items.slice(0, 3);
454 items = items.slice(3, items.length);
457 ['xs', 'xs', 'xs', 'wide'],
458 ['xs', 'xs', 'wide'],
470 ['wide', 'xs', 'xs', 'xs'],
471 ['wide', 'xs', 'xs'],
484 Roo.each(items, function(item, k){
521 var filterPattern = function(box, length)
529 var pattern = box.slice(0, length);
533 Roo.each(pattern, function(i){
537 Roo.each(standard, function(s){
539 if(String(s) != String(format)){
548 if(!match && length == 1){
553 filterPattern(box, length - 1);
559 box = box.slice(length, box.length);
561 filterPattern(box, 4);
567 Roo.each(boxes, function(box, k){
578 filterPattern(box, 4);
585 var pos = this.el.getBox(true);
589 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
593 Roo.each(queue, function(box){
597 Roo.each(box, function(b){
599 b.el.setVisibilityMode(Roo.Element.DISPLAY);
609 Roo.each(box, function(b){
611 b.el.setVisibilityMode(Roo.Element.DISPLAY);
614 mx = Math.max(mx, b.x);
618 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
622 Roo.each(box, function(b){
624 b.el.setVisibilityMode(Roo.Element.DISPLAY);
638 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
641 /** Sets position of item in DOM
642 * @param {Element} item
643 * @param {Number} x - horizontal position
644 * @param {Number} y - vertical position
645 * @param {Boolean} isInstant - disables transitions
647 _processVerticalLayoutQueue : function( queue, isInstant )
649 var pos = this.el.getBox(true);
654 for (var i = 0; i < this.cols; i++){
658 Roo.each(queue, function(box, k){
660 var col = k % this.cols;
662 Roo.each(box, function(b,kk){
664 b.el.position('absolute');
666 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
667 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
669 if(b.size == 'md-left' || b.size == 'md-right'){
670 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
671 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
674 b.el.setWidth(width);
675 b.el.setHeight(height);
677 b.el.select('iframe',true).setSize(width,height);
681 for (var i = 0; i < this.cols; i++){
683 if(maxY[i] < maxY[col]){
688 col = Math.min(col, i);
692 x = pos.x + col * (this.colWidth + this.padWidth);
700 positions = this.getVerticalOneBoxColPositions(x, y, box);
703 positions = this.getVerticalTwoBoxColPositions(x, y, box);
706 positions = this.getVerticalThreeBoxColPositions(x, y, box);
709 positions = this.getVerticalFourBoxColPositions(x, y, box);
715 Roo.each(box, function(b,kk){
717 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
719 var sz = b.el.getSize();
721 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
729 for (var i = 0; i < this.cols; i++){
730 mY = Math.max(mY, maxY[i]);
733 this.el.setHeight(mY - pos.y);
737 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
739 // var pos = this.el.getBox(true);
742 // var maxX = pos.right;
744 // var maxHeight = 0;
746 // Roo.each(items, function(item, k){
750 // item.el.position('absolute');
752 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
754 // item.el.setWidth(width);
756 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
758 // item.el.setHeight(height);
761 // item.el.setXY([x, y], isInstant ? false : true);
763 // item.el.setXY([maxX - width, y], isInstant ? false : true);
766 // y = y + height + this.alternativePadWidth;
768 // maxHeight = maxHeight + height + this.alternativePadWidth;
772 // this.el.setHeight(maxHeight);
776 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
778 var pos = this.el.getBox(true);
783 var maxX = pos.right;
785 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
787 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
789 Roo.each(queue, function(box, k){
791 Roo.each(box, function(b, kk){
793 b.el.position('absolute');
795 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
796 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
798 if(b.size == 'md-left' || b.size == 'md-right'){
799 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
800 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
803 b.el.setWidth(width);
804 b.el.setHeight(height);
816 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
819 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
822 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
825 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
831 Roo.each(box, function(b,kk){
833 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
835 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
843 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
845 Roo.each(eItems, function(b,k){
847 b.size = (k == 0) ? 'sm' : 'xs';
848 b.x = (k == 0) ? 2 : 1;
849 b.y = (k == 0) ? 2 : 1;
851 b.el.position('absolute');
853 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
855 b.el.setWidth(width);
857 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
859 b.el.setHeight(height);
866 x : maxX - this.unitWidth * 2 - this.gutter,
871 x : maxX - this.unitWidth,
872 y : minY + (this.unitWidth + this.gutter) * 2
876 x : maxX - this.unitWidth * 3 - this.gutter * 2,
880 Roo.each(eItems, function(b,k){
882 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
888 getVerticalOneBoxColPositions : function(x, y, box)
892 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
894 if(box[0].size == 'md-left'){
898 if(box[0].size == 'md-right'){
903 x : x + (this.unitWidth + this.gutter) * rand,
910 getVerticalTwoBoxColPositions : function(x, y, box)
914 if(box[0].size == 'xs'){
918 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
922 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
936 x : x + (this.unitWidth + this.gutter) * 2,
937 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
944 getVerticalThreeBoxColPositions : function(x, y, box)
948 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
956 x : x + (this.unitWidth + this.gutter) * 1,
961 x : x + (this.unitWidth + this.gutter) * 2,
969 if(box[0].size == 'xs' && box[1].size == 'xs'){
978 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
982 x : x + (this.unitWidth + this.gutter) * 1,
996 x : x + (this.unitWidth + this.gutter) * 2,
1001 x : x + (this.unitWidth + this.gutter) * 2,
1002 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
1009 getVerticalFourBoxColPositions : function(x, y, box)
1013 if(box[0].size == 'xs'){
1022 y : y + (this.unitHeight + this.gutter) * 1
1027 y : y + (this.unitHeight + this.gutter) * 2
1031 x : x + (this.unitWidth + this.gutter) * 1,
1045 x : x + (this.unitWidth + this.gutter) * 2,
1050 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
1051 y : y + (this.unitHeight + this.gutter) * 1
1055 x : x + (this.unitWidth + this.gutter) * 2,
1056 y : y + (this.unitWidth + this.gutter) * 2
1063 getHorizontalOneBoxColPositions : function(maxX, minY, box)
1067 if(box[0].size == 'md-left'){
1069 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1076 if(box[0].size == 'md-right'){
1078 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1079 y : minY + (this.unitWidth + this.gutter) * 1
1085 var rand = Math.floor(Math.random() * (4 - box[0].y));
1088 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1089 y : minY + (this.unitWidth + this.gutter) * rand
1096 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
1100 if(box[0].size == 'xs'){
1103 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1108 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1109 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
1117 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1122 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1123 y : minY + (this.unitWidth + this.gutter) * 2
1130 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
1134 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
1137 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1142 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1143 y : minY + (this.unitWidth + this.gutter) * 1
1147 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1148 y : minY + (this.unitWidth + this.gutter) * 2
1155 if(box[0].size == 'xs' && box[1].size == 'xs'){
1158 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1163 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1168 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1169 y : minY + (this.unitWidth + this.gutter) * 1
1177 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1182 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1183 y : minY + (this.unitWidth + this.gutter) * 2
1187 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1188 y : minY + (this.unitWidth + this.gutter) * 2
1195 getHorizontalFourBoxColPositions : function(maxX, minY, box)
1199 if(box[0].size == 'xs'){
1202 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1207 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1212 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),
1217 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
1218 y : minY + (this.unitWidth + this.gutter) * 1
1226 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1231 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1232 y : minY + (this.unitWidth + this.gutter) * 2
1236 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1237 y : minY + (this.unitWidth + this.gutter) * 2
1241 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),
1242 y : minY + (this.unitWidth + this.gutter) * 2
1250 * remove a Masonry Brick
1251 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
1253 removeBrick : function(brick_id)
1259 for (var i = 0; i<this.bricks.length; i++) {
1260 if (this.bricks[i].id == brick_id) {
1261 this.bricks.splice(i,1);
1262 this.selectedBrick = [];
1263 this.el.dom.removeChild(Roo.get(brick_id).dom);
1270 * adds a Masonry Brick
1271 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1273 addBrick : function(cfg)
1275 var cn = new Roo.bootstrap.MasonryBrick(cfg);
1276 //this.register(cn);
1277 cn.parentId = this.id;
1278 cn.onRender(this.el, null);
1283 * register a Masonry Brick
1284 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1287 register : function(brick)
1289 this.bricks.push(brick);
1290 brick.masonryId = this.id;
1294 * clear all the Masonry Brick
1296 clearAll : function()
1299 //this.getChildContainer().dom.innerHTML = "";
1300 this.el.dom.innerHTML = '';
1303 getSelected : function()
1305 if (!this.selectedBrick) {
1309 return this.selectedBrick;
1313 Roo.apply(Roo.bootstrap.LayoutMasonry, {
1317 * register a Masonry Layout
1318 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
1321 register : function(layout)
1323 this.groups[layout.id] = layout;
1326 * fetch a Masonry Layout based on the masonry layout ID
1327 * @param {string} the masonry layout to add
1328 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
1331 get: function(layout_id) {
1332 if (typeof(this.groups[layout_id]) == 'undefined') {
1335 return this.groups[layout_id] ;