Feature: Keyboard navigation in ledger with Remove and Undo.
This commit is contained in:
parent
4e85d97e47
commit
248a841695
brewman
static
views/reports
@ -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>
|
||||
|
105
brewman/static/js/jquery.scrolltoview.js
Normal file
105
brewman/static/js/jquery.scrolltoview.js
Normal 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);
|
@ -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>
|
||||
|
10
brewman/static/scripts/angular_directive.js
vendored
10
brewman/static/scripts/angular_directive.js
vendored
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user