|
@@ -1,5 +1,6 @@
|
1
|
1
|
var previousPoint = null;
|
2
|
2
|
var state = {};
|
|
3
|
+var oldState = {};
|
3
|
4
|
var plots = {};
|
4
|
5
|
|
5
|
6
|
// -----------------------------------------------------------------------------
|
|
@@ -131,11 +132,19 @@ function getDataForRange(start, end) {
|
131
|
132
|
*
|
132
|
133
|
* @param newState The new properties to add to the state
|
133
|
134
|
* @param invalidatedState An array of state keys to remove
|
|
135
|
+ * @param invalidatedSubState An map of state subkeys to remove
|
134
|
136
|
*/
|
135
|
|
-function setState(newState, invalidatedState) {
|
|
137
|
+function setState(newState, invalidatedState, invalidatedSubState) {
|
|
138
|
+ oldState = $.extend(true, {}, state);
|
|
139
|
+
|
136
|
140
|
$.extend(true, state, newState);
|
137
|
141
|
|
138
|
|
- $.each(invalidatedState, function(_, x) { delete state[x]; });
|
|
142
|
+ invalidatedState && $.each(invalidatedState, function(_, x) { delete state[x]; });
|
|
143
|
+ invalidatedSubState && $.each(invalidatedSubState, function(key, values) {
|
|
144
|
+ $.each(values, function() {
|
|
145
|
+ delete state[key][this];
|
|
146
|
+ });
|
|
147
|
+ });
|
139
|
148
|
|
140
|
149
|
$.history.load(JSON.stringify(state));
|
141
|
150
|
}
|
|
@@ -147,8 +156,6 @@ function setState(newState, invalidatedState) {
|
147
|
156
|
* @param {string} hash The new page fragment
|
148
|
157
|
*/
|
149
|
158
|
function handleStateChange(hash) {
|
150
|
|
- var oldState = $.extend({}, state);
|
151
|
|
-
|
152
|
159
|
try {
|
153
|
160
|
state = JSON.parse(hash);
|
154
|
161
|
} catch (ex) {
|
|
@@ -156,8 +163,13 @@ function handleStateChange(hash) {
|
156
|
163
|
}
|
157
|
164
|
|
158
|
165
|
if (state.start && state.end && state.type) {
|
159
|
|
- // Update the transaction table and pie charts
|
160
|
|
- showSelectedMonths(state.start, state.end, state.type == 'income', state.type == 'expenses', state.categoryFilter, state.expanded);
|
|
166
|
+ if (state.start == oldState.start && state.end == oldState.end && state.type == oldState.type && state.categoryFilter == oldState.categoryFilter) {
|
|
167
|
+ // Just show/hide nodes as required
|
|
168
|
+ ensureExpanded(oldState.expanded, state.expanded);
|
|
169
|
+ } else {
|
|
170
|
+ // Update the transaction table and pie charts
|
|
171
|
+ showSelectedMonths(state.start, state.end, state.type == 'income', state.type == 'expenses', state.categoryFilter, state.expanded);
|
|
172
|
+ }
|
161
|
173
|
|
162
|
174
|
// If the selection has changed, update the visual representation
|
163
|
175
|
(oldState.start != state.start || oldState.end != state.end) && plots.history.setSelection({ xaxis: { from: state.start, to: state.end }});
|
|
@@ -205,22 +217,51 @@ function expandLinkHandler(event) {
|
205
|
217
|
var text = $(this).text();
|
206
|
218
|
var expanded = text.substr(0, 2) == '(+';
|
207
|
219
|
|
208
|
|
- if (!state.expanded) {
|
209
|
|
- state.expanded = {};
|
210
|
|
- }
|
211
|
|
-
|
212
|
220
|
if (expanded) {
|
213
|
|
- state.expanded[event.data.id] = true;
|
214
|
|
- setState({}, []);
|
|
221
|
+ var newExpanded = {};
|
|
222
|
+ newExpanded[event.data.id] = true;
|
|
223
|
+ setState({expanded: newExpanded}, []);
|
215
|
224
|
} else {
|
216
|
|
- delete state.expanded[event.data.id];
|
217
|
|
- setState({}, []);
|
|
225
|
+ setState({}, [], {expanded: [event.data.id]});
|
218
|
226
|
}
|
219
|
227
|
|
220
|
228
|
colourTableRows($('#historytable'));
|
221
|
229
|
return false;
|
222
|
230
|
}
|
223
|
231
|
|
|
232
|
+/**
|
|
233
|
+ * Ensures that the desired elements are appropriately expanded or collapsed.
|
|
234
|
+ *
|
|
235
|
+ * @param oldList A map containing keys for each entry that was previously expanded
|
|
236
|
+ * @param newList A map containing keys for each entry that should now be expanded
|
|
237
|
+ */
|
|
238
|
+function ensureExpanded(oldList, newList) {
|
|
239
|
+ oldList = oldList || {};
|
|
240
|
+ newList = newList || {};
|
|
241
|
+
|
|
242
|
+ $.each(newList, function(id, _) {
|
|
243
|
+ if (!oldList[id]) {
|
|
244
|
+ // This entry needs to be expanded
|
|
245
|
+ $('.hidden' + id).show();
|
|
246
|
+ var handle = $('#collapseHandle' + id);
|
|
247
|
+ handle.text(handle.text().replace(/\+/, '-'));
|
|
248
|
+ handle.parents('tr').find('td.amount').text(handle.data('single'));
|
|
249
|
+ }
|
|
250
|
+ });
|
|
251
|
+
|
|
252
|
+ $.each(oldList, function(id, _) {
|
|
253
|
+ if (!newList[id]) {
|
|
254
|
+ // This entry needs to be collapsed
|
|
255
|
+ $('.hidden' + id).hide();
|
|
256
|
+ var handle = $('#collapseHandle' + id);
|
|
257
|
+ handle.text(handle.text().replace(/\-/, '+'));
|
|
258
|
+ handle.parents('tr').find('td.amount').text(handle.data('total'));
|
|
259
|
+ }
|
|
260
|
+ });
|
|
261
|
+
|
|
262
|
+ colourTableRows($('#historytable'));
|
|
263
|
+}
|
|
264
|
+
|
224
|
265
|
/**
|
225
|
266
|
* Determines if the two transactions should be merged together. That is,
|
226
|
267
|
* whether the transactions have an identical description, type and category.
|
|
@@ -280,15 +321,16 @@ function showSelectedMonths(start, end, incoming, outgoing, categoryFilter, expa
|
280
|
321
|
var lastEntry = {};
|
281
|
322
|
var id = 0;
|
282
|
323
|
var included = getDataForRange(startDate, endDate);
|
|
324
|
+ var filtered = $.grep(included, function(x) {
|
|
325
|
+ var category = x.Category ? x.Category : 'Unsorted';
|
|
326
|
+ return (incoming == x.Amount > 0) && (!categoryFilter || categoryFilter == category);
|
|
327
|
+ });
|
283
|
328
|
|
284
|
|
- $.each(included, function() {
|
|
329
|
+ $.each(filtered, function() {
|
285
|
330
|
trans = this;
|
286
|
|
- if (incoming != trans.Amount > 0) { return; }
|
287
|
331
|
|
288
|
332
|
var category = trans.Category ? trans.Category : 'Unsorted';
|
289
|
333
|
|
290
|
|
- if (categoryFilter && categoryFilter != category) { return; }
|
291
|
|
-
|
292
|
334
|
var tr = $('<tr/>').addClass('data').addClass('category' + category.replace(/[^a-zA-Z]*/g, '')).appendTo(table);
|
293
|
335
|
|
294
|
336
|
if (shouldMerge(lastEntry, trans)) {
|
|
@@ -300,11 +342,13 @@ function showSelectedMonths(start, end, incoming, outgoing, categoryFilter, expa
|
300
|
342
|
lastEntry.id = ++id;
|
301
|
343
|
lastEntry.count = 1;
|
302
|
344
|
var prefix = '(' + (expanded[lastEntry.id] ? '-' : '+');
|
303
|
|
- var a = $('<span>').addClass('link').text(prefix + '1)').appendTo($('td.desc', lastEntry.tr).append(' '));
|
304
|
|
- a.bind('click', { id: lastEntry.id, tr: lastEntry.tr }, expandLinkHandler);
|
|
345
|
+ var a = $('<span>').addClass('link').text(prefix + '1)').attr('id', 'collapseHandle' + lastEntry.id).appendTo($('td.desc', lastEntry.tr).append(' '));
|
|
346
|
+ a.bind('click', { id: lastEntry.id }, expandLinkHandler);
|
|
347
|
+ a.data('single', lastEntry.Amount);
|
305
|
348
|
}
|
306
|
349
|
|
307
|
350
|
lastEntry.Amount = Math.round(100 * (lastEntry.Amount + trans.Amount)) / 100;
|
|
351
|
+ $('#collapseHandle' + lastEntry.id).data('total', lastEntry.Amount);
|
308
|
352
|
|
309
|
353
|
!expanded[lastEntry.id] && tr.hide() && $('.amount', lastEntry.tr).text(lastEntry.Amount);
|
310
|
354
|
|
|
@@ -425,7 +469,7 @@ $(function() {
|
425
|
469
|
var date = new Date(x);
|
426
|
470
|
|
427
|
471
|
var seriesTitles = ["Money in", "Money out", "Balance change"];
|
428
|
|
- showTooltip(item.pageX, item.pageY, (seriesTitles[item.seriesIndex]) + " during " + months[date.getMonth()] + " " + date.getFullYear() + " = " + y);
|
|
472
|
+ showTooltip(item.pageX, item.pageY, (seriesTitles[item.seriesIndex]) + " during " + date.getDisplayMonth() + " " + date.getFullYear() + " = " + y);
|
429
|
473
|
}
|
430
|
474
|
} else {
|
431
|
475
|
$("#tooltip").remove();
|