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.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 Roo.log('run?????????');
205 if(this.isHorizontal){
206 this.horizontalMeasureColumns();
210 this.verticalMeasureColumns();
214 verticalMeasureColumns : function()
216 this.getContainerWidth();
218 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
219 // this.colWidth = Math.floor(this.containerWidth * 0.8);
223 var boxWidth = this.boxWidth + this.padWidth;
225 if(this.containerWidth < this.boxWidth){
226 boxWidth = this.containerWidth
229 var containerWidth = this.containerWidth;
231 var cols = Math.floor(containerWidth / boxWidth);
233 this.cols = Math.max( cols, 1 );
235 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
237 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
239 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
241 this.colWidth = boxWidth + avail - this.padWidth;
243 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
244 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
247 horizontalMeasureColumns : function()
249 this.getContainerWidth();
251 var boxWidth = this.boxWidth;
253 if(this.containerWidth < boxWidth){
254 boxWidth = this.containerWidth;
257 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
259 this.el.setHeight(boxWidth);
263 getContainerWidth : function()
265 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
268 layoutItems : function( isInstant )
270 Roo.log(this.bricks);
272 var items = Roo.apply([], this.bricks);
274 if(this.isHorizontal){
275 this._horizontalLayoutItems( items , isInstant );
279 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
280 // this._verticalAlternativeLayoutItems( items , isInstant );
284 this._verticalLayoutItems( items , isInstant );
288 _verticalLayoutItems : function ( items , isInstant)
290 if ( !items || !items.length ) {
295 ['xs', 'xs', 'xs', 'tall'],
296 ['xs', 'xs', 'tall'],
308 ['tall', 'xs', 'xs', 'xs'],
309 ['tall', 'xs', 'xs'],
321 Roo.each(items, function(item, k){
324 // these layouts take up a full box,
358 var filterPattern = function(box, length)
366 var pattern = box.slice(0, length);
370 Roo.each(pattern, function(i){
374 Roo.each(standard, function(s){
376 if(String(s) != String(format)){
385 if(!match && length == 1){
390 filterPattern(box, length - 1);
396 box = box.slice(length, box.length);
398 filterPattern(box, 4);
404 Roo.each(boxes, function(box, k){
415 filterPattern(box, 4);
419 this._processVerticalLayoutQueue( queue, isInstant );
423 // _verticalAlternativeLayoutItems : function( items , isInstant )
425 // if ( !items || !items.length ) {
429 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
433 _horizontalLayoutItems : function ( items , isInstant)
435 if ( !items || !items.length || items.length < 3) {
441 var eItems = items.slice(0, 3);
443 items = items.slice(3, items.length);
446 ['xs', 'xs', 'xs', 'wide'],
447 ['xs', 'xs', 'wide'],
459 ['wide', 'xs', 'xs', 'xs'],
460 ['wide', 'xs', 'xs'],
473 Roo.each(items, function(item, k){
510 var filterPattern = function(box, length)
518 var pattern = box.slice(0, length);
522 Roo.each(pattern, function(i){
526 Roo.each(standard, function(s){
528 if(String(s) != String(format)){
537 if(!match && length == 1){
542 filterPattern(box, length - 1);
548 box = box.slice(length, box.length);
550 filterPattern(box, 4);
556 Roo.each(boxes, function(box, k){
567 filterPattern(box, 4);
574 var pos = this.el.getBox(true);
578 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
582 Roo.each(queue, function(box){
586 Roo.each(box, function(b){
588 b.el.setVisibilityMode(Roo.Element.DISPLAY);
598 Roo.each(box, function(b){
600 b.el.setVisibilityMode(Roo.Element.DISPLAY);
603 mx = Math.max(mx, b.x);
607 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
611 Roo.each(box, function(b){
613 b.el.setVisibilityMode(Roo.Element.DISPLAY);
627 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
630 /** Sets position of item in DOM
631 * @param {Element} item
632 * @param {Number} x - horizontal position
633 * @param {Number} y - vertical position
634 * @param {Boolean} isInstant - disables transitions
636 _processVerticalLayoutQueue : function( queue, isInstant )
638 var pos = this.el.getBox(true);
643 for (var i = 0; i < this.cols; i++){
647 Roo.each(queue, function(box, k){
649 var col = k % this.cols;
651 Roo.each(box, function(b,kk){
653 b.el.position('absolute');
655 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
656 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
658 if(b.size == 'md-left' || b.size == 'md-right'){
659 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
660 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
663 b.el.setWidth(width);
664 b.el.setHeight(height);
666 b.el.select('iframe',true).setSize(width,height);
670 for (var i = 0; i < this.cols; i++){
672 if(maxY[i] < maxY[col]){
677 col = Math.min(col, i);
681 x = pos.x + col * (this.colWidth + this.padWidth);
689 positions = this.getVerticalOneBoxColPositions(x, y, box);
692 positions = this.getVerticalTwoBoxColPositions(x, y, box);
695 positions = this.getVerticalThreeBoxColPositions(x, y, box);
698 positions = this.getVerticalFourBoxColPositions(x, y, box);
704 Roo.each(box, function(b,kk){
706 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
708 var sz = b.el.getSize();
710 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
718 for (var i = 0; i < this.cols; i++){
719 mY = Math.max(mY, maxY[i]);
722 this.el.setHeight(mY - pos.y);
726 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
728 // var pos = this.el.getBox(true);
731 // var maxX = pos.right;
733 // var maxHeight = 0;
735 // Roo.each(items, function(item, k){
739 // item.el.position('absolute');
741 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
743 // item.el.setWidth(width);
745 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
747 // item.el.setHeight(height);
750 // item.el.setXY([x, y], isInstant ? false : true);
752 // item.el.setXY([maxX - width, y], isInstant ? false : true);
755 // y = y + height + this.alternativePadWidth;
757 // maxHeight = maxHeight + height + this.alternativePadWidth;
761 // this.el.setHeight(maxHeight);
765 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
767 var pos = this.el.getBox(true);
772 var maxX = pos.right;
774 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
776 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
778 Roo.each(queue, function(box, k){
780 Roo.each(box, function(b, kk){
782 b.el.position('absolute');
784 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
785 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
787 if(b.size == 'md-left' || b.size == 'md-right'){
788 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
789 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
792 b.el.setWidth(width);
793 b.el.setHeight(height);
805 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
808 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
811 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
814 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
820 Roo.each(box, function(b,kk){
822 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
824 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
832 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
834 Roo.each(eItems, function(b,k){
836 b.size = (k == 0) ? 'sm' : 'xs';
837 b.x = (k == 0) ? 2 : 1;
838 b.y = (k == 0) ? 2 : 1;
840 b.el.position('absolute');
842 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
844 b.el.setWidth(width);
846 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
848 b.el.setHeight(height);
855 x : maxX - this.unitWidth * 2 - this.gutter,
860 x : maxX - this.unitWidth,
861 y : minY + (this.unitWidth + this.gutter) * 2
865 x : maxX - this.unitWidth * 3 - this.gutter * 2,
869 Roo.each(eItems, function(b,k){
871 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
877 getVerticalOneBoxColPositions : function(x, y, box)
881 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
883 if(box[0].size == 'md-left'){
887 if(box[0].size == 'md-right'){
892 x : x + (this.unitWidth + this.gutter) * rand,
899 getVerticalTwoBoxColPositions : function(x, y, box)
903 if(box[0].size == 'xs'){
907 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
911 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
925 x : x + (this.unitWidth + this.gutter) * 2,
926 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
933 getVerticalThreeBoxColPositions : function(x, y, box)
937 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
945 x : x + (this.unitWidth + this.gutter) * 1,
950 x : x + (this.unitWidth + this.gutter) * 2,
958 if(box[0].size == 'xs' && box[1].size == 'xs'){
967 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
971 x : x + (this.unitWidth + this.gutter) * 1,
985 x : x + (this.unitWidth + this.gutter) * 2,
990 x : x + (this.unitWidth + this.gutter) * 2,
991 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
998 getVerticalFourBoxColPositions : function(x, y, box)
1002 if(box[0].size == 'xs'){
1011 y : y + (this.unitHeight + this.gutter) * 1
1016 y : y + (this.unitHeight + this.gutter) * 2
1020 x : x + (this.unitWidth + this.gutter) * 1,
1034 x : x + (this.unitWidth + this.gutter) * 2,
1039 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
1040 y : y + (this.unitHeight + this.gutter) * 1
1044 x : x + (this.unitWidth + this.gutter) * 2,
1045 y : y + (this.unitWidth + this.gutter) * 2
1052 getHorizontalOneBoxColPositions : function(maxX, minY, box)
1056 if(box[0].size == 'md-left'){
1058 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1065 if(box[0].size == 'md-right'){
1067 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
1068 y : minY + (this.unitWidth + this.gutter) * 1
1074 var rand = Math.floor(Math.random() * (4 - box[0].y));
1077 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1078 y : minY + (this.unitWidth + this.gutter) * rand
1085 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
1089 if(box[0].size == 'xs'){
1092 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1097 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1098 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
1106 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1111 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1112 y : minY + (this.unitWidth + this.gutter) * 2
1119 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
1123 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
1126 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1131 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1132 y : minY + (this.unitWidth + this.gutter) * 1
1136 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1137 y : minY + (this.unitWidth + this.gutter) * 2
1144 if(box[0].size == 'xs' && box[1].size == 'xs'){
1147 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1152 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1157 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1158 y : minY + (this.unitWidth + this.gutter) * 1
1166 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1171 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1172 y : minY + (this.unitWidth + this.gutter) * 2
1176 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1177 y : minY + (this.unitWidth + this.gutter) * 2
1184 getHorizontalFourBoxColPositions : function(maxX, minY, box)
1188 if(box[0].size == 'xs'){
1191 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1196 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1201 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),
1206 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
1207 y : minY + (this.unitWidth + this.gutter) * 1
1215 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
1220 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
1221 y : minY + (this.unitWidth + this.gutter) * 2
1225 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
1226 y : minY + (this.unitWidth + this.gutter) * 2
1230 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),
1231 y : minY + (this.unitWidth + this.gutter) * 2
1239 * remove a Masonry Brick
1240 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
1242 removeBrick : function(brick_id)
1248 for (var i = 0; i<this.bricks.length; i++) {
1249 if (this.bricks[i].id == brick_id) {
1250 this.bricks.splice(i,1);
1251 this.selectedBrick=[];
1252 this.el.dom.removeChild(Roo.get(brick_id).dom);
1259 * adds a Masonry Brick
1260 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1262 addBrick : function(cfg)
1264 var cn = new Roo.bootstrap.MasonryBrick(cfg);
1265 //this.register(cn);
1266 cn.parentId = this.id;
1267 cn.onRender(this.el, null);
1272 * register a Masonry Brick
1273 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
1276 register : function(brick)
1278 this.bricks.push(brick);
1279 brick.masonryId = this.id;
1283 * clear all the Masonry Brick
1285 clearAll : function()
1288 //this.getChildContainer().dom.innerHTML = "";
1289 this.el.dom.innerHTML = '';
1292 getSelected : function()
1294 if (!this.selectedBrick) {
1298 return this.selectedBrick;
1302 Roo.apply(Roo.bootstrap.LayoutMasonry, {
1306 * register a Masonry Layout
1307 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
1310 register : function(layout)
1312 this.groups[layout.id] = layout;
1315 * fetch a Masonry Layout based on the masonry layout ID
1316 * @param {string} the masonry layout to add
1317 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
1320 get: function(layout_id) {
1321 if (typeof(this.groups[layout_id]) == 'undefined') {
1324 return this.groups[layout_id] ;