<!DOCTYPE html>
<html>

<head>

  <link data-require="bootstrap-css@*" data-semver="3.0.3" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" />
  <link rel="stylesheet" href="style.css" />
</head>

<body ng-app="gridApp">
  <div class="container">
    <h1>Excel Sheet in AngularJS!</h1>
    <p class="alert alert-info">Right click on cells to avail actions</p>
    <div ng-controller="GridCtrl" class="spreadsheet-container">
      <table class="spreadsheet table table-condensed table-striped table-bordered">
        <thead>
          <tr class="row-header">
            <th class="col-sno"></th>
            <td class="col text-center" ng-repeat="col in records[0]">
              <span>{{$index}}</span>
            </td>
          </tr>
        </thead>
        <tbody>
          <tr ng-repeat="record in records">
            <td class="col-sno text-center">{{$index}}</td>
            <td class="col" ng-repeat="col in record" ng-right-click="openContextMenu($event, $parent.$index, $index)" ng-click="openContextMenu($event, $parent.$index, $index)">
              <input class="editable-cell" ng-model="col.value" />
            </td>
          </tr>
        </tbody>
      </table>
       <div class="context-menu" ng-show="isContextMenuVisible" ng-style="contextMenuStyle">
        <ul class="dropdown-menu">
          <li>
            <a tabindex="-1" ng-click="addRow()">Add Row</a>
          </li>
          <li>
            <a tabindex="-1" ng-click="removeRow()">Remove Row</a>
          </li>
          <li>
            <a tabindex="-1" ng-click="addColumn()">Add Column</a>
          </li>
          <li>
            <a tabindex="-1" ng-click="removeColumn()">Remove Column</a>
          </li>
        </ul>
      </div>
    </div>
    </div>
  </div>
  <script data-require="jquery@*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
  <script data-require="angular.js@*" data-semver="1.2.11" src="http://code.angularjs.org/1.2.11/angular.js"></script>
  <script src="script.js"></script>
</body>

</html>
// Code goes here
'use strict';

var gridApp = angular.module('gridApp', []);
gridApp.directive('ngRightClick', function($parse) {
  return function(scope, element, attrs) {
    var fn = $parse(attrs.ngRightClick);
    element.bind('contextmenu', function(event) {
      scope.$apply(function() {
        event.preventDefault();
        fn(scope, {
          $event: event
        });
      });
    });
  };
});

gridApp.controller('GridCtrl', function($scope, $document, $rootScope) {
  var hideContextMenu = function() {
    $scope.isContextMenuVisible = false;
    if (!$rootScope.$$phase) {
      $rootScope.$apply();
    }
  };
  $scope.numRows = 0;
  $scope.numColumns = 0;

  $scope.isContextMenuVisible = false;
  $scope.contextmenuRowIndex = -1;
  $scope.contextmenuColumnIndex = -1
  $scope.openContextMenu = function($event, rowIndex, columnIndex) {
    $event.preventDefault();
    
    if ($event.button === 0) {
      $scope.isContextMenuVisible = false;
      return;
    }

    $scope.contextmenuRowIndex = rowIndex;
    $scope.contextmenuColumnIndex = columnIndex;
    $scope.contextMenuStyle = {
      top: $event.clientY + 'px',
      left: $event.clientX + 'px'
    };
    $scope.isContextMenuVisible = true;
  };
  $scope.addRow = function() {
    var i,
      record,
      cell,
      index = $scope.contextmenuRowIndex;

    record = [];
    for (i = 0; i < $scope.numColumns; i++) {
      cell = {
        value: 'New Cell'
      }
      record.push(cell);
    }

    $scope.records.splice(index, 0, record);
    $scope.isContextMenuVisible = false;
    $scope.numRows = $scope.records.length;
  };
  $scope.removeRow = function() {
    var index = $scope.contextmenuRowIndex;
    $scope.records.splice(index, 1);
    $scope.isContextMenuVisible = false;
    $scope.numRows = $scope.records.length;
  };
  $scope.addColumn = function() {
    var i, record;
    for(i = 0; i < $scope.records.length; i++) {
      record = $scope.records[i];
      record.splice($scope.contextmenuColumnIndex, 0, {value: 'New Col'});
    }
    
    $scope.numColumns = record.length;
  };
  $scope.removeColumn = function() {
    var i, record;
    for(i = 0; i < $scope.records.length; i++) {
      record = $scope.records[i];
      record.splice($scope.contextmenuColumnIndex, 1);
    }
    
    $scope.numColumns = record.length;
  };

  $document.bind('click', function($evt) {
    var target = angular.element($evt.target).closest('table');
    if (target.length === 0) {
      hideContextMenu();
    }
  });

  $scope.init = function() {
    var i, j, column, cell;
    var records = [],
      record;
    $scope.numRows = 10;
    $scope.numColumns = 20;
    for (i = 0; i < $scope.numRows; i++) {
      record = [];
      for (j = 0; j < $scope.numColumns; j++) {
        cell = {
          value: ''
        }
        record.push(cell);
      }
      records.push(record);
    }
    $scope.records = records;
    
  }
  $scope.init();

});
/* Styles go here */

.editable-cell {
  border: none;
  background-color: inherit;
}
.container {
  position:relative;
}
.context-menu {
  position: absolute;
}
.context-menu .dropdown-menu {
  display:block;
  position:static;
}

input.editable-cell{
  padding-left: 5px;
  width: 100%;
  height: 100%;
}
input.editable-cell:focus {
  outline: 1px solid #777;
}
.spreadsheet-container {
  width: 100%;
  height: 100%;
  overflow: scroll;
}
.spreadsheet.table{
  
  width: auto;
  height: auto;
}
.spreadsheet th.col, .spreadsheet td.col{
  padding: 0;
  min-width: 90px;
  width: 120px;
}
.spreadsheet .col-sno{
  min-width: 30px;
  background-color: #EEE;
}
.spreadsheet.table .col-sno{
  width: 20px;
  background-color: #EEE;
}
.spreadsheet.table .row-header{
  background-color: #EEE;
}