A Grid Layout

Sencha Touch 2 has a couple of layouts already defined, probably most used of them are the HBox and the VBox.
However, I felt the need of a grid layout in a couple of situations, especially when I was building dashboard like views. I have written a couple of such layouts in time, and the main issue was to decide what is given and what is dynamic.
What do you want to be fixed? The rows number or the columns number? The cell height or the cell width?
I prefer the case of fixed column number with fixed row height.
Obviously there can be done something more flexible but for what I need I can admit that the number of columns is given as well as a max row height.

  source

Ext.define("Extras.layout.Grid",{
	extend:"Ext.layout.Default",
	alias: 'layout.grid',
	config:{ 
		columns:3,
		rowHeight:60
	},
	insertItem: function(item, index) {
       var container = this.container,
           items = container.getItems().items,
           innerItems = this.innerItems,
           containerDom = this.getInnerItemsContainer().dom,
           itemDom = item.renderElement.dom,
           relativeItem, relativeItemDom, domIndex, originalIndex=index;

       if (container.has(item)) {
           Ext.Array.remove(innerItems, item);
       }

       if (typeof index == 'number') {
           // Retrieve the *logical* relativeItem reference to insertBefore
           relativeItem = items[index];

           // If it is the item itself, get the next sibling
           if (relativeItem === item) {
               relativeItem = items[++index];
           }

           // Continue finding the relativeItem that is neither currently centered nor docked
           while (relativeItem && (relativeItem.isCentered() || relativeItem.isDocked())) {
               relativeItem = items[++index];
           }

           if (relativeItem) {
               // Retrieve the *physical* index of that relativeItem
               domIndex = innerItems.indexOf(relativeItem);

               if (domIndex !== -1) {
                   while (relativeItem && (relativeItem.isCentered() || relativeItem.isDocked())) {
                       relativeItem = innerItems[++domIndex];
                   }

                   if (relativeItem) {
                       innerItems.splice(domIndex, 0, item);

                       relativeItemDom = relativeItem.renderElement.dom;
                       containerDom.insertBefore(itemDom, relativeItemDom);

                       this.reposItems();

                       return this;
                   }
               }
           }
       }
      
       innerItems.push(item);
       originalIndex = innerItems.indexOf(item);
       containerDom.appendChild(itemDom);
       containerDom.style.position = 'relative';
       itemDom.style.position = 'absolute';
       var c = this.getColumns();
       itemDom.style.left = (originalIndex % c) *  100/c +'%';
       itemDom.style.width = 100/c +'%';
       itemDom.style.height = this.getRowHeight()+'px';
       itemDom.style.top = Math.floor(originalIndex / c) * this.getRowHeight()+'px';

       return this;
   },
   reposItems:function() {
   	 var container = this.container,
           items = container.getItems().items,
           innerItems = this.innerItems,
           containerDom = this.getInnerItemsContainer().dom,
           i=0, ln=innerItems.length, c=this.getColumns(), h = this.getRowHeight();
           for(;i<ln;i++) {
           		var itemDom = innerItems[i].renderElement.dom;
           		itemDom.style.position = 'absolute';
           		itemDom.style.left = (i % c) *  100/c +'%';
		       itemDom.style.width = 100/c +'%';
		       itemDom.style.height = h+'px';
		       itemDom.style.top = Math.floor(i / c) * h+'px';
           }

   }
})