Feature: Keyboard navigation in ledger with Remove and Undo.

This commit is contained in:
Amritanshu 2014-06-04 16:02:33 +05:30
parent 4e85d97e47
commit 248a841695
6 changed files with 186 additions and 23 deletions

View File

@ -25,8 +25,9 @@
}
</style>
<!-- <script src="/js/mousetrap.min.js"></script> -->
<script src="/js/mousetrap.min.js"></script>
<script src="/js/jquery-2.1.0.min.js"></script>
<script src="/js/jquery.scrolltoview.js"></script>
<script src="/js/lodash.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/ace/ace.js"></script>

View File

@ -0,0 +1,105 @@
/*!
* jQuery scrollintoview() plugin and :scrollable selector filter
*
* Version 1.8 (14 Jul 2011)
* Requires jQuery 1.4 or newer
*
* Copyright (c) 2011 Robert Koritnik
* Licensed under the terms of the MIT license
* http://www.opensource.org/licenses/mit-license.php
*/
(function ($) {
var settings = {
topBar: 51 // hack for brewman with bootstrap v3.1.1
};
var rootrx = /^(?:html)$/i;
// gets border dimensions
var borders = function (domElement, styles) {
styles = styles || (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(domElement, null) : domElement.currentStyle);
var px = document.defaultView && document.defaultView.getComputedStyle ? true : false;
var b = {
top: (parseFloat(px ? styles.borderTopWidth : $.css(domElement, "borderTopWidth")) || 0),
left: (parseFloat(px ? styles.borderLeftWidth : $.css(domElement, "borderLeftWidth")) || 0),
bottom: (parseFloat(px ? styles.borderBottomWidth : $.css(domElement, "borderBottomWidth")) || 0),
right: (parseFloat(px ? styles.borderRightWidth : $.css(domElement, "borderRightWidth")) || 0)
};
return {
top: b.top,
left: b.left,
bottom: b.bottom,
right: b.right,
vertical: b.top + b.bottom,
horizontal: b.left + b.right
};
};
var dimensions = function ($element) {
var win = $(window);
var isRoot = rootrx.test($element[0].nodeName);
return {
border: isRoot ? { top: 0, left: 0, bottom: 0, right: 0} : borders($element[0]),
scroll: {
top: (isRoot ? win : $element).scrollTop(),
left: (isRoot ? win : $element).scrollLeft()
},
scrollbar: {
right: isRoot ? 0 : $element.innerWidth() - $element[0].clientWidth,
bottom: isRoot ? 0 : $element.innerHeight() - $element[0].clientHeight
},
rect: (function () {
var r = $element[0].getBoundingClientRect();
return {
top: isRoot ? 0 : r.top,
left: isRoot ? 0 : r.left,
bottom: isRoot ? $element[0].clientHeight : r.bottom,
right: isRoot ? $element[0].clientWidth : r.right
};
})()
};
};
$.fn.extend({
scrollintoview: function (options) {
/// <summary>Scrolls the first element in the set into view by scrolling its closest scrollable parent.</summary>
/// <param name="options" type="Object">Additional options that can configure scrolling:
/// </param>
/// <return type="jQuery">Returns the same jQuery set that this function was run on.</return>
options = $.extend({}, settings, options);
var el = this.eq(0);
var scroller = $("html,body");
// check if there's anything to scroll in the first place
var dim = {
e: dimensions(el),
s: dimensions(scroller)
};
var rel = {
top: dim.e.rect.top,
bottom: dim.s.rect.bottom - dim.s.scrollbar.bottom - dim.e.rect.bottom
};
var scrollTop = null;
// scroll
if (rel.top < options.topBar) {
scrollTop = dim.s.scroll.top + rel.top - options.topBar;
}
else if (rel.top > 0 && rel.bottom < 0) {
scrollTop = dim.s.scroll.top + Math.min(rel.top, -rel.bottom);
}
// scroll if needed
if (scrollTop !== null) {
scroller.scrollTop(scrollTop);
}
// return set back
return this;
}
});
})(jQuery);

View File

@ -38,7 +38,7 @@
</div>
</div>
</div>
<table id="gvGrid" class="table table-condensed table-bordered table-striped">
<table id="gvGrid" class="table table-condensed table-bordered table-striped" keypress="shortcuts">
<thead>
<tr>
<th>Date</th>
@ -51,7 +51,7 @@
</tr>
</thead>
<tbody>
<tr ng-repeat="item in info.Body" ng-class="{danger:!item.Posted, warning:$index==selected}"
<tr id="{{$index}}" ng-repeat="item in display.Body" ng-class="{danger:!item.Posted, warning:$index==selected}"
ng-click="setSelected($index)">
<td class="no-wrap">{{item.Date}}</td>
<td><a href="{{item.Url}}">{{item.Name}}</a></td>
@ -64,13 +64,13 @@
</tbody>
<tfoot>
<tr>
<td class="no-wrap">{{info.Footer.Date}}</td>
<td>{{info.Footer.Name}}</td>
<td>{{info.Footer.Type}}</td>
<td>{{info.Footer.Narration}}</td>
<td class="text-right no-wrap">{{info.Footer.Debit | currency}}</td>
<td class="text-right no-wrap">{{info.Footer.Credit | currency}}</td>
<td class="text-right no-wrap">{{info.Footer.Running | accounting}}</td>
<td class="no-wrap">{{display.Footer.Date}}</td>
<td>{{display.Footer.Name}}</td>
<td>{{display.Footer.Type}}</td>
<td>{{display.Footer.Narration}}</td>
<td class="text-right no-wrap">{{display.Footer.Debit | currency}}</td>
<td class="text-right no-wrap">{{display.Footer.Credit | currency}}</td>
<td class="text-right no-wrap">{{display.Footer.Running | accounting}}</td>
</tr>
</tfoot>
</table>

View File

@ -125,13 +125,15 @@ overlord_directive.directive('keypress', [function () {
var attribute = scope.$eval(attrs.keypress || '{}');
for (var k in attribute) {
(function (k) {
Mousetrap.bind(k, function () {
return attribute[k](scope, element);
});
Mousetrap.bind(k, attribute[k]);
})(k);
}
element.on('$destroy', function () {
$interval.cancel(timeoutId);
for (var k in attribute) {
(function (k) {
Mousetrap.unbind(k);
})(k);
}
});
};

View File

@ -2,6 +2,7 @@
var LedgerCtrl = ['$scope', '$routeParams', '$location', 'dateFilter', 'ledger', 'Ledger', 'Account', function ($scope, $routeParams, $location, dateFilter, ledger, Ledger, Account) {
$scope.info = ledger;
$scope.hidden = [];
$scope.show = function () {
var id = $scope.info.Ledger.LedgerID;
var start_date = angular.isDate($scope.info.StartDate) ? dateFilter($scope.info.StartDate, 'dd-MMM-yyyy') : $scope.info.StartDate;
@ -14,6 +15,7 @@ var LedgerCtrl = ['$scope', '$routeParams', '$location', 'dateFilter', 'ledger',
$location.path('/Ledger/' + id).search('StartDate', start_date).search('FinishDate', finish_date);
}
};
$scope.downloadTable = function () {
var table = $('#gvGrid'),
html = table.clone().wrap('<div></div>').parent().html();
@ -32,32 +34,85 @@ var LedgerCtrl = ['$scope', '$routeParams', '$location', 'dateFilter', 'ledger',
$scope.selected = index;
};
$scope.$watch('hidden', function () {
$scope.display = doFilter($scope.info, $scope.hidden);
}, true);
var doFilter = function (input, hidden) {
var ledger = angular.copy(input),
data = ledger.Body,
footer = ledger.Footer,
debit = 0, credit = 0, running = 0;
if (hidden.length !== 0) {
data = _.filter(data, function (item) {
return !_.any(hidden, function (hi) {
if (!item.hasOwnProperty('Url') && !hi.hasOwnProperty('Url')) {
return true;
} else if (item.hasOwnProperty('Url') !== hi.hasOwnProperty('Url')) {
return false;
}
return item.Url === hi.Url;
});
});
}
_.forEach(data, function (item) {
debit += item.Debit;
credit += item.Credit;
running = debit - credit;
item.Running = running;
});
footer.Debit = debit;
footer.Credit = credit;
footer.Running = running;
return {Body: data, Footer: footer};
};
$scope.shortcuts = {
'up': function () {
'up': function (e) {
if ($scope.selected > 0) {
$scope.$apply(function () {
$scope.selected = $scope.selected -= 1;
});
$("#" + $scope.selected).scrollintoview({duration: 'fast'});
e.preventDefault();
}
},
'down': function () {
'down': function (e) {
if ($scope.selected < $scope.info.Body.length - 1) {
$scope.$apply(function () {
$scope.selected = $scope.selected += 1;
});
$("#" + $scope.selected).scrollintoview({duration: 'fast'});
e.preventDefault();
}
},
'alt+r': function () {
console.log('alt+r');
'alt+r': function (e) {
if ($scope.selected > -1) {
$scope.$apply(function () {
var max = $scope.display.Body.length;
$scope.hidden.push(angular.copy($scope.display.Body[$scope.selected]));
if ($scope.selected === max -1) {
$scope.selected = max - 2;
}
});
}
e.preventDefault();
},
'enter': function () {
'enter': function (e) {
var path = $scope.info.Body[$scope.selected].Url.replace(/^(?:\/\/|[^\/]+)*/, "");
$scope.$apply(function () {
$location.path(path).search('StartDate', null).search('FinishDate', null);
});
},
'alt+u': function () {
console.log('alt+u');
'alt+u': function (e) {
if ($scope.hidden.length !== 0) {
$scope.$apply(function () {
$scope.hidden.pop();
});
}
e.preventDefault();
}
};

View File

@ -71,11 +71,11 @@ def build_report(request, info):
if journal.debit == 1:
debit = journal.amount
total_debit += journal.amount
credit = ""
credit = 0
else:
credit = journal.amount
total_credit += journal.amount
debit = ""
debit = 0
for journal in voucher.journals:
if journal.debit != journal_debit:
name += "{0} / ".format(journal.ledger.name)