<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Angular Gridster</title>
    <meta name="description" content="" />
    <meta name="viewport" content="width=device-width" />

    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.css" rel="stylesheet">
    <link rel="stylesheet" href="angular-gridster.min.css" />
    <link rel="stylesheet" href="style.css" />

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
    <script src="https://code.angularjs.org/1.2.15/angular-route.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.10.0/ui-bootstrap-tpls.min.js"></script>

    <script src="angular-gridster.js"></script>

    <script type="text/javascript">
        (function() {
        	angular.module('app', ['gridster', 'ui.bootstrap', 'ngRoute'])
        		.config(['$routeProvider',
        			function($routeProvider) {
        				$routeProvider
        					.when('/main', {
        						templateUrl: 'main.view.html',
        						controller: 'MainCtrl'
        					})
        					.when('/dashboard', {
        						templateUrl: 'dashboard.view.html',
        						controller: 'DashboardCtrl'
        					})
        					.otherwise({
        						redirectTo: '/main'
        					});
        			}
        		])
        		.controller('RootCtrl', function($scope) {
        			$scope.$on('$locationChangeStart', function(e, next, current) {
        				$scope.page = next.split('/').splice(-1);
        				$scope.styleUrl = $scope.page + '.' + 'style.css'
        			});
        		});
        })();
    </script>

    <script src="main.script.js"></script>
    <script src="dashboard.script.js"></script>
</head>

<body ng-app="app">
    <div ng-controller="RootCtrl">
        <link rel="stylesheet" ng-href="{{ styleUrl }}" />

        <div class="navbar navbar-inverse">
            <div class="navbar-inner">
                <a class="navbar-brand" href="#">Angular Gridster</a>
            </div>
            <ul class="nav navbar-nav navbar-right">
                <li ng-class="{active: page == 'main'}"><a href="#/main">Main Demo</a>
                </li>
                <li ng-class="{active: page == 'dashboard'}"><a href="#/dashboard">Dashboard Demo</a>
                </li>
                <li><a>|</a>
                </li>
                <li>
                    <a href="coverage" target="_blank" class="code-coverage">Code Coverage</a>
                </li>
            </ul>
        </div>

        <div class="container" ng-view></div>

    </div>
</body>

</html>
// Code goes here

angular.module('app')

.directive('integer', function() {
	return {
		require: 'ngModel',
		link: function(scope, ele, attr, ctrl) {
			ctrl.$parsers.unshift(function(viewValue) {
				if (viewValue === '' || viewValue === null || typeof viewValue === 'undefined') {
					return null;
				}
				return parseInt(viewValue, 10);
			});
		}
	};
})

.controller('MainCtrl', function($scope) {

	$scope.gridsterOpts = {
		margins: [20, 20],
		outerMargin: false,
		pushing: true,
		floating: true,
		draggable: {
			enabled: false
		},
		resizable: {
			enabled: false,
			handles: ['n', 'e', 's', 'w', 'se', 'sw']
		}
	};

	// these map directly to gridsterItem options
	$scope.standardItems = [{
		sizeX: 2,
		sizeY: 1,
		row: 0,
		col: 0
	}, {
		sizeX: 2,
		sizeY: 2,
		row: 0,
		col: 2
	}, {
		sizeX: 2,
		sizeY: 1,
		row: 2,
		col: 1
	}, {
		sizeX: 1,
		sizeY: 1,
		row: 2,
		col: 3
	}, {
		sizeX: 1,
		sizeY: 1,
		row: 2,
		col: 4
	}, {
		sizeX: 1,
		sizeY: 1,
		row: 0,
		col: 4
	}, {
		sizeX: 1,
		sizeY: 1,
		row: 0,
		col: 5
	}, {
		sizeX: 2,
		sizeY: 1,
		row: 1,
		col: 0
	}, {
		sizeX: 1,
		sizeY: 1,
		row: 1,
		col: 4
	}, {
		sizeX: 1,
		sizeY: 2,
		row: 1,
		col: 5
	}, {
		sizeX: 1,
		sizeY: 1,
		row: 2,
		col: 0
	}];

	// these are non-standard, so they require mapping options
	$scope.customItems = [{
		size: {
			x: 2,
			y: 1
		},
		position: [0, 0]
	}, {
		size: {
			x: 2,
			y: 2
		},
		position: [0, 2]
	}, {
		size: {
			x: 1,
			y: 1
		},
		position: [1, 4]
	}, {
		size: {
			x: 1,
			y: 2
		},
		position: [1, 5]
	}, {
		size: {
			x: 1,
			y: 1
		},
		position: [2, 0]
	}, {
		size: {
			x: 2,
			y: 1
		},
		position: [2, 1]
	}, {
		size: {
			x: 1,
			y: 1
		},
		position: [2, 3]
	}, {
		size: {
			x: 1,
			y: 1
		},
		position: [0, 4]
	}, {
		size: {
			x: 1,
			y: 1
		},
		position: [0, 5]
	}, {
		size: {
			x: 2,
			y: 1
		},
		position: [1, 0]
	}, {
		size: {
			x: 1,
			y: 1
		},
		position: [2, 4]
	}];

	$scope.emptyItems = [{
		name: 'Item1'
	}, {
		name: 'Item2'
	}, {
		name: 'Item3'
	}, {
		name: 'Item4'
	}];

	// map the gridsterItem to the custom item structure
	$scope.customItemMap = {
		sizeX: 'item.size.x',
		sizeY: 'item.size.y',
		row: 'item.position[0]',
		col: 'item.position[1]'
	};

});
.navbar {
    padding: 0 20px;
}
a:hover {
    cursor: pointer;
}
input {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 14px;
    padding: 4px;
}
.container {
    margin: auto;
    max-width: 1000px;
}
.code-coverage {
    color: #fff;
    font-weight: bold;
    float: right;
    padding: 10px;
}

/*
 * angular-gridster
 * http://manifestwebdesign.github.io/angular-gridster
 *
 * @version: 0.13.5
 * @license: MIT
 */
!function(a,b){"use strict";"function"==typeof define&&define.amd?define(["angular"],b):"object"==typeof exports?module.exports=b(require("angular")):b(a.angular)}(this,function(a){"use strict";return a.module("gridster",[]).constant("gridsterConfig",{columns:6,pushing:!0,floating:!0,swapping:!1,width:"auto",colWidth:"auto",rowHeight:"match",margins:[10,10],outerMargin:!0,isMobile:!1,mobileBreakPoint:600,mobileModeEnabled:!0,minColumns:1,minRows:1,maxRows:100,defaultSizeX:2,defaultSizeY:1,minSizeX:1,maxSizeX:null,minSizeY:1,maxSizeY:null,saveGridItemCalculatedHeightInMobile:!1,resizable:{enabled:!0,handles:["s","e","n","w","se","ne","sw","nw"]},draggable:{enabled:!0,scrollSensitivity:20,scrollSpeed:15}}).controller("GridsterCtrl",["gridsterConfig","$timeout",function(b,c){var d=this;a.extend(this,b),this.resizable=a.extend({},b.resizable||{}),this.draggable=a.extend({},b.draggable||{});var e=!1;this.layoutChanged=function(){e||(e=!0,c(function(){e=!1,d.loaded&&d.floatItemsUp(),d.updateHeight(d.movingItem?d.movingItem.sizeY:0)},30))},this.grid=[],this.destroy=function(){this.grid&&(this.grid=[]),this.$element=null},this.setOptions=function(b){if(b)if(b=a.extend({},b),b.draggable&&(a.extend(this.draggable,b.draggable),delete b.draggable),b.resizable&&(a.extend(this.resizable,b.resizable),delete b.resizable),a.extend(this,b),this.margins&&2===this.margins.length)for(var c=0,d=this.margins.length;d>c;++c)this.margins[c]=parseInt(this.margins[c],10),isNaN(this.margins[c])&&(this.margins[c]=0);else this.margins=[0,0]},this.canItemOccupy=function(a,b,c){return b>-1&&c>-1&&a.sizeX+c<=this.columns&&a.sizeY+b<=this.maxRows},this.autoSetItemPosition=function(a){for(var b=0;b<this.maxRows;++b)for(var c=0;c<this.columns;++c){var d=this.getItems(b,c,a.sizeX,a.sizeY,a);if(0===d.length&&this.canItemOccupy(a,b,c))return void this.putItem(a,b,c)}throw new Error("Unable to place item!")},this.getItems=function(a,b,c,d,e){var f=[];c&&d||(c=d=1),!e||e instanceof Array||(e=[e]);for(var g=0;d>g;++g)for(var h=0;c>h;++h){var i=this.getItem(a+g,b+h,e);!i||e&&-1!==e.indexOf(i)||-1!==f.indexOf(i)||f.push(i)}return f},this.getBoundingBox=function(a){if(0===a.length)return null;if(1===a.length)return{row:a[0].row,col:a[0].col,sizeY:a[0].sizeY,sizeX:a[0].sizeX};for(var b=0,c=0,d=9999,e=9999,f=0,g=a.length;g>f;++f){var h=a[f];d=Math.min(h.row,d),e=Math.min(h.col,e),b=Math.max(h.row+h.sizeY,b),c=Math.max(h.col+h.sizeX,c)}return{row:d,col:e,sizeY:b-d,sizeX:c-e}},this.removeItem=function(a){for(var b=0,c=this.grid.length;c>b;++b){var d=this.grid[b];if(d){var e=d.indexOf(a);if(-1!==e){d[e]=null;break}}}this.layoutChanged()},this.getItem=function(a,b,c){!c||c instanceof Array||(c=[c]);for(var d=1;a>-1;){for(var e=1,f=b;f>-1;){var g=this.grid[a];if(g){var h=g[f];if(h&&(!c||-1===c.indexOf(h))&&h.sizeX>=e&&h.sizeY>=d)return h}++e,--f}--a,++d}return null},this.putItems=function(a){for(var b=0,c=a.length;c>b;++b)this.putItem(a[b])},this.putItem=function(a,b,c,d){if(("undefined"==typeof b||null===b)&&(b=a.row,c=a.col,"undefined"==typeof b||null===b))return void this.autoSetItemPosition(a);if(this.canItemOccupy(a,b,c)||(c=Math.min(this.columns-a.sizeX,Math.max(0,c)),b=Math.min(this.maxRows-a.sizeY,Math.max(0,b))),null!==a.oldRow&&"undefined"!=typeof a.oldRow){var e=a.oldRow===b&&a.oldColumn===c,f=this.grid[b]&&this.grid[b][c]===a;if(e&&f)return a.row=b,void(a.col=c);var g=this.grid[a.oldRow];g&&g[a.oldColumn]===a&&delete g[a.oldColumn]}a.oldRow=a.row=b,a.oldColumn=a.col=c,this.moveOverlappingItems(a,d),this.grid[b]||(this.grid[b]=[]),this.grid[b][c]=a,this.movingItem===a&&this.floatItemUp(a),this.layoutChanged()},this.swapItems=function(a,b){this.grid[a.row][a.col]=b,this.grid[b.row][b.col]=a;var c=a.row,d=a.col;a.row=b.row,a.col=b.col,b.row=c,b.col=d},this.moveOverlappingItems=function(a,b){b?-1===b.indexOf(a)&&(b=b.slice(0),b.push(a)):b=[a];var c=this.getItems(a.row,a.col,a.sizeX,a.sizeY,b);this.moveItemsDown(c,a.row+a.sizeY,b)},this.moveItemsDown=function(a,b,c){if(a&&0!==a.length){a.sort(function(a,b){return a.row-b.row}),c=c?c.slice(0):[];var d,e,f,g={};for(e=0,f=a.length;f>e;++e){d=a[e];var h=g[d.col];("undefined"==typeof h||d.row<h)&&(g[d.col]=d.row)}for(e=0,f=a.length;f>e;++e){d=a[e];var i=b-g[d.col];this.moveItemDown(d,d.row+i,c),c.push(d)}}},this.moveItemDown=function(a,b,c){if(!(a.row>=b)){for(;a.row<b;)++a.row,this.moveOverlappingItems(a,c);this.putItem(a,a.row,a.col,c)}},this.floatItemsUp=function(){if(this.floating!==!1)for(var a=0,b=this.grid.length;b>a;++a){var c=this.grid[a];if(c)for(var d=0,e=c.length;e>d;++d){var f=c[d];f&&this.floatItemUp(f)}}},this.floatItemUp=function(a){if(this.floating!==!1){for(var b=a.col,c=a.sizeY,d=a.sizeX,e=null,f=null,g=a.row-1;g>-1;){var h=this.getItems(g,b,d,c,a);if(0!==h.length)break;e=g,f=b,--g}null!==e&&this.putItem(a,e,f)}},this.updateHeight=function(a){var b=this.minRows;a=a||0;for(var c=this.grid.length;c>=0;--c){var d=this.grid[c];if(d)for(var e=0,f=d.length;f>e;++e)d[e]&&(b=Math.max(b,c+a+d[e].sizeY))}this.gridHeight=this.maxRows-b>0?Math.min(this.maxRows,b):Math.max(this.maxRows,b)},this.pixelsToRows=function(a,b){return this.outerMargin||(a+=this.margins[0]/2),b===!0?Math.ceil(a/this.curRowHeight):b===!1?Math.floor(a/this.curRowHeight):Math.round(a/this.curRowHeight)},this.pixelsToColumns=function(a,b){return this.outerMargin||(a+=this.margins[1]/2),b===!0?Math.ceil(a/this.curColWidth):b===!1?Math.floor(a/this.curColWidth):Math.round(a/this.curColWidth)}}]).directive("gridsterPreview",function(){return{replace:!0,scope:!0,require:"^gridster",template:'<div ng-style="previewStyle()" class="gridster-item gridster-preview-holder"></div>',link:function(a,b,c,d){a.previewStyle=function(){return d.movingItem?{display:"block",height:d.movingItem.sizeY*d.curRowHeight-d.margins[0]+"px",width:d.movingItem.sizeX*d.curColWidth-d.margins[1]+"px",top:d.movingItem.row*d.curRowHeight+(d.outerMargin?d.margins[0]:0)+"px",left:d.movingItem.col*d.curColWidth+(d.outerMargin?d.margins[1]:0)+"px"}:{display:"none"}}}}}).directive("gridster",["$timeout","$window","$rootScope","gridsterDebounce",function(b,c,d,e){return{scope:!0,restrict:"EAC",controller:"GridsterCtrl",controllerAs:"gridster",compile:function(f){return f.prepend('<div ng-if="gridster.movingItem" gridster-preview></div>'),function(f,g,h,i){function j(a){if(i.setOptions(a),l(g[0])){"auto"===i.width?i.curWidth=g[0].offsetWidth||parseInt(g.css("width"),10):i.curWidth=i.width,"auto"===i.colWidth?i.curColWidth=(i.curWidth+(i.outerMargin?-i.margins[1]:i.margins[1]))/i.columns:i.curColWidth=i.colWidth,i.curRowHeight=i.rowHeight,"string"==typeof i.rowHeight&&("match"===i.rowHeight?i.curRowHeight=Math.round(i.curColWidth):-1!==i.rowHeight.indexOf("*")?i.curRowHeight=Math.round(i.curColWidth*i.rowHeight.replace("*","").replace(" ","")):-1!==i.rowHeight.indexOf("/")&&(i.curRowHeight=Math.round(i.curColWidth/i.rowHeight.replace("/","").replace(" ","")))),i.isMobile=i.mobileModeEnabled&&i.curWidth<=i.mobileBreakPoint;for(var b=0,c=i.grid.length;c>b;++b){var d=i.grid[b];if(d)for(var e=0,f=d.length;f>e;++e)if(d[e]){var h=d[e];h.setElementPosition(),h.setElementSizeY(),h.setElementSizeX()}}k()}}function k(){g.css("height",i.gridHeight*i.curRowHeight+(i.outerMargin?i.margins[0]:-i.margins[0])+"px")}i.loaded=!1,i.$element=g,f.gridster=i,g.addClass("gridster");var l=function(a){return"hidden"!==a.style.visibility&&"none"!==a.style.display},m=h.gridster;m?f.$parent.$watch(m,function(a){j(a)},!0):j({}),f.$watch(function(){return i.loaded},function(){i.loaded?g.addClass("gridster-loaded"):g.removeClass("gridster-loaded")}),f.$watch(function(){return i.isMobile},function(){i.isMobile?g.addClass("gridster-mobile").removeClass("gridster-desktop"):g.removeClass("gridster-mobile").addClass("gridster-desktop"),d.$broadcast("gridster-mobile-changed",i)}),f.$watch(function(){return i.draggable},function(){d.$broadcast("gridster-draggable-changed",i)},!0),f.$watch(function(){return i.resizable},function(){d.$broadcast("gridster-resizable-changed",i)},!0),f.$watch(function(){return i.gridHeight},k),f.$watch(function(){return i.movingItem},function(){i.updateHeight(i.movingItem?i.movingItem.sizeY:0)});var n=g[0].offsetWidth||parseInt(g.css("width"),10),o=function(){var a=g[0].offsetWidth||parseInt(g.css("width"),10);a&&a!==n&&!i.movingItem&&(n=a,i.loaded&&g.removeClass("gridster-loaded"),j(),i.loaded&&g.addClass("gridster-loaded"),d.$broadcast("gridster-resized",[a,g[0].offsetHeight],i))},p=e(function(){o(),b(function(){f.$apply()})},100);f.$watch(function(){return l(g[0])},p),"function"==typeof window.addResizeListener?window.addResizeListener(g[0],p):f.$watch(function(){return g[0].offsetWidth||parseInt(g.css("width"),10)},o);var q=a.element(c);q.on("resize",p),f.$on("$destroy",function(){i.destroy(),q.off("resize",p),"function"==typeof window.removeResizeListener&&window.removeResizeListener(g[0],p)}),b(function(){f.$watch("gridster.floating",function(){i.floatItemsUp()}),i.loaded=!0},100)}}}}]).controller("GridsterItemCtrl",function(){this.$element=null,this.gridster=null,this.row=null,this.col=null,this.sizeX=null,this.sizeY=null,this.minSizeX=0,this.minSizeY=0,this.maxSizeX=null,this.maxSizeY=null,this.init=function(a,b){this.$element=a,this.gridster=b,this.sizeX=b.defaultSizeX,this.sizeY=b.defaultSizeY},this.destroy=function(){this.gridster=null,this.$element=null},this.toJSON=function(){return{row:this.row,col:this.col,sizeY:this.sizeY,sizeX:this.sizeX}},this.isMoving=function(){return this.gridster.movingItem===this},this.setPosition=function(a,b){this.gridster.putItem(this,a,b),this.isMoving()||this.setElementPosition()},this.setSize=function(a,b,c){a=a.toUpperCase();var d="size"+a,e="Size"+a;if(""!==b){b=parseInt(b,10),(isNaN(b)||0===b)&&(b=this.gridster["default"+e]);var f="X"===a?this.gridster.columns:this.gridster.maxRows;this["max"+e]&&(f=Math.min(this["max"+e],f)),this.gridster["max"+e]&&(f=Math.min(this.gridster["max"+e],f)),"X"===a&&this.cols?f-=this.cols:"Y"===a&&this.rows&&(f-=this.rows);var g=0;this["min"+e]&&(g=Math.max(this["min"+e],g)),this.gridster["min"+e]&&(g=Math.max(this.gridster["min"+e],g)),b=Math.max(Math.min(b,f),g);var h=this[d]!==b||this["old"+e]&&this["old"+e]!==b;return this["old"+e]=this[d]=b,this.isMoving()||this["setElement"+e](),!c&&h&&(this.gridster.moveOverlappingItems(this),this.gridster.layoutChanged()),h}},this.setSizeY=function(a,b){return this.setSize("Y",a,b)},this.setSizeX=function(a,b){return this.setSize("X",a,b)},this.setElementPosition=function(){this.$element.css(this.gridster.isMobile?{marginLeft:this.gridster.margins[0]+"px",marginRight:this.gridster.margins[0]+"px",marginTop:this.gridster.margins[1]+"px",marginBottom:this.gridster.margins[1]+"px",top:"",left:""}:{margin:0,top:this.row*this.gridster.curRowHeight+(this.gridster.outerMargin?this.gridster.margins[0]:0)+"px",left:this.col*this.gridster.curColWidth+(this.gridster.outerMargin?this.gridster.margins[1]:0)+"px"})},this.setElementSizeY=function(){this.gridster.isMobile&&!this.gridster.saveGridItemCalculatedHeightInMobile?this.$element.css("height",""):this.$element.css("height",this.sizeY*this.gridster.curRowHeight-this.gridster.margins[0]+"px")},this.setElementSizeX=function(){this.gridster.isMobile?this.$element.css("width",""):this.$element.css("width",this.sizeX*this.gridster.curColWidth-this.gridster.margins[1]+"px")},this.getElementSizeX=function(){return this.sizeX*this.gridster.curColWidth-this.gridster.margins[1]},this.getElementSizeY=function(){return this.sizeY*this.gridster.curRowHeight-this.gridster.margins[0]}}).factory("GridsterTouch",[function(){return function(a,b,c,d){var e,f,g={},h=function(a){if(Object.keys)return Object.keys(a).length;var b,c=0;for(b in a)++c;return c},i=function(a){for(var b=0,c=0,d=navigator.userAgent.match(/\bMSIE\b/),e=a;null!=e;e=e.offsetParent)d&&(!document.documentMode||document.documentMode<8)&&"relative"===e.currentStyle.position&&e.offsetParent&&"relative"===e.offsetParent.currentStyle.position&&e.offsetLeft===e.offsetParent.offsetLeft?c+=e.offsetTop:(b+=e.offsetLeft,c+=e.offsetTop);return{x:b,y:c}},j=i(a),k=function(e){if("mousemove"!==e.type||0!==h(g)){for(var f=!0,m=e.changedTouches?e.changedTouches:[e],n=0;n<m.length;++n){var o=m[n],p="undefined"!=typeof o.identifier?o.identifier:"undefined"!=typeof o.pointerId?o.pointerId:1;if("undefined"==typeof o.pageX)if(o.pageX=o.offsetX+j.x,o.pageY=o.offsetY+j.y,o.srcElement.offsetParent===a&&document.documentMode&&8===document.documentMode&&"mousedown"===o.type)o.pageX+=o.srcElement.offsetLeft,o.pageY+=o.srcElement.offsetTop;else if(o.srcElement!==a&&!document.documentMode||document.documentMode<8){for(var q=-2,r=-2,s=o.srcElement;null!==s;s=s.parentNode)q+=s.scrollLeft?s.scrollLeft:0,r+=s.scrollTop?s.scrollTop:0;o.pageX=o.clientX+q,o.pageY=o.clientY+r}var t=o.pageX,u=o.pageY;e.type.match(/(start|down)$/i)?(j=i(a),g[p]&&(d&&d({target:e.target,which:e.which,pointerId:p,pageX:t,pageY:u}),delete g[p]),b&&f&&(f=b({target:e.target,which:e.which,pointerId:p,pageX:t,pageY:u})),g[p]={x:t,y:u},a.msSetPointerCapture?a.msSetPointerCapture(p):"mousedown"===e.type&&1===h(g)&&(l?a.setCapture(!0):(document.addEventListener("mousemove",k,!1),document.addEventListener("mouseup",k,!1)))):e.type.match(/move$/i)?!g[p]||g[p].x===t&&g[p].y===u||(c&&f&&(f=c({target:e.target,which:e.which,pointerId:p,pageX:t,pageY:u})),g[p].x=t,g[p].y=u):g[p]&&e.type.match(/(up|end|cancel)$/i)&&(d&&f&&(f=d({target:e.target,which:e.which,pointerId:p,pageX:t,pageY:u})),delete g[p],a.msReleasePointerCapture?a.msReleasePointerCapture(p):"mouseup"===e.type&&0===h(g)&&(l?a.releaseCapture():(document.removeEventListener("mousemove",k,!1),document.removeEventListener("mouseup",k,!1))))}f&&(e.preventDefault&&e.preventDefault(),e.preventManipulation&&e.preventManipulation(),e.preventMouseEvent&&e.preventMouseEvent())}},l=!1;return this.enable=function(){window.navigator.msPointerEnabled?(a.addEventListener("MSPointerDown",k,!1),a.addEventListener("MSPointerMove",k,!1),a.addEventListener("MSPointerUp",k,!1),a.addEventListener("MSPointerCancel",k,!1),"undefined"!=typeof a.style.msContentZooming&&(e=a.style.msContentZooming,a.style.msContentZooming="none"),"undefined"!=typeof a.style.msTouchAction&&(f=a.style.msTouchAction,a.style.msTouchAction="none")):a.addEventListener?(a.addEventListener("touchstart",k,!1),a.addEventListener("touchmove",k,!1),a.addEventListener("touchend",k,!1),a.addEventListener("touchcancel",k,!1),a.addEventListener("mousedown",k,!1),a.setCapture&&!window.navigator.userAgent.match(/\bGecko\b/)&&(l=!0,a.addEventListener("mousemove",k,!1),a.addEventListener("mouseup",k,!1))):a.attachEvent&&a.setCapture&&(l=!0,a.attachEvent("onmousedown",function(){return k(window.event),window.event.returnValue=!1,!1}),a.attachEvent("onmousemove",function(){return k(window.event),window.event.returnValue=!1,!1}),a.attachEvent("onmouseup",function(){return k(window.event),window.event.returnValue=!1,!1}))},this.disable=function(){window.navigator.msPointerEnabled?(a.removeEventListener("MSPointerDown",k,!1),a.removeEventListener("MSPointerMove",k,!1),a.removeEventListener("MSPointerUp",k,!1),a.removeEventListener("MSPointerCancel",k,!1),e&&(a.style.msContentZooming=e),f&&(a.style.msTouchAction=f)):a.removeEventListener?(a.removeEventListener("touchstart",k,!1),a.removeEventListener("touchmove",k,!1),a.removeEventListener("touchend",k,!1),a.removeEventListener("touchcancel",k,!1),a.removeEventListener("mousedown",k,!1),a.setCapture&&!window.navigator.userAgent.match(/\bGecko\b/)&&(l=!0,a.removeEventListener("mousemove",k,!1),a.removeEventListener("mouseup",k,!1))):a.detachEvent&&a.setCapture&&(l=!0,a.detachEvent("onmousedown"),a.detachEvent("onmousemove"),a.detachEvent("onmouseup"))},this}}]).factory("GridsterDraggable",["$document","$window","GridsterTouch",function(b,c,d){function e(e,f,g,h,i){function j(b){if(-1!==F.indexOf(b.target.nodeName.toLowerCase()))return!1;var c=a.element(b.target);if(c.hasClass("gridster-item-resizable-handler"))return!1;if(c.attr("onclick")||c.attr("ng-click"))return!1;if(c.closest&&c.closest(".gridster-no-drag").length)return!1;switch(b.which){case 1:break;case 2:case 3:return}return x=b.pageX,y=b.pageY,p=parseInt(e.css("left"),10),q=parseInt(e.css("top"),10),r=e[0].offsetWidth,s=e[0].offsetHeight,t=h.col,u=h.row,m(b),!0}function k(a){if(!e.hasClass("gridster-item-moving")||e.hasClass("gridster-item-resizing"))return!1;var b=g.curWidth-1;v=a.pageX,w=a.pageY;var c=v-x+z,d=w-y+A;z=A=0,x=v,y=w;var f=c,h=d;return D>p+f?(c=D-p,z=f-c):p+r+f>b&&(c=b-p-r,z=f-c),B>q+h?(d=B-q,A=h-d):q+s+h>C&&(d=C-q-s,A=h-d),p+=c,q+=d,e.css({top:q+"px",left:p+"px"}),n(a),!0}function l(a){return!e.hasClass("gridster-item-moving")||e.hasClass("gridster-item-resizing")?!1:(z=A=0,o(a),!0)}function m(a){e.addClass("gridster-item-moving"),g.movingItem=h,g.updateHeight(h.sizeY),f.$apply(function(){g.draggable&&g.draggable.start&&g.draggable.start(a,e,i)})}function n(a){var b=h.row,d=h.col,j=g.draggable&&g.draggable.drag,k=g.draggable.scrollSensitivity,l=g.draggable.scrollSpeed,m=g.pixelsToRows(q),n=g.pixelsToColumns(p),o=g.getItems(m,n,h.sizeX,h.sizeY,h),r=0!==o.length;if(g.swapping===!0&&r){var s=g.getBoundingBox(o),t=s.sizeX===h.sizeX&&s.sizeY===h.sizeY,u=s.row===b,v=s.col===d,w=s.row===m&&s.col===n,x=u||v;if(t&&1===o.length){if(w)g.swapItems(h,o[0]);else if(x)return}else if(s.sizeX<=h.sizeX&&s.sizeY<=h.sizeY&&x)for(var y=h.row<=m?h.row:m+h.sizeY,z=h.col<=n?h.col:n+h.sizeX,A=y-s.row,B=z-s.col,C=0,D=o.length;D>C;++C){var F=o[C],G=g.getItems(F.row+A,F.col+B,F.sizeX,F.sizeY,h);0===G.length&&g.putItem(F,F.row+A,F.col+B)}}g.pushing===!1&&r||(h.row=m,h.col=n),a.pageY-E.body.scrollTop<k?E.body.scrollTop=E.body.scrollTop-l:c.innerHeight-(a.pageY-E.body.scrollTop)<k&&(E.body.scrollTop=E.body.scrollTop+l),a.pageX-E.body.scrollLeft<k?E.body.scrollLeft=E.body.scrollLeft-l:c.innerWidth-(a.pageX-E.body.scrollLeft)<k&&(E.body.scrollLeft=E.body.scrollLeft+l),(j||b!==h.row||d!==h.col)&&f.$apply(function(){j&&g.draggable.drag(a,e,i)})}function o(a){e.removeClass("gridster-item-moving");var b=g.pixelsToRows(q),c=g.pixelsToColumns(p);(g.pushing!==!1||0===g.getItems(b,c,h.sizeX,h.sizeY,h).length)&&(h.row=b,h.col=c),g.movingItem=null,h.setPosition(h.row,h.col),f.$apply(function(){g.draggable&&g.draggable.stop&&g.draggable.stop(a,e,i)})}var p,q,r,s,t,u,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=9999,D=0,E=b[0],F=["select","input","textarea","button"],G=null,H=null,I=[];this.enable=function(){G!==!0&&(G=!0,e.ready(function(){if(G===!0){for(var b=0,c=I.length;c>b;++b)I[b].disable();I=[],g.draggable&&g.draggable.handle?(H=a.element(e[0].querySelectorAll(g.draggable.handle)),0===H.length&&(H=e)):H=e;for(var f=0,h=H.length;h>f;++f)I[f]=new d(H[f],j,k,l),I[f].enable()}}))},this.disable=function(){if(G!==!1){G=!1;for(var a=0,b=I.length;b>a;++a)I[a].disable();I=[]}},this.toggle=function(a){a?this.enable():this.disable()},this.destroy=function(){this.disable()}}return e}]).factory("GridsterResizable",["GridsterTouch",function(b){function c(c,d,e,f,g){function h(h){function i(a){switch(a.which){case 1:break;case 2:case 3:return}return u=e.draggable.enabled,u&&(e.draggable.enabled=!1,d.$broadcast("gridster-draggable-changed",e)),z=a.pageX,A=a.pageY,o=parseInt(c.css("left"),10),p=parseInt(c.css("top"),10),q=c[0].offsetWidth,r=c[0].offsetHeight,s=f.sizeX,t=f.sizeY,j(a),!0}function j(a){c.addClass("gridster-item-moving"),c.addClass("gridster-item-resizing"),e.movingItem=f,f.setElementSizeX(),f.setElementSizeY(),f.setElementPosition(),e.updateHeight(1),d.$apply(function(){e.resizable&&e.resizable.start&&e.resizable.start(a,c,g)})}function k(a){var b=e.curWidth-1;x=a.pageX,y=a.pageY;var d=x-z+B,f=y-A+C;B=C=0,z=x,A=y;var g=f,h=d;return w.indexOf("n")>=0&&(r-g<G()?(f=r-G(),C=g-f):D>p+g&&(f=D-p,C=g-f),p+=f,r-=f),w.indexOf("s")>=0&&(r+g<G()?(f=G()-r,C=g-f):p+r+g>E&&(f=E-p-r,C=g-f),r+=f),w.indexOf("w")>=0&&(q-h<H()?(d=q-H(),B=h-d):F>o+h&&(d=F-o,B=h-d),o+=d,q-=d),w.indexOf("e")>=0&&(q+h<H()?(d=H()-q,B=h-d):o+q+h>b&&(d=b-o-q,B=h-d),q+=d),c.css({top:p+"px",left:o+"px",width:q+"px",height:r+"px"}),m(a),!0}function l(a){return e.draggable.enabled!==u&&(e.draggable.enabled=u,d.$broadcast("gridster-draggable-changed",e)),B=C=0,n(a),!0}function m(a){var b=f.row,i=f.col,j=f.sizeX,k=f.sizeY,l=e.resizable&&e.resizable.resize,m=f.col;-1!==["w","nw","sw"].indexOf(h)&&(m=e.pixelsToColumns(o,!1));var n=f.row;-1!==["n","ne","nw"].indexOf(h)&&(n=e.pixelsToRows(p,!1));var s=f.sizeX;-1===["n","s"].indexOf(h)&&(s=e.pixelsToColumns(q,!0));var t=f.sizeY;-1===["e","w"].indexOf(h)&&(t=e.pixelsToRows(r,!0));var u=n>-1&&m>-1&&s+m<=e.columns&&t+n<=e.maxRows;!u||e.pushing===!1&&0!==e.getItems(n,m,s,t,f).length||(f.row=n,f.col=m,f.sizeX=s,f.sizeY=t);var v=f.row!==b||f.col!==i||f.sizeX!==j||f.sizeY!==k;(l||v)&&d.$apply(function(){l&&e.resizable.resize(a,c,g)})}function n(a){c.removeClass("gridster-item-moving"),c.removeClass("gridster-item-resizing"),e.movingItem=null,f.setPosition(f.row,f.col),f.setSizeY(f.sizeY),f.setSizeX(f.sizeX),d.$apply(function(){e.resizable&&e.resizable.stop&&e.resizable.stop(a,c,g)})}var o,p,q,r,s,t,u,v,w=h,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=9999,F=0,G=function(){return(f.minSizeY?f.minSizeY:1)*e.curRowHeight-e.margins[0]},H=function(){return(f.minSizeX?f.minSizeX:1)*e.curColWidth-e.margins[1]},I=null;this.enable=function(){I||(I=a.element('<div class="gridster-item-resizable-handler handle-'+w+'"></div>'),c.append(I)),v=new b(I[0],i,k,l),v.enable()},this.disable=function(){I&&(I.remove(),I=null),v.disable(),v=void 0},this.destroy=function(){this.disable()}}var i=[],j=e.resizable.handles;"string"==typeof j&&(j=e.resizable.handles.split(","));for(var k=!1,l=0,m=j.length;m>l;l++)i.push(new h(j[l]));this.enable=function(){if(!k){for(var a=0,b=i.length;b>a;a++)i[a].enable();k=!0}},this.disable=function(){if(k){for(var a=0,b=i.length;b>a;a++)i[a].disable();k=!1}},this.toggle=function(a){a?this.enable():this.disable()},this.destroy=function(){for(var a=0,b=i.length;b>a;a++)i[a].destroy()}}return c}]).factory("gridsterDebounce",function(){return function(a,b,c){var d;return function(){var e=this,f=arguments,g=function(){d=null,c||a.apply(e,f)},h=c&&!d;clearTimeout(d),d=setTimeout(g,b),h&&a.apply(e,f)}}}).directive("gridsterItem",["$parse","GridsterDraggable","GridsterResizable","gridsterDebounce",function(a,b,c,d){return{scope:!0,restrict:"EA",controller:"GridsterItemCtrl",controllerAs:"gridsterItem",require:["^gridster","gridsterItem"],link:function(e,f,g,h){function i(){o.setPosition(o.row,o.col),r.row&&r.row.assign&&r.row.assign(e,o.row),r.col&&r.col.assign&&r.col.assign(e,o.col)}function j(){var a=o.setSizeX(o.sizeX,!0);a&&r.sizeX&&r.sizeX.assign&&r.sizeX.assign(e,o.sizeX);var b=o.setSizeY(o.sizeY,!0);b&&r.sizeY&&r.sizeY.assign&&r.sizeY.assign(e,o.sizeY),(a||b)&&(o.gridster.moveOverlappingItems(o),n.layoutChanged(),e.$broadcast("gridster-item-resized",o))}function k(){var a=document.createElement("div"),b={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(var c in b)if(void 0!==a.style[c])return b[c]}var l,m=g.gridsterItem,n=h[0],o=h[1];if(e.gridster=n,m){var p=a(m);l=p(e)||{},!l&&p.assign&&(l={row:o.row,col:o.col,sizeX:o.sizeX,sizeY:o.sizeY,minSizeX:0,minSizeY:0,maxSizeX:null,maxSizeY:null},p.assign(e,l))}else l=g;o.init(f,n),f.addClass("gridster-item");for(var q=["minSizeX","maxSizeX","minSizeY","maxSizeY","sizeX","sizeY","row","col"],r={},s=[],t=function(b){var c;if("string"==typeof l[b])c=l[b];else if("string"==typeof l[b.toLowerCase()])c=l[b.toLowerCase()];else{if(!m)return;c=m+"."+b}s.push('"'+b+'":'+c),r[b]=a(c);var d=r[b](e);"number"==typeof d&&(o[b]=d)},u=0,v=q.length;v>u;++u)t(q[u]);var w="{"+s.join(",")+"}";e.$watchCollection(w,function(a,b){for(var c in a){var d=a[c],e=b[c];e!==d&&(d=parseInt(d,10),isNaN(d)||(o[c]=d))}}),e.$watch(function(){return o.row+","+o.col},i),e.$watch(function(){return o.sizeY+","+o.sizeX+","+o.minSizeX+","+o.maxSizeX+","+o.minSizeY+","+o.maxSizeY},j);var x=new b(f,e,n,o,l),y=new c(f,e,n,o,l),z=function(){y.toggle(!n.isMobile&&n.resizable&&n.resizable.enabled)};z();var A=function(){x.toggle(!n.isMobile&&n.draggable&&n.draggable.enabled)};A(),e.$on("gridster-draggable-changed",A),e.$on("gridster-resizable-changed",z),e.$on("gridster-resized",z),e.$on("gridster-mobile-changed",function(){z(),A()});var B=d(function(){e.$apply(function(){e.$broadcast("gridster-item-transition-end",o)})},50);return f.on(k(),B),e.$broadcast("gridster-item-initialized",o),e.$on("$destroy",function(){try{y.destroy(),x.destroy()}catch(a){}try{n.removeItem(o)}catch(a){}try{o.destroy()}catch(a){}})}}}]).directive("gridsterNoDrag",function(){return{restrict:"A",link:function(a,b){b.addClass("gridster-no-drag")}}})});
.gridster{position:relative;margin:auto;height:0}.gridster>ul{margin:0;list-style:none;padding:0}.gridster-item{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;list-style:none;z-index:2;position:absolute;display:none}.gridster-loaded{-webkit-transition:height .3s;-moz-transition:height .3s;-o-transition:height .3s;transition:height .3s}.gridster-loaded .gridster-item{display:block;position:absolute;-webkit-transition:opacity .3s, left .3s, top .3s, width .3s, height .3s;-moz-transition:opacity .3s, left .3s, top .3s, width .3s, height .3s;-o-transition:opacity .3s, left .3s, top .3s, width .3s, height .3s;transition:opacity .3s, left .3s, top .3s, width .3s, height .3s;-webkit-transition-delay:50ms;-moz-transition-delay:50ms;-o-transition-delay:50ms;transition-delay:50ms}.gridster-loaded .gridster-preview-holder{display:none;z-index:1;position:absolute;background-color:#ddd;border-color:#fff;opacity:0.2}.gridster-loaded .gridster-item.gridster-item-moving,.gridster-loaded .gridster-preview-holder{-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.gridster-mobile{height:auto !important}.gridster-mobile .gridster-item{height:auto;position:static;float:none}.gridster-item.ng-leave.ng-leave-active{opacity:0}.gridster-item.ng-enter{opacity:1}.gridster-item-moving{z-index:3}.gridster-item-resizable-handler{position:absolute;font-size:1px;display:block;z-index:5}.handle-se{cursor:se-resize;width:0;height:0;right:1px;bottom:1px;border-style:solid;border-width:0 0 12px 12px;border-color:transparent}.handle-ne{cursor:ne-resize;width:12px;height:12px;right:1px;top:1px}.handle-nw{cursor:nw-resize;width:12px;height:12px;left:1px;top:1px}.handle-sw{cursor:sw-resize;width:12px;height:12px;left:1px;bottom:1px}.handle-e{cursor:e-resize;width:12px;bottom:0;right:1px;top:0}.handle-s{cursor:s-resize;height:12px;right:0;bottom:1px;left:0}.handle-n{cursor:n-resize;height:12px;right:0;top:1px;left:0}.handle-w{cursor:w-resize;width:12px;left:1px;top:0;bottom:0}.gridster .gridster-item:hover .gridster-box{border:1.5px solid #B3B2B3}.gridster .gridster-item:hover .handle-se{border-color:transparent transparent #ccc}
angular.module('app')

.controller('DashboardCtrl', ['$scope', '$timeout',
	function($scope, $timeout) {
		$scope.gridsterOptions = {
			margins: [20, 20],
			columns: 4,
			draggable: {
				handle: 'h3'
			}
		};

		$scope.dashboards = {
			'1': {
				id: '1',
				name: 'Home',
				widgets: [{
					col: 0,
					row: 0,
					sizeY: 1,
					sizeX: 1,
					name: "Widget 1"
				}, {
					col: 2,
					row: 1,
					sizeY: 1,
					sizeX: 1,
					name: "Widget 2"
				}]
			},
			'2': {
				id: '2',
				name: 'Other',
				widgets: [{
					col: 1,
					row: 1,
					sizeY: 1,
					sizeX: 2,
					name: "Other Widget 1"
				}, {
					col: 1,
					row: 3,
					sizeY: 1,
					sizeX: 1,
					name: "Other Widget 2"
				}]
			}
		};

		$scope.clear = function() {
			$scope.dashboard.widgets = [];
		};

		$scope.addWidget = function() {
			$scope.dashboard.widgets.push({
				name: "New Widget",
				sizeX: 1,
				sizeY: 1
			});
		};

		$scope.$watch('selectedDashboardId', function(newVal, oldVal) {
			if (newVal !== oldVal) {
				$scope.dashboard = $scope.dashboards[newVal];
			} else {
				$scope.dashboard = $scope.dashboards[1];
			}
		});

		// init dashboard
		$scope.selectedDashboardId = '1';

	}
])

.controller('CustomWidgetCtrl', ['$scope', '$modal',
	function($scope, $modal) {

		$scope.remove = function(widget) {
			$scope.dashboard.widgets.splice($scope.dashboard.widgets.indexOf(widget), 1);
		};

		$scope.openSettings = function(widget) {
			$modal.open({
				scope: $scope,
				templateUrl: 'widget_settings.html',
				controller: 'WidgetSettingsCtrl',
				resolve: {
					widget: function() {
						return widget;
					}
				}
			});
		};

	}
])

.controller('WidgetSettingsCtrl', ['$scope', '$timeout', '$rootScope', '$modalInstance', 'widget',
	function($scope, $timeout, $rootScope, $modalInstance, widget) {
		$scope.widget = widget;

		$scope.form = {
			name: widget.name,
			sizeX: widget.sizeX,
			sizeY: widget.sizeY,
			col: widget.col,
			row: widget.row
		};

		$scope.sizeOptions = [{
			id: '1',
			name: '1'
		}, {
			id: '2',
			name: '2'
		}, {
			id: '3',
			name: '3'
		}, {
			id: '4',
			name: '4'
		}];

		$scope.dismiss = function() {
			$modalInstance.dismiss();
		};

		$scope.remove = function() {
			$scope.dashboard.widgets.splice($scope.dashboard.widgets.indexOf(widget), 1);
			$modalInstance.close();
		};

		$scope.submit = function() {
			angular.extend(widget, $scope.form);

			$modalInstance.close(widget);
		};

	}
])

// helper code
.filter('object2Array', function() {
	return function(input) {
		var out = [];
		for (i in input) {
			out.push(input[i]);
		}
		return out;
	}
});
<div class="demo-container">
    <h2>Standard Items</h2>
    <input type="button" ng-click="gridsterOpts.draggable.enabled = !gridsterOpts.draggable.enabled" value="{{gridsterOpts.draggable.enabled ? 'Disable' : 'Enable' }} Draggability" />
    <input type="button" ng-click="gridsterOpts.resizable.enabled = !gridsterOpts.resizable.enabled" value="{{gridsterOpts.resizable.enabled ? 'Disable' : 'Enable' }} Resizability" />
	<input type="button" ng-click="gridsterOpts.floating = !gridsterOpts.floating" value="{{gridsterOpts.floating ? 'Disable' : 'Enable' }} Floating" />
	<input type="button" ng-click="gridsterOpts.pushing = !gridsterOpts.pushing" value="{{gridsterOpts.pushing ? 'Disable' : 'Enable' }} Pushing" />
	<input type="button" ng-click="gridsterOpts.swapping = !gridsterOpts.swapping" value="{{gridsterOpts.swapping ? 'Disable' : 'Enable' }} Swapping" />

	Margins:
	<input type="text" ng-model="gridsterOpts.margins[0]" size="3" />
	x
	<input type="text" ng-model="gridsterOpts.margins[1]" size="3" />

    <p>
        Each item provides its own dimensions and position using the standard fields: { row: row, col: col, sizeX: sizeX, sizeY: sizeY }.
    </p>
    <div gridster="gridsterOpts">
        <ul>
            <li gridster-item="item" ng-repeat="item in standardItems">
                <input type="text" integer ng-model="item.row" size="1" />,
                <input type="text" integer ng-model="item.col" size="1" />
                <br />
                <input type="text" integer ng-model="item.sizeX" size="1" />x
                <input type="text" integer ng-model="item.sizeY" size="1" />
            </li>
        </ul>
    </div>

    <h2>Custom Items</h2>
    <p>
        Each item provides its own dimensions but with custom fields defined using customItemMap: { position: [row, col], size: { x: sizeX, y: sizeY }}
    </p>
    <div gridster="gridsterOpts">
        <ul>
            <li gridster-item="customItemMap" ng-repeat="item in customItems">
                <input type="text" integer ng-model="item.position[0]" size="1" />,
                <input type="text" integer ng-model="item.position[1]" size="1" />
                <br />
                <input type="text" integer ng-model="item.size.x" size="1" />x
                <input type="text" integer ng-model="item.size.y" size="1" />
            </li>
        </ul>
    </div>

    <h2>Custom Items2</h2>
    <p>
        Each item provides its own dimensions but with custom fields indicated using html attributes: row, col, sizex, sizey. Size can also be in the form of data-size-x or data-sizex.
    </p>
    <div gridster="gridsterOpts">
        <ul>
            <li gridster-item row="item.position[0]" col="item.position[1]" size-x="item.size.x" size-y="item.size.y" ng-repeat="item in customItems">
                <input type="text" integer ng-model="item.position[0]" size="1" />,
                <input type="text" integer ng-model="item.position[1]" size="1" />
                <br />
                <input type="text" integer ng-model="item.size.x" size="1" />x
                <input type="text" integer ng-model="item.size.y" size="1" />
            </li>
        </ul>
    </div>

    <h2>Empty Items</h2>
    <p>
        Each item stores the standard options as an object within itself: { grid: {row: row, col: col, sizeX: sizeX, sizeY: sizeY }}
    </p>
    <div gridster="gridsterOpts">
        <ul>
            <li gridster-item="item.grid" ng-repeat="item in emptyItems">
                <input type="text" integer ng-model="item.grid.row" size="1" />,
                <input type="text" integer ng-model="item.grid.col" size="1" />
                <br />
                <input type="text" integer ng-model="item.grid.sizeX" size="1" />x
                <input type="text" integer ng-model="item.grid.sizeY" size="1" />
            </li>
        </ul>
    </div>

    <h2>No Configuration or Binding</h2>
    <p>
        No data binding or configuration provided.
    </p>
    <div gridster>
        <ul>
			<li gridster-item></li>
			<li gridster-item></li>
			<li gridster-item></li>
        </ul>
    </div>
</div>
<div class="page-header">
	<a class="pull-right btn btn-primary" ng-click="addWidget()"><i class="glyphicon glyphicon-plus"></i> Add Widget</a>
	<a class="pull-right btn btn-warning" ng-click="clear()"><i class="glyphicon glyphicon-trash"></i> Clear</a>
	<h1 style="display: inline-block; width: 200px;">Dashboard</h1>
	<select class="form-control" style="width: 150px; margin-bottom: 20px; display:inline-block;" ng-change="changeDashboard()" ng-model="selectedDashboardId" ng-options="d.id as d.name for d in dashboards | object2Array | orderBy:'id'">
	</select>

</div>
<div gridster="gridsterOptions">
	<ul>
		<li gridster-item="widget" ng-repeat="widget in dashboard.widgets">
			<div class="box" ng-controller="CustomWidgetCtrl">
				<div class="box-header">
					<h3>{{ widget.name }}</h3>
					<div class="box-header-btns pull-right">
						<a title="settings" ng-click="openSettings(widget)"><i class="glyphicon glyphicon-cog"></i></a>
						<a title="Remove widget" ng-click="remove(widget)"><i class="glyphicon glyphicon-trash"></i></a>
					</div>
				</div>
				<div class="box-content">
				</div>
			</div>
		</li>
	</ul>
</div>
<div>
    <form name="_form" class="form-horizontal" ng-submit="submit(_form)">
        <div class="modal-header">
            <button type="button" class="close" ng-click="dismiss()" aria-hidden="true">&times;</button>
            <h3>Widget Settings</h3>
        </div>

        <div class="modal-body">
            <div class="form-group" ng-class="{error: _form.name.$error && _form.submitted}">
                <label class="control-label col-lg-3 col-md-3">Name</label>
                <div class="col-lg-9 col-md-9">
                    <input name="name" type="text" ng-model="form.name" class="form-control" />
                </div>
            </div>
            <div class="row">
                <div class="col-lg-6 col-md-6">
                    <div class="form-group" ng-class="{error: _form.sizeX.$error && _form.submitted}">
                        <label class="control-label col-lg-6 col-md-6">Width</label>
                        <div class="col-lg-6 col-md-6">
                            <input name="sizeX" ng-model="form.sizeX" class="form-control" />
                        </div>
                    </div>
                </div>
                <div class="col-lg-6 col-md-6">
                    <div class="form-group">
                        <label class="control-label col-lg-6 col-md-6">Height</label>
                        <div class="col-lg-6 col-md-6">
                            <input name="sizeY" ng-model="form.sizeY" class="form-control" />
                        </div>
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-6 col-md-6">
                    <div class="form-group" ng-class="{error: _form.sizeX.$error && _form.submitted}">
                        <label class="control-label col-lg-6 col-md-6">Column</label>
                        <div class="col-lg-6 col-md-6">
                            <input name="col" ng-model="form.col" class="form-control" />
                        </div>
                    </div>
                </div>
                <div class="col-lg-6 col-md-6">
                    <div class="form-group">
                        <label class="control-label col-lg-6 col-md-6">Row</label>
                        <div class="col-lg-6 col-md-6">
                            <input name="row" ng-model="form.row" class="form-control" />
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="modal-footer">
            <a ng-click="remove()" class="btn btn-danger pull-left" tabindex="-1"><i class="glyphicon glyphicon-trash"></i>Delete</a>
            <a ng-click="dismiss()" class="btn btn-default" tabindex="-1"><i class="glyphicon glyphicon-remove"></i>Cancel</a>
            <button type="submit" class="btn btn-primary btn-lg"><i class="glyphicon glyphicon-ok"></i>Save</button>
        </div>
    </form>
</div>
body {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    background: #004756;
    color: #fff;
}
.gridster .gridster-item {
    -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
    -moz-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
    color: #004756;
    background: #ffffff;
    padding: 10px;
}

.controls {
    margin-bottom: 20px;
}
.page-header {
    margin-top: 20px;
}
ul {
    list-style: none;
}
.box {
    height: 100%;
    border: 1px solid #ccc;
    background-color: #fff;
}
.box-header {
    background-color: #eee;
    padding: 0 30px 0 10px;
    border-bottom: 1px solid #ccc;
    cursor: move;
    position: relative;
}
.box-header h3 {
    margin-top: 10px;
    display: inline-block;
}
.box-content {
    padding: 10px;
}
.box-header-btns {
    top: 15px;
    right: 10px;
    cursor: pointer;
    position: absolute;
}
a {
    color: #ccc;
}
form {
    margin-bottom: 0;
}
.gridster {
    border: 1px solid #ccc;
}