├── README.md ├── fontello ├── font │ ├── nsvb-symbol.eot │ ├── nsvb-symbol.ttf │ ├── nsvb-symbol.woff │ ├── nsvb-symbol.woff2 │ └── nsvb-symbol.svg ├── LICENSE.txt ├── config.json ├── css │ ├── animation.css │ └── nsvb-symbol.css └── README.txt ├── fonts └── gudea │ ├── gudea-v8-latin-700.woff │ ├── gudea-v8-latin-700.woff2 │ ├── gudea-v8-latin-italic.woff │ ├── gudea-v8-latin-italic.woff2 │ ├── gudea-v8-latin-regular.woff │ ├── gudea-v8-latin-regular.woff2 │ └── LICENSE ├── .gitignore ├── api ├── get_sum_months.php ├── get_accounts.php ├── get_overview_year.php ├── get_overview_month.php ├── get_categories.php ├── set_account.php ├── get_overview_year_category.php ├── restore.php ├── delete.php ├── get_trashed.php ├── add.php ├── search.php ├── edit.php └── get_month.php ├── generatehash.php ├── js ├── de.js └── moment.min.js ├── login.js ├── preload.js ├── api.php ├── index.php ├── PasswordHash.php ├── login.php ├── db └── eua.sql ├── main.css └── main.js /README.md: -------------------------------------------------------------------------------- 1 | EuA 2 | === -------------------------------------------------------------------------------- /fontello/font/nsvb-symbol.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ns130291/EuA/develop/fontello/font/nsvb-symbol.eot -------------------------------------------------------------------------------- /fontello/font/nsvb-symbol.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ns130291/EuA/develop/fontello/font/nsvb-symbol.ttf -------------------------------------------------------------------------------- /fontello/font/nsvb-symbol.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ns130291/EuA/develop/fontello/font/nsvb-symbol.woff -------------------------------------------------------------------------------- /fontello/font/nsvb-symbol.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ns130291/EuA/develop/fontello/font/nsvb-symbol.woff2 -------------------------------------------------------------------------------- /fonts/gudea/gudea-v8-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ns130291/EuA/develop/fonts/gudea/gudea-v8-latin-700.woff -------------------------------------------------------------------------------- /fonts/gudea/gudea-v8-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ns130291/EuA/develop/fonts/gudea/gudea-v8-latin-700.woff2 -------------------------------------------------------------------------------- /fonts/gudea/gudea-v8-latin-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ns130291/EuA/develop/fonts/gudea/gudea-v8-latin-italic.woff -------------------------------------------------------------------------------- /fonts/gudea/gudea-v8-latin-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ns130291/EuA/develop/fonts/gudea/gudea-v8-latin-italic.woff2 -------------------------------------------------------------------------------- /fonts/gudea/gudea-v8-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ns130291/EuA/develop/fonts/gudea/gudea-v8-latin-regular.woff -------------------------------------------------------------------------------- /fonts/gudea/gudea-v8-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ns130291/EuA/develop/fonts/gudea/gudea-v8-latin-regular.woff2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tmp/* 2 | config/database.php 3 | app/tmp/* 4 | app/config/database.php 5 | !empty 6 | /nbproject/private/ 7 | nbproject 8 | -------------------------------------------------------------------------------- /api/get_sum_months.php: -------------------------------------------------------------------------------- 1 | query(sprintf('CALL eua.summeAusgabenMonate(%s);', $kontoid)); 9 | 10 | if (!$result) { 11 | echo '{"error":"server","msg":"Keine Ergebnisse"}'; 12 | } else { 13 | $rows = array(); 14 | while ($array = $result->fetch_assoc()) { 15 | $rows[] = $array; 16 | } 17 | $ausgaben = json_encode($rows); 18 | $json = '{"ausgaben":' . $ausgaben . '}'; 19 | echo $json; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /fontello/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Font license info 2 | 3 | 4 | ## Elusive 5 | 6 | Copyright (C) 2013 by Aristeides Stathopoulos 7 | 8 | Author: Aristeides Stathopoulos 9 | License: SIL (http://scripts.sil.org/OFL) 10 | Homepage: http://aristeides.com/ 11 | 12 | 13 | ## Fontelico 14 | 15 | Copyright (C) 2012 by Fontello project 16 | 17 | Author: Crowdsourced, for Fontello project 18 | License: SIL (http://scripts.sil.org/OFL) 19 | Homepage: http://fontello.com 20 | 21 | 22 | ## Font Awesome 23 | 24 | Copyright (C) 2016 by Dave Gandy 25 | 26 | Author: Dave Gandy 27 | License: SIL () 28 | Homepage: http://fortawesome.github.com/Font-Awesome/ 29 | 30 | 31 | -------------------------------------------------------------------------------- /api/get_accounts.php: -------------------------------------------------------------------------------- 1 | 'not_logged_in']); 6 | exit; 7 | } 8 | $user = $_SESSION['user']; 9 | $stmt = $mysqli->prepare('SELECT k.idkonto, k.name FROM konto k JOIN userkonto uk ON uk.kontoid = k.idkonto WHERE uk.user = ?'); 10 | $stmt->bind_param('s', $user); 11 | $stmt->execute(); 12 | $result = $stmt->get_result(); 13 | $accounts = []; 14 | while ($row = $result->fetch_assoc()) { 15 | $row['idkonto'] = (int)$row['idkonto']; 16 | $accounts[] = $row; 17 | } 18 | $current = isset($_SESSION['currentKonto']) ? $_SESSION['currentKonto'] : $_SESSION['defaultKonto']; 19 | echo json_encode(['accounts'=>$accounts, 'current'=>$current]); 20 | -------------------------------------------------------------------------------- /api/get_overview_year.php: -------------------------------------------------------------------------------- 1 | query(sprintf('CALL eua.jahresuebersicht(%s, %s);', $jahr, $kontoid)); 13 | 14 | if (!$result) { 15 | echo '{"error":"server","msg":"Keine Ergebnisse"}'; 16 | } else { 17 | $rows = array(); 18 | while ($array = $result->fetch_assoc()) { 19 | $rows[] = $array; 20 | } 21 | $ausgaben = json_encode($rows); 22 | $json = '{"ausgaben":' . $ausgaben . '}'; 23 | echo $json; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /api/get_overview_month.php: -------------------------------------------------------------------------------- 1 | query(sprintf('CALL eua.monatsuebersicht(%s, %s, %s);', $monat, $jahr, $kontoid)); 15 | 16 | if (!$result) { 17 | echo '{"error":"server","msg":"Keine Ergebnisse"}'; 18 | } else { 19 | $rows = array(); 20 | while ($array = $result->fetch_assoc()) { 21 | $rows[] = $array; 22 | } 23 | $ausgaben = json_encode($rows); 24 | $json = '{"ausgaben":' . $ausgaben . '}'; 25 | echo $json; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /api/get_categories.php: -------------------------------------------------------------------------------- 1 | query(sprintf('CALL eua.getCategories(%s, %s);', $_POST['mincount'], $kontoid)); 10 | } else { 11 | $result = $mysqli->query(sprintf('CALL eua.getCategories(0, %s);', $kontoid)); 12 | } 13 | 14 | if (!$result) { 15 | echo '{"error":"server","msg":"Keine Ergebnisse"}'; 16 | } else { 17 | $rows = array(); 18 | while ($array = $result->fetch_assoc()) { 19 | $rows[] = $array['kategorie']; 20 | } 21 | $kategorien = json_encode($rows); 22 | $json = '{"kategorien":' . $kategorien . '}'; 23 | echo $json; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /api/set_account.php: -------------------------------------------------------------------------------- 1 | 'kontoid_missing']); 8 | exit; 9 | } 10 | if (!isset($_SESSION['user'])) { 11 | echo json_encode(['error'=>'not_logged_in']); 12 | exit; 13 | } 14 | $user = $_SESSION['user']; 15 | $stmt = $mysqli->prepare('SELECT 1 FROM userkonto WHERE user = ? AND kontoid = ?'); 16 | $stmt->bind_param('si', $user, $kontoid); 17 | $stmt->execute(); 18 | $stmt->store_result(); 19 | if ($stmt->num_rows !== 1) { 20 | echo json_encode(['error'=>'invalid_konto']); 21 | exit; 22 | } 23 | // Set current konto in session 24 | $_SESSION['currentKonto'] = $kontoid; 25 | echo json_encode(['success'=>true]); -------------------------------------------------------------------------------- /generatehash.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | PW Hasher 4 | 5 | 6 | 7 | HashPassword($_POST['pw']); 16 | echo $hashPassword; 17 | } 18 | } else { 19 | ?> 20 |
21 | 22 | 23 |
24 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /api/get_overview_year_category.php: -------------------------------------------------------------------------------- 1 | query(sprintf('CALL eua.jahresuebersichtKategorie(%s, NULL, %s);', $jahr, $kontoid)); 20 | } else { 21 | $result = $mysqli->query(sprintf('CALL eua.jahresuebersichtKategorie(%s, "%s", %s);', $jahr, $kategorie, $kontoid)); 22 | } 23 | 24 | if (!$result) { 25 | echo '{"error":"server","msg":"Keine Ergebnisse"}'; 26 | } else { 27 | $rows = array(); 28 | while ($array = $result->fetch_assoc()) { 29 | $rows[] = $array; 30 | } 31 | $ausgaben = json_encode($rows); 32 | $json = '{"ausgaben":' . $ausgaben . '}'; 33 | echo $json; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /api/restore.php: -------------------------------------------------------------------------------- 1 | 'params_missing', 'msg' => 'Type oder ID fehlt'])); 7 | } 8 | 9 | $type = $_POST['type']; 10 | $id = filter_input(INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT); 11 | 12 | // Determine active account 13 | $kontoid = isset($_SESSION['currentKonto']) ? $_SESSION['currentKonto'] : $_SESSION['defaultKonto']; 14 | 15 | // Prepare update based on type 16 | if ($type === 'ausgaben') { 17 | $stmt = $mysqli->prepare('UPDATE ausgabe SET trash=0, trashdate=NULL WHERE idausgabe=? AND konto=?'); 18 | } elseif ($type === 'einnahmen') { 19 | $stmt = $mysqli->prepare('UPDATE einnahme SET trash=0, trashdate=NULL WHERE ideinnahme=? AND konto=?'); 20 | } else { 21 | die(json_encode(['error' => 'invalid_type', 'msg' => 'Ungültiger Typ'])); 22 | } 23 | 24 | if (!$stmt) { 25 | die(json_encode(['error' => 'server', 'msg' => 'Datenbankfehler: ' . $mysqli->error])); 26 | } 27 | 28 | $stmt->bind_param('ii', $id, $kontoid); 29 | if (!$stmt->execute()) { 30 | die(json_encode(['error' => 'server', 'msg' => 'Fehler beim Wiederherstellen: ' . $stmt->error])); 31 | } 32 | 33 | echo json_encode(['success' => true]); 34 | ?> -------------------------------------------------------------------------------- /api/delete.php: -------------------------------------------------------------------------------- 1 | query(sprintf('CALL eua.einnahmeLöschen(%s, %s);', $ideinnahme, $kontoid)); 16 | 17 | $json = array(); 18 | 19 | $json["idausgabe"] = $ideinnahme; 20 | 21 | if ($result == true) { 22 | $json["deleted"] = "true"; 23 | } else { 24 | $json["deleted"] = "false"; 25 | } 26 | 27 | echo json_encode($json); 28 | } else { 29 | if (!isset($_POST["idausgabe"])) { 30 | die('{"error":"server","msg":"Ausgaben ID fehlt"}'); 31 | } 32 | 33 | $idausgabe = $_POST["idausgabe"]; 34 | 35 | $result = $mysqli->query(sprintf('CALL eua.ausgabeLöschen(%s, %s);', $idausgabe, $kontoid)); 36 | 37 | $json = array(); 38 | 39 | $json["idausgabe"] = $idausgabe; 40 | 41 | if ($result == true) { 42 | $json["deleted"] = "true"; 43 | } else { 44 | $json["deleted"] = "false"; 45 | } 46 | 47 | echo json_encode($json); 48 | } 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /api/get_trashed.php: -------------------------------------------------------------------------------- 1 | query($query); 12 | if (!$result) { 13 | die(json_encode(array('error' => 'server', 'msg' => 'Fehler beim Abrufen der Ausgaben: ' . $mysqli->error))); 14 | } 15 | while ($row = $result->fetch_assoc()) { 16 | foreach ($row as $key => $val) { 17 | $row[$key] = htmlspecialchars($val); 18 | } 19 | $ausgaben[] = $row; 20 | } 21 | 22 | // Fetch trashed income 23 | $einnahmen = array(); 24 | $query = "SELECT ideinnahme, datum, kategorie, art, preis, beschreibung FROM einnahme WHERE trash=1 AND konto=" . intval($kontoid) . " ORDER BY trashdate DESC"; 25 | $result = $mysqli->query($query); 26 | if (!$result) { 27 | die(json_encode(array('error' => 'server', 'msg' => 'Fehler beim Abrufen der Einnahmen: ' . $mysqli->error))); 28 | } 29 | while ($row = $result->fetch_assoc()) { 30 | foreach ($row as $key => $val) { 31 | $row[$key] = htmlspecialchars($val); 32 | } 33 | $einnahmen[] = $row; 34 | } 35 | 36 | // Return combined JSON 37 | echo json_encode(array( 38 | 'ausgaben' => $ausgaben, 39 | 'einnahmen' => $einnahmen 40 | )); 41 | ?> -------------------------------------------------------------------------------- /js/de.js: -------------------------------------------------------------------------------- 1 | //! moment.js locale configuration 2 | //! locale : german (de) 3 | //! author : lluchs : https://github.com/lluchs 4 | //! author: Menelion Elensúle: https://github.com/Oire 5 | //! author : Mikolaj Dadela : https://github.com/mik01aj 6 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module&&"function"==typeof require?n(require("../moment")):"function"==typeof define&&define.amd?define(["moment"],n):n(e.moment)}(this,function(e){"use strict";function n(e,n,t,a){var r={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return n?r[t][0]:r[t][1]}var t=e.defineLocale("de",{months:"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",m:n,mm:"%d Minuten",h:n,hh:"%d Stunden",d:n,dd:n,M:n,MM:n,y:n,yy:n},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}});return t}); 7 | -------------------------------------------------------------------------------- /login.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | window.addEventListener('DOMContentLoaded', function() { 4 | var form = document.getElementById("loginform"); 5 | form.addEventListener('submit', login, false); 6 | document.getElementById("loginbutton").addEventListener('click', function() { 7 | document.getElementById("loginform").submit(); 8 | }, false); 9 | }, false); 10 | 11 | function login(e) { 12 | var errors = document.getElementsByClassName("error-login"); 13 | for (var i = 0; i < errors.length; i++) { 14 | document.getElementById("loginformcontainer").removeChild(errors[i]); 15 | } 16 | if (document.getElementById("load")) { 17 | document.getElementById("loginbutton").removeChild(document.getElementById("load")); 18 | } 19 | 20 | var user = document.getElementById("user").value; 21 | if (user === "" || user === null) { 22 | var error = document.createElement("div"); 23 | error.innerHTML = "Username muss angegeben werden"; 24 | error.className = "error-login"; 25 | document.getElementById("loginformcontainer").insertBefore(error, document.getElementById("loginform")); 26 | e.preventDefault(); 27 | } 28 | 29 | var pw = document.getElementById("pw").value; 30 | if (pw === "" || pw === null) { 31 | var error = document.createElement("div"); 32 | error.innerHTML = "Passwort fehlt"; 33 | error.className = "error-login"; 34 | document.getElementById("loginformcontainer").insertBefore(error, document.getElementById("loginform")); 35 | e.preventDefault(); 36 | } 37 | 38 | var load = document.createElement("span"); 39 | load.id = "load"; 40 | load.className = "animate-spin"; 41 | load.innerHTML = "\uE803"; 42 | document.getElementById("loginbutton").insertBefore(load, document.getElementById("submitBtn")); 43 | } -------------------------------------------------------------------------------- /api/add.php: -------------------------------------------------------------------------------- 1 | real_escape_string(urldecode($_POST["kategorie"]))) . '"'; 12 | } else { 13 | $kategorie = "null"; 14 | } 15 | $art = '"' . trim($mysqli->real_escape_string(urldecode($_POST["art"]))) . '"'; 16 | $preis = $_POST["preis"]; 17 | $beschreibung = ""; 18 | if (isset($_POST["beschreibung"]) && $_POST["beschreibung"] !== "") { 19 | $beschreibung = '"' . $mysqli->real_escape_string(urldecode($_POST["beschreibung"])) . '"'; 20 | } else { 21 | $beschreibung = "null"; 22 | } 23 | 24 | $query = ''; 25 | if($_POST["entrytype"] === 'earnings') { 26 | $query = sprintf('CALL eua.einnahmeSpeichern(%s,%s,%s,%s,%s,%s);', $datum, $kategorie, $art, $preis, $beschreibung, $kontoid); 27 | } else { 28 | $query = sprintf('CALL eua.ausgabeSpeichern(%s,%s,%s,%s,%s,%s);', $datum, $kategorie, $art, $preis, $beschreibung, $kontoid); 29 | } 30 | 31 | $result = $mysqli->query($query); 32 | if ($result) { 33 | $insertId = $mysqli->insert_id; 34 | 35 | if ($insertId == 0) { 36 | if($_POST["entrytype"] === 'earnings') { 37 | $result = $mysqli->query('SELECT MAX(ideinnahme) as insertid FROM einnahme;'); 38 | } else { 39 | $result = $mysqli->query('SELECT MAX(idausgabe) as insertid FROM ausgabe;'); 40 | } 41 | if ($result) { 42 | $row = $result->fetch_assoc(); 43 | $insertId = $row['insertid']; 44 | } 45 | } 46 | echo '{"id":"' . $insertId . '", "entrytype":"' . $_POST["entrytype"] . '"}'; 47 | } else { 48 | echo('{"error":"server","msg":"Insert error ' . $mysqli->error . '"}'); 49 | } 50 | 51 | -------------------------------------------------------------------------------- /api/search.php: -------------------------------------------------------------------------------- 1 | 'server', 'msg' => 'Query parameter missing')); 7 | exit; 8 | } 9 | 10 | $q = $mysqli->real_escape_string(trim($_POST['q'])); 11 | if ($q === '') { 12 | echo json_encode(array('ausgaben' => array(), 'einnahmen' => array())); 13 | exit; 14 | } 15 | 16 | // Determine active account 17 | $kontoid = isset($_SESSION['currentKonto']) ? $_SESSION['currentKonto'] : $_SESSION['defaultKonto']; 18 | 19 | $like = "%%%s%%"; 20 | $like = sprintf($like, $q); 21 | 22 | $ausgaben = array(); 23 | $query = sprintf("SELECT idausgabe, datum, kategorie, art, preis, beschreibung FROM ausgabe WHERE konto=%d AND trash=0 AND art LIKE '%s' ORDER BY datum DESC LIMIT 100", intval($kontoid), $mysqli->real_escape_string($like)); 24 | $result = $mysqli->query($query); 25 | if ($result) { 26 | while ($row = $result->fetch_assoc()) { 27 | foreach ($row as $key => $val) { 28 | $row[$key] = htmlspecialchars($val); 29 | } 30 | $ausgaben[] = $row; 31 | } 32 | } else { 33 | die(json_encode(array('error' => 'server', 'msg' => 'Fehler bei Suche (Ausgaben): ' . $mysqli->error))); 34 | } 35 | 36 | $einnahmen = array(); 37 | $query = sprintf("SELECT ideinnahme, datum, kategorie, art, preis, beschreibung FROM einnahme WHERE konto=%d AND trash=0 AND art LIKE '%s' ORDER BY datum DESC LIMIT 100", intval($kontoid), $mysqli->real_escape_string($like)); 38 | $result = $mysqli->query($query); 39 | if ($result) { 40 | while ($row = $result->fetch_assoc()) { 41 | foreach ($row as $key => $val) { 42 | $row[$key] = htmlspecialchars($val); 43 | } 44 | $einnahmen[] = $row; 45 | } 46 | } else { 47 | die(json_encode(array('error' => 'server', 'msg' => 'Fehler bei Suche (Einnahmen): ' . $mysqli->error))); 48 | } 49 | 50 | echo json_encode(array('ausgaben' => $ausgaben, 'einnahmen' => $einnahmen)); 51 | ?> 52 | -------------------------------------------------------------------------------- /fontello/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nsvb-symbol", 3 | "css_prefix_text": "icon-", 4 | "css_use_suffix": false, 5 | "hinting": true, 6 | "units_per_em": 1000, 7 | "ascent": 850, 8 | "glyphs": [ 9 | { 10 | "uid": "2a6740fc2f9d0edea54205963f662594", 11 | "css": "spin3", 12 | "code": 59394, 13 | "src": "fontelico" 14 | }, 15 | { 16 | "uid": "5d2d07f112b8de19f2c0dbfec3e42c05", 17 | "css": "spin5", 18 | "code": 59395, 19 | "src": "fontelico" 20 | }, 21 | { 22 | "uid": "48b87105bd38c20315f1b705b8c7b38c", 23 | "css": "list", 24 | "code": 59399, 25 | "src": "fontawesome" 26 | }, 27 | { 28 | "uid": "ce7452abce8b55ded1c393997a51e6b3", 29 | "css": "ok", 30 | "code": 59396, 31 | "src": "elusive" 32 | }, 33 | { 34 | "uid": "499b745a2e2485bdd059c3a53d048e5f", 35 | "css": "cancel", 36 | "code": 59397, 37 | "src": "elusive" 38 | }, 39 | { 40 | "uid": "55e2ff85b1c459c383f46da6e96014b0", 41 | "css": "plus", 42 | "code": 59393, 43 | "src": "elusive" 44 | }, 45 | { 46 | "uid": "62b0580ee8edc3a3edfbf68a47c852d5", 47 | "css": "pencil", 48 | "code": 59398, 49 | "src": "elusive" 50 | }, 51 | { 52 | "uid": "3ab2abf6f936d3e53ee8c184cedaed82", 53 | "css": "trash", 54 | "code": 59392, 55 | "src": "elusive" 56 | }, 57 | { 58 | "uid": "64abb7c56aefca89046bb69f7251d2e2", 59 | "css": "calendar", 60 | "code": 59400, 61 | "src": "elusive" 62 | }, 63 | { 64 | "uid": "f9c3205df26e7778abac86183aefdc99", 65 | "css": "ccw", 66 | "code": 59401, 67 | "src": "fontawesome" 68 | }, 69 | { 70 | "uid": "2d6150442079cbda7df64522dc24f482", 71 | "css": "down-dir", 72 | "code": 59402, 73 | "src": "fontawesome" 74 | }, 75 | { 76 | "uid": "80cd1022bd9ea151d554bec1fa05f2de", 77 | "css": "up-dir", 78 | "code": 59403, 79 | "src": "fontawesome" 80 | }, 81 | { 82 | "uid": "9dd9e835aebe1060ba7190ad2b2ed951", 83 | "css": "search", 84 | "code": 59404, 85 | "src": "fontawesome" 86 | } 87 | ] 88 | } -------------------------------------------------------------------------------- /fontello/css/animation.css: -------------------------------------------------------------------------------- 1 | /* 2 | Animation example, for spinners 3 | */ 4 | .animate-spin { 5 | -moz-animation: spin 2s infinite linear; 6 | -o-animation: spin 2s infinite linear; 7 | -webkit-animation: spin 2s infinite linear; 8 | animation: spin 2s infinite linear; 9 | display: inline-block; 10 | } 11 | @-moz-keyframes spin { 12 | 0% { 13 | -moz-transform: rotate(0deg); 14 | -o-transform: rotate(0deg); 15 | -webkit-transform: rotate(0deg); 16 | transform: rotate(0deg); 17 | } 18 | 19 | 100% { 20 | -moz-transform: rotate(359deg); 21 | -o-transform: rotate(359deg); 22 | -webkit-transform: rotate(359deg); 23 | transform: rotate(359deg); 24 | } 25 | } 26 | @-webkit-keyframes spin { 27 | 0% { 28 | -moz-transform: rotate(0deg); 29 | -o-transform: rotate(0deg); 30 | -webkit-transform: rotate(0deg); 31 | transform: rotate(0deg); 32 | } 33 | 34 | 100% { 35 | -moz-transform: rotate(359deg); 36 | -o-transform: rotate(359deg); 37 | -webkit-transform: rotate(359deg); 38 | transform: rotate(359deg); 39 | } 40 | } 41 | @-o-keyframes spin { 42 | 0% { 43 | -moz-transform: rotate(0deg); 44 | -o-transform: rotate(0deg); 45 | -webkit-transform: rotate(0deg); 46 | transform: rotate(0deg); 47 | } 48 | 49 | 100% { 50 | -moz-transform: rotate(359deg); 51 | -o-transform: rotate(359deg); 52 | -webkit-transform: rotate(359deg); 53 | transform: rotate(359deg); 54 | } 55 | } 56 | @-ms-keyframes spin { 57 | 0% { 58 | -moz-transform: rotate(0deg); 59 | -o-transform: rotate(0deg); 60 | -webkit-transform: rotate(0deg); 61 | transform: rotate(0deg); 62 | } 63 | 64 | 100% { 65 | -moz-transform: rotate(359deg); 66 | -o-transform: rotate(359deg); 67 | -webkit-transform: rotate(359deg); 68 | transform: rotate(359deg); 69 | } 70 | } 71 | @keyframes spin { 72 | 0% { 73 | -moz-transform: rotate(0deg); 74 | -o-transform: rotate(0deg); 75 | -webkit-transform: rotate(0deg); 76 | transform: rotate(0deg); 77 | } 78 | 79 | 100% { 80 | -moz-transform: rotate(359deg); 81 | -o-transform: rotate(359deg); 82 | -webkit-transform: rotate(359deg); 83 | transform: rotate(359deg); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /preload.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var loadingDone = false; 4 | var json; 5 | var mainLoaded; 6 | preload(); 7 | 8 | function preload() { 9 | console.log("starting preload " + new Date().getTime()); 10 | var location = window.location.search; 11 | if (location !== null && location !== "") { 12 | var regYear = new RegExp("year=(\\d{4})"); 13 | var regMonth = new RegExp("month=(\\d{1,2})"); 14 | var year = regYear.exec(location); 15 | var month = regMonth.exec(location); 16 | if (month !== null && month.length === 2 && month[1] >= 1 && month[1] <= 12 && year !== null && year.length === 2) { 17 | var url = "api.php"; 18 | 19 | var params = `action=get_month&month=${month[1]}&year=${year[1]}`; 20 | 21 | var xhr = new XMLHttpRequest(); 22 | xhr.open("POST", url, true); 23 | 24 | //Send the proper header information along with the request 25 | xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8"); 26 | 27 | xhr.onload = function() { 28 | if (xhr.status === 200) { 29 | json = JSON.parse(xhr.response); 30 | if (json['error'] === undefined) { 31 | loadingDone = true; 32 | console.log("preload DONE"); 33 | if (mainLoaded === true) { 34 | showEntries(); 35 | console.log("preload main already finished"); 36 | } 37 | } 38 | else { 39 | loadingDone = "error"; 40 | console.log("preload error"); 41 | } 42 | } 43 | else { 44 | loadingDone = "error"; 45 | console.log("preload error"); 46 | } 47 | }; 48 | xhr.onerror = function() { 49 | loadingDone = "error"; 50 | console.log("preload error"); 51 | }; 52 | 53 | xhr.send(params); 54 | } 55 | else { 56 | loadingDone = "error"; 57 | console.log("preload error"); 58 | } 59 | } 60 | else { 61 | loadingDone = "error"; 62 | console.log("preload error"); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /api/edit.php: -------------------------------------------------------------------------------- 1 | real_escape_string($_POST["ideinnahme"]) . ' AND konto = ' . $mysqli->real_escape_string($kontoid) . ';'; 18 | } else { 19 | if (!isset($_POST["idausgabe"])) { 20 | die('{"error":"server","msg":"Ausgaben ID fehlt"}'); 21 | } 22 | $json["idausgabe"] = $_POST["idausgabe"]; 23 | $sql = 'UPDATE eua.ausgabe SET'; 24 | $sqlWhere = ' WHERE idausgabe = ' . $mysqli->real_escape_string($_POST["idausgabe"]) . ' AND konto = ' . $mysqli->real_escape_string($kontoid) . ';'; 25 | } 26 | 27 | 28 | $set = ''; 29 | if (isset($_POST["datum"])) { 30 | $set .= ' datum="' . $mysqli->real_escape_string($_POST["datum"]) . '",'; 31 | } 32 | if (isset($_POST["kategorie"])) { 33 | if ($_POST["kategorie"] !== "") { 34 | $set .= ' kategorie="' . trim($mysqli->real_escape_string(urldecode($_POST["kategorie"]))) . '",'; 35 | } else { 36 | $set .= ' kategorie=null,'; 37 | } 38 | } 39 | if (isset($_POST["art"])) { 40 | $set .= ' art="' . trim($mysqli->real_escape_string(urldecode($_POST["art"]))) . '",'; 41 | } 42 | if (isset($_POST["preis"])) { 43 | $set .= ' preis=' . $mysqli->real_escape_string($_POST["preis"]) . ','; 44 | } 45 | if (isset($_POST["beschreibung"])) { 46 | if($_POST["beschreibung"] !== "") { 47 | $set .= ' beschreibung="' . $mysqli->real_escape_string(urldecode($_POST["beschreibung"])) . '",'; 48 | } else { 49 | $set .= ' beschreibung=null,'; 50 | } 51 | } 52 | 53 | if (!empty($set)) { 54 | $sql .= rtrim($set, ","); 55 | $sql .= $sqlWhere; 56 | 57 | $result = $mysqli->query($sql); 58 | 59 | if ($result) { 60 | $json["changed"] = "true"; 61 | } else { 62 | $json["changed"] = "false"; 63 | } 64 | } else { 65 | $json["changed"] = "true"; 66 | } 67 | 68 | echo json_encode($json); 69 | 70 | -------------------------------------------------------------------------------- /fontello/css/nsvb-symbol.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'nsvb-symbol'; 3 | src: url('../font/nsvb-symbol.eot?14891385'); 4 | src: url('../font/nsvb-symbol.eot?14891385#iefix') format('embedded-opentype'), 5 | url('../font/nsvb-symbol.woff2?14891385') format('woff2'), 6 | url('../font/nsvb-symbol.woff?14891385') format('woff'), 7 | url('../font/nsvb-symbol.ttf?14891385') format('truetype'), 8 | url('../font/nsvb-symbol.svg?14891385#nsvb-symbol') format('svg'); 9 | font-weight: normal; 10 | font-style: normal; 11 | } 12 | /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ 13 | /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ 14 | /* 15 | @media screen and (-webkit-min-device-pixel-ratio:0) { 16 | @font-face { 17 | font-family: 'nsvb-symbol'; 18 | src: url('../font/nsvb-symbol.svg?14891385#nsvb-symbol') format('svg'); 19 | } 20 | } 21 | */ 22 | [class^="icon-"]:before, [class*=" icon-"]:before { 23 | font-family: "nsvb-symbol"; 24 | font-style: normal; 25 | font-weight: normal; 26 | speak: never; 27 | 28 | display: inline-block; 29 | text-decoration: inherit; 30 | width: 1em; 31 | margin-right: .2em; 32 | text-align: center; 33 | /* opacity: .8; */ 34 | 35 | /* For safety - reset parent styles, that can break glyph codes*/ 36 | font-variant: normal; 37 | text-transform: none; 38 | 39 | /* fix buttons height, for twitter bootstrap */ 40 | line-height: 1em; 41 | 42 | /* Animation center compensation - margins should be symmetric */ 43 | /* remove if not needed */ 44 | margin-left: .2em; 45 | 46 | /* you can be more comfortable with increased icons size */ 47 | /* font-size: 120%; */ 48 | 49 | /* Font smoothing. That was taken from TWBS */ 50 | -webkit-font-smoothing: antialiased; 51 | -moz-osx-font-smoothing: grayscale; 52 | 53 | /* Uncomment for 3D effect */ 54 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ 55 | } 56 | 57 | .icon-trash:before { content: '\e800'; } /* '' */ 58 | .icon-plus:before { content: '\e801'; } /* '' */ 59 | .icon-spin3:before { content: '\e802'; } /* '' */ 60 | .icon-spin5:before { content: '\e803'; } /* '' */ 61 | .icon-ok:before { content: '\e804'; } /* '' */ 62 | .icon-cancel:before { content: '\e805'; } /* '' */ 63 | .icon-pencil:before { content: '\e806'; } /* '' */ 64 | .icon-list:before { content: '\e807'; } /* '' */ 65 | .icon-calendar:before { content: '\e808'; } /* '' */ 66 | .icon-ccw:before { content: '\e809'; } /* '' */ 67 | .icon-down-dir:before { content: '\e80a'; } /* '' */ 68 | .icon-up-dir:before { content: '\e80b'; } /* '' */ 69 | .icon-search:before { content: '\e80c'; } /* '' */ 70 | -------------------------------------------------------------------------------- /api.php: -------------------------------------------------------------------------------- 1 | connect_error) { 21 | die('{"error":"server","msg":"Datenbankfehler: #' . $mysqli->connect_errno . ' ' . $mysqli->connect_error . '"}'); 22 | } 23 | 24 | $mysqli->set_charset('utf8'); 25 | 26 | define('SECURE', true); 27 | 28 | switch ($_POST['action']) { 29 | case 'delete': 30 | require 'api/delete.php'; 31 | break; 32 | case 'edit': 33 | require 'api/edit.php'; 34 | break; 35 | case 'add': 36 | require 'api/add.php'; 37 | break; 38 | case 'get_month': 39 | require 'api/get_month.php'; 40 | break; 41 | case 'get_sum_months': 42 | require 'api/get_sum_months.php'; 43 | break; 44 | case 'get_overview_month': 45 | require 'api/get_overview_month.php'; 46 | break; 47 | case 'get_overview_year': 48 | require 'api/get_overview_year.php'; 49 | break; 50 | case 'get_overview_year_category': 51 | require 'api/get_overview_year_category.php'; 52 | break; 53 | case 'get_categories': 54 | require 'api/get_categories.php'; 55 | break; 56 | case 'get_accounts': 57 | require 'api/get_accounts.php'; 58 | break; 59 | case 'set_account': 60 | require 'api/set_account.php'; 61 | break; 62 | case 'get_trashed': 63 | require 'api/get_trashed.php'; 64 | break; 65 | case 'search': 66 | require 'api/search.php'; 67 | break; 68 | case 'restore': 69 | require 'api/restore.php'; 70 | break; 71 | 72 | default: 73 | $json = array(); 74 | 75 | $json['error'] = 'not_implemented'; 76 | $json['msg'] = 'Action ' . $_POST['action'] . ' is not implemented'; 77 | 78 | echo json_encode($json); 79 | break; 80 | } 81 | 82 | $mysqli->close(); 83 | } else { 84 | $json = array(); 85 | 86 | $json['error'] = 'wrong_method'; 87 | $json['msg'] = 'Only POST requests are accepted'; 88 | 89 | echo json_encode($json); 90 | } 91 | -------------------------------------------------------------------------------- /fontello/README.txt: -------------------------------------------------------------------------------- 1 | This webfont is generated by https://fontello.com open source project. 2 | 3 | 4 | ================================================================================ 5 | Please, note, that you should obey original font licenses, used to make this 6 | webfont pack. Details available in LICENSE.txt file. 7 | 8 | - Usually, it's enough to publish content of LICENSE.txt file somewhere on your 9 | site in "About" section. 10 | 11 | - If your project is open-source, usually, it will be ok to make LICENSE.txt 12 | file publicly available in your repository. 13 | 14 | - Fonts, used in Fontello, don't require a clickable link on your site. 15 | But any kind of additional authors crediting is welcome. 16 | ================================================================================ 17 | 18 | 19 | Comments on archive content 20 | --------------------------- 21 | 22 | - /font/* - fonts in different formats 23 | 24 | - /css/* - different kinds of css, for all situations. Should be ok with 25 | twitter bootstrap. Also, you can skip style and assign icon classes 26 | directly to text elements, if you don't mind about IE7. 27 | 28 | - demo.html - demo file, to show your webfont content 29 | 30 | - LICENSE.txt - license info about source fonts, used to build your one. 31 | 32 | - config.json - keeps your settings. You can import it back into fontello 33 | anytime, to continue your work 34 | 35 | 36 | Why so many CSS files ? 37 | ----------------------- 38 | 39 | Because we like to fit all your needs :) 40 | 41 | - basic file, .css - is usually enough, it contains @font-face 42 | and character code definitions 43 | 44 | - *-ie7.css - if you need IE7 support, but still don't wish to put char codes 45 | directly into html 46 | 47 | - *-codes.css and *-ie7-codes.css - if you like to use your own @font-face 48 | rules, but still wish to benefit from css generation. That can be very 49 | convenient for automated asset build systems. When you need to update font - 50 | no need to manually edit files, just override old version with archive 51 | content. See fontello source code for examples. 52 | 53 | - *-embedded.css - basic css file, but with embedded WOFF font, to avoid 54 | CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain. 55 | We strongly recommend to resolve this issue by `Access-Control-Allow-Origin` 56 | server headers. But if you ok with dirty hack - this file is for you. Note, 57 | that data url moved to separate @font-face to avoid problems with query(sprintf('CALL eua.holeAusgabenMonat("%s","%s",%s);', $startDate, $endDate, $kontoid)); 27 | 28 | if (!$result) { 29 | die('{"error":"server","msg":"Keine Ergebnisse (Ausgaben)"}'); 30 | } 31 | 32 | $rows = array(); 33 | while ($array = $result->fetch_assoc()) { 34 | foreach ($array as $key => $entry) { 35 | $array[$key] = htmlspecialchars($entry); 36 | } 37 | $rows[] = $array; 38 | } 39 | $ausgaben = json_encode($rows); 40 | 41 | //$result->close(); // Did not work; closing and reopening link instead... 42 | $mysqli->close(); 43 | $mysqli = new mysqli('mysql', 'eua', NULL, 'eua'); 44 | $mysqli->set_charset('utf8'); 45 | 46 | $result = $mysqli->query(sprintf('CALL eua.summeAusgabenMonat("%s","%s",%s);', $startDate, $endDate, $kontoid)); 47 | 48 | if (!$result) { 49 | die('{"error":"server","msg":"Keine Daten (Ausgaben) für diesem Monat: Summe fehlt:' . $mysqli->error . ' "}'); 50 | } 51 | 52 | $row = $result->fetch_row(); 53 | if ($row[0] == "") { 54 | $row[0] = "0.00"; 55 | } 56 | 57 | $summeAusgaben = $row[0]; 58 | 59 | // Einnahmen 60 | $mysqli->close(); 61 | $mysqli = new mysqli('mysql', 'eua', NULL, 'eua'); 62 | $mysqli->set_charset('utf8'); 63 | 64 | $result = $mysqli->query(sprintf('CALL eua.holeEinnahmenMonat("%s","%s",%s);', $startDate, $endDate, $kontoid)); 65 | 66 | if (!$result) { 67 | die('{"error":"server","msg":"Keine Ergebnisse (Einnahmen) ' . $mysqli->error . '"}'); 68 | } 69 | 70 | $rows = array(); 71 | while ($array = $result->fetch_assoc()) { 72 | foreach ($array as $key => $entry) { 73 | $array[$key] = htmlspecialchars($entry); 74 | } 75 | $rows[] = $array; 76 | } 77 | $einnahmen = json_encode($rows); 78 | 79 | $mysqli->close(); 80 | $mysqli = new mysqli('mysql', 'eua', NULL, 'eua'); 81 | $mysqli->set_charset('utf8'); 82 | 83 | $result = $mysqli->query(sprintf('CALL eua.summeEinnahmenMonat("%s","%s",%s);', $startDate, $endDate, $kontoid)); 84 | 85 | if (!$result) { 86 | die('{"error":"server","msg":"Keine Daten (Einnahmen) für diesem Monat: Summe fehlt:' . $mysqli->error . ' "}'); 87 | } 88 | 89 | $row = $result->fetch_row(); 90 | if ($row[0] == "") { 91 | $row[0] = "0.00"; 92 | } 93 | 94 | $summeEinnahmen = $row[0]; 95 | 96 | // Result 97 | $json = '{"summeausgaben":"' . $summeAusgaben . '","summeeinnahmen":"' . $summeEinnahmen . '","jahr":"' . $year . '","monat":"' . $month . '","ausgaben":' . $ausgaben . ',"einnahmen":' . $einnahmen . '}'; 98 | echo $json; 99 | -------------------------------------------------------------------------------- /fonts/gudea/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Agustina Mingote (agustinamingote@gmail.com), 2 | with Reserved Font Names "Gudea" 3 | 4 | 5 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 6 | This license is copied below, and is also available with a FAQ at: 7 | http://scripts.sil.org/OFL 8 | 9 | 10 | ----------------------------------------------------------- 11 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 12 | ----------------------------------------------------------- 13 | 14 | PREAMBLE 15 | The goals of the Open Font License (OFL) are to stimulate worldwide 16 | development of collaborative font projects, to support the font creation 17 | efforts of academic and linguistic communities, and to provide a free and 18 | open framework in which fonts may be shared and improved in partnership 19 | with others. 20 | 21 | The OFL allows the licensed fonts to be used, studied, modified and 22 | redistributed freely as long as they are not sold by themselves. The 23 | fonts, including any derivative works, can be bundled, embedded, 24 | redistributed and/or sold with any software provided that any reserved 25 | names are not used by derivative works. The fonts and derivatives, 26 | however, cannot be released under any other type of license. The 27 | requirement for fonts to remain under this license does not apply 28 | to any document created using the fonts or their derivatives. 29 | 30 | DEFINITIONS 31 | "Font Software" refers to the set of files released by the Copyright 32 | Holder(s) under this license and clearly marked as such. This may 33 | include source files, build scripts and documentation. 34 | 35 | "Reserved Font Name" refers to any names specified as such after the 36 | copyright statement(s). 37 | 38 | "Original Version" refers to the collection of Font Software components as 39 | distributed by the Copyright Holder(s). 40 | 41 | "Modified Version" refers to any derivative made by adding to, deleting, 42 | or substituting -- in part or in whole -- any of the components of the 43 | Original Version, by changing formats or by porting the Font Software to a 44 | new environment. 45 | 46 | "Author" refers to any designer, engineer, programmer, technical 47 | writer or other person who contributed to the Font Software. 48 | 49 | PERMISSION & CONDITIONS 50 | Permission is hereby granted, free of charge, to any person obtaining 51 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 52 | redistribute, and sell modified and unmodified copies of the Font 53 | Software, subject to the following conditions: 54 | 55 | 1) Neither the Font Software nor any of its individual components, 56 | in Original or Modified Versions, may be sold by itself. 57 | 58 | 2) Original or Modified Versions of the Font Software may be bundled, 59 | redistributed and/or sold with any software, provided that each copy 60 | contains the above copyright notice and this license. These can be 61 | included either as stand-alone text files, human-readable headers or 62 | in the appropriate machine-readable metadata fields within text or 63 | binary files as long as those fields can be easily viewed by the user. 64 | 65 | 3) No Modified Version of the Font Software may use the Reserved Font 66 | Name(s) unless explicit written permission is granted by the corresponding 67 | Copyright Holder. This restriction only applies to the primary font name as 68 | presented to the users. 69 | 70 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 71 | Software shall not be used to promote, endorse or advertise any 72 | Modified Version, except to acknowledge the contribution(s) of the 73 | Copyright Holder(s) and the Author(s) or with their explicit written 74 | permission. 75 | 76 | 5) The Font Software, modified or unmodified, in part or in whole, 77 | must be distributed entirely under this license, and must not be 78 | distributed under any other license. The requirement for fonts to 79 | remain under this license does not apply to any document created 80 | using the Font Software. 81 | 82 | TERMINATION 83 | This license becomes null and void if any of the above conditions are 84 | not met. 85 | 86 | DISCLAIMER 87 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 88 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 89 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 90 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 91 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 92 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 93 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 94 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 95 | OTHER DEALINGS IN THE FONT SOFTWARE. 96 | -------------------------------------------------------------------------------- /fontello/font/nsvb-symbol.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2025 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | EuA 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | 68 |
69 |
70 |
71 | Datum 72 |
73 |
74 | Kategorie 75 |
76 |
77 | Art 78 |
79 |
80 | Preis 81 |
82 |
83 | Beschreibung 84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | 93 | 94 | 95 |
96 |
97 | 98 |
99 |
100 | 101 |
102 |
103 | 104 |  € 105 |
106 |
107 | 108 |
109 |
110 | 111 |
112 |
113 |
114 |
115 |
116 |
117 | 118 | -------------------------------------------------------------------------------- /PasswordHash.php: -------------------------------------------------------------------------------- 1 | in 2004-2006 and placed in 8 | # the public domain. Revised in subsequent years, still public domain. 9 | # 10 | # There's absolutely no warranty. 11 | # 12 | # The homepage URL for this framework is: 13 | # 14 | # http://www.openwall.com/phpass/ 15 | # 16 | # Please be sure to update the Version line if you edit this file in any way. 17 | # It is suggested that you leave the main version number intact, but indicate 18 | # your project name (after the slash) and add your own revision information. 19 | # 20 | # Please do not change the "private" password hashing method implemented in 21 | # here, thereby making your hashes incompatible. However, if you must, please 22 | # change the hash type identifier (the "$P$") to something different. 23 | # 24 | # Obviously, since this code is in the public domain, the above are not 25 | # requirements (there can be none), but merely suggestions. 26 | # 27 | class PasswordHash { 28 | var $itoa64; 29 | var $iteration_count_log2; 30 | var $portable_hashes; 31 | var $random_state; 32 | 33 | function PasswordHash($iteration_count_log2, $portable_hashes) 34 | { 35 | $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 36 | 37 | if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) 38 | $iteration_count_log2 = 8; 39 | $this->iteration_count_log2 = $iteration_count_log2; 40 | 41 | $this->portable_hashes = $portable_hashes; 42 | 43 | $this->random_state = microtime(); 44 | if (function_exists('getmypid')) 45 | $this->random_state .= getmypid(); 46 | } 47 | 48 | function get_random_bytes($count) 49 | { 50 | $output = ''; 51 | if (is_readable('/dev/urandom') && 52 | ($fh = @fopen('/dev/urandom', 'rb'))) { 53 | $output = fread($fh, $count); 54 | fclose($fh); 55 | } 56 | 57 | if (strlen($output) < $count) { 58 | $output = ''; 59 | for ($i = 0; $i < $count; $i += 16) { 60 | $this->random_state = 61 | md5(microtime() . $this->random_state); 62 | $output .= 63 | pack('H*', md5($this->random_state)); 64 | } 65 | $output = substr($output, 0, $count); 66 | } 67 | 68 | return $output; 69 | } 70 | 71 | function encode64($input, $count) 72 | { 73 | $output = ''; 74 | $i = 0; 75 | do { 76 | $value = ord($input[$i++]); 77 | $output .= $this->itoa64[$value & 0x3f]; 78 | if ($i < $count) 79 | $value |= ord($input[$i]) << 8; 80 | $output .= $this->itoa64[($value >> 6) & 0x3f]; 81 | if ($i++ >= $count) 82 | break; 83 | if ($i < $count) 84 | $value |= ord($input[$i]) << 16; 85 | $output .= $this->itoa64[($value >> 12) & 0x3f]; 86 | if ($i++ >= $count) 87 | break; 88 | $output .= $this->itoa64[($value >> 18) & 0x3f]; 89 | } while ($i < $count); 90 | 91 | return $output; 92 | } 93 | 94 | function gensalt_private($input) 95 | { 96 | $output = '$P$'; 97 | $output .= $this->itoa64[min($this->iteration_count_log2 + 98 | ((PHP_VERSION >= '5') ? 5 : 3), 30)]; 99 | $output .= $this->encode64($input, 6); 100 | 101 | return $output; 102 | } 103 | 104 | function crypt_private($password, $setting) 105 | { 106 | $output = '*0'; 107 | if (substr($setting, 0, 2) == $output) 108 | $output = '*1'; 109 | 110 | $id = substr($setting, 0, 3); 111 | # We use "$P$", phpBB3 uses "$H$" for the same thing 112 | if ($id != '$P$' && $id != '$H$') 113 | return $output; 114 | 115 | $count_log2 = strpos($this->itoa64, $setting[3]); 116 | if ($count_log2 < 7 || $count_log2 > 30) 117 | return $output; 118 | 119 | $count = 1 << $count_log2; 120 | 121 | $salt = substr($setting, 4, 8); 122 | if (strlen($salt) != 8) 123 | return $output; 124 | 125 | # We're kind of forced to use MD5 here since it's the only 126 | # cryptographic primitive available in all versions of PHP 127 | # currently in use. To implement our own low-level crypto 128 | # in PHP would result in much worse performance and 129 | # consequently in lower iteration counts and hashes that are 130 | # quicker to crack (by non-PHP code). 131 | if (PHP_VERSION >= '5') { 132 | $hash = md5($salt . $password, TRUE); 133 | do { 134 | $hash = md5($hash . $password, TRUE); 135 | } while (--$count); 136 | } else { 137 | $hash = pack('H*', md5($salt . $password)); 138 | do { 139 | $hash = pack('H*', md5($hash . $password)); 140 | } while (--$count); 141 | } 142 | 143 | $output = substr($setting, 0, 12); 144 | $output .= $this->encode64($hash, 16); 145 | 146 | return $output; 147 | } 148 | 149 | function gensalt_extended($input) 150 | { 151 | $count_log2 = min($this->iteration_count_log2 + 8, 24); 152 | # This should be odd to not reveal weak DES keys, and the 153 | # maximum valid value is (2**24 - 1) which is odd anyway. 154 | $count = (1 << $count_log2) - 1; 155 | 156 | $output = '_'; 157 | $output .= $this->itoa64[$count & 0x3f]; 158 | $output .= $this->itoa64[($count >> 6) & 0x3f]; 159 | $output .= $this->itoa64[($count >> 12) & 0x3f]; 160 | $output .= $this->itoa64[($count >> 18) & 0x3f]; 161 | 162 | $output .= $this->encode64($input, 3); 163 | 164 | return $output; 165 | } 166 | 167 | function gensalt_blowfish($input) 168 | { 169 | # This one needs to use a different order of characters and a 170 | # different encoding scheme from the one in encode64() above. 171 | # We care because the last character in our encoded string will 172 | # only represent 2 bits. While two known implementations of 173 | # bcrypt will happily accept and correct a salt string which 174 | # has the 4 unused bits set to non-zero, we do not want to take 175 | # chances and we also do not want to waste an additional byte 176 | # of entropy. 177 | $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 178 | 179 | $output = '$2a$'; 180 | $output .= chr(ord('0') + $this->iteration_count_log2 / 10); 181 | $output .= chr(ord('0') + $this->iteration_count_log2 % 10); 182 | $output .= '$'; 183 | 184 | $i = 0; 185 | do { 186 | $c1 = ord($input[$i++]); 187 | $output .= $itoa64[$c1 >> 2]; 188 | $c1 = ($c1 & 0x03) << 4; 189 | if ($i >= 16) { 190 | $output .= $itoa64[$c1]; 191 | break; 192 | } 193 | 194 | $c2 = ord($input[$i++]); 195 | $c1 |= $c2 >> 4; 196 | $output .= $itoa64[$c1]; 197 | $c1 = ($c2 & 0x0f) << 2; 198 | 199 | $c2 = ord($input[$i++]); 200 | $c1 |= $c2 >> 6; 201 | $output .= $itoa64[$c1]; 202 | $output .= $itoa64[$c2 & 0x3f]; 203 | } while (1); 204 | 205 | return $output; 206 | } 207 | 208 | function HashPassword($password) 209 | { 210 | $random = ''; 211 | 212 | if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) { 213 | $random = $this->get_random_bytes(16); 214 | $hash = 215 | crypt($password, $this->gensalt_blowfish($random)); 216 | if (strlen($hash) == 60) 217 | return $hash; 218 | } 219 | 220 | if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) { 221 | if (strlen($random) < 3) 222 | $random = $this->get_random_bytes(3); 223 | $hash = 224 | crypt($password, $this->gensalt_extended($random)); 225 | if (strlen($hash) == 20) 226 | return $hash; 227 | } 228 | 229 | if (strlen($random) < 6) 230 | $random = $this->get_random_bytes(6); 231 | $hash = 232 | $this->crypt_private($password, 233 | $this->gensalt_private($random)); 234 | if (strlen($hash) == 34) 235 | return $hash; 236 | 237 | # Returning '*' on error is safe here, but would _not_ be safe 238 | # in a crypt(3)-like function used _both_ for generating new 239 | # hashes and for validating passwords against existing hashes. 240 | return '*'; 241 | } 242 | 243 | function CheckPassword($password, $stored_hash) 244 | { 245 | $hash = $this->crypt_private($password, $stored_hash); 246 | if ($hash[0] == '*') 247 | $hash = crypt($password, $stored_hash); 248 | 249 | return $hash == $stored_hash; 250 | } 251 | } 252 | 253 | ?> 254 | -------------------------------------------------------------------------------- /login.php: -------------------------------------------------------------------------------- 1 | connect_error) { 15 | echo 'false'; 16 | exit; 17 | } 18 | $mysqli->set_charset('utf8'); 19 | $result = $mysqli->query('SELECT * FROM users.tokens WHERE token="' . $mysqli->real_escape_string($_POST['auth']) . '";'); 20 | if (!$result) { 21 | echo 'false'; 22 | exit; 23 | } else { 24 | if($result->num_rows !== 1) { 25 | echo 'false'; 26 | exit; 27 | } // else --> token is valid, continue 28 | } 29 | $mysqli->close(); 30 | if (!isset($_POST['pw']) || $_POST['pw'] == '') { // only check if user exists 31 | $mysqli = new mysqli('mysql', 'eua', NULL, 'eua'); 32 | if ($mysqli->connect_error) { 33 | echo 'false'; 34 | exit; 35 | } 36 | $mysqli->set_charset('utf8'); 37 | $result = $mysqli->query('SELECT * FROM eua.user WHERE user="' . $mysqli->real_escape_string($_POST['user']) . '";'); 38 | if (!$result) { 39 | echo 'false'; 40 | exit; 41 | } else { 42 | if($result->num_rows !== 1) { 43 | echo 'false'; 44 | exit; 45 | } else { 46 | echo 'true'; 47 | exit; 48 | } 49 | } 50 | $mysqli->close(); 51 | } 52 | } 53 | if (!isset($_POST['user']) || $_POST['user'] == '') { 54 | $errorUser = true; 55 | } 56 | if (!isset($_POST['pw']) || $_POST['pw'] == '') { 57 | $errorPW = true; 58 | } 59 | if (!$errorPW && !$errorUser) { 60 | session_start(); 61 | $mysqli = new mysqli('mysql', 'eua', NULL, 'eua'); 62 | if ($mysqli->connect_error) { 63 | $_SESSION['angemeldet'] = false; 64 | $errorServer = true; 65 | } 66 | $mysqli->set_charset('utf8'); 67 | $t_hasher = new PasswordHash(8, FALSE); 68 | 69 | $result = $mysqli->query(sprintf('CALL eua.checkPw("%s");', $_POST["user"])); 70 | if (!$result) { 71 | $_SESSION['angemeldet'] = false; 72 | $errorServer = true; 73 | } else { 74 | $pw = $result->fetch_array(); 75 | $pw = $pw[0]; 76 | if ($pw) { 77 | $check = $t_hasher->CheckPassword($_POST["pw"], $pw); 78 | if ($check) { 79 | $mysqli->close(); 80 | $mysqli = new mysqli('mysql', 'eua', NULL, 'eua'); 81 | $result = $mysqli->query(sprintf('CALL eua.standardKonto("%s");', $_POST["user"])); 82 | if (!$result) { 83 | $_SESSION['angemeldet'] = false; 84 | $errorServer = true; 85 | } else { 86 | $defaultKonto = $result->fetch_array(); 87 | $defaultKonto = $defaultKonto[0]; 88 | if ($defaultKonto) { 89 | $_SESSION['user'] = $_POST["user"]; 90 | $_SESSION['defaultKonto'] = $defaultKonto; 91 | $hostname = $_SERVER['HTTP_HOST']; 92 | $path = dirname($_SERVER['PHP_SELF']); 93 | $_SESSION['angemeldet'] = true; 94 | } else { 95 | $_SESSION['angemeldet'] = false; 96 | $errorServer = true; 97 | } 98 | } 99 | } else { 100 | $_SESSION['angemeldet'] = false; 101 | $errorLogin = true; 102 | } 103 | } else { 104 | $_SESSION['angemeldet'] = false; 105 | $errorLogin = true; 106 | } 107 | } 108 | $mysqli->close(); 109 | if (isset($_POST['auth'])) { // authentication for external services 110 | if ($_SESSION['angemeldet'] == true) { 111 | echo 'true'; 112 | exit; 113 | } else { 114 | echo 'false'; 115 | exit; 116 | } 117 | } else { 118 | if ($_SESSION['angemeldet'] == true) { 119 | if (isset($_SESSION['lastURL'])) { 120 | header('Location: https://' . $hostname . $_SESSION['lastURL'], true, 303); 121 | unset($_SESSION['lastURL']); 122 | } else { 123 | header('Location: https://' . $hostname . ($path == '/' ? '' : $path) . '/index.php', true, 303); 124 | } 125 | exit; 126 | } 127 | } 128 | } 129 | } else { 130 | session_start(); 131 | 132 | if (isset($_GET['logout'])) { 133 | session_destroy(); 134 | $_SESSION = array(); 135 | session_start(); 136 | } 137 | 138 | if ($_SESSION) { 139 | if (isset($_SESSION['angemeldet']) && $_SESSION['angemeldet']) { 140 | $hostname = $_SERVER['HTTP_HOST']; 141 | $path = dirname($_SERVER['PHP_SELF']); 142 | header('Location: https://' . $hostname . ($path == '/' ? '' : $path) . '/index.php'); 143 | exit; 144 | } 145 | } 146 | } 147 | ?> 148 | 149 | 150 | 151 | 152 | Login 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 |
162 |
163 |
164 |
165 | 166 |
167 | Username muss angegeben werden
'; 170 | } 171 | if ($errorPW) { 172 | echo ''; 173 | } 174 | if ($errorLogin) { 175 | echo ''; 176 | } 177 | if ($errorServer) { 178 | echo ''; 179 | } 180 | ?> 181 |
182 | 183 |
184 |
185 | 186 |
187 |
188 |
189 | 190 |
191 | 192 |
193 | 194 |
195 |
196 | 197 | 198 | -------------------------------------------------------------------------------- /db/eua.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS `eua` /*!40100 DEFAULT CHARACTER SET utf8 */; 2 | USE `eua`; 3 | -- MySQL dump 10.13 Distrib 5.6.24, for Win64 (x86_64) 4 | -- 5 | -- Host: 127.0.0.1 Database: eua 6 | -- ------------------------------------------------------ 7 | -- Server version 5.5.47-0+deb7u1 8 | 9 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 10 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 11 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 12 | /*!40101 SET NAMES utf8 */; 13 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 14 | /*!40103 SET TIME_ZONE='+00:00' */; 15 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 16 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 17 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 18 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 19 | 20 | -- 21 | -- Table structure for table `ausgabe` 22 | -- 23 | 24 | DROP TABLE IF EXISTS `ausgabe`; 25 | /*!40101 SET @saved_cs_client = @@character_set_client */; 26 | /*!40101 SET character_set_client = utf8 */; 27 | CREATE TABLE `ausgabe` ( 28 | `idausgabe` int(11) NOT NULL AUTO_INCREMENT, 29 | `datum` date NOT NULL, 30 | `kategorie` varchar(100) DEFAULT NULL, 31 | `art` varchar(100) NOT NULL, 32 | `preis` decimal(10,2) NOT NULL, 33 | `beschreibung` varchar(5000) DEFAULT NULL, 34 | `trash` tinyint(1) NOT NULL DEFAULT '0', 35 | `trashdate` datetime DEFAULT NULL, 36 | `konto` int(11) NOT NULL, 37 | PRIMARY KEY (`idausgabe`), 38 | KEY `kontoid_idx` (`konto`), 39 | CONSTRAINT `kontokey` FOREIGN KEY (`konto`) REFERENCES `konto` (`idkonto`) ON DELETE NO ACTION ON UPDATE NO ACTION 40 | ) ENGINE=InnoDB AUTO_INCREMENT=2254 DEFAULT CHARSET=utf8; 41 | /*!40101 SET character_set_client = @saved_cs_client */; 42 | 43 | -- 44 | -- Table structure for table `bild` 45 | -- 46 | 47 | DROP TABLE IF EXISTS `bild`; 48 | /*!40101 SET @saved_cs_client = @@character_set_client */; 49 | /*!40101 SET character_set_client = utf8 */; 50 | CREATE TABLE `bild` ( 51 | `idbild` int(11) NOT NULL AUTO_INCREMENT, 52 | `titel` varchar(150) DEFAULT NULL, 53 | `bild` blob NOT NULL, 54 | `ausgabe_idausgabe` int(11) NOT NULL, 55 | PRIMARY KEY (`idbild`), 56 | KEY `fk_bild_ausgabe` (`ausgabe_idausgabe`) 57 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 58 | /*!40101 SET character_set_client = @saved_cs_client */; 59 | 60 | -- 61 | -- Table structure for table `einnahme` 62 | -- 63 | 64 | DROP TABLE IF EXISTS `einnahme`; 65 | /*!40101 SET @saved_cs_client = @@character_set_client */; 66 | /*!40101 SET character_set_client = utf8 */; 67 | CREATE TABLE `einnahme` ( 68 | `ideinnahme` int(11) NOT NULL, 69 | `datum` date DEFAULT NULL, 70 | `kategorie` varchar(100) DEFAULT NULL, 71 | `art` varchar(100) NOT NULL, 72 | `preis` decimal(10,2) NOT NULL, 73 | `beschreibung` varchar(5000) DEFAULT NULL, 74 | `trash` tinyint(1) NOT NULL DEFAULT '0', 75 | `trashdate` datetime DEFAULT NULL, 76 | `konto` int(11) NOT NULL, 77 | PRIMARY KEY (`ideinnahme`), 78 | KEY `kontokey_idx` (`konto`), 79 | CONSTRAINT `kontokeyeinnahme` FOREIGN KEY (`konto`) REFERENCES `konto` (`idkonto`) ON DELETE NO ACTION ON UPDATE NO ACTION 80 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 81 | /*!40101 SET character_set_client = @saved_cs_client */; 82 | 83 | -- 84 | -- Table structure for table `konto` 85 | -- 86 | 87 | DROP TABLE IF EXISTS `konto`; 88 | /*!40101 SET @saved_cs_client = @@character_set_client */; 89 | /*!40101 SET character_set_client = utf8 */; 90 | CREATE TABLE `konto` ( 91 | `idkonto` int(11) NOT NULL AUTO_INCREMENT, 92 | `name` varchar(100) NOT NULL, 93 | PRIMARY KEY (`idkonto`) 94 | ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; 95 | /*!40101 SET character_set_client = @saved_cs_client */; 96 | 97 | -- 98 | -- Table structure for table `user` 99 | -- 100 | 101 | DROP TABLE IF EXISTS `user`; 102 | /*!40101 SET @saved_cs_client = @@character_set_client */; 103 | /*!40101 SET character_set_client = utf8 */; 104 | CREATE TABLE `user` ( 105 | `user` varchar(20) NOT NULL, 106 | `pw` varchar(100) DEFAULT NULL, 107 | `defaultkonto` int(11) NOT NULL, 108 | PRIMARY KEY (`user`), 109 | KEY `defaultkontokey_idx` (`defaultkonto`), 110 | CONSTRAINT `defaultkontokey` FOREIGN KEY (`defaultkonto`) REFERENCES `konto` (`idkonto`) ON DELETE NO ACTION ON UPDATE NO ACTION 111 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 112 | /*!40101 SET character_set_client = @saved_cs_client */; 113 | 114 | -- 115 | -- Table structure for table `userkonto` 116 | -- 117 | 118 | DROP TABLE IF EXISTS `userkonto`; 119 | /*!40101 SET @saved_cs_client = @@character_set_client */; 120 | /*!40101 SET character_set_client = utf8 */; 121 | CREATE TABLE `userkonto` ( 122 | `user` varchar(20) NOT NULL, 123 | `kontoid` int(11) NOT NULL, 124 | PRIMARY KEY (`user`,`kontoid`), 125 | KEY `kontoid_idx` (`kontoid`), 126 | CONSTRAINT `kontoid` FOREIGN KEY (`kontoid`) REFERENCES `konto` (`idkonto`) ON DELETE NO ACTION ON UPDATE NO ACTION, 127 | CONSTRAINT `user` FOREIGN KEY (`user`) REFERENCES `user` (`user`) ON DELETE NO ACTION ON UPDATE NO ACTION 128 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 129 | /*!40101 SET character_set_client = @saved_cs_client */; 130 | 131 | -- 132 | -- Dumping routines for database 'eua' 133 | -- 134 | /*!50003 DROP PROCEDURE IF EXISTS `ausgabeLöschen` */; 135 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 136 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 137 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 138 | /*!50003 SET character_set_client = utf8 */ ; 139 | /*!50003 SET character_set_results = utf8 */ ; 140 | /*!50003 SET collation_connection = utf8_general_ci */ ; 141 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 142 | /*!50003 SET sql_mode = '' */ ; 143 | DELIMITER ;; 144 | CREATE DEFINER=`root`@`localhost` PROCEDURE `ausgabeLöschen`( 145 | IN ausgaben_id INT(11), 146 | IN kontoid INT 147 | ) 148 | BEGIN 149 | UPDATE ausgabe set trash=1, trashdate=NOW() where idausgabe=ausgaben_id AND konto=kontoid; 150 | END ;; 151 | DELIMITER ; 152 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 153 | /*!50003 SET character_set_client = @saved_cs_client */ ; 154 | /*!50003 SET character_set_results = @saved_cs_results */ ; 155 | /*!50003 SET collation_connection = @saved_col_connection */ ; 156 | /*!50003 DROP PROCEDURE IF EXISTS `ausgabeSpeichern` */; 157 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 158 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 159 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 160 | /*!50003 SET character_set_client = utf8 */ ; 161 | /*!50003 SET character_set_results = utf8 */ ; 162 | /*!50003 SET collation_connection = utf8_general_ci */ ; 163 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 164 | /*!50003 SET sql_mode = '' */ ; 165 | DELIMITER ;; 166 | CREATE DEFINER=`root`@`localhost` PROCEDURE `ausgabeSpeichern`( 167 | IN _datum DATE, 168 | IN _kategorie VARCHAR(100), 169 | IN _art VARCHAR(100), 170 | IN _preis DECIMAL(10,2), 171 | IN _beschreibung VARCHAR(5000), 172 | IN kontoid INT 173 | ) 174 | BEGIN 175 | INSERT INTO ausgabe(datum, kategorie, art, preis, beschreibung, konto) VALUES (_datum, _kategorie, _art, _preis, _beschreibung, kontoid); 176 | END ;; 177 | DELIMITER ; 178 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 179 | /*!50003 SET character_set_client = @saved_cs_client */ ; 180 | /*!50003 SET character_set_results = @saved_cs_results */ ; 181 | /*!50003 SET collation_connection = @saved_col_connection */ ; 182 | /*!50003 DROP PROCEDURE IF EXISTS `checkPw` */; 183 | ALTER DATABASE `eua` CHARACTER SET latin1 COLLATE latin1_swedish_ci ; 184 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 185 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 186 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 187 | /*!50003 SET character_set_client = utf8 */ ; 188 | /*!50003 SET character_set_results = utf8 */ ; 189 | /*!50003 SET collation_connection = utf8_general_ci */ ; 190 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 191 | /*!50003 SET sql_mode = '' */ ; 192 | DELIMITER ;; 193 | CREATE DEFINER=`root`@`localhost` PROCEDURE `checkPw`( 194 | IN user_name VARCHAR(20) 195 | ) 196 | BEGIN 197 | SELECT pw FROM user WHERE user = user_name; 198 | END ;; 199 | DELIMITER ; 200 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 201 | /*!50003 SET character_set_client = @saved_cs_client */ ; 202 | /*!50003 SET character_set_results = @saved_cs_results */ ; 203 | /*!50003 SET collation_connection = @saved_col_connection */ ; 204 | ALTER DATABASE `eua` CHARACTER SET utf8 COLLATE utf8_general_ci ; 205 | /*!50003 DROP PROCEDURE IF EXISTS `einnahmeLöschen` */; 206 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 207 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 208 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 209 | /*!50003 SET character_set_client = utf8 */ ; 210 | /*!50003 SET character_set_results = utf8 */ ; 211 | /*!50003 SET collation_connection = utf8_general_ci */ ; 212 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 213 | /*!50003 SET sql_mode = '' */ ; 214 | DELIMITER ;; 215 | CREATE DEFINER=`root`@`localhost` PROCEDURE `einnahmeLöschen`( 216 | IN einnahmen_id INT(11), 217 | IN kontoid INT 218 | ) 219 | BEGIN 220 | UPDATE einnahme set trash=1, trashdate=NOW() where ideinnahme=einnahmen_id AND konto=kontoid; 221 | END ;; 222 | DELIMITER ; 223 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 224 | /*!50003 SET character_set_client = @saved_cs_client */ ; 225 | /*!50003 SET character_set_results = @saved_cs_results */ ; 226 | /*!50003 SET collation_connection = @saved_col_connection */ ; 227 | /*!50003 DROP PROCEDURE IF EXISTS `einnahmeSpeichern` */; 228 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 229 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 230 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 231 | /*!50003 SET character_set_client = utf8 */ ; 232 | /*!50003 SET character_set_results = utf8 */ ; 233 | /*!50003 SET collation_connection = utf8_general_ci */ ; 234 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 235 | /*!50003 SET sql_mode = '' */ ; 236 | DELIMITER ;; 237 | CREATE DEFINER=`root`@`localhost` PROCEDURE `einnahmeSpeichern`( 238 | IN _datum DATE, 239 | IN _kategorie VARCHAR(100), 240 | IN _art VARCHAR(100), 241 | IN _preis DECIMAL(10,2), 242 | IN _beschreibung VARCHAR(5000), 243 | IN kontoid INT 244 | ) 245 | BEGIN 246 | INSERT INTO einnahme(datum, kategorie, art, preis, beschreibung, konto) VALUES (_datum, _kategorie, _art, _preis, _beschreibung, kontoid); 247 | END ;; 248 | DELIMITER ; 249 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 250 | /*!50003 SET character_set_client = @saved_cs_client */ ; 251 | /*!50003 SET character_set_results = @saved_cs_results */ ; 252 | /*!50003 SET collation_connection = @saved_col_connection */ ; 253 | /*!50003 DROP PROCEDURE IF EXISTS `holeAusgabenMonat` */; 254 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 255 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 256 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 257 | /*!50003 SET character_set_client = utf8 */ ; 258 | /*!50003 SET character_set_results = utf8 */ ; 259 | /*!50003 SET collation_connection = utf8_general_ci */ ; 260 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 261 | /*!50003 SET sql_mode = '' */ ; 262 | DELIMITER ;; 263 | CREATE DEFINER=`root`@`localhost` PROCEDURE `holeAusgabenMonat`( 264 | IN start DATE, 265 | IN ende DATE, 266 | IN kontoid INT 267 | ) 268 | BEGIN 269 | SELECT idausgabe, datum, kategorie, art, preis, beschreibung FROM ausgabe WHERE datum BETWEEN start AND ende AND trash=0 AND konto=kontoid ORDER BY datum ASC; 270 | END ;; 271 | DELIMITER ; 272 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 273 | /*!50003 SET character_set_client = @saved_cs_client */ ; 274 | /*!50003 SET character_set_results = @saved_cs_results */ ; 275 | /*!50003 SET collation_connection = @saved_col_connection */ ; 276 | /*!50003 DROP PROCEDURE IF EXISTS `holeEinnahmenMonat` */; 277 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 278 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 279 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 280 | /*!50003 SET character_set_client = utf8 */ ; 281 | /*!50003 SET character_set_results = utf8 */ ; 282 | /*!50003 SET collation_connection = utf8_general_ci */ ; 283 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 284 | /*!50003 SET sql_mode = '' */ ; 285 | DELIMITER ;; 286 | CREATE DEFINER=`root`@`localhost` PROCEDURE `holeEinnahmenMonat`( 287 | IN start DATE, 288 | IN ende DATE, 289 | IN kontoid INT 290 | ) 291 | BEGIN 292 | SELECT ideinnahme, datum, kategorie, art, preis, beschreibung FROM einnahme WHERE datum BETWEEN start AND ende AND trash=0 AND konto=kontoid ORDER BY datum ASC; 293 | END ;; 294 | DELIMITER ; 295 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 296 | /*!50003 SET character_set_client = @saved_cs_client */ ; 297 | /*!50003 SET character_set_results = @saved_cs_results */ ; 298 | /*!50003 SET collation_connection = @saved_col_connection */ ; 299 | /*!50003 DROP PROCEDURE IF EXISTS `jahresuebersicht` */; 300 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 301 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 302 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 303 | /*!50003 SET character_set_client = utf8 */ ; 304 | /*!50003 SET character_set_results = utf8 */ ; 305 | /*!50003 SET collation_connection = utf8_general_ci */ ; 306 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 307 | /*!50003 SET sql_mode = '' */ ; 308 | DELIMITER ;; 309 | CREATE DEFINER=`root`@`localhost` PROCEDURE `jahresuebersicht`( 310 | IN jahr INT(4), 311 | IN kontoid INT 312 | ) 313 | BEGIN 314 | SELECT kategorie, sum(preis) as preis, month(datum) as monat FROM ausgabe WHERE year(datum) = jahr AND trash=0 AND konto=kontoid GROUP BY month(datum), kategorie ORDER BY kategorie ASC; 315 | END ;; 316 | DELIMITER ; 317 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 318 | /*!50003 SET character_set_client = @saved_cs_client */ ; 319 | /*!50003 SET character_set_results = @saved_cs_results */ ; 320 | /*!50003 SET collation_connection = @saved_col_connection */ ; 321 | /*!50003 DROP PROCEDURE IF EXISTS `monatsuebersicht` */; 322 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 323 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 324 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 325 | /*!50003 SET character_set_client = utf8 */ ; 326 | /*!50003 SET character_set_results = utf8 */ ; 327 | /*!50003 SET collation_connection = utf8_general_ci */ ; 328 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 329 | /*!50003 SET sql_mode = '' */ ; 330 | DELIMITER ;; 331 | CREATE DEFINER=`root`@`localhost` PROCEDURE `monatsuebersicht`( 332 | IN monat INT(2), 333 | IN jahr INT(4), 334 | IN kontoid INT 335 | ) 336 | BEGIN 337 | SELECT kategorie, sum(preis) as preis FROM ausgabe WHERE year(datum) = jahr AND month(datum) = monat AND trash=0 AND konto=kontoid GROUP BY month(datum), kategorie ORDER BY kategorie ASC; 338 | END ;; 339 | DELIMITER ; 340 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 341 | /*!50003 SET character_set_client = @saved_cs_client */ ; 342 | /*!50003 SET character_set_results = @saved_cs_results */ ; 343 | /*!50003 SET collation_connection = @saved_col_connection */ ; 344 | /*!50003 DROP PROCEDURE IF EXISTS `standardKonto` */; 345 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 346 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 347 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 348 | /*!50003 SET character_set_client = utf8 */ ; 349 | /*!50003 SET character_set_results = utf8 */ ; 350 | /*!50003 SET collation_connection = utf8_general_ci */ ; 351 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 352 | /*!50003 SET sql_mode = '' */ ; 353 | DELIMITER ;; 354 | CREATE DEFINER=`root`@`localhost` PROCEDURE `standardKonto`( 355 | IN user_name VARCHAR(20) 356 | ) 357 | BEGIN 358 | SELECT defaultkonto from user WHERE user = user_name; 359 | END ;; 360 | DELIMITER ; 361 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 362 | /*!50003 SET character_set_client = @saved_cs_client */ ; 363 | /*!50003 SET character_set_results = @saved_cs_results */ ; 364 | /*!50003 SET collation_connection = @saved_col_connection */ ; 365 | /*!50003 DROP PROCEDURE IF EXISTS `summeAusgabenMonat` */; 366 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 367 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 368 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 369 | /*!50003 SET character_set_client = utf8 */ ; 370 | /*!50003 SET character_set_results = utf8 */ ; 371 | /*!50003 SET collation_connection = utf8_general_ci */ ; 372 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 373 | /*!50003 SET sql_mode = '' */ ; 374 | DELIMITER ;; 375 | CREATE DEFINER=`root`@`localhost` PROCEDURE `summeAusgabenMonat`( 376 | IN start DATE, 377 | IN ende DATE, 378 | IN kontoid INT 379 | ) 380 | BEGIN 381 | SELECT sum(preis) FROM ausgabe WHERE datum BETWEEN start AND ende AND trash=0 AND konto=kontoid; 382 | END ;; 383 | DELIMITER ; 384 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 385 | /*!50003 SET character_set_client = @saved_cs_client */ ; 386 | /*!50003 SET character_set_results = @saved_cs_results */ ; 387 | /*!50003 SET collation_connection = @saved_col_connection */ ; 388 | /*!50003 DROP PROCEDURE IF EXISTS `summeAusgabenMonate` */; 389 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 390 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 391 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 392 | /*!50003 SET character_set_client = utf8 */ ; 393 | /*!50003 SET character_set_results = utf8 */ ; 394 | /*!50003 SET collation_connection = utf8_general_ci */ ; 395 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 396 | /*!50003 SET sql_mode = '' */ ; 397 | DELIMITER ;; 398 | CREATE DEFINER=`root`@`localhost` PROCEDURE `summeAusgabenMonate`( 399 | IN kontoid INT 400 | ) 401 | BEGIN 402 | SELECT sum(preis) as preis, month(datum) as monat, year(datum) as jahr FROM ausgabe WHERE trash=0 AND konto=kontoid GROUP BY month(datum), year(datum) ORDER BY jahr DESC, monat DESC; 403 | END ;; 404 | DELIMITER ; 405 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 406 | /*!50003 SET character_set_client = @saved_cs_client */ ; 407 | /*!50003 SET character_set_results = @saved_cs_results */ ; 408 | /*!50003 SET collation_connection = @saved_col_connection */ ; 409 | /*!50003 DROP PROCEDURE IF EXISTS `summeEinnahmenMonat` */; 410 | /*!50003 SET @saved_cs_client = @@character_set_client */ ; 411 | /*!50003 SET @saved_cs_results = @@character_set_results */ ; 412 | /*!50003 SET @saved_col_connection = @@collation_connection */ ; 413 | /*!50003 SET character_set_client = utf8 */ ; 414 | /*!50003 SET character_set_results = utf8 */ ; 415 | /*!50003 SET collation_connection = utf8_general_ci */ ; 416 | /*!50003 SET @saved_sql_mode = @@sql_mode */ ; 417 | /*!50003 SET sql_mode = '' */ ; 418 | DELIMITER ;; 419 | CREATE DEFINER=`root`@`localhost` PROCEDURE `summeEinnahmenMonat`( 420 | IN start DATE, 421 | IN ende DATE, 422 | IN kontoid INT 423 | ) 424 | BEGIN 425 | SELECT sum(preis) FROM einnahme WHERE datum BETWEEN start AND ende AND trash=0 AND konto=kontoid; 426 | END ;; 427 | DELIMITER ; 428 | /*!50003 SET sql_mode = @saved_sql_mode */ ; 429 | /*!50003 SET character_set_client = @saved_cs_client */ ; 430 | /*!50003 SET character_set_results = @saved_cs_results */ ; 431 | /*!50003 SET collation_connection = @saved_col_connection */ ; 432 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 433 | 434 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 435 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 436 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 437 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 438 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 439 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 440 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 441 | 442 | -- Dump completed on 2016-02-25 23:03:02 443 | -------------------------------------------------------------------------------- /main.css: -------------------------------------------------------------------------------- 1 | /* css reset*/ 2 | 3 | 4 | /* for buttons */ 5 | 6 | button::-moz-focus-inner, 7 | input::-moz-focus-inner { 8 | border: 0; 9 | padding: 0; 10 | } 11 | 12 | 13 | /* removes spinner buttons */ 14 | 15 | input[type=number]::-webkit-outer-spin-button, 16 | input[type=number]::-webkit-inner-spin-button { 17 | -webkit-appearance: none; 18 | margin: 0; 19 | } 20 | 21 | input[type=number] { 22 | -moz-appearance: textfield; 23 | } 24 | 25 | /* gudea-regular - latin */ 26 | @font-face { 27 | font-family: 'Gudea'; 28 | font-style: normal; 29 | font-weight: 400; 30 | src: local('Gudea'), 31 | url('fonts/gudea/gudea-v8-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ 32 | url('fonts/gudea/gudea-v8-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 33 | } 34 | 35 | /* gudea-italic - latin */ 36 | @font-face { 37 | font-family: 'Gudea'; 38 | font-style: italic; 39 | font-weight: 400; 40 | src: local('Gudea Italic'), local('Gudea-Italic'), 41 | url('fonts/gudea/gudea-v8-latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ 42 | url('fonts/gudea/gudea-v8-latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 43 | } 44 | 45 | /* gudea-700 - latin */ 46 | @font-face { 47 | font-family: 'Gudea'; 48 | font-style: normal; 49 | font-weight: 700; 50 | src: local('Gudea Bold'), local('Gudea-Bold'), 51 | url('fonts/gudea/gudea-v8-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ 52 | url('fonts/gudea/gudea-v8-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 53 | } 54 | 55 | 56 | html, 57 | body { 58 | height: 100%; 59 | margin: 0; 60 | overflow: hidden; 61 | } 62 | 63 | body, 64 | input { 65 | font-size: 16px; 66 | font-family: 'Gudea', sans-serif; 67 | } 68 | 69 | #spacertop { 70 | height: 35%; 71 | } 72 | 73 | input { 74 | border-radius: 0; 75 | } 76 | 77 | header { 78 | /*overflow: auto;*/ 79 | } 80 | 81 | h3 { 82 | padding-left: 5px; 83 | padding-right: 5px; 84 | } 85 | 86 | 87 | /* fix for FF Android background for inputs */ 88 | 89 | button, 90 | input, 91 | select { 92 | background-image: none; 93 | } 94 | 95 | .hidden { 96 | display: none; 97 | } 98 | 99 | #load { 100 | font-family: 'nsvb-symbol'; 101 | } 102 | 103 | .login-input { 104 | font-size: 16px; 105 | border: none; 106 | font-family: sans-serif; 107 | padding: 5px; 108 | border-radius: 2px; 109 | } 110 | 111 | .login-label { 112 | padding: 5px; 113 | } 114 | 115 | #logincontainer { 116 | background-color: #4bb1ff; 117 | padding-top: 20px; 118 | padding-bottom: 20px; 119 | } 120 | 121 | #login { 122 | margin: 0 auto; 123 | font-family: sans-serif; 124 | } 125 | 126 | #loginformcontainer { 127 | margin-left: 25px; 128 | margin-right: 25px; 129 | } 130 | 131 | #loginbutton { 132 | background-color: white; 133 | border: 2px solid #3388ff; 134 | padding: 5px 10px; 135 | cursor: pointer; 136 | color: #114480; 137 | font-size: 16px; 138 | border-radius: 3px; 139 | } 140 | 141 | #loginbutton:hover { 142 | background-color: #3388ff; 143 | color: white; 144 | border: 2px solid #0066ff; 145 | } 146 | 147 | #submitBtn, 148 | #submitBtn:hover { 149 | border: none; 150 | background: none; 151 | color: #114480; 152 | font-size: 16px; 153 | cursor: pointer; 154 | } 155 | 156 | :root { 157 | --bar-padding: 5px; 158 | --bar-el-padding-tb: 3px; 159 | --bar-el-padding-lr: 8px; 160 | --bar-el-br: 5px; 161 | --bar-el-brdr-w: 1px; 162 | --bar-el-margin: var(--bar-padding); 163 | --bar-line-height: 23px; 164 | } 165 | 166 | #menu { 167 | position: relative; 168 | margin-left: var(--bar-el-margin); 169 | } 170 | 171 | .bar-menu { 172 | display: none; 173 | position: absolute; 174 | right: calc(var(--bar-el-brdr-w) * -1); 175 | top: calc(var(--bar-el-brdr-w) * -1); 176 | padding: 0; 177 | overflow: hidden; 178 | } 179 | 180 | .bar-menu a { 181 | display: block; 182 | text-decoration: none; 183 | color: inherit; 184 | } 185 | 186 | .bar-menu a:visited { 187 | color: inherit; 188 | } 189 | 190 | .bar { 191 | background-color: #4bb1ff; 192 | padding: var(--bar-padding) var(--bar-padding) 0 var(--bar-padding); 193 | display: flex; 194 | align-items: flex-start; 195 | } 196 | 197 | .bar-sub { 198 | flex-grow: 1; 199 | display: flex; 200 | flex-wrap: wrap; 201 | justify-content: space-between; 202 | } 203 | 204 | .bar-collection { 205 | display: flex; 206 | } 207 | 208 | bar { 209 | background-color: white; 210 | border-radius: var(--bar-el-br); 211 | padding: var(--bar-el-padding-tb) var(--bar-el-padding-lr); 212 | border: var(--bar-el-brdr-w) solid #666666; 213 | line-height: var(--bar-line-height); 214 | } 215 | 216 | bar div { 217 | white-space: nowrap; 218 | padding: 0 var(--bar-el-padding-lr); 219 | } 220 | 221 | bar div:first-of-type { 222 | padding-top: var(--bar-el-padding-tb); 223 | } 224 | 225 | bar div:last-of-type { 226 | padding-bottom: var(--bar-el-padding-tb); 227 | } 228 | 229 | bar div:hover { 230 | background-color: #dddddd; 231 | } 232 | 233 | .bar-element { 234 | display: inline-block; 235 | margin-right: var(--bar-el-margin); 236 | min-width: 25px; 237 | text-align: center; 238 | margin-bottom: var(--bar-el-margin); 239 | } 240 | 241 | .bar-element:last-child { 242 | margin-right: 0; 243 | } 244 | 245 | .bar-element:hover { 246 | cursor: pointer; 247 | background-color: #dddddd; 248 | } 249 | 250 | /* Make search input visually match a bar element */ 251 | #search-input { 252 | background-color: white; 253 | border-radius: var(--bar-el-br); 254 | padding: var(--bar-el-padding-tb) var(--bar-el-padding-lr); 255 | border: var(--bar-el-brdr-w) solid #666666; 256 | line-height: var(--bar-line-height); 257 | min-width: 10ch; 258 | flex-grow: 1; 259 | } 260 | 261 | #search-input:focus { 262 | outline: none; 263 | box-shadow: 0 0 0 2px rgba(75,177,255,0.2); 264 | } 265 | 266 | .spacer { 267 | flex-grow: 1; 268 | min-width: var(--bar-el-margin); 269 | } 270 | 271 | .merge-start { 272 | border-radius: 5px 0 0 5px; 273 | margin-right: 0; 274 | border-right: none; 275 | } 276 | 277 | .merge-end { 278 | border-radius: 0 5px 5px 0; 279 | } 280 | 281 | #previous-month, #next-month { 282 | line-height: initial; 283 | } 284 | 285 | .active { 286 | background-color: #aaaaaa; 287 | } 288 | 289 | .active:hover { 290 | background-color: #aaaaaa; 291 | } 292 | 293 | #month { 294 | width: 15ch; 295 | } 296 | 297 | #month-overview { 298 | position: absolute; 299 | top: -1px; 300 | right: -1px; 301 | width: 250px; 302 | height: 500px; 303 | background-color: white; 304 | border-radius: 5px; 305 | padding: 10px; 306 | border: 1px solid #666666; 307 | overflow-y: scroll; 308 | cursor: auto; 309 | text-align: left; 310 | animation: open 1s; 311 | -webkit-animation: open 1s; 312 | } 313 | 314 | #konto-selection { 315 | position: relative; 316 | width: 20ch; 317 | } 318 | 319 | #konto-selection-overlay { 320 | display: none; 321 | position: absolute; 322 | right: calc(var(--bar-el-brdr-w) * -1); 323 | top: calc(var(--bar-el-brdr-w) * -1); 324 | padding: 0; 325 | overflow: hidden; 326 | /* width: calc((var(--bar-el-brdr-w) + var(--bar-el-padding-lr)) * 2 + 20ch); */ 327 | width: calc(var(--bar-el-padding-lr) * 2 + 20ch); 328 | } 329 | 330 | #konto-selection-overlay > div { 331 | padding: var(--bar-el-padding-tb) var(--bar-el-padding-lr); 332 | height: var(--bar-line-height); 333 | } 334 | 335 | .dropdown-indicator { 336 | position: absolute; 337 | right: 0; 338 | top: 0; 339 | padding: var(--bar-el-padding-tb) var(--bar-el-padding-lr); 340 | border-radius: var(--bar-el-br); 341 | } 342 | 343 | .dropdown-indicator:hover { 344 | background-color: transparent; 345 | } 346 | 347 | @-webkit-keyframes open { 348 | 0% { 349 | width: 60px; 350 | height: 120px; 351 | opacity: 0; 352 | } 353 | 100% { 354 | width: 250px; 355 | height: 500px; 356 | opacity: 1; 357 | } 358 | } 359 | 360 | @keyframes open { 361 | 0% { 362 | width: 60px; 363 | height: 120px; 364 | opacity: 0; 365 | } 366 | 100% { 367 | width: 250px; 368 | height: 500px; 369 | opacity: 1; 370 | } 371 | } 372 | 373 | .error-login { 374 | background-color: #FF6964; 375 | padding: 5px; 376 | margin-bottom: 5px; 377 | border-radius: 2px; 378 | } 379 | 380 | .right { 381 | float: right; 382 | } 383 | 384 | .left { 385 | float: left; 386 | } 387 | 388 | .cf:before, 389 | .cf:after { 390 | content: " "; 391 | display: table; 392 | } 393 | 394 | .cf:after { 395 | clear: both; 396 | } 397 | 398 | .new { 399 | animation: fadeout 3s; 400 | } 401 | 402 | @keyframes fadeout { 403 | 0% { 404 | background-color: green; 405 | } 406 | 33% { 407 | background-color: green; 408 | } 409 | 100% { 410 | background-color: none 411 | } 412 | } 413 | 414 | .remove, 415 | .edit, 416 | .cancel, 417 | .update, 418 | .restore { 419 | cursor: pointer; 420 | display: inline-block; 421 | border: 1px solid transparent; 422 | /* remove? */ 423 | } 424 | 425 | .change { 426 | display: inline-block; 427 | border: 1px solid transparent; 428 | /* remove? */ 429 | } 430 | 431 | .edit { 432 | display: none; 433 | } 434 | 435 | .update:hover { 436 | color: #8fff00; 437 | } 438 | 439 | .remove:hover, 440 | .cancel:hover { 441 | color: #D40000; 442 | } 443 | 444 | .edit:hover, 445 | .restore:hover { 446 | color: #4BB1FF; 447 | } 448 | 449 | content { 450 | border: 0 none; 451 | margin: 0 auto; 452 | max-width: 800px; 453 | padding: 0; 454 | width: 100%; 455 | font-family: sans-serif; 456 | } 457 | 458 | #content { 459 | height: 100%; 460 | display: flex; 461 | flex-direction: column; 462 | } 463 | 464 | #header { 465 | flex-shrink: 0; 466 | } 467 | 468 | #section-ausgabe { 469 | display: flex; 470 | flex-direction: column; 471 | flex-grow: 1; 472 | overflow-y: hidden; 473 | } 474 | 475 | #ausgabenliste { 476 | overflow-y: scroll; 477 | flex-grow: 1; 478 | } 479 | 480 | .ausgabe { 481 | -webkit-transition: height 1.5s ease; 482 | transition: max-height 1.5s ease, opacity 1.5s linear; 483 | max-height: 50px; 484 | } 485 | 486 | .remove-animation { 487 | max-height: 0; 488 | overflow-y: hidden; 489 | opacity: 0; 490 | } 491 | 492 | #einnahmen {} 493 | 494 | .clear { 495 | clear: both; 496 | } 497 | 498 | .error { 499 | position: absolute; 500 | background-color: #FFD036; 501 | bottom: 40px; 502 | text-align: center; 503 | padding: 5px; 504 | } 505 | 506 | .remove { 507 | cursor: pointer; 508 | } 509 | 510 | .th { 511 | font-weight: bold; 512 | border-bottom: 2px solid darkgray; 513 | flex-shrink: 0; 514 | } 515 | 516 | .th .td-preis { 517 | justify-content: flex-start; 518 | } 519 | 520 | .tr { 521 | border-bottom: 1px solid darkgray; 522 | } 523 | 524 | .tr:last-of-type { 525 | border-bottom: none; 526 | } 527 | 528 | .tr, 529 | .th { 530 | display: flex; 531 | } 532 | 533 | .tr-edit { 534 | background-color: #5bc1ff; 535 | color: white; 536 | } 537 | 538 | .td { 539 | vertical-align: top; 540 | padding-top: 5px; 541 | padding-bottom: 5px; 542 | padding-left: 5px; 543 | overflow-x: hidden; 544 | white-space: nowrap; 545 | text-overflow: ellipsis; 546 | line-height: 21px; 547 | } 548 | 549 | .td-art { 550 | flex-grow: 1; 551 | } 552 | 553 | .td input { 554 | border: none; 555 | padding: 0; 556 | width: calc(100% - 2px); 557 | outline: none; 558 | } 559 | 560 | .td input:focus-visible { 561 | outline: none; 562 | } 563 | 564 | .tr-edit input { 565 | background-color: #5bc1ff; 566 | color: white; 567 | width: calc(100% - 4px); 568 | border: 1px solid white; 569 | padding: 0 1px 2px 1px; 570 | line-height: 21px; 571 | } 572 | 573 | .tr-edit > .td { 574 | padding: 4px 0 4px 3px; 575 | } 576 | 577 | .td input.preis { 578 | flex: auto; 579 | inline-size: 3ch; 580 | } 581 | 582 | .preis { 583 | text-align: right; 584 | } 585 | 586 | .plus { 587 | cursor: pointer; 588 | } 589 | 590 | .plus:hover { 591 | color: #4bb1ff; 592 | } 593 | 594 | #plusbutton { 595 | background: transparent none repeat scroll 0px 0px; 596 | border-spacing: 0px; 597 | font-size: 16px; 598 | font-weight: normal; 599 | line-height: 1.42rem; 600 | list-style: outside none none; 601 | text-align: left; 602 | text-decoration: none; 603 | text-indent: 0px; 604 | margin: 0px; 605 | padding: 0px; 606 | border: medium none; 607 | } 608 | 609 | .td-datum { 610 | width: 9ch; 611 | flex-shrink: 0; 612 | } 613 | 614 | .tr-edit > .td-datum { 615 | width: calc(9ch + 2px); 616 | } 617 | 618 | .td-kategorie { 619 | width: 7ch; 620 | flex-shrink: 0; 621 | } 622 | 623 | .tr-edit > .td-kategorie { 624 | width: calc(7ch + 2px); 625 | } 626 | 627 | .td-preis { 628 | width: 8ch; 629 | flex-shrink: 0; 630 | display: flex; 631 | justify-content: flex-end; 632 | align-items: baseline; 633 | } 634 | 635 | .td-preis > span{ 636 | flex: none; 637 | border-bottom: 1px solid #4bb1ff; 638 | margin-bottom: 1px; 639 | line-height: 25px; 640 | } 641 | 642 | .tr-edit > .td-preis { 643 | text-align: left; 644 | width: calc(7ch + 2px); 645 | } 646 | 647 | .tr-edit > .td-preis > input { 648 | border-right: none; 649 | text-align: right; 650 | padding-right: 0; 651 | } 652 | 653 | .tr-edit > .td-preis > .input-suffix { 654 | border: 1px solid white; 655 | border-left: none; 656 | line-height: 21px; 657 | padding-bottom: 2px; 658 | padding-right: 1px; 659 | display: inline-block; 660 | text-align: right; 661 | margin-bottom: 0; 662 | } 663 | 664 | .td-beschreibung { 665 | width: 0; 666 | display: none; 667 | flex-shrink: 0; 668 | } 669 | 670 | .td-optionen { 671 | width: 30px; 672 | flex-shrink: 0; 673 | } 674 | 675 | #input-form { 676 | border-top: 2px solid darkgray; 677 | } 678 | 679 | #input input { 680 | border-bottom: 1px solid #4bb1ff; 681 | height: 25px; 682 | margin-bottom: 1px; 683 | } 684 | 685 | #input input:focus { 686 | border-bottom: 2px solid #4bb1ff; 687 | margin-bottom: 0px; 688 | } 689 | 690 | #input input:focus + span{ 691 | border-bottom: 2px solid #4bb1ff; 692 | margin-bottom: 0px; 693 | } 694 | 695 | .loading { 696 | vertical-align: middle; 697 | text-align: center; 698 | } 699 | 700 | #previous-month, 701 | #next-month { 702 | -webkit-user-select: none; 703 | /* Chrome/Safari */ 704 | -moz-user-select: none; 705 | /* Firefox */ 706 | -ms-user-select: none; 707 | /* IE10+ */ 708 | /* Rules below not implemented in browsers yet */ 709 | -o-user-select: none; 710 | user-select: none; 711 | } 712 | 713 | .error:after { 714 | content: ""; 715 | position: absolute; 716 | width: 0; 717 | height: 0; 718 | border-width: 10px; 719 | border-style: solid; 720 | border-color: #FFD036 transparent transparent transparent; 721 | top: 29px; 722 | left: 15px; 723 | } 724 | 725 | #overlay { 726 | display: none; 727 | background-color: #4BB1FF; 728 | height: 100%; 729 | /* overflow-x: hidden; */ 730 | flex-direction: column; 731 | /* TODO: optimize, maybe scroll select list */ 732 | } 733 | 734 | #overlay-close { 735 | margin-left: var(--bar-el-margin); 736 | } 737 | 738 | #overlay-close:hover { 739 | cursor: pointer; 740 | } 741 | 742 | #overlay-content { 743 | padding: 0 5px 5px 5px; 744 | overflow-y: scroll; 745 | } 746 | 747 | #select { 748 | display: none; 749 | } 750 | 751 | #details:hover { 752 | text-decoration: underline; 753 | cursor: pointer; 754 | } 755 | 756 | #stats-wrapper { 757 | /*display: table;*/ 758 | /*table doesn't resize smaller*/ 759 | border: 1px solid #666666; 760 | border-radius: 5px; 761 | background-color: white; 762 | width: 100%; 763 | clear: right; 764 | flex-grow: 1; 765 | } 766 | 767 | .flex-row { 768 | display: flex; 769 | flex-direction: row; 770 | } 771 | 772 | #details { 773 | float: right; 774 | } 775 | 776 | .chart { 777 | width: 100%; 778 | min-height: 500px; 779 | } 780 | 781 | #chart-category-select { 782 | display: inline-block; 783 | } 784 | 785 | #empty { 786 | color: lightgray; 787 | } 788 | 789 | .vert-center { 790 | position: relative; 791 | top: 50%; 792 | transform: translateY(-50%); 793 | } 794 | 795 | .text-center { 796 | text-align: center; 797 | } 798 | 799 | .preload-symbol { 800 | font-family: 'nsvb-symbol'; 801 | } 802 | 803 | #trash-section { 804 | display: flex; 805 | flex-direction: column; 806 | background-color: white; 807 | overflow-y: auto; 808 | } 809 | 810 | #trash-list { 811 | overflow-y: scroll; 812 | flex-grow: 1; 813 | } 814 | 815 | /* Search section uses same layout as trash-section */ 816 | #search-section { 817 | display: flex; 818 | flex-direction: column; 819 | background-color: white; 820 | overflow-y: auto; 821 | } 822 | 823 | #search-results { 824 | overflow-y: scroll; 825 | flex-grow: 1; 826 | } 827 | 828 | /* per-category search block and rows container */ 829 | .search-block { 830 | display: flex; 831 | flex-direction: column; 832 | background-color: white; 833 | } 834 | 835 | .search-rows { 836 | overflow-y: auto; 837 | flex-grow: 1; 838 | } 839 | 840 | @media (min-width:400px) { 841 | #login { 842 | max-width: 360px; 843 | } 844 | .td-kategorie { 845 | width: 10ch; 846 | } 847 | .tr-edit > .td-kategorie { 848 | width: calc(10ch + 2px); 849 | } 850 | } 851 | 852 | @media (min-width:600px) { 853 | .edit { 854 | display: inline-block; 855 | } 856 | .td-optionen { 857 | width: 50px; 858 | } 859 | } 860 | 861 | @media (max-width: 699px) { 862 | #input-datum{ 863 | display: none; 864 | } 865 | #opendatepicker{ 866 | display: none !important; 867 | } 868 | .bar-sub { 869 | justify-content: space-around; 870 | } 871 | } 872 | 873 | @media (min-width:700px) { 874 | body { 875 | min-width: 700px; 876 | } 877 | .td-datum { 878 | display: flex; 879 | width: 11ch; 880 | position: relative; 881 | } 882 | .tr-edit > .td-datum { 883 | width: calc(11ch + 2px); 884 | } 885 | #input-datum { 886 | /*flex: auto;*/ 887 | } 888 | #datepicker{ 889 | z-index: -1; 890 | position: absolute; 891 | width: 1px; 892 | padding: 0px; 893 | border: 0px; 894 | background: none; 895 | color: transparent; 896 | outline: none; 897 | } 898 | #opendatepicker{ 899 | cursor: pointer; 900 | display: none; 901 | } 902 | .td-beschreibung { 903 | width: 150px; 904 | display: inherit; 905 | } 906 | .tr-edit > .td-beschreibung { 907 | width: calc(150px + 2px); 908 | } 909 | .td-kategorie { 910 | width: 15ch; 911 | } 912 | .tr-edit > .td-kategorie { 913 | width: calc(15ch + 2px); 914 | } 915 | .td-preis { 916 | width: 10ch; 917 | } 918 | .tr-edit > .td-preis { 919 | text-align: left; 920 | width: calc(10ch + 2px); 921 | } 922 | #month { 923 | width: 20ch; 924 | } 925 | #select-mobile { 926 | display: none; 927 | } 928 | #select { 929 | display: block; 930 | width: 201px; 931 | margin: 10px 0; 932 | /*margin-right: 20px;*/ 933 | z-index: 1; 934 | } 935 | .select-element { 936 | padding: 10px; 937 | border: 1px solid transparent; 938 | border-right: none; 939 | } 940 | .select-element:hover { 941 | cursor: pointer; 942 | border: 1px solid #666666; 943 | border-right: none; 944 | border-radius: 5px 0 0 5px; 945 | background-color: #4BB1FF; 946 | } 947 | .select-element.year { 948 | text-decoration: underline; 949 | font-weight: bold; 950 | } 951 | .select-element.active { 952 | /*background-color: #4BB1FF;*/ 953 | border: 1px solid #666666; 954 | border-right: none; 955 | border-radius: 5px 0 0 5px; 956 | background-color: white; 957 | } 958 | #stats-wrapper { 959 | display: block; 960 | padding: 10px 15px; 961 | width: auto; 962 | margin-left: -1px; 963 | } 964 | } 965 | -------------------------------------------------------------------------------- /js/moment.min.js: -------------------------------------------------------------------------------- 1 | //! moment.js 2 | //! version : 2.11.2 3 | //! authors : Tim Wood, Iskren Chernev, Moment.js contributors 4 | //! license : MIT 5 | //! momentjs.com 6 | !function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return Uc.apply(null,arguments)}function b(a){Uc=a}function c(a){return"[object Array]"===Object.prototype.toString.call(a)}function d(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function e(a,b){var c,d=[];for(c=0;c0)for(c in Wc)d=Wc[c],e=b[d],m(e)||(a[d]=e);return a}function o(b){n(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),Xc===!1&&(Xc=!0,a.updateOffset(this),Xc=!1)}function p(a){return a instanceof o||null!=a&&null!=a._isAMomentObject}function q(a){return 0>a?Math.ceil(a):Math.floor(a)}function r(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=q(b)),c}function s(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&r(a[d])!==r(b[d]))&&g++;return g+f}function t(){}function u(a){return a?a.toLowerCase().replace("_","-"):a}function v(a){for(var b,c,d,e,f=0;f0;){if(d=w(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&s(e,c,!0)>=b-1)break;b--}f++}return null}function w(a){var b=null;if(!Yc[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=Vc._abbr,require("./locale/"+a),x(b)}catch(c){}return Yc[a]}function x(a,b){var c;return a&&(c=m(b)?z(a):y(a,b),c&&(Vc=c)),Vc._abbr}function y(a,b){return null!==b?(b.abbr=a,Yc[a]=Yc[a]||new t,Yc[a].set(b),x(a),Yc[a]):(delete Yc[a],null)}function z(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Vc;if(!c(a)){if(b=w(a))return b;a=[a]}return v(a)}function A(a,b){var c=a.toLowerCase();Zc[c]=Zc[c+"s"]=Zc[b]=a}function B(a){return"string"==typeof a?Zc[a]||Zc[a.toLowerCase()]:void 0}function C(a){var b,c,d={};for(c in a)f(a,c)&&(b=B(c),b&&(d[b]=a[c]));return d}function D(a){return a instanceof Function||"[object Function]"===Object.prototype.toString.call(a)}function E(b,c){return function(d){return null!=d?(G(this,b,d),a.updateOffset(this,c),this):F(this,b)}}function F(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function G(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)}function H(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else if(a=B(a),D(this[a]))return this[a](b);return this}function I(a,b,c){var d=""+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}function J(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(bd[a]=e),b&&(bd[b[0]]=function(){return I(e.apply(this,arguments),b[1],b[2])}),c&&(bd[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function K(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function L(a){var b,c,d=a.match($c);for(b=0,c=d.length;c>b;b++)bd[d[b]]?d[b]=bd[d[b]]:d[b]=K(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function M(a,b){return a.isValid()?(b=N(b,a.localeData()),ad[b]=ad[b]||L(b),ad[b](a)):a.localeData().invalidDate()}function N(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(_c.lastIndex=0;d>=0&&_c.test(a);)a=a.replace(_c,c),_c.lastIndex=0,d-=1;return a}function O(a,b,c){td[a]=D(b)?b:function(a,d){return a&&c?c:b}}function P(a,b){return f(td,a)?td[a](b._strict,b._locale):new RegExp(Q(a))}function Q(a){return R(a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function R(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function S(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=r(a)}),c=0;cd;d++){if(e=h([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}function Z(a,b){var c;return a.isValid()?"string"==typeof b&&(b=a.localeData().monthsParse(b),"number"!=typeof b)?a:(c=Math.min(a.date(),V(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a):a}function $(b){return null!=b?(Z(this,b),a.updateOffset(this,!0),this):F(this,"Month")}function _(){return V(this.year(),this.month())}function aa(a){return this._monthsParseExact?(f(this,"_monthsRegex")||ca.call(this),a?this._monthsShortStrictRegex:this._monthsShortRegex):this._monthsShortStrictRegex&&a?this._monthsShortStrictRegex:this._monthsShortRegex}function ba(a){return this._monthsParseExact?(f(this,"_monthsRegex")||ca.call(this),a?this._monthsStrictRegex:this._monthsRegex):this._monthsStrictRegex&&a?this._monthsStrictRegex:this._monthsRegex}function ca(){function a(a,b){return b.length-a.length}var b,c,d=[],e=[],f=[];for(b=0;12>b;b++)c=h([2e3,b]),d.push(this.monthsShort(c,"")),e.push(this.months(c,"")),f.push(this.months(c,"")),f.push(this.monthsShort(c,""));for(d.sort(a),e.sort(a),f.sort(a),b=0;12>b;b++)d[b]=R(d[b]),e[b]=R(e[b]),f[b]=R(f[b]);this._monthsRegex=new RegExp("^("+f.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+e.join("|")+")$","i"),this._monthsShortStrictRegex=new RegExp("^("+d.join("|")+")$","i")}function da(a){var b,c=a._a;return c&&-2===j(a).overflow&&(b=c[wd]<0||c[wd]>11?wd:c[xd]<1||c[xd]>V(c[vd],c[wd])?xd:c[yd]<0||c[yd]>24||24===c[yd]&&(0!==c[zd]||0!==c[Ad]||0!==c[Bd])?yd:c[zd]<0||c[zd]>59?zd:c[Ad]<0||c[Ad]>59?Ad:c[Bd]<0||c[Bd]>999?Bd:-1,j(a)._overflowDayOfYear&&(vd>b||b>xd)&&(b=xd),j(a)._overflowWeeks&&-1===b&&(b=Cd),j(a)._overflowWeekday&&-1===b&&(b=Dd),j(a).overflow=b),a}function ea(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function fa(a,b){var c=!0;return g(function(){return c&&(ea(a+"\nArguments: "+Array.prototype.slice.call(arguments).join(", ")+"\n"+(new Error).stack),c=!1),b.apply(this,arguments)},b)}function ga(a,b){Jd[a]||(ea(b),Jd[a]=!0)}function ha(a){var b,c,d,e,f,g,h=a._i,i=Kd.exec(h)||Ld.exec(h);if(i){for(j(a).iso=!0,b=0,c=Nd.length;c>b;b++)if(Nd[b][1].exec(i[1])){e=Nd[b][0],d=Nd[b][2]!==!1;break}if(null==e)return void(a._isValid=!1);if(i[3]){for(b=0,c=Od.length;c>b;b++)if(Od[b][1].exec(i[3])){f=(i[2]||" ")+Od[b][0];break}if(null==f)return void(a._isValid=!1)}if(!d&&null!=f)return void(a._isValid=!1);if(i[4]){if(!Md.exec(i[4]))return void(a._isValid=!1);g="Z"}a._f=e+(f||"")+(g||""),wa(a)}else a._isValid=!1}function ia(b){var c=Pd.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(ha(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}function ja(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 100>a&&a>=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function ka(a){var b=new Date(Date.UTC.apply(null,arguments));return 100>a&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}function la(a){return ma(a)?366:365}function ma(a){return a%4===0&&a%100!==0||a%400===0}function na(){return ma(this.year())}function oa(a,b,c){var d=7+b-c,e=(7+ka(a,0,d).getUTCDay()-b)%7;return-e+d-1}function pa(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=oa(a,d,e),j=1+7*(b-1)+h+i;return 0>=j?(f=a-1,g=la(f)+j):j>la(a)?(f=a+1,g=j-la(a)):(f=a,g=j),{year:f,dayOfYear:g}}function qa(a,b,c){var d,e,f=oa(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return 1>g?(e=a.year()-1,d=g+ra(e,b,c)):g>ra(a.year(),b,c)?(d=g-ra(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function ra(a,b,c){var d=oa(a,b,c),e=oa(a+1,b,c);return(la(a)-d+e)/7}function sa(a,b,c){return null!=a?a:null!=b?b:c}function ta(b){var c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}function ua(a){var b,c,d,e,f=[];if(!a._d){for(d=ta(a),a._w&&null==a._a[xd]&&null==a._a[wd]&&va(a),a._dayOfYear&&(e=sa(a._a[vd],d[vd]),a._dayOfYear>la(e)&&(j(a)._overflowDayOfYear=!0),c=ka(e,0,a._dayOfYear),a._a[wd]=c.getUTCMonth(),a._a[xd]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;7>b;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[yd]&&0===a._a[zd]&&0===a._a[Ad]&&0===a._a[Bd]&&(a._nextDay=!0,a._a[yd]=0),a._d=(a._useUTC?ka:ja).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[yd]=24)}}function va(a){var b,c,d,e,f,g,h,i;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=sa(b.GG,a._a[vd],qa(Ea(),1,4).year),d=sa(b.W,1),e=sa(b.E,1),(1>e||e>7)&&(i=!0)):(f=a._locale._week.dow,g=a._locale._week.doy,c=sa(b.gg,a._a[vd],qa(Ea(),f,g).year),d=sa(b.w,1),null!=b.d?(e=b.d,(0>e||e>6)&&(i=!0)):null!=b.e?(e=b.e+f,(b.e<0||b.e>6)&&(i=!0)):e=f),1>d||d>ra(c,f,g)?j(a)._overflowWeeks=!0:null!=i?j(a)._overflowWeekday=!0:(h=pa(c,d,e,f,g),a._a[vd]=h.year,a._dayOfYear=h.dayOfYear)}function wa(b){if(b._f===a.ISO_8601)return void ha(b);b._a=[],j(b).empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,k=0;for(e=N(b._f,b._locale).match($c)||[],c=0;c0&&j(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),k+=d.length),bd[f]?(d?j(b).empty=!1:j(b).unusedTokens.push(f),U(f,d,b)):b._strict&&!d&&j(b).unusedTokens.push(f);j(b).charsLeftOver=i-k,h.length>0&&j(b).unusedInput.push(h),j(b).bigHour===!0&&b._a[yd]<=12&&b._a[yd]>0&&(j(b).bigHour=void 0),b._a[yd]=xa(b._locale,b._a[yd],b._meridiem),ua(b),da(b)}function xa(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function ya(a){var b,c,d,e,f;if(0===a._f.length)return j(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;ef)&&(d=f,c=b));g(a,c||b)}function za(a){if(!a._d){var b=C(a._i);a._a=e([b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],function(a){return a&&parseInt(a,10)}),ua(a)}}function Aa(a){var b=new o(da(Ba(a)));return b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b}function Ba(a){var b=a._i,e=a._f;return a._locale=a._locale||z(a._l),null===b||void 0===e&&""===b?l({nullInput:!0}):("string"==typeof b&&(a._i=b=a._locale.preparse(b)),p(b)?new o(da(b)):(c(e)?ya(a):e?wa(a):d(b)?a._d=b:Ca(a),k(a)||(a._d=null),a))}function Ca(b){var f=b._i;void 0===f?b._d=new Date(a.now()):d(f)?b._d=new Date(+f):"string"==typeof f?ia(b):c(f)?(b._a=e(f.slice(0),function(a){return parseInt(a,10)}),ua(b)):"object"==typeof f?za(b):"number"==typeof f?b._d=new Date(f):a.createFromInputFallback(b)}function Da(a,b,c,d,e){var f={};return"boolean"==typeof c&&(d=c,c=void 0),f._isAMomentObject=!0,f._useUTC=f._isUTC=e,f._l=c,f._i=a,f._f=b,f._strict=d,Aa(f)}function Ea(a,b,c,d){return Da(a,b,c,d,!1)}function Fa(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return Ea();for(d=b[0],e=1;ea&&(a=-a,c="-"),c+I(~~(a/60),2)+b+I(~~a%60,2)})}function La(a,b){var c=(b||"").match(a)||[],d=c[c.length-1]||[],e=(d+"").match(Ud)||["-",0,0],f=+(60*e[1])+r(e[2]);return"+"===e[0]?f:-f}function Ma(b,c){var e,f;return c._isUTC?(e=c.clone(),f=(p(b)||d(b)?+b:+Ea(b))-+e,e._d.setTime(+e._d+f),a.updateOffset(e,!1),e):Ea(b).local()}function Na(a){return 15*-Math.round(a._d.getTimezoneOffset()/15)}function Oa(b,c){var d,e=this._offset||0;return this.isValid()?null!=b?("string"==typeof b?b=La(qd,b):Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Na(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?cb(this,Za(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Na(this):null!=b?this:NaN}function Pa(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Qa(a){return this.utcOffset(0,a)}function Ra(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Na(this),"m")),this}function Sa(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(La(pd,this._i)),this}function Ta(a){return this.isValid()?(a=a?Ea(a).utcOffset():0,(this.utcOffset()-a)%60===0):!1}function Ua(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Va(){if(!m(this._isDSTShifted))return this._isDSTShifted;var a={};if(n(a,this),a=Ba(a),a._a){var b=a._isUTC?h(a._a):Ea(a._a);this._isDSTShifted=this.isValid()&&s(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Wa(){return this.isValid()?!this._isUTC:!1}function Xa(){return this.isValid()?this._isUTC:!1}function Ya(){return this.isValid()?this._isUTC&&0===this._offset:!1}function Za(a,b){var c,d,e,g=a,h=null;return Ja(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(g={},b?g[b]=a:g.milliseconds=a):(h=Vd.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:r(h[xd])*c,h:r(h[yd])*c,m:r(h[zd])*c,s:r(h[Ad])*c,ms:r(h[Bd])*c}):(h=Wd.exec(a))?(c="-"===h[1]?-1:1,g={y:$a(h[2],c),M:$a(h[3],c),d:$a(h[4],c),h:$a(h[5],c),m:$a(h[6],c),s:$a(h[7],c),w:$a(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=ab(Ea(g.from),Ea(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new Ia(g),Ja(a)&&f(a,"_locale")&&(d._locale=a._locale),d}function $a(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function _a(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function ab(a,b){var c;return a.isValid()&&b.isValid()?(b=Ma(b,a),a.isBefore(b)?c=_a(a,b):(c=_a(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}function bb(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(ga(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Za(c,d),cb(this,e,a),this}}function cb(b,c,d,e){var f=c._milliseconds,g=c._days,h=c._months;b.isValid()&&(e=null==e?!0:e,f&&b._d.setTime(+b._d+f*d),g&&G(b,"Date",F(b,"Date")+g*d),h&&Z(b,F(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function db(a,b){var c=a||Ea(),d=Ma(c,this).startOf("day"),e=this.diff(d,"days",!0),f=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse",g=b&&(D(b[f])?b[f]():b[f]);return this.format(g||this.localeData().calendar(f,this,Ea(c)))}function eb(){return new o(this)}function fb(a,b){var c=p(a)?a:Ea(a);return this.isValid()&&c.isValid()?(b=B(m(b)?"millisecond":b),"millisecond"===b?+this>+c:+c<+this.clone().startOf(b)):!1}function gb(a,b){var c=p(a)?a:Ea(a);return this.isValid()&&c.isValid()?(b=B(m(b)?"millisecond":b),"millisecond"===b?+c>+this:+this.clone().endOf(b)<+c):!1}function hb(a,b,c){return this.isAfter(a,c)&&this.isBefore(b,c)}function ib(a,b){var c,d=p(a)?a:Ea(a);return this.isValid()&&d.isValid()?(b=B(b||"millisecond"),"millisecond"===b?+this===+d:(c=+d,+this.clone().startOf(b)<=c&&c<=+this.clone().endOf(b))):!1}function jb(a,b){return this.isSame(a,b)||this.isAfter(a,b)}function kb(a,b){return this.isSame(a,b)||this.isBefore(a,b)}function lb(a,b,c){var d,e,f,g;return this.isValid()?(d=Ma(a,this),d.isValid()?(e=6e4*(d.utcOffset()-this.utcOffset()),b=B(b),"year"===b||"month"===b||"quarter"===b?(g=mb(this,d),"quarter"===b?g/=3:"year"===b&&(g/=12)):(f=this-d,g="second"===b?f/1e3:"minute"===b?f/6e4:"hour"===b?f/36e5:"day"===b?(f-e)/864e5:"week"===b?(f-e)/6048e5:f),c?g:q(g)):NaN):NaN}function mb(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function nb(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function ob(){var a=this.clone().utc();return 0f&&(b=f),Ob.call(this,a,b,c,d,e))}function Ob(a,b,c,d,e){var f=pa(a,b,c,d,e),g=ka(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}function Pb(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}function Qb(a){return qa(a,this._week.dow,this._week.doy).week}function Rb(){return this._week.dow}function Sb(){return this._week.doy}function Tb(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function Ub(a){var b=qa(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function Vb(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Wb(a,b){return c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]}function Xb(a){return this._weekdaysShort[a.day()]}function Yb(a){return this._weekdaysMin[a.day()]}function Zb(a,b,c){var d,e,f;for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;7>d;d++){if(e=Ea([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}function $b(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Vb(a,this.localeData()),this.add(a-b,"d")):b}function _b(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function ac(a){return this.isValid()?null==a?this.day()||7:this.day(this.day()%7?a:a-7):null!=a?this:NaN}function bc(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function cc(){return this.hours()%12||12}function dc(a,b){J(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function ec(a,b){return b._meridiemParse}function fc(a){return"p"===(a+"").toLowerCase().charAt(0)}function gc(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function hc(a,b){b[Bd]=r(1e3*("0."+a))}function ic(){return this._isUTC?"UTC":""}function jc(){return this._isUTC?"Coordinated Universal Time":""}function kc(a){return Ea(1e3*a)}function lc(){return Ea.apply(null,arguments).parseZone()}function mc(a,b,c){var d=this._calendar[a];return D(d)?d.call(b,c):d}function nc(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function oc(){return this._invalidDate}function pc(a){return this._ordinal.replace("%d",a)}function qc(a){return a}function rc(a,b,c,d){var e=this._relativeTime[c];return D(e)?e(a,b,c,d):e.replace(/%d/i,a)}function sc(a,b){var c=this._relativeTime[a>0?"future":"past"];return D(c)?c(b):c.replace(/%s/i,b)}function tc(a){var b,c;for(c in a)b=a[c],D(b)?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function uc(a,b,c,d){var e=z(),f=h().set(d,b);return e[c](f,a)}function vc(a,b,c,d,e){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return uc(a,b,c,e);var f,g=[];for(f=0;d>f;f++)g[f]=uc(a,f,c,e);return g}function wc(a,b){return vc(a,b,"months",12,"month")}function xc(a,b){return vc(a,b,"monthsShort",12,"month")}function yc(a,b){return vc(a,b,"weekdays",7,"day")}function zc(a,b){return vc(a,b,"weekdaysShort",7,"day")}function Ac(a,b){return vc(a,b,"weekdaysMin",7,"day")}function Bc(){var a=this._data;return this._milliseconds=se(this._milliseconds),this._days=se(this._days),this._months=se(this._months),a.milliseconds=se(a.milliseconds),a.seconds=se(a.seconds),a.minutes=se(a.minutes),a.hours=se(a.hours),a.months=se(a.months),a.years=se(a.years),this}function Cc(a,b,c,d){var e=Za(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function Dc(a,b){return Cc(this,a,b,1)}function Ec(a,b){return Cc(this,a,b,-1)}function Fc(a){return 0>a?Math.floor(a):Math.ceil(a)}function Gc(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;return f>=0&&g>=0&&h>=0||0>=f&&0>=g&&0>=h||(f+=864e5*Fc(Ic(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=q(f/1e3),i.seconds=a%60,b=q(a/60),i.minutes=b%60,c=q(b/60),i.hours=c%24,g+=q(c/24),e=q(Hc(g)),h+=e,g-=Fc(Ic(e)),d=q(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function Hc(a){return 4800*a/146097}function Ic(a){return 146097*a/4800}function Jc(a){var b,c,d=this._milliseconds;if(a=B(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+Hc(b),"month"===a?c:c/12;switch(b=this._days+Math.round(Ic(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}function Kc(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*r(this._months/12)}function Lc(a){return function(){return this.as(a)}}function Mc(a){return a=B(a),this[a+"s"]()}function Nc(a){return function(){return this._data[a]}}function Oc(){return q(this.days()/7)}function Pc(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function Qc(a,b,c){var d=Za(a).abs(),e=Ie(d.as("s")),f=Ie(d.as("m")),g=Ie(d.as("h")),h=Ie(d.as("d")),i=Ie(d.as("M")),j=Ie(d.as("y")),k=e=f&&["m"]||f=g&&["h"]||g=h&&["d"]||h=i&&["M"]||i=j&&["y"]||["yy",j];return k[2]=b,k[3]=+a>0,k[4]=c,Pc.apply(null,k)}function Rc(a,b){return void 0===Je[a]?!1:void 0===b?Je[a]:(Je[a]=b,!0)}function Sc(a){var b=this.localeData(),c=Qc(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function Tc(){var a,b,c,d=Ke(this._milliseconds)/1e3,e=Ke(this._days),f=Ke(this._months);a=q(d/60),b=q(a/60),d%=60,a%=60,c=q(f/12),f%=12;var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(0>m?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var Uc,Vc,Wc=a.momentProperties=[],Xc=!1,Yc={},Zc={},$c=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,_c=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,ad={},bd={},cd=/\d/,dd=/\d\d/,ed=/\d{3}/,fd=/\d{4}/,gd=/[+-]?\d{6}/,hd=/\d\d?/,id=/\d\d\d\d?/,jd=/\d\d\d\d\d\d?/,kd=/\d{1,3}/,ld=/\d{1,4}/,md=/[+-]?\d{1,6}/,nd=/\d+/,od=/[+-]?\d+/,pd=/Z|[+-]\d\d:?\d\d/gi,qd=/Z|[+-]\d\d(?::?\d\d)?/gi,rd=/[+-]?\d+(\.\d{1,3})?/,sd=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,td={},ud={},vd=0,wd=1,xd=2,yd=3,zd=4,Ad=5,Bd=6,Cd=7,Dd=8;J("M",["MM",2],"Mo",function(){return this.month()+1}),J("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),J("MMMM",0,0,function(a){return this.localeData().months(this,a)}),A("month","M"),O("M",hd),O("MM",hd,dd),O("MMM",function(a,b){return b.monthsShortRegex(a)}),O("MMMM",function(a,b){return b.monthsRegex(a)}),S(["M","MM"],function(a,b){b[wd]=r(a)-1}),S(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[wd]=e:j(c).invalidMonth=a});var Ed=/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/,Fd="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),Gd="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),Hd=sd,Id=sd,Jd={};a.suppressDeprecationWarnings=!1;var Kd=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,Ld=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,Md=/Z|[+-]\d\d(?::?\d\d)?/,Nd=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Od=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Pd=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=fa("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),J("Y",0,0,function(){var a=this.year();return 9999>=a?""+a:"+"+a}),J(0,["YY",2],0,function(){return this.year()%100}),J(0,["YYYY",4],0,"year"),J(0,["YYYYY",5],0,"year"),J(0,["YYYYYY",6,!0],0,"year"),A("year","y"),O("Y",od),O("YY",hd,dd),O("YYYY",ld,fd),O("YYYYY",md,gd),O("YYYYYY",md,gd),S(["YYYYY","YYYYYY"],vd),S("YYYY",function(b,c){c[vd]=2===b.length?a.parseTwoDigitYear(b):r(b)}),S("YY",function(b,c){c[vd]=a.parseTwoDigitYear(b)}),S("Y",function(a,b){b[vd]=parseInt(a,10)}),a.parseTwoDigitYear=function(a){return r(a)+(r(a)>68?1900:2e3)};var Qd=E("FullYear",!1);a.ISO_8601=function(){};var Rd=fa("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var a=Ea.apply(null,arguments);return this.isValid()&&a.isValid()?this>a?this:a:l()}),Sd=fa("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var a=Ea.apply(null,arguments);return this.isValid()&&a.isValid()?a>this?this:a:l()}),Td=function(){return Date.now?Date.now():+new Date};Ka("Z",":"),Ka("ZZ",""),O("Z",qd),O("ZZ",qd),S(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=La(qd,a)});var Ud=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var Vd=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/,Wd=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/; 7 | Za.fn=Ia.prototype;var Xd=bb(1,"add"),Yd=bb(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var Zd=fa("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});J(0,["gg",2],0,function(){return this.weekYear()%100}),J(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Ib("gggg","weekYear"),Ib("ggggg","weekYear"),Ib("GGGG","isoWeekYear"),Ib("GGGGG","isoWeekYear"),A("weekYear","gg"),A("isoWeekYear","GG"),O("G",od),O("g",od),O("GG",hd,dd),O("gg",hd,dd),O("GGGG",ld,fd),O("gggg",ld,fd),O("GGGGG",md,gd),O("ggggg",md,gd),T(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=r(a)}),T(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),J("Q",0,"Qo","quarter"),A("quarter","Q"),O("Q",cd),S("Q",function(a,b){b[wd]=3*(r(a)-1)}),J("w",["ww",2],"wo","week"),J("W",["WW",2],"Wo","isoWeek"),A("week","w"),A("isoWeek","W"),O("w",hd),O("ww",hd,dd),O("W",hd),O("WW",hd,dd),T(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=r(a)});var $d={dow:0,doy:6};J("D",["DD",2],"Do","date"),A("date","D"),O("D",hd),O("DD",hd,dd),O("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),S(["D","DD"],xd),S("Do",function(a,b){b[xd]=r(a.match(hd)[0],10)});var _d=E("Date",!0);J("d",0,"do","day"),J("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),J("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),J("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),J("e",0,0,"weekday"),J("E",0,0,"isoWeekday"),A("day","d"),A("weekday","e"),A("isoWeekday","E"),O("d",hd),O("e",hd),O("E",hd),O("dd",sd),O("ddd",sd),O("dddd",sd),T(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);null!=e?b.d=e:j(c).invalidWeekday=a}),T(["d","e","E"],function(a,b,c,d){b[d]=r(a)});var ae="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),be="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),ce="Su_Mo_Tu_We_Th_Fr_Sa".split("_");J("DDD",["DDDD",3],"DDDo","dayOfYear"),A("dayOfYear","DDD"),O("DDD",kd),O("DDDD",ed),S(["DDD","DDDD"],function(a,b,c){c._dayOfYear=r(a)}),J("H",["HH",2],0,"hour"),J("h",["hh",2],0,cc),J("hmm",0,0,function(){return""+cc.apply(this)+I(this.minutes(),2)}),J("hmmss",0,0,function(){return""+cc.apply(this)+I(this.minutes(),2)+I(this.seconds(),2)}),J("Hmm",0,0,function(){return""+this.hours()+I(this.minutes(),2)}),J("Hmmss",0,0,function(){return""+this.hours()+I(this.minutes(),2)+I(this.seconds(),2)}),dc("a",!0),dc("A",!1),A("hour","h"),O("a",ec),O("A",ec),O("H",hd),O("h",hd),O("HH",hd,dd),O("hh",hd,dd),O("hmm",id),O("hmmss",jd),O("Hmm",id),O("Hmmss",jd),S(["H","HH"],yd),S(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),S(["h","hh"],function(a,b,c){b[yd]=r(a),j(c).bigHour=!0}),S("hmm",function(a,b,c){var d=a.length-2;b[yd]=r(a.substr(0,d)),b[zd]=r(a.substr(d)),j(c).bigHour=!0}),S("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[yd]=r(a.substr(0,d)),b[zd]=r(a.substr(d,2)),b[Ad]=r(a.substr(e)),j(c).bigHour=!0}),S("Hmm",function(a,b,c){var d=a.length-2;b[yd]=r(a.substr(0,d)),b[zd]=r(a.substr(d))}),S("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[yd]=r(a.substr(0,d)),b[zd]=r(a.substr(d,2)),b[Ad]=r(a.substr(e))});var de=/[ap]\.?m?\.?/i,ee=E("Hours",!0);J("m",["mm",2],0,"minute"),A("minute","m"),O("m",hd),O("mm",hd,dd),S(["m","mm"],zd);var fe=E("Minutes",!1);J("s",["ss",2],0,"second"),A("second","s"),O("s",hd),O("ss",hd,dd),S(["s","ss"],Ad);var ge=E("Seconds",!1);J("S",0,0,function(){return~~(this.millisecond()/100)}),J(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),J(0,["SSS",3],0,"millisecond"),J(0,["SSSS",4],0,function(){return 10*this.millisecond()}),J(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),J(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),J(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),J(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),J(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),A("millisecond","ms"),O("S",kd,cd),O("SS",kd,dd),O("SSS",kd,ed);var he;for(he="SSSS";he.length<=9;he+="S")O(he,nd);for(he="S";he.length<=9;he+="S")S(he,hc);var ie=E("Milliseconds",!1);J("z",0,0,"zoneAbbr"),J("zz",0,0,"zoneName");var je=o.prototype;je.add=Xd,je.calendar=db,je.clone=eb,je.diff=lb,je.endOf=xb,je.format=pb,je.from=qb,je.fromNow=rb,je.to=sb,je.toNow=tb,je.get=H,je.invalidAt=Gb,je.isAfter=fb,je.isBefore=gb,je.isBetween=hb,je.isSame=ib,je.isSameOrAfter=jb,je.isSameOrBefore=kb,je.isValid=Eb,je.lang=Zd,je.locale=ub,je.localeData=vb,je.max=Sd,je.min=Rd,je.parsingFlags=Fb,je.set=H,je.startOf=wb,je.subtract=Yd,je.toArray=Bb,je.toObject=Cb,je.toDate=Ab,je.toISOString=ob,je.toJSON=Db,je.toString=nb,je.unix=zb,je.valueOf=yb,je.creationData=Hb,je.year=Qd,je.isLeapYear=na,je.weekYear=Jb,je.isoWeekYear=Kb,je.quarter=je.quarters=Pb,je.month=$,je.daysInMonth=_,je.week=je.weeks=Tb,je.isoWeek=je.isoWeeks=Ub,je.weeksInYear=Mb,je.isoWeeksInYear=Lb,je.date=_d,je.day=je.days=$b,je.weekday=_b,je.isoWeekday=ac,je.dayOfYear=bc,je.hour=je.hours=ee,je.minute=je.minutes=fe,je.second=je.seconds=ge,je.millisecond=je.milliseconds=ie,je.utcOffset=Oa,je.utc=Qa,je.local=Ra,je.parseZone=Sa,je.hasAlignedHourOffset=Ta,je.isDST=Ua,je.isDSTShifted=Va,je.isLocal=Wa,je.isUtcOffset=Xa,je.isUtc=Ya,je.isUTC=Ya,je.zoneAbbr=ic,je.zoneName=jc,je.dates=fa("dates accessor is deprecated. Use date instead.",_d),je.months=fa("months accessor is deprecated. Use month instead",$),je.years=fa("years accessor is deprecated. Use year instead",Qd),je.zone=fa("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",Pa);var ke=je,le={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},me={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},ne="Invalid date",oe="%d",pe=/\d{1,2}/,qe={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},re=t.prototype;re._calendar=le,re.calendar=mc,re._longDateFormat=me,re.longDateFormat=nc,re._invalidDate=ne,re.invalidDate=oc,re._ordinal=oe,re.ordinal=pc,re._ordinalParse=pe,re.preparse=qc,re.postformat=qc,re._relativeTime=qe,re.relativeTime=rc,re.pastFuture=sc,re.set=tc,re.months=W,re._months=Fd,re.monthsShort=X,re._monthsShort=Gd,re.monthsParse=Y,re._monthsRegex=Id,re.monthsRegex=ba,re._monthsShortRegex=Hd,re.monthsShortRegex=aa,re.week=Qb,re._week=$d,re.firstDayOfYear=Sb,re.firstDayOfWeek=Rb,re.weekdays=Wb,re._weekdays=ae,re.weekdaysMin=Yb,re._weekdaysMin=ce,re.weekdaysShort=Xb,re._weekdaysShort=be,re.weekdaysParse=Zb,re.isPM=fc,re._meridiemParse=de,re.meridiem=gc,x("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===r(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=fa("moment.lang is deprecated. Use moment.locale instead.",x),a.langData=fa("moment.langData is deprecated. Use moment.localeData instead.",z);var se=Math.abs,te=Lc("ms"),ue=Lc("s"),ve=Lc("m"),we=Lc("h"),xe=Lc("d"),ye=Lc("w"),ze=Lc("M"),Ae=Lc("y"),Be=Nc("milliseconds"),Ce=Nc("seconds"),De=Nc("minutes"),Ee=Nc("hours"),Fe=Nc("days"),Ge=Nc("months"),He=Nc("years"),Ie=Math.round,Je={s:45,m:45,h:22,d:26,M:11},Ke=Math.abs,Le=Ia.prototype;Le.abs=Bc,Le.add=Dc,Le.subtract=Ec,Le.as=Jc,Le.asMilliseconds=te,Le.asSeconds=ue,Le.asMinutes=ve,Le.asHours=we,Le.asDays=xe,Le.asWeeks=ye,Le.asMonths=ze,Le.asYears=Ae,Le.valueOf=Kc,Le._bubble=Gc,Le.get=Mc,Le.milliseconds=Be,Le.seconds=Ce,Le.minutes=De,Le.hours=Ee,Le.days=Fe,Le.weeks=Oc,Le.months=Ge,Le.years=He,Le.humanize=Sc,Le.toISOString=Tc,Le.toString=Tc,Le.toJSON=Tc,Le.locale=ub,Le.localeData=vb,Le.toIsoString=fa("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Tc),Le.lang=Zd,J("X",0,0,"unix"),J("x",0,0,"valueOf"),O("x",od),O("X",rd),S("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),S("x",function(a,b,c){c._d=new Date(r(a))}),a.version="2.11.2",b(Ea),a.fn=ke,a.min=Ga,a.max=Ha,a.now=Td,a.utc=h,a.unix=kc,a.months=wc,a.isDate=d,a.locale=x,a.invalid=l,a.duration=Za,a.isMoment=p,a.weekdays=yc,a.parseZone=lc,a.localeData=z,a.isDuration=Ja,a.monthsShort=xc,a.weekdaysMin=Ac,a.defineLocale=y,a.weekdaysShort=zc,a.normalizeUnits=B,a.relativeTimeThreshold=Rc,a.prototype=ke;var Me=a;return Me}); -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /*global moment*/ 3 | /*global Highcharts*/ 4 | /*global $*/ 5 | 6 | if (!String.prototype.includes) { 7 | String.prototype.includes = function (s) { 8 | return this.indexOf(s) > -1 9 | } 10 | } 11 | 12 | /* http://stackoverflow.com/a/16771535/1565646 */ 13 | var getScrollbarWidth = function () { 14 | var div, width = getScrollbarWidth.width; 15 | if (width === undefined) { 16 | div = document.createElement('div'); 17 | div.innerHTML = '
'; 18 | div = div.firstChild; 19 | document.body.appendChild(div); 20 | width = getScrollbarWidth.width = div.offsetWidth - div.clientWidth; 21 | document.body.removeChild(div); 22 | } 23 | return width; 24 | }; 25 | 26 | var json; 27 | moment.locale("de"); 28 | var datum = moment(); 29 | var chart = null; 30 | var currentView = "spendings"; 31 | var mainLoaded = false; 32 | var pendingUpdate = false; 33 | var dataDirty = false; 34 | 35 | var openMenuID = ''; 36 | 37 | $(document).ready(function () { 38 | mainLoaded = true; 39 | 40 | window.visualViewport.addEventListener("resize", ev => { 41 | if (pendingUpdate) { 42 | return; 43 | } 44 | pendingUpdate = true; 45 | 46 | requestAnimationFrame(() => { 47 | pendingUpdate = false; 48 | let content = document.querySelector('#content'); 49 | if (content) { 50 | let viewport = ev.target; 51 | content.style.height = viewport.height + "px"; 52 | console.log("Viewport Height " + viewport.height); 53 | } 54 | }); 55 | }); 56 | 57 | window.visualViewport.addEventListener("scroll", ev => { 58 | requestAnimationFrame(() => { 59 | window.scroll({ 60 | top: 0, 61 | left: 0, 62 | behavior: 'instant' 63 | }); 64 | }); 65 | }); 66 | 67 | document.querySelectorAll("input").forEach(el => { 68 | // https://gist.github.com/kiding/72721a0553fa93198ae2bb6eefaa3299 69 | el.addEventListener("focus", ev => { 70 | requestAnimationFrame(() => { 71 | el.style.opacity = 0; 72 | setTimeout(() => el.style.opacity = 1, 10); 73 | }); 74 | }); 75 | }); 76 | 77 | $("#next-month").click(naechsterMonat); 78 | $("#previous-month").click(vorherigerMonat); 79 | $("#switch-to-stats").click(showStatsView); 80 | $("#switch-to-trash").click(showTrashView); 81 | $("#switch-to-search").click(showSearchView); 82 | $("#input-form").submit(function (e) { 83 | saveEntry(); 84 | e.preventDefault(); 85 | }); 86 | $("#spendings").click(function () { 87 | $("#earnings").removeClass("active"); 88 | $("#spendings").addClass("active"); 89 | switchView("spendings"); 90 | }); 91 | $("#earnings").click(function () { 92 | $("#spendings").removeClass("active"); 93 | $("#earnings").addClass("active"); 94 | switchView("earnings"); 95 | }); 96 | 97 | document.querySelector('#menu').addEventListener('click', ev => { 98 | document.body.addEventListener('click', closeMenu); 99 | openMenuID = 'menu-overlay'; 100 | document.querySelector('#menu-overlay').style.setProperty('display', 'block'); 101 | ev.stopPropagation(); 102 | }); 103 | 104 | if (!hasWebkitDatepicker('#datepicker')) { 105 | $("#opendatepicker").css('display', 'inline-block'); 106 | } 107 | $("#opendatepicker").click(function () { 108 | $("#datepicker").focus().click(); 109 | }); 110 | $("#datepicker").change(function () { 111 | $("#input-datum").val($("#datepicker").val()); 112 | prettifyDate() 113 | }); 114 | $("#input-datum").change(function () { 115 | prettifyDate(); 116 | let datestring = $("#input-datum").val(); 117 | datestring = moment(datestring, "D.M.YYYY").format("YYYY-MM-DD"); 118 | $("#datepicker").val(datestring); 119 | }); 120 | $("#input-preis").change(e => formatPreisInput(e.target)); 121 | 122 | var scrollbarWidth = getScrollbarWidth(); 123 | $("#ausgabenliste-header").css("padding-right", scrollbarWidth); 124 | $("#input").css("padding-right", scrollbarWidth); 125 | $(window).on('popstate', back); 126 | processURL(); 127 | 128 | // Account selection dropdown initialization 129 | $.post('api.php', { action: 'get_accounts' }).done(function (resp) { 130 | if (resp.error !== undefined) { 131 | console.error('Error fetching accounts:', resp.error); 132 | return; 133 | } 134 | var accounts = resp.accounts; 135 | var current = resp.current; 136 | var $overlay = $('#konto-selection-overlay'); 137 | $overlay.children().filter(':not(#konto-selection-overlay-close)').remove(); 138 | var currentName = ''; 139 | accounts.forEach(function(acc) { 140 | var $item = $('
') 141 | .addClass('konto-item') 142 | .attr('data-id', acc.idkonto) 143 | .text(acc.name); 144 | if (acc.idkonto == current) { 145 | $item.addClass('active'); 146 | currentName = acc.name; 147 | } 148 | $overlay.append($item); 149 | }); 150 | if (currentName) { 151 | $('#konto-name').text(currentName); 152 | } 153 | }); 154 | 155 | // Show/hide account selection overlay 156 | $('#konto-selection').click(function(ev) { 157 | ev.stopPropagation(); 158 | $('#konto-selection-overlay').css('display', 'block'); 159 | }); 160 | 161 | // Hide overlay on outside click 162 | $(document).click(function() { 163 | $('#konto-selection-overlay').css('display', 'none'); 164 | }); 165 | 166 | $('#konto-selection-overlay-close').click(function (ev) { 167 | ev.stopPropagation(); 168 | $('#konto-selection-overlay').css('display', 'none'); 169 | }); 170 | 171 | // Handle account selection 172 | $('#konto-selection-overlay').on('click', '.konto-item', function(ev) { 173 | ev.stopPropagation(); 174 | var id = $(this).data('id'); 175 | var name = $(this).text(); 176 | $.post('api.php', {action: 'set_account', kontoid: id}).done(function(resp) { 177 | if (resp.error !== undefined) { 178 | console.error('Error setting account:', resp.error); 179 | return; 180 | } 181 | $('#konto-name').text(name); 182 | $('#konto-selection-overlay').css('display', 'none'); 183 | $('#konto-selection-overlay .konto-item').removeClass('active'); 184 | $(`#konto-selection-overlay .konto-item[data-id="${id}"]`).addClass('active'); 185 | holeDaten(); 186 | }); 187 | }); 188 | }); 189 | 190 | function closeMenu(ev) { 191 | if (ev.target.id != openMenuID) { 192 | document.body.removeEventListener('click', closeMenu); 193 | openMenuID = ''; 194 | document.querySelector('#menu-overlay').style.removeProperty('display'); 195 | } 196 | } 197 | 198 | function switchView(view) { 199 | if (currentView !== view) { 200 | currentView = view; 201 | datenAnzeigen(); 202 | /*if(currentView === "earnings"){ 203 | $('.edit').css('display', 'none'); 204 | } else {*/ 205 | $('.edit').css('display', ''); 206 | //} 207 | } 208 | } 209 | 210 | function back(e) { 211 | var state = e.originalEvent.state; 212 | if (state !== null && state.year !== undefined && state.month !== undefined) { 213 | datum.year(state.year).month(state.month); 214 | } else { 215 | datum = moment(); 216 | } 217 | if (state !== null && state.statistics !== undefined) { 218 | showStatsView(); 219 | } else { 220 | showDataView(); 221 | loadingScreen(); 222 | } 223 | holeDaten(); 224 | } 225 | 226 | function showDataView() { 227 | if (dataDirty) { 228 | loadingScreen(); 229 | holeDaten(function () { 230 | dataDirty = false; 231 | }); 232 | } 233 | 234 | let newElements = document.getElementById("ausgabenliste").querySelectorAll(".tr.ausgabe.new"); 235 | for (let i = 0; i < newElements.length; i++) { 236 | newElements[i].classList.remove("new"); 237 | } 238 | $('#overlay').css('display', 'none'); 239 | $('#content').css('display', ''); 240 | window.history.pushState({ 241 | "year": datum.year(), 242 | "month": datum.month() 243 | }, "", "index.php?year=" + datum.year() + "&month=" + (datum.month() + 1)); 244 | } 245 | 246 | function showStatsView() { 247 | $('#content').css('display', 'none'); 248 | let overlay = $('#overlay'); 249 | overlay.empty(); 250 | createStatsElements(); 251 | overlay.css('display', 'flex'); 252 | window.history.pushState({ 253 | "year": datum.year(), 254 | "month": datum.month(), 255 | "statistics": "" 256 | }, "", "index.php?year=" + datum.year() + "&month=" + (datum.month() + 1) + "&statistics"); 257 | overlayCharts(); 258 | } 259 | 260 | // Show search view overlay 261 | function showSearchView() { 262 | $('#content').css('display', 'none'); 263 | let overlay = $('#overlay'); 264 | overlay.empty(); 265 | overlaySearch(); 266 | overlay.css('display', 'flex'); 267 | window.history.pushState({ 268 | year: datum.year(), 269 | month: datum.month(), 270 | search: true 271 | }, "", "index.php?year=" + datum.year() + "&month=" + (datum.month() + 1) + "&search"); 272 | } 273 | 274 | function overlaySearch() { 275 | let tabBar = $('
'); 276 | let subBar = $('
'); 277 | let searchIconBar = $('') 278 | var $tabs = $('
'); 279 | let closeButton = $('×'); 280 | 281 | // top search input in navbar 282 | let searchInputWrapper = $('
').css("flex-grow", "1"); 283 | let $searchInput = $(''); 284 | searchInputWrapper.append($searchInput); 285 | 286 | subBar.append(searchInputWrapper); 287 | tabBar.append(searchIconBar).append(subBar).append(closeButton); 288 | 289 | $('#overlay').append(tabBar).append('
') 290 | $("#overlay-close").click(showDataView); 291 | 292 | // debounce helper 293 | function debounce(fn, delay) { 294 | let t; 295 | return function() { 296 | const args = arguments; 297 | clearTimeout(t); 298 | t = setTimeout(function() { fn.apply(null, args); }, delay); 299 | }; 300 | } 301 | 302 | function renderResults(data) { 303 | // clear search-section 304 | $('#search-section').empty(); 305 | 306 | var hasAus = data.ausgaben && data.ausgaben.length > 0; 307 | var hasEin = data.einnahmen && data.einnahmen.length > 0; 308 | 309 | if (!hasAus && !hasEin) { 310 | // show single no-results message inside search-section 311 | $('#search-section').append($('
').text('Keine Treffer')); 312 | return; 313 | } 314 | 315 | const headerHtml = ` 316 |
317 |
Datum
318 |
Kategorie
319 |
Art
320 |
Preis
321 |
Beschreibung
322 |
`; 323 | 324 | if (hasAus) { 325 | $('#search-section').append(` 326 |
327 |

Ausgaben

328 | ${headerHtml} 329 |
330 |
331 | `); 332 | let ausContainer = $('#search-results-ausgaben'); 333 | data.ausgaben.forEach(function(item) { 334 | var $row = $('
'); 335 | $row.append('
' + dateToLocal(item.datum) + '
'); 336 | $row.append('
' + (item.kategorie || '') + '
'); 337 | $row.append('
' + item.art + '
'); 338 | $row.append('
' + formatPreis(item.preis) + '
'); 339 | $row.append('
' + (item.beschreibung || '') + '
'); 340 | ausContainer.append($row); 341 | }); 342 | } 343 | 344 | if (hasEin) { 345 | $('#search-section').append(` 346 |
347 |

Einnahmen

348 | ${headerHtml} 349 |
350 |
351 | `); 352 | let einContainer = $('#search-results-einnahmen'); 353 | data.einnahmen.forEach(function(item) { 354 | var $row = $('
'); 355 | $row.append('
' + dateToLocal(item.datum) + '
'); 356 | $row.append('
' + (item.kategorie || '') + '
'); 357 | $row.append('
' + item.art + '
'); 358 | $row.append('
' + formatPreis(item.preis) + '
'); 359 | $row.append('
' + (item.beschreibung || '') + '
'); 360 | einContainer.append($row); 361 | }); 362 | } 363 | } 364 | 365 | function doSearch(q) { 366 | if (!q || q.trim() === '') { 367 | $('#search-section').empty(); 368 | return; 369 | } 370 | $.post('api.php', {action: 'search', q: q}).done(function(resp) { 371 | try { 372 | var data = JSON.parse(resp); 373 | if (data.error !== undefined) { 374 | errorHandling(data); 375 | } else { 376 | renderResults(data); 377 | } 378 | } catch (e) { 379 | console.error('Invalid search response', e, resp); 380 | } 381 | }); 382 | } 383 | 384 | var debounced = debounce(function(e) { doSearch(e.target.value); }, 300); 385 | $searchInput.on('input', debounced); 386 | } 387 | 388 | function createStatsElements() { 389 | const htmlString = ` 390 |
391 |
392 | 393 |
394 |
395 |
396 |
397 |
398 | × 399 |
400 |
401 |
402 |
403 |
404 |
405 |
Details →
406 |
407 |
408 |
409 |
410 | 419 |
420 |
421 |
422 |
423 | `; 424 | 425 | document.querySelector('#overlay').innerHTML = htmlString; 426 | $("#overlay-close").click(showDataView); 427 | $('#chart-category-add').click(addChart); 428 | } 429 | 430 | 431 | // Show trashed items view (Papierkorb) 432 | function showTrashView() { 433 | $('#content').css('display', 'none'); 434 | let overlay = $('#overlay'); 435 | overlay.empty(); 436 | overlayTrash(); 437 | overlay.css('display', 'flex'); 438 | window.history.pushState({ 439 | year: datum.year(), 440 | month: datum.month(), 441 | trash: true 442 | }, "", "index.php?year=" + datum.year() + "&month=" + (datum.month() + 1) + "&trash"); 443 | } 444 | // Load and display trash items in overlay 445 | function overlayTrash() { 446 | let tabBar = $('
'); 447 | 448 | let subBar = $('
'); 449 | let trashIconBar = $('') 450 | var $tabs = $('
'); 451 | var $tabA = $('Ausgaben'); 452 | var $tabE = $('Einnahmen'); 453 | 454 | let closeButton = $('×'); 455 | 456 | $tabs.append($tabA).append($tabE); 457 | subBar.append($tabs); 458 | tabBar.append(trashIconBar).append(subBar).append(closeButton); 459 | $('#overlay').append(tabBar).append('
') 460 | $("#overlay-close").click(showDataView); 461 | 462 | // Fetch trashed entries 463 | $.post('api.php', {action: 'get_trashed'}).done(function(data) { 464 | var jsonTrash = JSON.parse(data); 465 | if (jsonTrash.error) { 466 | console.error('Error fetching trash:', jsonTrash.msg); 467 | $('#trash-list').append($('
').text('Fehler beim Laden des Papierkorbs')); 468 | return; 469 | } 470 | window.trashData = jsonTrash; 471 | renderTrashList('ausgaben'); 472 | }); 473 | $tabE.click(function() { 474 | $('#trash-tabs .bar-element').removeClass('active'); 475 | $(this).addClass('active'); 476 | renderTrashList('einnahmen'); 477 | }); 478 | $tabA.click(function() { 479 | $('#trash-tabs .bar-element').removeClass('active'); 480 | $(this).addClass('active'); 481 | renderTrashList('ausgaben'); 482 | }); 483 | } 484 | // Render trashed entries list for given type 485 | function renderTrashList(type) { 486 | let items = window.trashData[type] || []; 487 | let section = $('#trash-section'); 488 | // Header 489 | var $header = $('
'); 490 | $header.append('
Datum
'); 491 | $header.append('
Kategorie
'); 492 | $header.append('
Art
'); 493 | $header.append('
Preis
'); 494 | $header.append('
Beschreibung
'); 495 | $header.append('
Optionen
'); 496 | section.append($header).append($('
')); 497 | let list = $('#trash-list'); 498 | if (items.length === 0) { 499 | list.append($('
').text('Kein Eintrag im Papierkorb für ' + (type === 'einnahmen' ? 'Einnahmen' : 'Ausgaben'))); 500 | return; 501 | } 502 | items.forEach(function(item) { 503 | var idField = (type === 'einnahmen' ? 'ideinnahme' : 'idausgabe'); 504 | var $row = $('
').attr('data-id', item[idField]); 505 | $row.append('
' + dateToLocal(item.datum) + '
'); 506 | $row.append('
' + (item.kategorie || '') + '
'); 507 | $row.append('
' + item.art + '
'); 508 | $row.append('
' + formatPreis(item.preis) + '
'); 509 | $row.append('
' + (item.beschreibung || '') + '
'); 510 | var $opt = $('
'); 511 | var $btn = $('
'); 512 | $btn.click(function() { 513 | $.post('api.php', {action: 'restore', type: type, id: item[idField]}).done(function(resp) { 514 | var jr = JSON.parse(resp); 515 | if (jr.error) { 516 | alert('Fehler: ' + jr.msg); 517 | } else { 518 | $row.remove(); 519 | dataDirty = true; 520 | } 521 | }); 522 | }); 523 | $opt.append($btn); 524 | $row.append($opt); 525 | list.append($row); 526 | }); 527 | } 528 | 529 | function overlayCharts() { 530 | $.post('api.php', { 531 | action: 'get_sum_months' 532 | }).done(function (data) { 533 | var json = JSON.parse(data); 534 | if (json['error'] === undefined) { 535 | if (json.ausgaben) { 536 | $('#select').children().remove(); 537 | $('#select-mobile > select').children().remove(); 538 | var ausgaben = json.ausgaben; 539 | 540 | let yearlySums = {}; 541 | ausgaben.forEach(entry => { 542 | let year = entry.jahr; 543 | let preis = parseFloat(entry.preis); // Convert preis to a number 544 | if (!yearlySums[year]) { 545 | yearlySums[year] = 0; 546 | } 547 | yearlySums[year] += preis; 548 | }); 549 | 550 | var currentYear = 0; 551 | for (var x in ausgaben) { 552 | var tempDate = moment([ausgaben[x].jahr, ausgaben[x].monat - 1]); 553 | if (currentYear === 0 || currentYear > tempDate.year()) { 554 | currentYear = tempDate.year(); 555 | overlayAddSelect(currentYear, currentYear, formatPreis(Math.floor(yearlySums[currentYear]), false)); 556 | } 557 | overlayAddSelect(tempDate.format('MMMM'), currentYear,formatPreis(Math.floor(ausgaben[x].preis), false), tempDate.month() + 1); 558 | } 559 | $('#select .select-element').first().addClass('active'); 560 | $('#select-mobile > select > optgroup').first().children('option').first().attr('selected', 'selected'); 561 | 562 | //change listener on select element for mobile 563 | //TODO: change active element in desktop version and vice versa 564 | $('#select-mobile > select').change(function (e) { 565 | var optionSelected = $(this).find("option:selected"); 566 | if ($(optionSelected).attr('data-month') != null) { 567 | monthChart($(optionSelected).attr('data-month'), $(optionSelected).attr('data-year')); 568 | } else { 569 | yearChart($(optionSelected).attr('data-year')); 570 | } 571 | 572 | }); 573 | 574 | $.post('api.php', { 575 | action: 'get_categories', 576 | mincount: 2 577 | }).done(function (data) { 578 | let json = JSON.parse(data); 579 | if (json['error'] === undefined) { 580 | if (json.kategorien) { 581 | let categorySelect = $('#chart-category-select > select'); 582 | for (let kategorie of json.kategorien) { 583 | if (kategorie === null) { 584 | kategorie = "Ohne Kategorie" 585 | } 586 | categorySelect.append($('