summaryrefslogtreecommitdiff
path: root/kosten/static/js/kosten.js
diff options
context:
space:
mode:
Diffstat (limited to 'kosten/static/js/kosten.js')
-rw-r--r--kosten/static/js/kosten.js280
1 files changed, 280 insertions, 0 deletions
diff --git a/kosten/static/js/kosten.js b/kosten/static/js/kosten.js
new file mode 100644
index 0000000..3821283
--- /dev/null
+++ b/kosten/static/js/kosten.js
@@ -0,0 +1,280 @@
+"use strict";
+
+{
+
+jQuery.fn.extend({
+ copy: function(){
+ return this.clone().removeAttr('id class');
+ }
+ });
+
+String.prototype.splitAt = function(pos){
+ return [this.slice(0, pos), this.slice(pos)];
+};
+
+Date.prototype.format = function(){
+ return $.datepicker.formatDate('dd.mm.yy', this);
+};
+
+let jq = (f) => () => $(f);
+
+// Call this to localize HighCharts
+let setLang = function(){
+ Highcharts.setOptions({
+ colors: ['#2f7ed8', '#0d233a', '#8bbc21', '#910000', '#1aadce', '#492970', '#f28f43', '#77a1e5', '#c42525', '#a6c96a'],
+ lang: {
+ months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
+ shortMonths: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],
+ weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
+ rangeSelectorFrom: 'von',
+ rangeSelectorTo: 'bis',
+ rangeSelectorZoom: null,
+ numericSymbols: null
+ }
+ });
+};
+
+let extendDate = function(input) {
+ const re = /^([12][0-9]|3[01]|0?[1-9])(?:(0?[1-9]|1[0-2])((?:20)?[0-9][0-9])?)?$/;
+ let match, day, month, year;
+
+ if (match = re.exec(input.val())) {
+ const now = new Date();
+ [ , day, month, year] = match;
+
+ if (year == null) year = now.getFullYear();
+ if (month == null) month = now.getMonth() + 1;
+
+ if (year <= 99) year = "20" + year;
+
+ const date = new Date(year, month - 1, day).format();
+
+ input.val(date);
+ }
+};
+
+let searchController = function() {
+ $('form.search').hide();
+ $('li.search').click(() => {
+ const search = $('form.search');
+ search.toggle();
+ if (search.is(':visible')) $('input.search').focus();
+ });
+
+ $('input.search').focusout(() => $('form.search').hide());
+};
+
+$(searchController);
+
+var showJS = jq(() => {
+ setLang();
+
+ $(".detail .heading").click(function() {
+ $(this).closest('.detail').children('.mark:first').click();
+ });
+
+ $(".detail > .mark").click(function() {
+ if (this.src.indexOf('closed') !== -1) {
+ this.src = this.src.replace('closed', 'open');
+ } else {
+ this.src = this.src.replace('open', 'closed');
+ }
+ $(this).nextAll('.details:first').toggle();
+ });
+
+ $('.details').hide();
+
+ // draw the pies
+ $('.pie').each(function() {
+ const pie = $(this);
+ const piedata = Object.entries(pie.data('pie')).map(([key, value]) => (
+ {
+ name: value > 0 ? key : '',
+ y: value,
+ visible: value > 0
+ }));
+
+ pie.highcharts({
+ title: {
+ text: null
+ },
+ tooltip: {
+ hideDelay: 200,
+ formatter: function() {
+ return `${this.key}: <b>${this.y.toFixed(2)}€</b> / ${this.percentage.toFixed(2)}%`;
+ }
+ },
+ chart: {
+ backgroundColor: null,
+ plotBorderWidth: null,
+ plotShadow: false,
+ spacingTop: 0
+ },
+ credits: {
+ enabled: false
+ },
+ series: [{
+ type: 'pie',
+ size: '70%',
+ states: {
+ hover: {
+ halo: null
+ }
+ },
+ allowPointSelect: true,
+ dataLabels: {
+ color: pie.css('color'),
+ distance: 20
+ },
+ data: piedata
+ }]
+ });
+ });
+});
+
+var statJS = jq(() => {
+ setLang();
+
+ const df = Highcharts.dateFormat;
+ const month = 30 * 24 * 60 * 60 * 1000;
+
+ const constDialog = function() {
+ const time = this.x;
+
+ $.get(df('/stats/_const/%Y/%m', time),
+ data => $(data).dialog({ title: df('%B %Y', time) })
+ );
+ };
+
+ $('.stats').each(function (){
+ const stats = $(this);
+ stats.highcharts('StockChart', {
+ credits: {
+ enabled: false
+ },
+ rangeSelector: {
+ buttons: [],
+ inputDateFormat: "%b %Y",
+ inputEditDateFormat: "%m.%Y",
+ inputDateParser: value => {
+ value = value.split(/\./);
+ return Date.UTC(
+ value[1], // year
+ value[0] - 1, // month ... 0-based -.-
+ 1, // day
+ 0, 0, 0, 0 // time
+ );
+ }
+ },
+ plotOptions: {
+ series: {
+ stacking: 'normal',
+ marker: {
+ enabled: false,
+ radius: 2
+ }
+ }
+ },
+ chart: {
+ events: {
+ click: function() {
+ for (let point of this.series[0].data) {
+ if (point.state) {
+ // constDialog is used as a normal callback later on, so has to use 'this'
+ constDialog.apply(point);
+ break;
+ }
+ }
+ }
+ }
+ },
+ xAxis: {
+ minTickInterval: month,
+ minRange: month
+ },
+ yAxis: {
+ reversedStacks: false,
+ labels: {
+ x: 5,
+ align: 'left'
+ }
+ },
+ series: [
+ {
+ data: stats.data('consts'),
+ step: 'left',
+ name: 'Konstant',
+ point: {
+ events: {
+ click: constDialog
+ }
+ }
+ }, {
+ data: stats.data('expenses'),
+ name: 'Variabel',
+ step: 'left'
+ }
+ ],
+ tooltip: {
+ formatter: function(){
+ const header = `<span style="font-size: 10px">${df('%B %Y', this.x)}</span><br/>`;
+ const body = this.points.map(p => `${p.series.name}: <b>${p.point.y} €</b><br/>`).join('');
+ const footer = `<strong>Summe: ${this.points[0].total}</strong>`;
+ return header + body + footer;
+ }
+ }
+ });
+ });
+});
+
+var catsJS = jq(() => {
+ let counter = 0;
+ const addImg = $('img#add');
+ const newInput = $('input#new');
+ const newImage = newName => {
+ const copy = addImg.copy();
+ copy.attr('src', function() {
+ return this.src.replace('add', newName);
+ });
+ return copy;
+ };
+
+ $("li > span").click(function() {
+ const span = $(this);
+ const input = span.next();
+ const img = newImage('undo');
+
+ img.click(function() {
+ $(this).remove();
+ input.val(span.text());
+ input.fadeOut('slow', () => span.toggle() );
+ });
+
+ span.toggle();
+ input.fadeIn('slow', () => img.insertAfter(input));
+ });
+
+ addImg.click(() => {
+ const img = newImage('minus');
+ img.click(function() {
+ $(this).parent().fadeOut('slow', function() {
+ $(this).remove();
+ });
+ });
+
+ const input = newInput.copy();
+ console.log(input.focus);
+ input
+ .attr('name', function(){ return this.name + counter; })
+ .removeAttr('style')
+ .wrap("<li />")
+ .parent()
+ .append(img)
+ .hide()
+ .insertBefore(addImg.parent())
+ .fadeIn('slow', () => input.focus() );
+
+ counter++;
+ });
+});
+}