├── test ├── multi │ ├── 1.txt │ ├── 2.txt │ ├── 3.txt │ ├── 4.txt │ ├── 5.txt │ └── README.md ├── error.txt ├── ok-generator.py ├── ok.txt └── functions.js ├── netlify.toml ├── public ├── google2d9f556896e1d223.html ├── config.js ├── README.md └── privacidade.txt ├── .gitignore ├── util ├── lint.sh ├── set-commit-id.sh ├── gen-cloud-analytics.html ├── deploy.sh ├── gen-beta-config ├── gen-cloud-config ├── conversor │ ├── Quicken.qif │ ├── MSMoney97.qif │ ├── MSMoney98.qif │ ├── MSMoney99.qif │ ├── myMoneyLog.txt │ ├── moneylog4-ok.txt │ ├── moneylog4.txt │ ├── Caixa.ofc │ ├── Real.ofx │ ├── Caixa.ofx │ └── conversor.html ├── gen-browser ├── gen-cloud ├── portable-vs-browser.diff └── gen-portable ├── storage ├── drivers │ ├── html.js │ ├── browser.js │ ├── filesystem.js │ └── googledrive.js └── index.js ├── README.md ├── sample ├── widget-hello-world.js ├── config-dev.js ├── widget-hello-checkbox.js ├── widget-nerd-toy.js ├── widget-hello-translation.js ├── data-es.txt ├── data-en.txt ├── data-pt.txt └── config-pt.js ├── css ├── browser.css ├── cloud.css ├── portable.css ├── print.css └── mobile.css ├── LICENSE.txt ├── .eslintrc.yml ├── NEWS.t2t ├── moneylog.html ├── moneylog.css └── NEWS.html /test/multi/1.txt: -------------------------------------------------------------------------------- 1 | 2009-08-01 1 um|Um 2 | -------------------------------------------------------------------------------- /test/multi/2.txt: -------------------------------------------------------------------------------- 1 | 2009-08-02 2 dois|Dois 2 | -------------------------------------------------------------------------------- /test/multi/3.txt: -------------------------------------------------------------------------------- 1 | 2009-08-03 3 tres|Três 2 | -------------------------------------------------------------------------------- /test/multi/4.txt: -------------------------------------------------------------------------------- 1 | 2009-08-04 4 quatro|Quatro 2 | -------------------------------------------------------------------------------- /test/multi/5.txt: -------------------------------------------------------------------------------- 1 | 2009-08-05 5 cinco|Cinco 2 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "public" 3 | command = "util/deploy.sh" 4 | -------------------------------------------------------------------------------- /public/google2d9f556896e1d223.html: -------------------------------------------------------------------------------- 1 | google-site-verification: google2d9f556896e1d223.html -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # user personal settings for the Beta version 2 | /config.js 3 | 4 | # user data folder for the Beta version 5 | /txt/ 6 | -------------------------------------------------------------------------------- /util/lint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Call ESLint to lint our JavaScript files. 3 | # Lint rules are on .eslintrc.yml at repo root. 4 | 5 | # Enter repo root 6 | cd $(dirname "$0") 7 | cd .. 8 | 9 | # Lint all JavaScript files 10 | eslint --fix \ 11 | *.js \ 12 | */*.js \ 13 | */*/*.js 14 | -------------------------------------------------------------------------------- /storage/drivers/html.js: -------------------------------------------------------------------------------- 1 | // HTML:
2 |
3 | ml.storage.drivers.html = {
4 | id: 'html',
5 | name: ' element',
6 | config: {
7 | isAsync: false,
8 | isEditable: false,
9 | isFileBased: false,
10 | isReloadable: false,
11 | loadDataAtSetup: true
12 | },
13 |
14 | read: function () {
15 | return document.getElementById('data').innerText;
16 | },
17 |
18 | init: function () {
19 | // none
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/util/set-commit-id.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Aurelio Jargas
3 | #
4 | # Set the hash for the latest Git commit in $commit_id variable
5 | #
6 | # Usage:
7 | # source set-commit-id.sh
8 | #
9 |
10 | commit_id=$(git log -1 --format="%H" | cut -c 1-8) # 8 chars are enough
11 |
12 | # Check
13 | if ! echo "$commit_id" | grep '^[0-9a-f]\{8\}$' > /dev/null
14 | then
15 | echo "ERROR: Invalid Git commit hash: '$commit_id'. Aborting." >&2
16 | exit 1
17 | fi
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MoneyLog Experience, by Aurelio Jargas
2 |
3 | English website: https://aurelio.net/soft/moneylog/
4 |
5 | Portuguese website: https://aurelio.net/moneylog/
6 |
7 |
8 | ## Deploy
9 |
10 | Every commit to the `master` branch triggers an app deploy to https://moneylog.aurelio.net.
11 |
12 | The deploy logs are in https://app.netlify.com/sites/moneylog/deploys.
13 |
14 | More information in the [public/](https://github.com/aureliojargas/moneylog/blob/master/public/) folder.
15 |
--------------------------------------------------------------------------------
/public/config.js:
--------------------------------------------------------------------------------
1 | // See configuration help at:
2 | // https://aurelio.net/moneylog/config/
3 |
4 | // Set app lang
5 | // Using portuguese because the userbase is mainly from Brazil
6 | lang = 'pt';
7 |
8 | // Disable drivers that do not make sense on this online version
9 | ml.storage.availableDrivers = [
10 | // 'html',
11 | // 'filesystem',
12 | 'browser',
13 | 'googledrive'
14 | ];
15 |
16 | // Set the default driver activated at startup
17 | ml.storage.defaultDriver = 'browser';
18 |
--------------------------------------------------------------------------------
/sample/widget-hello-world.js:
--------------------------------------------------------------------------------
1 | // --------------------------------------------------------------------
2 | // Hello World Widget
3 | // by Aurelio Jargas 2012-02-17
4 | //
5 | // A sample widget. Simple. Readable.
6 | //
7 | // Copy/paste all this code to the end of your config.js file.
8 |
9 |
10 | // Create a new widget instance (id, name, instance name)
11 | var HelloWorld = new Widget('hello-world', 'Hello World', 'HelloWorld');
12 |
13 | // Set widget contents
14 | HelloWorld.populate = function () {
15 | this.content.innerHTML = 'Hellooo!';
16 | };
17 |
--------------------------------------------------------------------------------
/util/gen-cloud-analytics.html:
--------------------------------------------------------------------------------
1 |
2 |
15 |
--------------------------------------------------------------------------------
/util/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Build website https://moneylog.aurelio.net
3 | # The actual deploy is handled automatically by Netlify.
4 |
5 | # Enter repo root
6 | cd $(dirname "$0")
7 | cd ..
8 | root="$PWD"
9 |
10 | deploy_dir="$root/public"
11 |
12 | # Copy main file
13 | cp moneylog.html "$deploy_dir/index.html"
14 |
15 | # Copy sample file (localStorage default text)
16 | mkdir -p "$deploy_dir/sample"
17 | cp sample/data-pt.txt "$deploy_dir/sample"
18 |
19 | # Copy other files
20 | cp -r \
21 | moneylog.css \
22 | moneylog.js \
23 | css/ \
24 | storage/ \
25 | "$deploy_dir"
26 |
27 |
--------------------------------------------------------------------------------
/public/README.md:
--------------------------------------------------------------------------------
1 | # Deploy folder for the MoneyLog app
2 |
3 | This is the root of the https://moneylog.aurelio.net website.
4 |
5 | - Put static site-only files here.
6 |
7 | - Repository files are added here at deploy time by the
8 | [util/deploy.sh](https://github.com/aureliojargas/moneylog/blob/master/util/deploy.sh)
9 | script.
10 |
11 | The deploy is handled automatically by Netlify:
12 | every commit to the `master` branch triggers a deploy.
13 |
14 | Deploy logs at: https://app.netlify.com/sites/moneylog/deploys/
15 |
16 | See [netlify.toml](https://github.com/aureliojargas/moneylog/blob/master/netlify.toml)
17 | for the build commands.
18 |
--------------------------------------------------------------------------------
/sample/config-dev.js:
--------------------------------------------------------------------------------
1 | // MoneyLog config for devs
2 | //
3 | // Handy configurations to test MoneyLog features.
4 | // Copy to repo root as config.js and fiddle.
5 |
6 | // Set the default driver at app init
7 | ml.storage.defaultDriver = 'html';
8 | ml.storage.defaultDriver = 'browser';
9 | ml.storage.defaultDriver = 'googledrive';
10 | ml.storage.defaultDriver = 'filesystem';
11 |
12 | // Test files for the filesystem driver
13 | ml.storage.drivers.filesystem.defaultFile = 'sample/data-en.txt';
14 | ml.storage.drivers.filesystem.dataFiles = [
15 | 'sample/data-pt.txt',
16 | 'sample/data-en.txt',
17 | 'sample/data-es.txt'
18 | ];
19 |
20 | // LEGACY global configuration for the filesystem driver.
21 | // Won't be applied if the previous two configs are active.
22 | dataFilesDefault = 'sample/data-es.txt';
23 | dataFiles = [
24 | 'sample/data-pt.txt',
25 | 'sample/data-es.txt'
26 | ];
27 |
--------------------------------------------------------------------------------
/util/gen-beta-config:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Aurelio Jargas, https://aurelio.net/moneylog/
3 | #
4 | # Generates the commented config.js sample, with Beta specific sections.
5 | #
6 | # Usage:
7 | # gen-beta-config [--lang XX]
8 | #
9 | # Examples:
10 | # gen-beta-config # Portuguese version
11 | # gen-beta-config --lang en # English version
12 |
13 |
14 | cd $(dirname "$0")
15 |
16 | lang="pt" # pt, en, es, ca. Use --lang to change it.
17 |
18 | # Option --lang
19 | if test "$1" = '--lang'
20 | then
21 | lang=$2
22 | shift
23 | shift
24 | fi
25 |
26 | file_path="../sample/config-$lang.js"
27 |
28 | if test -f "$file_path"
29 | then
30 | sed '
31 | # Remove Dropbox-specific data
32 | /^\/\/ /, /^\/\/ <\/Dropbox>/ d
33 |
34 | # Remove marker lines
35 | /^\/\/ / d
36 | /^\/\/ <\/Beta>/ d
37 |
38 | ' "$file_path"
39 | else
40 | echo "Sorry, file not found: $file_path"
41 | fi
42 |
--------------------------------------------------------------------------------
/util/gen-cloud-config:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Aurelio Jargas, https://aurelio.net/moneylog/
3 | #
4 | # Generates the commented config.js sample, with Dropbox specific sections.
5 | #
6 | # Usage:
7 | # gen-cloud-config [--lang XX]
8 | #
9 | # Examples:
10 | # gen-cloud-config # Portuguese version
11 | # gen-cloud-config --lang en # English version
12 |
13 |
14 | cd $(dirname "$0")
15 |
16 | lang="pt" # pt, en, es, ca. Use --lang to change it.
17 |
18 | # Option --lang
19 | if test "$1" = '--lang'
20 | then
21 | lang=$2
22 | shift
23 | shift
24 | fi
25 |
26 | file_path="../sample/config-$lang.js"
27 |
28 | if test -f "$file_path"
29 | then
30 | sed '
31 | # Remove Beta-specific data
32 | /^\/\/ /, /^\/\/ <\/Beta>/ d
33 |
34 | # Remove marker lines
35 | /^\/\/ / d
36 | /^\/\/ <\/Dropbox>/ d
37 |
38 | ' "$file_path"
39 | else
40 | echo "Sorry, file not found: $file_path"
41 | fi
42 |
--------------------------------------------------------------------------------
/util/conversor/Quicken.qif:
--------------------------------------------------------------------------------
1 |
2 | !Account
3 | N1234_1234567
4 | TBank
5 | ^
6 | !Type:Bank
7 | D07/01'09
8 | T5.37
9 | N0001813
10 | MJUROS POUPANCA
11 | ^
12 | D07/01'09
13 | T0.70
14 | N0002251
15 | MCORRECAO POUPANCA
16 | ^
17 | D07/02'09
18 | T-650.00
19 | N0007389
20 | MTRANSF.P/ FULANO DA SILVA
21 | ^
22 | D07/03'09
23 | T1234.56
24 | N0123482
25 | MDOC REM 12345678000102
26 | ^
27 | D07/04'09
28 | T567.00
29 | N0002452
30 | MTRANSF.DE CICRANO DA SILVA
31 | ^
32 | D07/05'09
33 | T-234.56
34 | N0001555
35 | MTITULO COBRANCA-IB
36 | ^
37 | D07/06'09
38 | T-999.99
39 | N0000198
40 | MFATURA REALVISA
41 | ^
42 | D07/07'09
43 | T-34.67
44 | N0000077
45 | MCONTA DE LUZ
46 | ^
47 | D07/08'09
48 | T345.67
49 | N0002234
50 | MTED REM 12345678000102
51 | ^
52 | D07/13'09
53 | T-21.00
54 | N0001234
55 | MCOMPRA VISA ELECTRON
56 | ^
57 | D07/21'09
58 | T-100.00
59 | N0000123
60 | MSAQUE COM CARTAO
61 | ^
62 |
63 |
--------------------------------------------------------------------------------
/util/conversor/MSMoney97.qif:
--------------------------------------------------------------------------------
1 |
2 | !Account
3 | N1234_1234567
4 | TBank
5 | ^
6 | !Type:Bank
7 | D01/07'09
8 | T5.37
9 | N0001813
10 | MJUROS POUPANCA
11 | ^
12 | D01/07'09
13 | T0.70
14 | N0002251
15 | MCORRECAO POUPANCA
16 | ^
17 | D02/07'09
18 | T-650.00
19 | N0007389
20 | MTRANSF.P/ FULANO DA SILVA
21 | ^
22 | D03/07'09
23 | T1234.56
24 | N0123482
25 | MDOC REM 12345678000102
26 | ^
27 | D04/07'09
28 | T567.00
29 | N0002452
30 | MTRANSF.DE CICRANO DA SILVA
31 | ^
32 | D05/07'09
33 | T-234.56
34 | N0001555
35 | MTITULO COBRANCA-IB
36 | ^
37 | D06/07'09
38 | T-999.99
39 | N0000198
40 | MFATURA REALVISA
41 | ^
42 | D07/07'09
43 | T-34.67
44 | N0000077
45 | MCONTA DE LUZ
46 | ^
47 | D08/07'09
48 | T345.67
49 | N0002234
50 | MTED REM 12345678000102
51 | ^
52 | D13/07'09
53 | T-21.00
54 | N0001234
55 | MCOMPRA VISA ELECTRON
56 | ^
57 | D21/07'09
58 | T-100.00
59 | N0000123
60 | MSAQUE COM CARTAO
61 | ^
62 |
63 |
--------------------------------------------------------------------------------
/util/conversor/MSMoney98.qif:
--------------------------------------------------------------------------------
1 |
2 | !Account
3 | N1234_1234567
4 | TBank
5 | ^
6 | !Type:Bank
7 | D01/07'09
8 | T5.37
9 | N0001813
10 | MJUROS POUPANCA
11 | ^
12 | D01/07'09
13 | T0.70
14 | N0002251
15 | MCORRECAO POUPANCA
16 | ^
17 | D02/07'09
18 | T-650.00
19 | N0007389
20 | MTRANSF.P/ FULANO DA SILVA
21 | ^
22 | D03/07'09
23 | T1234.56
24 | N0123482
25 | MDOC REM 12345678000102
26 | ^
27 | D04/07'09
28 | T567.00
29 | N0002452
30 | MTRANSF.DE CICRANO DA SILVA
31 | ^
32 | D05/07'09
33 | T-234.56
34 | N0001555
35 | MTITULO COBRANCA-IB
36 | ^
37 | D06/07'09
38 | T-999.99
39 | N0000198
40 | MFATURA REALVISA
41 | ^
42 | D07/07'09
43 | T-34.67
44 | N0000077
45 | MCONTA DE LUZ
46 | ^
47 | D08/07'09
48 | T345.67
49 | N0002234
50 | MTED REM 12345678000102
51 | ^
52 | D13/07'09
53 | T-21.00
54 | N0001234
55 | MCOMPRA VISA ELECTRON
56 | ^
57 | D21/07'09
58 | T-100.00
59 | N0000123
60 | MSAQUE COM CARTAO
61 | ^
62 |
63 |
--------------------------------------------------------------------------------
/util/conversor/MSMoney99.qif:
--------------------------------------------------------------------------------
1 |
2 | !Account
3 | N1234_1234567
4 | TBank
5 | ^
6 | !Type:Bank
7 | D01/07/09
8 | T5.37
9 | N0001813
10 | MJUROS POUPANCA
11 | ^
12 | D01/07/09
13 | T0.70
14 | N0002251
15 | MCORRECAO POUPANCA
16 | ^
17 | D02/07/09
18 | T-650.00
19 | N0007389
20 | MTRANSF.P/ FULANO DA SILVA
21 | ^
22 | D03/07/09
23 | T1234.56
24 | N0123482
25 | MDOC REM 12345678000102
26 | ^
27 | D04/07/09
28 | T567.00
29 | N0002452
30 | MTRANSF.DE CICRANO DA SILVA
31 | ^
32 | D05/07/09
33 | T-234.56
34 | N0001555
35 | MTITULO COBRANCA-IB
36 | ^
37 | D06/07/09
38 | T-999.99
39 | N0000198
40 | MFATURA REALVISA
41 | ^
42 | D07/07/09
43 | T-34.67
44 | N0000077
45 | MCONTA DE LUZ
46 | ^
47 | D08/07/09
48 | T345.67
49 | N0002234
50 | MTED REM 12345678000102
51 | ^
52 | D13/07/09
53 | T-21.00
54 | N0001234
55 | MCOMPRA VISA ELECTRON
56 | ^
57 | D21/07/09
58 | T-100.00
59 | N0000123
60 | MSAQUE COM CARTAO
61 | ^
62 |
63 |
--------------------------------------------------------------------------------
/test/error.txt:
--------------------------------------------------------------------------------
1 | # https://aurelio.net/moneylog/
2 | # MoneyLog ERROR test file.
3 | # Uncomment one by one to see the error.
4 | #
5 | # Use these settings to test this file:
6 | # reportType = 'd';
7 | # checkDateFrom = false;
8 | # useLegacyDataFormat = false;
9 | # dataFiles = ['test/error.txt'];
10 |
11 |
12 | ### No value
13 | # 2000-01-01
14 |
15 | ### Invalid value: spaces are not allowed between signal and number
16 | # 2000-01-01 - 10
17 |
18 | ### Invalid value: unrecognized number format.
19 | # 2000-01-01 ++2
20 | # 2000-01-01 -+2
21 | # 2000-01-01 .50
22 | # 2000-01-01 1,2
23 |
24 | ### Invalid value: cents are ok, but other punctuation is wrong
25 | # 2000-01-01 1.23,45
26 | # 2000-01-01 12.34.234,56
27 |
28 | ### Invalid recurrent period: zero or negative
29 | # 2000-01-01 100/0
30 | # 2000-01-01 100/-2
31 | # 2000-01-01 100*-2
32 |
33 |
34 | ### useLegacyDataFormat: two or more Tabs in description
35 | # 2000-01-01 10 foo bar
36 | # 2000-01-01 10 foo bar baz
37 |
--------------------------------------------------------------------------------
/test/multi/README.md:
--------------------------------------------------------------------------------
1 | # MoneyLog Multi Files Test
2 |
3 | Test files for the multiple TXT files feature.
4 |
5 | Put the following lines in `config.js`:
6 |
7 | dataFiles = [
8 | 'test/multi/1.txt',
9 | 'test/multi/2.txt',
10 | 'test/multi/3.txt',
11 | 'test/multi/4.txt',
12 | 'test/multi/5.txt',
13 | '*'
14 | ];
15 |
16 | And check the following behavior:
17 |
18 | - The first file is the default and it's data must be loaded at MoneyLog startup.
19 |
20 | - Selecting a different file in the file chooser will clear the current data and load the new file's data.
21 |
22 | - Selecting the asterisk `*`, all TXT files are simultaneously loaded, as if they were just a single file.
23 |
24 | - Edit `config.js` to place the asterisk as the first array item. All TXT files must be loaded at MoneyLog startup.
25 |
26 | - Observe the behavior of the tags (selected or not), the other filtering options and the type of report.
27 |
28 | - Use the Reload button to verify it's working.
29 |
30 |
31 | > Note: If you use an extra comma in the last array item, IE attempts to load the `undefined` item :/
32 |
--------------------------------------------------------------------------------
/public/privacidade.txt:
--------------------------------------------------------------------------------
1 | Política de Privacidade
2 | -----------------------
3 |
4 | Este site não identifica o usuário.
5 |
6 | Este site não guarda nenhum dado do usuário.
7 |
8 | Este site é apenas um programa simples, para uso anônimo, sem cadastro
9 | nem login.
10 |
11 | Este programa funciona exclusivamente no equipamento do usuário
12 | (JavaScript client side). Não há processamento no servidor. Não há envio
13 | de dados para o servidor.
14 |
15 | É a API oficial do Google Drive quem autentica e obtém o arquivo do
16 | usuário. Esta comunicação acontece diretamente entre o equipamento do
17 | usuário e a API, sem intermédio do servidor deste programa.
18 |
19 | Os dados do arquivo do Google Drive ficam apenas na memória do
20 | equipamento do usuário, e são apagados ao fechar a janela ou aba do
21 | navegador.
22 |
23 | O responsável pelo site não tem acesso à identidade do usuário, aos
24 | dados carregados no programa nem à conta do usuário no Google Drive.
25 |
26 | Este programa é um software livre e todo o seu código fonte está disponível
27 | para inspeção em https://github.com/aureliojargas/moneylog/
28 |
--------------------------------------------------------------------------------
/css/browser.css:
--------------------------------------------------------------------------------
1 | /*
2 | MoneyLog Browser theme
3 | by Aurelio Jargas
4 | https://aurelio.net/moneylog/
5 |
6 | Light orange: #FFEED1
7 | Dark orange: #E89E00
8 | */
9 |
10 |
11 | #app-flavor {
12 | color: #E89E00;
13 | }
14 |
15 | /* Dark background for active/special buttons */
16 | #fullscreen,
17 | .report th:hover,
18 | #editor-file-name,
19 | .button.active,
20 | a.button:active {
21 | background-color: #E89E00;
22 | }
23 |
24 | /* Dark background for selected rows */
25 | tr.selected,
26 | tr.selected:hover td,
27 | tr.selected .neg {
28 | background-color: #E89E00;
29 | }
30 |
31 | /* Dark color for borders */
32 | #editor-data-wrapper,
33 | #rows-summary,
34 | .button.active,
35 | a.button:active {
36 | border-color: #E89E00;
37 | }
38 |
39 | /* Light background for selections */
40 | .hl,
41 | #tag-cloud-tags a.selected {
42 | background-color: #FFEED1;
43 | }
44 |
45 | /* Light background for totals */
46 | tr.totals,
47 | td.totals,
48 | #rows-summary {
49 | background-color: #FFEED1;
50 | }
51 |
52 | /* Light color for the report borders */
53 | .report td {
54 | border-color: #FFEED1;
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/sample/widget-hello-checkbox.js:
--------------------------------------------------------------------------------
1 | // --------------------------------------------------------------------
2 | // Hello Checkbox Widget
3 | // by Aurelio Jargas 2012-02-17
4 | //
5 | // A simple sample widget, using a checkbox.
6 | //
7 | // Copy/paste all this code to the end of your config.js file.
8 |
9 |
10 | // Create a new widget instance (id, name, instance name)
11 | var HelloCheckbox = new Widget('hello-checkbox', 'Hello Checkbox', 'HelloCheckbox');
12 |
13 | // Widget config
14 | HelloCheckbox.config.active = true; // Is this widget active?
15 | HelloCheckbox.config.opened = true; // Start app with this widget opened?
16 |
17 | // Set widget contents
18 | HelloCheckbox.populate = function () {
19 | this.addCheckbox('foo', 'Hello?'); // id suffix, label
20 | };
21 |
22 | // Handle checkbox click
23 | HelloCheckbox.checkboxClicked = function (checkbox) {
24 | if (checkbox.checked) {
25 | this.header.innerHTML = 'I am checked';
26 | } else {
27 | this.header.innerHTML = 'I am not checked';
28 | }
29 |
30 | // Debug
31 | console.log('Checkbox ID: ' + checkbox.id);
32 | console.log(this); // Widget instance
33 | };
34 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2006-2014 Aurelio Jargas
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 | of the Software, and to permit persons to whom the Software is furnished to do
10 | so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/css/cloud.css:
--------------------------------------------------------------------------------
1 | /*
2 | MoneyLog Cloud theme
3 | by Aurelio Jargas
4 | https://aurelio.net/moneylog/
5 |
6 | Light blue: #D5EAFB
7 | Dark blue: #2B97E9
8 | */
9 |
10 |
11 | #app-flavor {
12 | color: #2B97E9;
13 | }
14 |
15 | /* Dark background for active/special buttons */
16 | #fullscreen,
17 | .report th:hover,
18 | #editor-file-name,
19 | .button.active,
20 | a.button:active {
21 | background-color: #2B97E9;
22 | }
23 |
24 | /* Dark background for selected rows */
25 | tr.selected,
26 | tr.selected:hover td,
27 | tr.selected .neg {
28 | background-color: #2B97E9;
29 | }
30 |
31 | /* Dark color for borders */
32 | #editor-data-wrapper,
33 | #rows-summary,
34 | .button.active,
35 | a.button:active {
36 | border-color: #2B97E9;
37 | }
38 |
39 | /* Light background for selections */
40 | .hl,
41 | #tag-cloud-tags a.selected {
42 | background-color: #D5EAFB;
43 | }
44 |
45 | /* Light background for totals */
46 | tr.totals,
47 | td.totals,
48 | #rows-summary {
49 | background-color: #D5EAFB;
50 | }
51 |
52 | /* Light color for the report borders */
53 | .report td {
54 | border-color: #D5EAFB;
55 | }
56 |
57 |
58 | /* Special: interface dark blue for the positive chart bar */
59 | .posbar {
60 | background-color: #2B97E9;
61 | }
62 |
--------------------------------------------------------------------------------
/css/portable.css:
--------------------------------------------------------------------------------
1 | /*
2 | MoneyLog Portable theme
3 | by Aurelio Jargas
4 | https://aurelio.net/moneylog/
5 |
6 | Light green: #E5EFDE
7 | Dark green: #4D8A68
8 | */
9 |
10 |
11 | #app-flavor {
12 | color: #4D8A68;
13 | }
14 |
15 | /* Dark background for active/special buttons */
16 | #fullscreen,
17 | .report th:hover,
18 | #editor-file-name,
19 | .button.active,
20 | a.button:active {
21 | background-color: #4D8A68;
22 | }
23 |
24 | /* Dark background for selected rows */
25 | tr.selected,
26 | tr.selected:hover td,
27 | tr.selected .neg {
28 | background-color: #4D8A68;
29 | }
30 |
31 | /* Dark color for borders */
32 | #editor-data-wrapper,
33 | #rows-summary,
34 | .button.active,
35 | a.button:active {
36 | border-color: #4D8A68;
37 | }
38 |
39 | /* Light background for selections */
40 | .hl,
41 | #tag-cloud-tags a.selected {
42 | background-color: #E5EFDE;
43 | }
44 |
45 | /* Light background for totals */
46 | tr.totals,
47 | td.totals,
48 | #rows-summary {
49 | background-color: #E5EFDE;
50 | }
51 |
52 | /* Light color for the report borders */
53 | .report td {
54 | border-color: #E5EFDE;
55 | }
56 |
57 |
58 | /* Special: interface dark green for the positive chart bar */
59 | .posbar {
60 | background-color: #4D8A68;
61 | }
62 |
--------------------------------------------------------------------------------
/css/print.css:
--------------------------------------------------------------------------------
1 | /*
2 | MoneyLog print theme
3 | by Aurelio Jargas
4 | https://aurelio.net/moneylog/
5 | */
6 |
7 | /* No toolbar */
8 | #toolbar {
9 | display: none;
10 | }
11 |
12 | /* No margin/padding */
13 | #content {
14 | margin: 0;
15 | padding: 0;
16 | }
17 |
18 | /* Remove row backgrounds */
19 | tr.future,
20 | tr.totals,
21 | td.totals {
22 | background-color: white !important;
23 | }
24 |
25 | /* Remove minibars from monthly/yearly reports */
26 | th.percent,
27 | td.minibar {
28 | display: none;
29 | }
30 |
31 | /* Remove chart bars background and use outlines instead */
32 | .posbar {
33 | background-color: white;
34 | border: 1px solid silver; /* solid */
35 | }
36 | .negbar {
37 | background-color: white;
38 | border: 1px dashed silver; /* dashed */
39 | }
40 |
41 | /* Make the SELECT button appear as plain text */
42 | #chart-selector {
43 | -webkit-appearance: none;
44 | background: white;
45 | border-width: 0;
46 | }
47 |
48 | /* Remove (or lighten, or force B&W) colors */
49 | .report td {
50 | border-color: #DDDDDD;
51 | }
52 | tr.selected,
53 | tr.selected .neg {
54 | background-color: #EEEEEE;
55 | color: black ;
56 | }
57 | #rows-summary {
58 | border: 1px solid silver;
59 | background-color: white;
60 | }
61 |
--------------------------------------------------------------------------------
/storage/drivers/browser.js:
--------------------------------------------------------------------------------
1 | // browser: localStorage
2 |
3 | ml.storage.drivers.browser = {
4 | id: 'browser',
5 | name: 'Browser (localStorage)',
6 | config: {
7 | isAsync: false,
8 | isEditable: true,
9 | isFileBased: false,
10 | isReloadable: false,
11 | loadDataAtSetup: true
12 | },
13 |
14 | // localStorage database key
15 | database: 'moneylogData',
16 |
17 | read: function () {
18 | return localStorage.getItem(this.database) || '';
19 | },
20 |
21 | write: function (contents) {
22 | localStorage.setItem(this.database, contents);
23 | },
24 |
25 | setDefaultData: function () {
26 | ml.storage.drivers.filesystem.readAsync(
27 | {name: 'sample/data-pt.txt'},
28 | function (contents) {
29 | ml.storage.drivers.browser.write(contents);
30 | loadData();
31 | }
32 | );
33 | },
34 |
35 | init: function () {
36 |
37 | // Browser support check
38 | if (!window.localStorage) {
39 | showError(
40 | i18n.errorNoLocalStorage.replace('%s', appName),
41 | '' + i18n.errorRequirements +
42 | array2ul(['Internet Explorer 8', 'Firefox 3', 'Google Chrome 3', 'Safari 4', 'Opera 10.50'])
43 | );
44 | }
45 |
46 | // Empty database? Initialize with sample content
47 | if (this.read().strip() === '') {
48 | this.setDefaultData();
49 | }
50 | }
51 | };
52 |
--------------------------------------------------------------------------------
/sample/widget-nerd-toy.js:
--------------------------------------------------------------------------------
1 | // --------------------------------------------------------------------
2 | // Nerd Toy Widget
3 | // by Aurelio Jargas 2012-02-16
4 | //
5 | // A sample widget that shows some MoneyLog options
6 | // for you to turn ON or OFF with handy checkboxes.
7 | //
8 | // Copy/paste all this code to the end of your config.js file.
9 |
10 |
11 | // Create a new widget instance
12 | var NerdToy = new Widget('nerd-toy', 'Nerd Toy', 'NerdToy');
13 |
14 | // Widget config
15 | NerdToy.config.active = true; // Is this widget active?
16 | NerdToy.config.opened = true; // Start app with this widget opened?
17 |
18 | // This function fills the widget contents, creating all the checkboxes.
19 | // populate() is called automatically in the default this.init().
20 | NerdToy.populate = function () {
21 | var i, opts, opt;
22 | opts = [
23 | 'showBalance',
24 | 'showChartBarLabel',
25 | 'showCharts',
26 | 'showLocaleDate',
27 | 'showMiniBars',
28 | 'showMiniBarsLabels',
29 | 'showRowCount',
30 | 'showTagReport',
31 | 'monthlyRowCount'
32 | ];
33 | for (i = 0; i < opts.length; i++) {
34 | opt = opts[i];
35 | this.addCheckbox(opt, opt, (window[opt] == true));
36 | }
37 | };
38 |
39 | // This is called automatically whenever a checkbox is clicked.
40 | NerdToy.checkboxClicked = function (checkbox) {
41 | var optionName = checkbox.id.replace('nerd-toy-', '');
42 | window[optionName] = checkbox.checked; // set config
43 | showReport(); // reload the report
44 | };
45 |
--------------------------------------------------------------------------------
/util/conversor/myMoneyLog.txt:
--------------------------------------------------------------------------------
1 | # http://nishimura.eti.br/mymoneylog/moneylog2my.html
2 |
3 | 2009-05-01 -100 Saldo inicial da conta :( CONTA
4 | 2009-05-15 -74.23 mercado CONTA
5 | 2009-05-15 -1.99 Prestação do mouse 10/12 nerd CONTA
6 | 2009-05-23 -39.90 Livro "Horóscopo dos Duendes" presente; livro CONTA
7 | 2009-06-03 -342.59 Um Shrubbery presente CONTA
8 | 2009-06-11 30 Ganhei a aposta com o Zé CONTA
9 | 2009-06-12 -35 Poster colorido 3D do Tux em Ascii Art presente; nerd CONTA
10 | 2009-06-15 -1.99 Prestação do mouse 11/12 nerd CONTA
11 | 2009-06-29 -95.67 mercado CONTA
12 | 2009-07-12 -199.90 Segway usado no Mercado Livre presente CONTA
13 | 2009-07-15 -1.99 Prestação do mouse 12/12 (acabou!) nerd CONTA
14 | 2009-08-20 -10 Carnê do Baú CONTA
15 | 2009-05-05 500 salario CONTA
16 | 2009-06-05 500 salario CONTA
17 | 2009-07-05 500 salario CONTA
18 | 2009-08-05 500 salario CONTA
19 | 2009-05-07 -25 luz CONTA
20 | 2009-06-07 -20 luz CONTA
21 | 2009-07-07 -29 luz CONTA
22 | 2009-08-07 -25 luz CONTA
23 | 2009-05-07 -20 agua CONTA
24 | 2009-06-07 -17.80 agua CONTA
25 | 2009-07-07 -32.37 agua CONTA
26 | 2009-08-07 -30 agua CONTA
27 | 2009-12-31 99.99 Bônus salario CONTA
28 | 2009-08-05 -500/5 Netbook usado comprado parcelado nerd CONTA
29 | 2009-11-25 100/2 Presente de Natal, metade Nov, metade Dez presente CONTA
30 | 2009-05-05 -200*6 Aluguel da casa (seis meses) aluguel CONTA
31 | 2009-09-10 100*4 O Zé vai me dar 100 pilas por mês até o fim do ano presente CONTA
32 |
--------------------------------------------------------------------------------
/sample/widget-hello-translation.js:
--------------------------------------------------------------------------------
1 | // --------------------------------------------------------------------
2 | // Hello Translation Widget
3 | // by Aurelio Jargas 2012-02-17
4 | //
5 | // A simple sample widget, using translated strings.
6 | //
7 | // Copy/paste all this code to the end of your config.js file.
8 |
9 | // Create a new widget instance (id, name, instance name)
10 | var HelloTranslation = new Widget('hello-translation', 'Hello Translation', 'HelloTranslation');
11 |
12 | // Save widget translation to the main database
13 | // header
14 | i18nDatabase.en.HelloTranslationHeaderLabel = 'Hello Translation';
15 | i18nDatabase.es.HelloTranslationHeaderLabel = 'Hola Traducción';
16 | i18nDatabase.pt.HelloTranslationHeaderLabel = 'Oi Tradução';
17 | // checkbox label
18 | i18nDatabase.en.HelloTranslationOptionLabel = 'Say hello!';
19 | i18nDatabase.es.HelloTranslationOptionLabel = '¡Decir hola!';
20 | i18nDatabase.pt.HelloTranslationOptionLabel = 'Diga oi!';
21 | // Note: always use {InstanceName}HeaderLabel for automatic header translation
22 |
23 | // Debug: change the app language to test the translations
24 | // lang = 'es'; // en:English, es:Spanish, pt:Portuguese
25 |
26 |
27 | // Set widget contents
28 | HelloTranslation.populate = function () {
29 | // Here we use the translated label.
30 | // Note that the prefix is just i18n.
31 | this.addCheckbox('foo', i18n.HelloTranslationOptionLabel);
32 | };
33 |
34 | // Handle checkbox click
35 | HelloTranslation.checkboxClicked = function (checkbox) {
36 | console.log('clicked ' + checkbox.id);
37 | };
38 |
--------------------------------------------------------------------------------
/util/conversor/moneylog4-ok.txt:
--------------------------------------------------------------------------------
1 | # comentário
2 |
3 | 2009-05-01 -100 normal, sem centavos
4 | 2009-05-01 -100,00 normal, com centavos
5 | 2009-05-01 +100.00 normal, com centavos ponto
6 |
7 | 2009-05-01 -100 4 espaços antes do sinal, sem centavos
8 | 2009-05-01 +100,00 4 espaços antes do sinal, com centavos
9 | 2009-05-01 -100.00 4 espaços antes do sinal, com centavos ponto
10 |
11 | 2009-05-01 +100 4 espaços após o sinal, sem centavos
12 | 2009-05-01 -100,00 4 espaços após o sinal, com centavos
13 | 2009-05-01 -100.00 4 espaços após o sinal, com centavos ponto
14 |
15 | 2009-05-01 -100/2 normal, sem centavos, recorrente sem espaços
16 | 2009-05-01 -100,00/2 normal, com centavos, recorrente sem espaços
17 | 2009-05-01 +100.00/2 normal, com centavos ponto, recorrente sem espaços
18 |
19 | 2009-05-01 -100*2 normal, sem centavos, recorrente sem espaços
20 | 2009-05-01 +100,00*2 normal, com centavos, recorrente sem espaços
21 | 2009-05-01 -100.00*2 normal, com centavos ponto, recorrente sem espaços
22 |
23 | 2009-05-01 +100*2 4 espaços após o sinal, sem centavos, recorrente com espaços
24 | 2009-05-01 -100,00*2 4 espaços após o sinal, com centavos, recorrente com espaços
25 | 2009-05-01 -100.00*2 4 espaços após o sinal, com centavos ponto, recorrente com espaços
26 |
27 | 2009-05-01 -100/2 4 espaços após o sinal, sem centavos, recorrente com espaços
28 | 2009-05-01 -100,00/2 4 espaços após o sinal, com centavos, recorrente com espaços
29 | 2009-05-01 +100.00/2 4 espaços após o sinal, com centavos ponto, recorrente com espaços
30 |
--------------------------------------------------------------------------------
/util/conversor/moneylog4.txt:
--------------------------------------------------------------------------------
1 | # comentário
2 |
3 | 2009-05-01 -100 normal, sem centavos
4 | 2009-05-01 -100,00 normal, com centavos
5 | 2009-05-01 +100.00 normal, com centavos ponto
6 |
7 | 2009-05-01 -100 4 espaços antes do sinal, sem centavos
8 | 2009-05-01 +100,00 4 espaços antes do sinal, com centavos
9 | 2009-05-01 -100.00 4 espaços antes do sinal, com centavos ponto
10 |
11 | 2009-05-01 + 100 4 espaços após o sinal, sem centavos
12 | 2009-05-01 - 100,00 4 espaços após o sinal, com centavos
13 | 2009-05-01 - 100.00 4 espaços após o sinal, com centavos ponto
14 |
15 | 2009-05-01 -100/2 normal, sem centavos, recorrente sem espaços
16 | 2009-05-01 -100,00/2 normal, com centavos, recorrente sem espaços
17 | 2009-05-01 +100.00/2 normal, com centavos ponto, recorrente sem espaços
18 |
19 | 2009-05-01 -100*2 normal, sem centavos, recorrente sem espaços
20 | 2009-05-01 +100,00*2 normal, com centavos, recorrente sem espaços
21 | 2009-05-01 -100.00*2 normal, com centavos ponto, recorrente sem espaços
22 |
23 | 2009-05-01 + 100 *2 4 espaços após o sinal, sem centavos, recorrente com espaços
24 | 2009-05-01 - 100,00 *2 4 espaços após o sinal, com centavos, recorrente com espaços
25 | 2009-05-01 - 100.00 *2 4 espaços após o sinal, com centavos ponto, recorrente com espaços
26 |
27 | 2009-05-01 - 100 /2 4 espaços após o sinal, sem centavos, recorrente com espaços
28 | 2009-05-01 - 100,00 /2 4 espaços após o sinal, com centavos, recorrente com espaços
29 | 2009-05-01 + 100.00 /2 4 espaços após o sinal, com centavos ponto, recorrente com espaços
30 |
--------------------------------------------------------------------------------
/sample/data-es.txt:
--------------------------------------------------------------------------------
1 | # Cambie estos datos por los suyos, separando las columnas usando espacios en blanco
2 | # La fecha debe ser ingresada en el formato AÑO-MES-DÍA
3 |
4 | 2016-11-01 -100,00 Saldo inicial :(
5 |
6 | 2016-12-15 -74,23 comida|
7 | 2016-12-23 -39,90 regalos, libros| Libro "Horóscopo de los Duendes"
8 |
9 | 2017-01-03 -342,59 regalos| Un Shrubbery
10 | 2017-01-11 +30,00 Le gané una apuesta a Marcos
11 | 2017-01-12 -35,00 regalos, nerd| Poster 3D en colores de Tux en Ascii Art
12 | 2017-01-29 -95,67 comida|
13 |
14 | 2017-02-12 -199,90 regalos| Segway usado en mercadolibre.com
15 |
16 | 2017-03-20 -10,00 Carnet del Club
17 |
18 | # Es posible dejar juntos todos los movimientos periodicos. El orden no importa en este caso
19 |
20 | 2016-12-05 500 salario|
21 | 2017-01-05 500 salario|
22 | 2017-02-05 500 salario|
23 | 2017-03-05 500 salario|
24 | 2017-04-05 500 salario|
25 |
26 | 2016-12-07 -25,00 luz|
27 | 2017-01-07 -20,00 luz|
28 | 2017-02-07 -29,00 luz|
29 | 2017-03-07 -25,00 luz|
30 |
31 | 2016-12-07 -20,00 agua|
32 | 2017-01-07 -17,80 agua|
33 | 2017-02-07 -32,37 agua|
34 | 2017-03-07 -30,00 agua|
35 |
36 | # Ingresos y Egresos en cuotas
37 |
38 | 2016-12-05 -500/5 nerd| Netbook usado comprado en cuotas
39 | 2016-11-25 100/2 regalos| Regalo de Navidad, mitad Nov., mitad Dic.
40 |
41 | # Ingresos y Egresos recurrentes
42 |
43 | 2017-01-05 -200*6 alquiler| Alquiler de la casa (seis meses)
44 | 2016-11-10 100*2 apuestas| Marcos me va a dar 100 pesos por mes hasta fin de año
45 |
--------------------------------------------------------------------------------
/sample/data-en.txt:
--------------------------------------------------------------------------------
1 | # Change this data by yours, separated by spaces
2 | # The date is on the YEAR-MONTH-DAY format
3 | # The amount may be positive or negative, with or without cents
4 | # The tags are optional, separated from the description by a |
5 | # The description is also optional
6 |
7 | 2016-11-01 -100.00 My initial balance :(
8 |
9 | 2016-12-15 -74.23 supermarket|
10 | 2016-12-23 -39.90 gift, book| "Gremlins Horoscope" book
11 |
12 | 2017-01-03 -342.59 gift| One Shrubbery
13 | 2017-01-11 +30.00 I've won that bet with John
14 | 2017-01-12 -35.00 gift, geek| Ascii Art Tux 3D poster
15 | 2017-01-29 -95.67 supermarket|
16 |
17 | 2017-02-12 -199.90 gift| Used Segway on E-bay
18 |
19 | 2017-03-20 -10.00 Dinner at downtown
20 |
21 | # The order is not important. You can join together recurring transactions.
22 |
23 | 2016-12-05 500 salary|
24 | 2017-01-05 500 salary|
25 | 2017-02-05 500 salary|
26 | 2017-03-05 500 salary|
27 | 2017-04-05 500 salary|
28 |
29 | 2016-12-07 -25.00 energy|
30 | 2017-01-07 -20.00 energy|
31 | 2017-02-07 -29.00 energy|
32 | 2017-03-07 -25.00 energy|
33 |
34 | 2016-12-07 -20.00 water|
35 | 2017-01-07 -17.80 water|
36 | 2017-02-07 -32.37 water|
37 | 2017-03-07 -30.00 water|
38 |
39 | # Installment payments: use a / and the number of months
40 |
41 | 2016-12-05 -500/5 geek| Used Netbook bought in 5 payments
42 | 2016-11-25 100/2 gift| Christmas gift: half in November, half in December
43 |
44 | # Recurring payments: use a * and the number of months
45 |
46 | 2017-01-05 -200*6 rental| Home rental (seis months)
47 | 2016-11-10 100*2 gift| Uncle Arnold will give me 100 bucks/month until December
48 |
--------------------------------------------------------------------------------
/sample/data-pt.txt:
--------------------------------------------------------------------------------
1 | # Troque estes dados pelos seus, separados por espaços
2 | # A data é no formato ANO-MES-DIA
3 | # O valor pode ser positivo ou negativo, com ou sem centavos
4 | # As tags são opcionais, separadas da descrição por uma |
5 | # A descrição também é opcional
6 | # Guia completo em https://aurelio.net/moneylog/input/
7 |
8 | 2016-11-01 -100,00 Saldo inicial da conta :(
9 |
10 | 2016-12-15 -74,23 mercado|
11 | 2016-12-23 -39,90 presente, livro| Livro "Horóscopo dos Duendes"
12 |
13 | 2017-01-03 -342,59 presente| Um Shrubbery
14 | 2017-01-11 +30,00 Ganhei a aposta com o Zé
15 | 2017-01-12 -35,00 presente, nerd| Poster colorido 3D do Tux em Ascii Art
16 | 2017-01-29 -95,67 mercado|
17 |
18 | 2017-02-12 -199,90 presente| Segway usado no Mercado Livre
19 |
20 | 2017-03-20 -10,00 Carnê do Baú
21 |
22 | # A ordem não importa, é possível deixar juntas as transações periódicas
23 |
24 | 2016-12-05 500 salário|
25 | 2017-01-05 500 salário|
26 | 2017-02-05 500 salário|
27 | 2017-03-05 500 salário|
28 | 2017-04-05 500 salário|
29 |
30 | 2016-12-07 -25,00 luz|
31 | 2017-01-07 -20,00 luz|
32 | 2017-02-07 -29,00 luz|
33 | 2017-03-07 -25,00 luz|
34 |
35 | 2016-12-07 -20,00 água|
36 | 2017-01-07 -17,80 água|
37 | 2017-02-07 -32,37 água|
38 | 2017-03-07 -30,00 água|
39 |
40 | # Pagamentos e ganhos parcelados: use uma / e o número de meses
41 |
42 | 2016-12-05 -500/5 nerd| Netbook usado comprado parcelado
43 | 2016-11-25 100/2 presente| Presente de Natal, metade Nov, metade Dez
44 |
45 | # Pagamentos e ganhos recorrentes: use um * e o número de meses
46 |
47 | 2017-01-05 -200*6 aluguel| Aluguel da casa (seis meses)
48 | 2016-11-10 100*2 presente| O Zé vai me dar 100 pilas por mês até o fim do ano
49 |
--------------------------------------------------------------------------------
/storage/drivers/filesystem.js:
--------------------------------------------------------------------------------
1 | // File system: local text files
2 |
3 | ml.storage.drivers.filesystem = {
4 | id: 'filesystem',
5 | name: 'Local text files',
6 | config: {
7 | isAsync: true,
8 | isEditable: false,
9 | isFileBased: true,
10 | isReloadable: true,
11 | showFolderLink: false,
12 | loadDataAtSetup: true,
13 | maxFilesForStar: 999
14 | },
15 |
16 | dataFiles: [], // flat array, meant for easier user config
17 | userFiles: [], // [{id:'', name:''}, ...]
18 | defaultFile: '',
19 |
20 | setUserFilesFromFlatArray: function (arr) {
21 | var i;
22 | this.userFiles = [];
23 | for (i = 0; i < arr.length; i++) {
24 | this.userFiles.push({
25 | id: i,
26 | name: arr[i]
27 | });
28 | }
29 | },
30 |
31 | // Use a temporary iframe to read a local text file contents.
32 | // Note: Firefox won't read text files in a parent folder.
33 | readAsync: function (fileData, callback) {
34 | var iframe = document.createElement('iframe');
35 | iframe.style.display = 'none';
36 | iframe.src = fileData.name;
37 | iframe.onload = function () {
38 | callback(iframe.contentWindow.document.getElementsByTagName('pre')[0].innerText);
39 | iframe.parentNode.removeChild(iframe); // del iframe
40 | };
41 | document.body.appendChild(iframe); // add iframe
42 | },
43 |
44 | init: function () {
45 | var filesCombo;
46 |
47 | // Honor legacy global config: dataFiles array
48 | if (this.dataFiles.length === 0 && dataFiles && dataFiles.length > 0) {
49 | this.dataFiles = dataFiles;
50 | }
51 |
52 | // Honor legacy global config: dataFilesDefault
53 | if (!this.defaultFile && dataFilesDefault) {
54 | this.defaultFile = dataFilesDefault;
55 | }
56 |
57 | // Set user files from config array
58 | if (this.dataFiles.length > 0) {
59 | this.setUserFilesFromFlatArray(this.dataFiles);
60 | }
61 |
62 | ml.storage.populateFilesCombo();
63 |
64 | // Set the default file to load when using multiple files
65 | if (this.defaultFile) {
66 | filesCombo = document.getElementById('source-file');
67 | selectOptionByText(filesCombo, this.defaultFile);
68 | }
69 | }
70 | };
71 |
--------------------------------------------------------------------------------
/util/gen-browser:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Aurelio Jargas, https://aurelio.net/moneylog/
3 | #
4 | # Script to join all the MoneyLog pieces in one singe HTML file, generating
5 | # the MoneyLog Browser version, who uses localStorage instead of text files.
6 | #
7 | # Usage:
8 | # gen-browser [--lang XX]
9 | #
10 | # Examples:
11 | # gen-browser # Portuguese browser version
12 | # gen-browser --lang en # English browser version
13 | #
14 | # Note:
15 | # The results are Windows-style line break: CR+LF
16 |
17 |
18 | cd $(dirname "$0")
19 |
20 | lang="pt" # pt, en, es, ca. Use --lang to change it.
21 |
22 | # Option --lang
23 | if test "$1" = '--lang'
24 | then
25 | lang=$2
26 | shift
27 | shift
28 | fi
29 |
30 | # Files
31 | html_path="../moneylog.html"
32 | txt_path="../sample/data-$lang.txt"
33 |
34 | # Set $commit_id to the latest Git commit hash
35 | source set-commit-id.sh
36 |
37 | # Patterns:
38 | #
39 | #
40 |
41 | insert_css='
42 | /^
45 | r ../moneylog.css
46 | a \
47 | \
48 |
52 | d
53 | }
54 |
55 | /^
58 | r ../css/mobile.css
59 | a \
60 |
61 | d
62 | }
63 |
64 | /^
67 | r ../css/print.css
68 | a \
69 |
70 | d
71 | }
72 | '
73 | insert_js='
74 | /^
80 | d
81 | }
82 | '
83 | insert_txt="
84 | /^
sed_script
88 |
89 | # Do it
90 | control_m=$(printf '\r')
91 |
92 | sed -f sed_script "$html_path" |
93 | # Set language
94 | sed "/^var lang = 'pt';/ s/pt/$lang/" |
95 | # Set commit id
96 | sed "/^var appCommit = '';/ s/'/'$commit_id/" |
97 | # clean up
98 | sed '
99 | # Remove config.js call
100 | /^
39 |
40 | insert_css='
41 | /^
44 | r ../moneylog.css
45 | a \
46 | \
47 |
51 | d
52 | }
53 |
54 | /^
57 | r ../css/mobile.css
58 | a \
59 |
60 | d
61 | }
62 |
63 | /^
66 | r ../css/print.css
67 | a \
68 |
69 | d
70 | }
71 | '
72 | insert_js='
73 | /^\
79 | \
80 | \
81 | \
82 | \
83 | {{ user_config }}
84 | d
85 | }
86 | '
87 | insert_meta='
88 | /^
90 | '
91 | insert_analytics='
92 | /^<\/head>/ {
93 | r gen-cloud-analytics.html
94 | a \
95 |
96 | d
97 | }
98 | '
99 |
100 | echo "$insert_css $insert_js $insert_meta $insert_analytics" > sed_script
101 |
102 | # Do it
103 | control_m=$(printf '\r')
104 |
105 | sed -f sed_script "$html_path" |
106 | # Set language
107 | sed "/^var lang = 'pt';/ s/pt/$lang/" |
108 | # Set commit id
109 | sed "/^var appCommit = '';/ s/'/'$commit_id/" |
110 | # clean up
111 | sed '
112 | # Remove config.js call
113 | /^
69 |
70 | insert_css='
71 | /^
74 | r ../moneylog.css
75 | a \
76 |
77 | d
78 | }
79 |
80 | /^
83 | r ../css/portable.css
84 | a \
85 |
86 | d
87 | }
88 |
89 | /^
92 | r ../css/mobile.css
93 | a \
94 |
95 | d
96 | }
97 |
98 | /^
101 | r ../css/print.css
102 | a \
103 |
104 | d
105 | }
106 | '
107 | insert_js='
108 | /^
114 | d
115 | }
116 | /^
122 | d
123 | }
124 | /^
130 | d
131 | }
132 | /^
8 | // 2. In your browser, open the JavaScript console to see the messages.
9 | // 3. Run MoneyLog, every tests should report "ok".
10 |
11 | /* eslint no-plusplus: "off" */
12 |
13 | var zz, suffix;
14 |
15 | suffix = ' (expected, results):';
16 |
17 |
18 | // Disable MoneyLog init() process
19 | window.onload = function () {
20 | document.getElementById('report').innerHTML =
21 | 'MoneyLog Test Mode
' +
22 | 'Open the JavaScript console to see the test messages.';
23 | };
24 |
25 |
26 | function check(results, ok) {
27 | // Tests strings and numbers
28 |
29 | var prefix = 'Test ' + zz + ': ';
30 |
31 | if (results === ok) {
32 | console.log(prefix + 'ok');
33 | } else {
34 | console.log(prefix + 'FAILED' + suffix);
35 | console.log(ok);
36 | console.log(results);
37 | }
38 | }
39 |
40 | function checkArray(results, ok, quiet) {
41 | // Special function to test arrays because [] == [] returns false.
42 |
43 | // console.log('checkArray called with (results, ok, quiet);
44 | // console.log(results);
45 | // console.log(ok);
46 | // console.log(quiet);
47 |
48 | var i, failed;
49 | var prefix = 'Test ' + zz + ': ';
50 |
51 | for (i = 0; i < ok.length; i++) {
52 |
53 | // Array inside array?
54 | if (typeof results[i] === 'object') {
55 | if (checkArray(results[i], ok[i], 'quiet')) {
56 | continue;
57 | } else {
58 | failed = i;
59 | break;
60 | }
61 | }
62 |
63 | // string|number contents, just test
64 | if (results[i] !== ok[i]) {
65 | failed = i;
66 | break;
67 | }
68 | }
69 | if (failed !== undefined) {
70 | if (!quiet) {
71 | console.log(prefix + 'FAILED at array item ' + failed + suffix);
72 | console.log(ok[failed]);
73 | console.log(results[failed]);
74 | }
75 | return false;
76 | } else {
77 | if (!quiet) {
78 | console.log(prefix + 'ok');
79 | }
80 | return true;
81 | }
82 | }
83 |
84 | function checkObject(results, ok) {
85 | // Loop and check all object properties
86 |
87 | var x, failed;
88 | var prefix = 'Test ' + zz + ': ';
89 |
90 | for (x in ok) {
91 |
92 | // Array inside object?
93 | // Note: nested objects are not supported
94 | if (typeof results[x] === 'object') {
95 | if (checkArray(results[x], ok[x], 'quiet')) {
96 | continue;
97 | } else {
98 | failed = x;
99 | break;
100 | }
101 | }
102 |
103 | // string|number contents, just test
104 | if (results[x] !== ok[x]) {
105 | failed = x;
106 | break;
107 | }
108 | }
109 | if (failed !== undefined) {
110 | console.log(prefix + 'FAILED at property "' + failed + '"' + suffix);
111 | console.log(ok[failed]);
112 | console.log(results[failed]);
113 |
114 | console.log('*** Full objects (expected, results):');
115 | console.log(ok);
116 | console.log(results);
117 | return false;
118 | } else {
119 | console.log(prefix + 'ok');
120 | return true;
121 | }
122 | }
123 |
124 | console.log('-------------- MoneyLog Tests BEGIN');
125 |
126 | zz = 0;
127 | zz++; checkArray([], []);
128 | zz++; checkArray([1, 2, 3], [1, 2, 3]);
129 | zz++; checkArray([[1, 2, 3]], [[1, 2, 3]]);
130 | zz++; checkArray([1, [2, [3, [4]]]], [1, [2, [3, [4]]]]);
131 | zz++; checkObject({}, {});
132 | zz++; checkObject({n: 1}, {n: 1});
133 | zz++; checkObject({n: 1, s: 'x', a: [1]}, {n: 1, s: 'x', a: [1]});
134 | zz++; checkObject({n: 1, s: 'x', a: [1, [2, [3]]]}, {n: 1, s: 'x', a: [1, [2, [3]]]});
135 | zz++; checkObject({a1: [1, [2, [3]]], a2: [3, [2, [1]]]}, {a2: [3, [2, [1]]], a1: [1, [2, [3]]]});
136 | // -------------------------------------------------------------- ^ Test 9
137 |
138 | // function Array.getColumn(n)
139 | zz++; checkArray([].getColumn(1), []);
140 | zz++; checkArray([[], [], []].getColumn(1), [undefined, undefined, undefined]);
141 | zz++; checkArray([[0, 1, 2], [3, 4, 5], [6, 7, 8]].getColumn(0), [0, 3, 6]);
142 | zz++; checkArray([[0, 1, 2], [3, 4, 5], [6, 7, 8]].getColumn(1), [1, 4, 7]);
143 | zz++; checkArray([[0, 1, 2], [3, 4, 5], [6, 7, 8]].getColumn(2), [2, 5, 8]);
144 | zz++; checkArray([[0, 1, 2], [3, 4], [6, 7, 8]].getColumn(2), [2, undefined, 8]);
145 | zz++; checkArray([[0, 1, 2], [3, 4, 5], [6, 7, 8]].getColumn(3), [undefined, undefined, undefined]);
146 | // -------------------------------------------------------------- ^ Test 16
147 |
148 | // function computeTotals(arr)
149 | zz++; check(computeTotals([]), undefined);
150 | zz++; checkObject(
151 | computeTotals([0]),
152 | {min: 0, max: 0, sum: 0, average: 0, sumPositive: 0, sumNegative: 0, balance: [0]}
153 | );
154 | zz++; checkObject(
155 | computeTotals([1]),
156 | {min: 1, max: 1, sum: 1, average: 1, sumPositive: 1, sumNegative: 0, balance: [1]}
157 | );
158 | zz++; checkObject(
159 | computeTotals([-1]),
160 | {min: -1, max: -1, sum: -1, average: -1, sumPositive: 0, sumNegative: -1, balance: [-1]}
161 | );
162 | zz++; checkObject(
163 | computeTotals([0, 0, 0, 0]),
164 | {min: 0, max: 0, sum: 0, average: 0, sumPositive: 0, sumNegative: 0, balance: [0, 0, 0, 0]}
165 | );
166 | zz++; checkObject(
167 | computeTotals([-2, -1, 0, 1, 2]),
168 | {min: -2, max: 2, sum: 0, average: 0, sumPositive: 3, sumNegative: -3, balance: [-2, -3, -3, -2, 0]}
169 | );
170 | zz++; checkObject(
171 | computeTotals([10.00, 25.50, -5.50, 33.33]),
172 | {min: -5.50, max: 33.33, sum: 63.33, average: 15.8325, sumPositive: 68.83, sumNegative: -5.50, balance: [10.00, 35.50, 30.00, 63.33]}
173 | );
174 | // -------------------------------------------------------------- ^ Test 23
175 |
176 | // function groupByPeriod(arr, periodType) { // m, y
177 | zz++; checkObject(
178 | groupByPeriod([
179 | ['2012-02-15', '1', 'foo1'],
180 | ['2012-02-18', '2', 'foo2'],
181 | ['2012-02-28', '3', 'foo3'],
182 | ['2012-03-04', '-4', 'bar1'],
183 | ['2012-03-18', '-5', 'bar2'],
184 | ['2012-04-01', '6', 'baz']
185 | ], 'm'),
186 | {
187 | '2012-02': [
188 | ['2012-02-15', '1', 'foo1'],
189 | ['2012-02-18', '2', 'foo2'],
190 | ['2012-02-28', '3', 'foo3']
191 | ],
192 | '2012-03': [
193 | ['2012-03-04', '-4', 'bar1'],
194 | ['2012-03-18', '-5', 'bar2']
195 | ],
196 | '2012-04': [['2012-04-01', '6', 'baz']],
197 | 'keys': ['2012-02', '2012-03', '2012-04']
198 | }
199 | );
200 | zz++; checkObject(
201 | groupByPeriod([ // input sorted
202 | ['2012-02-15', '1', 'foo1'],
203 | ['2012-02-18', '2', 'foo2'],
204 | ['2012-02-28', '3', 'foo3'],
205 | ['2013-03-04', '-4', 'bar1'],
206 | ['2013-03-18', '-5', 'bar2'],
207 | ['2014-04-01', '6', 'baz']
208 | ], 'y'),
209 | {
210 | '2012': [
211 | ['2012-02-15', '1', 'foo1'],
212 | ['2012-02-18', '2', 'foo2'],
213 | ['2012-02-28', '3', 'foo3']
214 | ],
215 | '2013': [
216 | ['2013-03-04', '-4', 'bar1'],
217 | ['2013-03-18', '-5', 'bar2']
218 | ],
219 | '2014': [['2014-04-01', '6', 'baz']],
220 | 'keys': ['2012', '2013', '2014']
221 | }
222 | );
223 | zz++; checkObject(
224 | groupByPeriod([ // input unsorted
225 | ['2012-02-15', '1', 'foo1'],
226 | ['2014-04-01', '6', 'baz'],
227 | ['2013-03-04', '-4', 'bar1'],
228 | ['2012-02-18', '2', 'foo2'],
229 | ['2013-03-18', '-5', 'bar2'],
230 | ['2012-02-28', '3', 'foo3']
231 | ], 'y'),
232 | {
233 | '2012': [
234 | ['2012-02-15', '1', 'foo1'],
235 | ['2012-02-18', '2', 'foo2'],
236 | ['2012-02-28', '3', 'foo3']
237 | ],
238 | '2013': [
239 | ['2013-03-04', '-4', 'bar1'],
240 | ['2013-03-18', '-5', 'bar2']
241 | ],
242 | '2014': [['2014-04-01', '6', 'baz']],
243 | 'keys': ['2012', '2013', '2014']
244 | }
245 | );
246 | // -------------------------------------------------------------- ^ Test 26
247 |
248 |
249 | console.log('-------------- MoneyLog Tests END');
250 |
--------------------------------------------------------------------------------
/storage/drivers/googledrive.js:
--------------------------------------------------------------------------------
1 | // Google Drive integration for MoneyLog
2 | //
3 | // By default, it searches for a MoneyLog folder in the root of your Drive,
4 | // and load all its files automatically, no user action required.
5 | //
6 | // If that folder is not found, then the Google Picker is loaded so the
7 | // user can point where the MoneyLog folder is located.
8 |
9 | ml.storage.drivers.googledrive = {
10 | id: 'googledrive',
11 | name: 'Google Drive',
12 | config: {
13 | isAsync: true,
14 | isEditable: false,
15 | isFileBased: true,
16 | isReloadable: true,
17 | showFolderLink: true,
18 | loadDataAtSetup: false,
19 |
20 | // Google Drive API has a User Rate Limit of 10 requests per second
21 | // See https://github.com/aureliojargas/moneylog/issues/22
22 | maxFilesForStar: 9
23 | },
24 |
25 | userFolder: {}, // {id:'', name:''}
26 | configFile: {}, // {id:'', name:''}
27 | userFiles: [], // [{id:'', name:''}, ...]
28 | defaultFile: '',
29 |
30 | readAsync: function (fileData, callback) {
31 | this.readFile(fileData.id, callback);
32 | },
33 |
34 | init: function () {
35 | ml.storage.resetFilesCombo();
36 | ml.storage.resetWidgetFolder();
37 |
38 | if (!window.gapi) {
39 | // Load the Google API
40 | addScript('https://apis.google.com/js/api.js', this.onApiLoad.bind(this));
41 | } else {
42 | // Already loaded, call API entrypoint
43 | this.onApiLoad();
44 | }
45 | },
46 |
47 | // -----------------------------------------------------------------------
48 |
49 | // The base of this code is a copy/paste from the official documentation:
50 | // https://developers.google.com/picker/docs/
51 |
52 | // The Browser API and Client ID keys obtained from the Google API Console
53 | developerKey: 'AIzaSyAgPNmODKpMNzP30VdvvgQFSw-H8mtIegc',
54 | clientId: '372105999892-po48pkb5kjlhlf1t3j2bj96se9v986cp.apps.googleusercontent.com',
55 | oauthToken: '',
56 |
57 | // Scope to use to access user's files (the more restrictive, the better)
58 | // https://developers.google.com/drive/v3/web/about-auth
59 | scope: ['https://www.googleapis.com/auth/drive.readonly'],
60 |
61 | // https://developers.google.com/picker/docs/#i18n
62 | pickerLanguages: {
63 | pt: 'pt-BR',
64 | en: 'en',
65 | es: 'es',
66 | ca: 'ca'
67 | },
68 |
69 | // Use the API Loader script to load google.picker and gapi.auth.
70 | onApiLoad: function () {
71 | gapi.load('auth', this.onAuthApiLoad.bind(this));
72 | },
73 |
74 | onAuthApiLoad: function () {
75 | gapi.auth.authorize(
76 | {
77 | 'client_id': this.clientId,
78 | 'scope': this.scope,
79 | 'immediate': false
80 | },
81 | function handleAuthResult(authResult) {
82 | if (authResult && !authResult.error) {
83 | this.oauthToken = authResult.access_token;
84 | this.onAuthOk();
85 | } else {
86 | console.log('Google auth failed:', authResult);
87 | }
88 | }.bind(this)
89 | );
90 | },
91 |
92 | onAuthOk: function () {
93 | this.findUserFolder(function () {
94 | this.setWidgetFolder();
95 | this.listAllUserFiles(this.processFiles.bind(this));
96 | }.bind(this));
97 | },
98 |
99 | runPicker: function (callback) {
100 |
101 | // Load Picker API
102 | gapi.load(
103 | 'picker',
104 | function onPickerApiLoad() {
105 |
106 | // Picker setup: will show folders only, in hierarquical view
107 | var view = new google.picker.DocsView(google.picker.ViewId.FOLDERS)
108 | .setParent('root')
109 | .setIncludeFolders(true)
110 | .setSelectFolderEnabled(true)
111 | .setMode(google.picker.DocsViewMode.LIST);
112 |
113 | // Load Picker
114 | var picker = new google.picker.PickerBuilder()
115 | .addView(view)
116 | .setOAuthToken(this.oauthToken)
117 | .setDeveloperKey(this.developerKey)
118 | .enableFeature(google.picker.Feature.NAV_HIDDEN)
119 | .setLocale(this.pickerLanguages[lang])
120 | .setTitle(i18n.labelLocateAppFolder)
121 | .setCallback(function onPickerDone(data) {
122 | if (data.action == google.picker.Action.PICKED) {
123 | this.userFolder = data.docs[0]; // Save picked folder metadata
124 | callback();
125 | }
126 | }.bind(this))
127 | .build();
128 | picker.setVisible(true);
129 |
130 | }.bind(this)
131 | );
132 | },
133 |
134 | processFiles: function (files) {
135 |
136 | // Filter relevant files
137 | this.userFiles = files.filter(function (file) { return file.name.endsWith('.txt'); });
138 | this.configFile = files.filter(function (file) { return file.name === 'config.js'; })[0] || {};
139 |
140 | ml.storage.populateFilesCombo();
141 |
142 | // Apply user config.js file (if any)
143 | if (this.configFile.id) {
144 | this.readFile(this.configFile.id, function (contents) {
145 | ml.storage.applyUserConfig(contents);
146 | ml.storage.setFilesCombo(this.defaultFile);
147 | loadData();
148 | }.bind(this));
149 | } else {
150 | ml.storage.setFilesCombo(this.defaultFile);
151 | loadData();
152 | }
153 | },
154 |
155 | // Set this.userFolder and callback
156 | findUserFolder: function (callback) {
157 | this.findDefaultUserFolder(function () {
158 |
159 | // Found default /MoneyLog folder
160 | if (this.userFolder.id) {
161 | callback();
162 |
163 | // Not found, will prompt user with the Picker
164 | } else {
165 | this.runPicker(callback);
166 | }
167 | }.bind(this));
168 | },
169 |
170 | findDefaultUserFolder: function (callback) {
171 | // Folder named MoneyLog at Google Drive root
172 | var query = '"root" in parents and name = "MoneyLog" and mimeType = "application/vnd.google-apps.folder"';
173 | this.listFiles(query, function (files) {
174 | if (files && files.length > 0) {
175 | this.userFolder = files[0];
176 | }
177 | callback();
178 | }.bind(this));
179 | },
180 |
181 | setWidgetFolder: function () {
182 | var a = document.getElementById('storage-folder');
183 | a.href = 'https://drive.google.com/drive/folders/' + this.userFolder.id;
184 | a.innerText = this.userFolder.name;
185 | },
186 |
187 | listAllUserFiles: function (callback) {
188 | var query;
189 | if (this.userFolder.id) {
190 | query = '"' + this.userFolder.id + '" in parents and (mimeType = "text/plain" or mimeType = "application/x-javascript")';
191 | this.listFiles(query, callback);
192 | }
193 | },
194 |
195 | // https://developers.google.com/drive/v3/web/folder
196 | // https://developers.google.com/drive/v3/reference/files/list
197 | // https://developers.google.com/drive/v3/web/search-parameters
198 | listFiles: function (query, callback) {
199 | var url, queryString, accessToken, xhr, data;
200 |
201 | accessToken = gapi.auth.getToken().access_token;
202 | url = 'https://www.googleapis.com/drive/v3/files';
203 | queryString = encodeQueryData({
204 | q: 'trashed = false and ' + query, // never list trashed
205 | spaces: 'drive',
206 | orderBy: 'name',
207 | fields: 'files(id, name)'
208 | });
209 |
210 | xhr = new XMLHttpRequest();
211 | xhr.open('GET', url + '?' + queryString);
212 | xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
213 | xhr.onreadystatechange = function () {
214 | if (xhr.readyState === XMLHttpRequest.DONE) {
215 | if (xhr.status === 200) {
216 | data = JSON.parse(xhr.responseText);
217 | callback(data.files);
218 | } else {
219 | console.log(xhr.responseText);
220 | }
221 | }
222 | };
223 | xhr.send();
224 | },
225 |
226 | // https://developers.google.com/drive/v3/web/manage-downloads
227 | readFile: function (id, callback) {
228 | var downloadUrl, accessToken, xhr;
229 |
230 | if (id) {
231 | downloadUrl = 'https://www.googleapis.com/drive/v3/files/' + id + '?alt=media';
232 | accessToken = gapi.auth.getToken().access_token;
233 |
234 | xhr = new XMLHttpRequest();
235 | xhr.open('GET', downloadUrl);
236 | xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
237 | xhr.onreadystatechange = function () {
238 | if (xhr.readyState === XMLHttpRequest.DONE) {
239 | if (xhr.status === 200) {
240 | callback(xhr.responseText);
241 | } else {
242 | console.log(xhr.responseText);
243 | }
244 | }
245 | };
246 | xhr.send();
247 | } else {
248 | console.log('ERROR: No file id informed');
249 | }
250 | }
251 | };
252 |
--------------------------------------------------------------------------------
/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | env:
2 | browser: true
3 |
4 | # Unfortunately, MoneyLog is a globals festival :(
5 | # These globals are used by other files than moneylog.js
6 | globals:
7 | addScript: false
8 | appName: false
9 | array2ul: false
10 | computeTotals: false
11 | encodeQueryData: false
12 | gapi: false
13 | google: false
14 | groupByPeriod: false
15 | i18nDatabase: false
16 | initUI: false
17 | loadData: false
18 | ml: false
19 | resetData: false
20 | sanitizeConfig: false
21 | selectOptionByText: false
22 | showError: false
23 | showReport: false
24 | Widget: false
25 | # modified
26 | dataFiles: true
27 | dataFilesDefault: true
28 | i18n: true
29 | lang: true
30 |
31 | extends: 'eslint:recommended'
32 | rules:
33 | accessor-pairs: error
34 | array-bracket-newline:
35 | - error
36 | - multiline: true
37 | array-bracket-spacing:
38 | - error
39 | - never
40 | array-callback-return: error
41 | array-element-newline: 'off' #ok
42 | block-scoped-var: error
43 | block-spacing:
44 | - error
45 | - always
46 | brace-style:
47 | - error
48 | - 1tbs
49 | - allowSingleLine: true
50 | callback-return: 'off' #ok
51 | camelcase: error
52 | capitalized-comments: 'off' #ok
53 | class-methods-use-this: error
54 | comma-dangle: error
55 | comma-spacing: error
56 | comma-style:
57 | - error
58 | - last
59 | complexity: 'off' #ok
60 | computed-property-spacing:
61 | - error
62 | - never
63 | consistent-return: error
64 | consistent-this: error
65 | curly: error
66 | default-case: error
67 | dot-location:
68 | - error
69 | - property
70 | dot-notation: error
71 | eol-last: error
72 | eqeqeq: 'off'
73 | for-direction: error
74 | func-call-spacing: error
75 | func-name-matching: error
76 | func-names: 'off' #ok
77 | func-style:
78 | - error
79 | - declaration
80 | function-paren-newline: error
81 | getter-return: error
82 | global-require: error
83 | guard-for-in: 'off'
84 | handle-callback-err: error
85 | id-blacklist: error
86 | id-length: 'off' #ok
87 | id-match: error
88 | implicit-arrow-linebreak: error
89 | indent:
90 | - error
91 | - tab
92 | init-declarations: 'off' #ok
93 | jsx-quotes: error
94 | key-spacing: error
95 | keyword-spacing: error
96 | line-comment-position: 'off' #ok
97 | linebreak-style:
98 | - error
99 | - unix
100 | lines-around-comment: error
101 | lines-between-class-members: error
102 | max-depth: 'off'
103 | max-len: 'off' #ok
104 | max-lines: 'off' #ok
105 | max-nested-callbacks: error
106 | max-params: 'off' #ok
107 | max-statements: 'off' #ok
108 | max-statements-per-line:
109 | - error
110 | - max: 2
111 | multiline-comment-style:
112 | - error
113 | - separate-lines
114 | multiline-ternary:
115 | - error
116 | - always-multiline
117 | new-cap: error
118 | new-parens: error
119 | newline-per-chained-call: 'off' #ok
120 | no-alert: error
121 | no-array-constructor: error
122 | no-await-in-loop: error
123 | no-bitwise: error
124 | no-buffer-constructor: error
125 | no-caller: error
126 | no-catch-shadow: error
127 | no-console: 'off' #ok
128 | no-continue: 'off' #ok
129 | no-div-regex: error
130 | no-else-return: 'off' #ok
131 | no-empty:
132 | - error
133 | - allowEmptyCatch: true
134 | no-empty-function: error
135 | no-eq-null: error
136 | no-eval: error
137 | no-extend-native: 'off' #ok
138 | no-extra-bind: error
139 | no-extra-label: error
140 | no-extra-parens: 'off' #ok
141 | no-floating-decimal: error
142 | no-implicit-coercion: error
143 | no-implicit-globals: 'off' #ok
144 | no-implied-eval: error
145 | no-inline-comments: 'off' #ok
146 | no-inner-declarations:
147 | - error
148 | - functions
149 | no-invalid-this: error
150 | no-iterator: error
151 | no-label-var: error
152 | no-labels: error
153 | no-lone-blocks: error
154 | no-lonely-if: 'off' #ok
155 | no-loop-func: error
156 | no-magic-numbers: 'off' #ok
157 | no-mixed-operators:
158 | - error
159 | - allowSamePrecedence: true
160 | no-mixed-requires: error
161 | no-multi-assign: error
162 | no-multi-spaces: 'off' #ok
163 | no-multi-str: error
164 | no-multiple-empty-lines:
165 | - error
166 | - max: 2
167 | maxBOF: 0
168 | maxEOF: 0
169 | no-negated-condition: 'off' #ok
170 | no-nested-ternary: 'off'
171 | no-new: error
172 | no-new-func: error
173 | no-new-object: error
174 | no-new-require: error
175 | no-new-wrappers: error
176 | no-octal-escape: error
177 | no-param-reassign: 'off' #ok
178 | no-path-concat: error
179 | no-plusplus:
180 | - error
181 | - allowForLoopAfterthoughts: true
182 | no-process-env: error
183 | no-process-exit: error
184 | no-proto: error
185 | no-prototype-builtins: error
186 | no-restricted-globals: error
187 | no-restricted-modules: error
188 | no-restricted-properties: error
189 | no-restricted-syntax: error
190 | no-return-assign: error
191 | no-return-await: error
192 | no-script-url: error
193 | no-self-compare: error
194 | no-sequences: error
195 | no-shadow: error
196 | no-shadow-restricted-names: error
197 | no-sync: error
198 | no-tabs: 'off' #ok
199 | no-template-curly-in-string: error
200 | no-ternary: 'off' #ok
201 | no-throw-literal: error
202 | no-trailing-spaces: error
203 | no-undef-init: error
204 | no-undefined: 'off'
205 | no-underscore-dangle: error
206 | no-unmodified-loop-condition: error
207 | no-unneeded-ternary: error
208 | no-unused-expressions: error
209 | no-use-before-define: 'off' #ok
210 | no-useless-call: error
211 | no-useless-concat: error
212 | no-useless-return: error
213 | no-void: error
214 | no-warning-comments: error
215 | no-whitespace-before-property: error
216 | no-with: error
217 | nonblock-statement-body-position: error
218 | object-curly-newline: error
219 | object-curly-spacing: error
220 | one-var:
221 | - error
222 | - uninitialized: always
223 | initialized: never
224 | one-var-declaration-per-line: error
225 | operator-assignment: 'off' #ok
226 | operator-linebreak:
227 | - error
228 | - after
229 | padded-blocks: 'off' #ok
230 | padding-line-between-statements:
231 | - error
232 | - blankLine: always
233 | prev: "*"
234 | next: function
235 | prefer-promise-reject-errors: error
236 | quote-props: 'off' #ok
237 | quotes:
238 | - error
239 | - single
240 | radix:
241 | - error
242 | - always
243 | require-await: error
244 | require-jsdoc: 'off' #ok
245 | semi: error
246 | semi-spacing:
247 | - error
248 | - after: true
249 | before: false
250 | semi-style:
251 | - error
252 | - last
253 | sort-keys: 'off' #ok
254 | sort-vars: 'off' #ok
255 | space-before-blocks: error
256 | space-before-function-paren:
257 | - error
258 | - anonymous: always
259 | named: never
260 | asyncArrow: always
261 | space-in-parens: 'off' #ok
262 | space-infix-ops: error
263 | space-unary-ops: error
264 | spaced-comment: error
265 | strict: 'off' #ok
266 | switch-colon-spacing: error
267 | template-tag-spacing: error
268 | unicode-bom:
269 | - error
270 | - never
271 | valid-jsdoc: error
272 | vars-on-top: error
273 | wrap-iife:
274 | - error
275 | - inside
276 | wrap-regex: error
277 | yoda:
278 | - error
279 | - never
280 |
281 | ### ES6 rules - not for me
282 | # arrow-body-style: error
283 | # arrow-parens: error
284 | # arrow-spacing: error
285 | # generator-star-spacing: error
286 | # no-confusing-arrow: error
287 | # no-duplicate-imports: error
288 | # no-restricted-imports: error
289 | # no-useless-computed-key: error
290 | # no-useless-constructor: error
291 | # no-useless-rename: error
292 | # no-var: 'off' #ok
293 | # object-shorthand: 'off' #ok
294 | # prefer-arrow-callback: 'off' #ok
295 | # prefer-const: error
296 | # prefer-destructuring: 'off' #ok
297 | # prefer-numeric-literals: error
298 | # prefer-rest-params: 'off' #ok
299 | # prefer-spread: error
300 | # prefer-template: 'off' #ok
301 | # rest-spread-spacing: error
302 | # sort-imports: error
303 | # symbol-description: error
304 | # template-curly-spacing: error
305 | # yield-star-spacing: error
306 |
--------------------------------------------------------------------------------
/NEWS.t2t:
--------------------------------------------------------------------------------
1 | NEWS — MoneyLog v5
2 | March, 2012
3 |
4 | %%% txt2tags config - http://txt2tags.org
5 | %
6 | %!target: html
7 | %!encoding: UTF-8
8 | %!options: --toc
9 | %
10 | % Twitter autolink
11 | %!preproc(html): @([A-Za-z0-9_]+) [@\1 http://twitter.com/\1]
12 | %
13 | % Add links to SVN revisions [r123]
14 | %!postproc(html): '\[r(\d+)\]' 'r\1'
15 | %
16 | % Add links to configuration keys ``fooBar``
17 | %!preproc(html): ``(.*?)`` [\1 https://aurelio.net/moneylog/config/#\1]
18 | %
19 | % Fix some config links: #i18nDatabase.pt.dateFormat -> #i18nDatabase-pt-dateFormat
20 | %!postproc(html): (/config/#[A-Za-z0-9-]+?)\. \1-
21 | %!postproc(html): (/config/#[A-Za-z0-9-]+?)\. \1-
22 |
23 |
24 | == New flavors ==[flavors]
25 | - Now the app come in four flavors:
26 | - **MoneyLog Cloud** — runs online, get TXT and config files from [Dropbox http://dropbox.com]. (by @xupisco)
27 | - **MoneyLog Browser** — runs online and offline, saves data to browser [localStorage http://en.wikipedia.org/wiki/Web_storage].
28 | - **MoneyLog Portable** — runs offline, all-in-one HTML file with app and user data.
29 | - **MoneyLog Beta** — runs offline, with local TXT files. This is the default SVN version.
30 | - These flavors are generated by the scripts named gen-* in [SVN/trunk/util/ http://code.google.com/p/moneylog-dev/source/browse/#svn%2Ftrunk%2Futil].
31 |
32 |
33 | == New interface (UI) ==[ui]
34 | - All new user interface. (by @xupisco) [r285]
35 | - Toolbar at left side, with collapsable boxes.
36 | - Reports at right.
37 | - Help screen is gone.
38 | - No colors, black & white UI. Each MoneyLog flavor will have its own color theme.
39 |
40 |
41 | == Translations ==[i18n]
42 | - Added es **Spanish** (Argentina) translation. (by @g_nemmi and Isadora Pinardi) [r137]
43 | - Added ca **Catalan** translation. (by @pacoriviere) [r126]
44 |
45 |
46 | == Mobile ==[mobile]
47 | - New mobile UI, for screens with 480px width or less. [r459]
48 | - New iOS icon. (by @xupisco) [r466]
49 |
50 |
51 | == Printer ready ==[print]
52 | - New print style, removing colors and undesired elements from interface. (thanks @xupisco) [r465]
53 |
54 |
55 | == User data ==[user-data]
56 | - **New data separator:** spaces are now allowed, the TAB is no longer mandatory. DO NOT use spaces inside values. [r268] [r392]
57 | - Out-of-range days (2000-01-99) will turn to last month day (2000-01-31). [r496]
58 | - New config ``dataFilesDefault`` to set the default file when using multiple TXT files (local or Dropbox). [r260]
59 | - New config ``ignoreDataOlderThan``, to ignore entries older than the specified date. [r415]
60 | - New config ``ignoreDataNewerThan``, to ignore entries newer than the specified date. [r417]
61 |
62 |
63 | == Password ==[password]
64 | - **New feature: access password.** Use the ``myPassword`` config. (thanks @bebetasso) [r434]
65 |
66 |
67 | == Full Screen mode ==[full-screen]
68 | - New button for Full Screen mode. [r119]
69 | - New config ``initFullScreen`` to start app in Full Screen mode. (thanks @xupisco) [r324]
70 |
71 |
72 | == Filters for all reports ==[filters-all]
73 | - Now all filters are also available in Monthly and Yearly reports. (thanks @denilsonsa, @eeev2011) [r514]
74 |
75 |
76 | == View widget ==[widget-view]
77 | - New config ``showViewWidget`` to enable/disable the View widget. [r387]
78 | - New config ``initViewWidgetOpen`` to open/close the View widget. [r386]
79 |
80 |
81 | == Tag Cloud widget ==[widget-tag-cloud]
82 | - New option in Tag Cloud: [X] Reset. (thanks @wcomnisky) [r383]
83 | - **New tri-state Tag Cloud:** first click select, second exclude (negate), third unselect. The option "[X] Group selected tags" does not affect excluded tags. [r451]
84 | - New config ``showTagCloud`` to enable/disable the Tag Cloud. [r387]
85 | - New config ``initTagCloudOpen`` to open/close the Tag Cloud. [r386]
86 | - New config ``initSelectedTags``, to select some tags at start up. [r444]
87 | - New config ``initExcludedTags``, to exclude some tags at start up. [r452]
88 | - New config ``ignoreTags`` to ignore all entries with one of the specified tags. (thanks @erickmor) [r435]
89 | - The config ``highlightTags`` now can also be an array. Useful for tags with spaces. [r431]
90 |
91 |
92 | == Tag Summary widget ==[widget-tag-summary]
93 | - New feature: Tag Summary. [r194] [r511]
94 | - New option in Tag Summary: [X] Sort by value. [r429]
95 | - New config ``TagSummary.config.active`` to enable/disable the Tag Summary. [r387] [r511]
96 | - New config ``TagSummary.config.opened`` to open/close the Tag Summary. [r386] [r511]
97 | - New config ``TagSummary.config.showTagless`` to show/hide the EMPTY tag. (thanks @denilsonsa) [r211] [r511]
98 | - New config ``TagSummary.config.checkSort`` to check the option [X] Order by value. [r430] [r511]
99 |
100 |
101 | == About widget ==[widget-about]
102 |
103 | - New About widget. [r591]
104 |
105 |
106 | == Tag report ==[tag-report]
107 | - **New feature: Tag Report** in monthly and yearly reports. Table headings are clickable for sorting. (thanks @denilsonsa) [r524]
108 | - New option in Tag Report: [X] Hide related tags. [r527]
109 | - New config ``checkHideRelatedTags``, to check/uncheck the option [X] Hide related tags. [r527]
110 | - New config ``showTagReport``, to enable/disable the Tag Report. [r533]
111 |
112 |
113 | == Rows Summary ==[rows-summary]
114 | - New feature: click a report row to highlight it. Click again to un-highlight it. [r180]
115 | - **New feature: Rows Summary.** When selecting rows, a popup appears with: sum, max, min, average, count. (thanks @denilsonsa) [r207]
116 | - Only show the rows summary when two or more rows are selected. [r281]
117 | - Rows Summary now works for the monthly and yearly reports, with a new combo to choose the column: Incoming, Expense, Partial. [r342]
118 | - New button to reset the Rows Summary, undoing all user selections in the report. (thanks @denilsonsa) [r478]
119 |
120 |
121 | == Date format ==[date-format]
122 | - **New configs to set locale date**: ``showLocaleDate``, ``i18nDatabase.pt.dateFormat``, ``i18nDatabase.pt.dateFormatMonth``, ``i18nDatabase.pt.dateFormatYear``. Change "pt" to "en", "es"…. (thanks @g_nemmi) [r113] [r352]
123 | - New tokens for locale dates: B = full month name, b = abbreviated month name. [r356]
124 | - **Now showing locale dates by default.** [r412]
125 | - Now using month names instead numbers in default locale format. [r420]
126 |
127 |
128 | == Date range ==[date-range]
129 | - **New date filter:** combos to choose an initial and final month for the reports. It disables the Recent Only and Future Data options. (thanks @denilsonsa, @adolfont, @magasine) [r358]
130 | - Now the new date filter is the default. New config ``useLegacyDateFilter`` to bring the old options back. (thanks @denilsonsa) [r369]
131 | - New configs ``checkDateFrom`` and ``checkDateUntil``, to check/uncheck date filters at startup. [r378]
132 | - New config ``initMonthsOffsetFrom`` to set the initial selected item for From:. [r405]
133 | - New config ``initMonthsOffsetUntil`` to set the initial selected item for Until:. [r407]
134 |
135 |
136 | == Charts ==[charts]
137 | - Now showing chart bar original value as a tooltip. (by @_Felipe) [r144]
138 | - **New feature: charts at daily reports.** [r190]
139 | - New configs to set the initial selected item for each chart type: ``initChartDaily``, ``initChartMonthly``, ``initChartYearly``. [r192]
140 | - Fixed two bugs in the chart bar label. (thanks @xupisco) [r350]
141 | - When the value was exactly 1000, it was showing 1 instead 1k.
142 | - When the value was 1 million (or greater), it was showing 1000m instead 1m.
143 |
144 |
145 | == Misc ==[misc]
146 | - Faster TXT file loading. (thanks @ricobl) [r125]
147 | - Added tooltips (help) for all controls. [r165]
148 | - Added favicon. (by @xupisco) [r340]
149 | - Set the page TITLE to full app name. (thanks @xupisco) [r341]
150 | - Hide the totals rows if there's only one row in the report. [r460]
151 |
152 |
153 | == Config ==[config]
154 | - New sample config file, in Portuguese. [r274]
155 | - Renamed some config names from default* to check*: ``checkMonthPartials``, ``checkRegex``, ``checkNegate``. [r380]
156 | - New config ``showBalance``, to show/hide the Balance column in all reports. [r529]
157 | - New configs for the default report sorting: ``sortData.d.index``, ``sortData.d.rev``, ``sortData.m.index``, ``sortData.m.rev``, ``sortData.y.index``, ``sortData.y.rev``. [r523]
158 | - The config ``oneFile`` was removed. [r288]
159 | - Check the new config guide https://aurelio.net/moneylog/config/
160 |
161 |
162 | == Widgets ==[widgets]
163 | - Added Widget support. See sample in sample/widget-nerd-toy.js. [r505]
164 | - Added three new "hello world" sample Widgets. [r513]
165 |
166 |
167 | == Test Suite ==[test-suite]
168 | - New test-suite test/functions.js. Instructions at file header. [r549]
169 |
170 |
--------------------------------------------------------------------------------
/moneylog.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
28 |
29 | MoneyLog
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | online
70 |
71 |
72 | ||
73 |
74 |
75 |
76 |
77 |
78 |
79 |
93 |
94 |
95 |
96 |
97 |
103 |
104 |
105 |
106 |
107 |
124 |
125 |
126 |
127 |
174 |
175 |
176 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
237 |
239 |
240 |
241 |
242 |
243 |
248 |
249 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
--------------------------------------------------------------------------------
/sample/config-pt.js:
--------------------------------------------------------------------------------
1 | //
2 | // Este é o arquivo de configuração do MoneyLog.
3 | //
4 | // Aqui você pode alterar o comportamento padrão do programa, modificando as
5 | // configurações disponíveis. Você pode, por exemplo, mudar o idioma para
6 | // inglês ou sempre iniciar no relatório mensal.
7 | //
8 | // Para saber mais informações sobre cada uma das configurações, visite:
9 | //
10 | // https://aurelio.net/moneylog/config/
11 | //
12 | // --------------------------------------------------------------------------
13 | //
14 | // Este é um arquivo em JavaScript, você deve seguir as regras de sintaxe da
15 | // linguagem. Se você não sabe nada de JavaScript, não se preocupe. Vou lhe
16 | // explicar o básico necessário. As configurações estão logo após este texto
17 | // explicativo.
18 | //
19 | // COMO ATIVAR/DESATIVAR UMA CONFIGURAÇÃO
20 | // --------------------------------------
21 | //
22 | // Todas as configurações deste arquivo estão desativadas. Isso quer dizer
23 | // que nenhuma delas vai afetar o funcionamento do MoneyLog. Você precisa
24 | // ativar aquelas que desejar utilizar.
25 | //
26 | // É muito simples, para ativar uma configuração, basta apagar os // que
27 | // estão no começo da linha.
28 | //
29 | // De:
30 | // // opcaoBacana = 12 ;// comentário
31 | //
32 | // Para:
33 | // opcaoBacana = 12 ;// comentário
34 | //
35 | // Se você mudar de ideia e quiser desativar a configuração, fazendo o
36 | // MoneyLog voltar ao seu comportamento padrão, basta recolocar os // na
37 | // frente.
38 | //
39 | //
40 | // COMO ALTERAR UMA CONFIGURAÇÃO ATIVA
41 | // -----------------------------------
42 | //
43 | // Basta apenas alterar o conteúdo de cada configuração e não mexer no resto.
44 | // Por exemplo, estes são os três formatos que você vai encontrar:
45 | //
46 | // opcaoBacana = 12 ;// comentário
47 | // opcaoBacana = S ;// comentário
48 | // opcaoBacana = 'texto' ;// comentário
49 | //
50 | // No primeiro exemplo o conteúdo é um número, 12. Basta você trocar este
51 | // número por outro e pronto. Deixe todo o resto intocado.
52 | //
53 | // No segundo exemplo é uma configuração do tipo LIGA/DESLIGA. Há somente
54 | // dois valores possíveis para ela: S e N, que significam sim e não. Não use
55 | // números ou qualquer outra letra, nem aspas. Não use minúsculas.
56 | //
57 | // No terceiro exemplo é uma configuração que recebe um texto entre aspas.
58 | // As aspas são importantes, não as apague. Apenas troque a palavra que está
59 | // dentro delas.
60 | //
61 | // --------------------------------------------------------------------------
62 |
63 |
64 | // SENHA DE ACESSO
65 | //
66 | // Você pode definir uma senha de acesso, para impedir que outras pessoas
67 | // vejam seus dados. Porém, saiba que esta é uma proteção bem simples, que
68 | // pode ser facilmente quebrada por quem entende de tecnologias web. Use
69 | // apenas para impedir o acesso casual de familiares ou colegas não-nerds.
70 | //
71 | // myPassword = 'abc123' ;// Pedir esta senha ao iniciar o app
72 |
73 |
74 | // IDIOMA
75 | //
76 | // lang = 'pt' ;// pt, en, es (Português, Inglês, Espanhol)
77 |
78 |
79 | // EXTRATO PADRÃO AO INICIAR
80 | //
81 | // reportType = 'd' ;// d, m, y (diário, mensal, anual)
82 |
83 |
84 | // TELA CHEIA
85 | //
86 | // initFullScreen = N ;// Iniciar o app já no modo Tela Cheia?
87 |
88 |
89 | // BUSCA
90 | //
91 | // defaultSearch = '' ;// Iniciar já pesquisando por este texto
92 | // checkRegex = N ;// Marcar a opção [X] regex?
93 | // checkNegate = N ;// Marcar a opção [X] excluir?
94 |
95 |
96 | // PERÍODO - DATA INICIAL E FINAL
97 | //
98 | // checkDateFrom = S ;// Marcar a opção [X] De:?
99 | // checkDateUntil = S ;// Marcar a opção [X] Até:?
100 | //
101 | // As duas configurações seguintes servem para escolher qual será o valor
102 | // padrão que virá escolhido nos seletores de data De: e Até:. Coloque um
103 | // número, positivo ou negativo, que indicará o número de meses à partir da
104 | // data atual. Use números positivos para meses futuros e negativos para os
105 | // passados. Por exemplo, para dizer "três meses atrás", use -3. Para dizer
106 | // mês seguinte, use 1. Zero significa o mês corrente.
107 | //
108 | // initMonthOffsetFrom = -2 ;// Valor inicial da opção [X] De:
109 | // initMonthOffsetUntil = 0 ;// Valor inicial da opção [X] Até:
110 |
111 |
112 | // PARCIAIS MENSAIS
113 | //
114 | // checkMonthPartials = S ;// Marcar a opção [X] Parciais Mensais?
115 |
116 |
117 | // SOMENTE VALORES
118 | //
119 | // Nada ainda.
120 |
121 |
122 | // WIDGETS
123 | //
124 | // initViewWidgetOpen = S ;// Iniciar com a caixa Visualizar aberta?
125 | // initTagCloudOpen = S ;// Iniciar com a Nuvem de Tags aberta?
126 | // showTagCloud = S ;// Usar o widget Nuvem de Tags?
127 |
128 |
129 | // WIDGET: SOMATÓRIO DE TAGS
130 | // TagSummary.config.active = S ;// Usar o widget Somatório de tags?
131 | // TagSummary.config.opened = S ;// Iniciar com este widget já aberto?
132 | // TagSummary.config.showTagless = S ;// Mostrar o item (sem tag)?
133 | // TagSummary.config.checkSort = N ;// Marcar a opção [X] Ordenar por valor?
134 |
135 |
136 | // TABELA DO EXTRATO
137 | //
138 | // showBalance = S ;// Mostrar a coluna Acumulado?
139 | // showRowCount = S ;// Mostrar o número da linha à esquerda?
140 | // monthlyRowCount = S ;// O número da linha recomeça a cada mês?
141 | //
142 | // highlightWords = 'XXX TODO' ;// Destacar estas palavras na Descrição
143 | // highlightTags = 'luz água' ;// Destacar estas tags no extrato
144 | //
145 | // sortData.d.index = 1 ;// Diário: iniciar ordenando por esta coluna (1-4)
146 | // sortData.m.index = 1 ;// Mensal: iniciar ordenando por esta coluna (1-5)
147 | // sortData.y.index = 1 ;// Anual : iniciar ordenando por esta coluna (1-5)
148 | // sortData.d.rev = N ;// Diário: iniciar com a ordem inversa?
149 | // sortData.m.rev = N ;// Mensal: iniciar com a ordem inversa?
150 | // sortData.y.rev = N ;// Anual : iniciar com a ordem inversa?
151 |
152 |
153 | // GRÁFICO DE BARRAS
154 | //
155 | // showCharts = S ;// Mostrar gráfico de barras depois do extrato?
156 | // showChartBarLabel = S ;// Mostrar os números no topo de cada barra?
157 | //
158 | // initChartDaily = 3 ;// Iniciar mostrando este item no gráfico diário [1-4]
159 | // initChartMonthly = 1 ;// Iniciar mostrando este item no gráfico mensal [1-4]
160 | // initChartYearly = 1 ;// Iniciar mostrando este item no gráfico anual [1-4]
161 |
162 |
163 | // BARRA DE PORCENTAGEM
164 | //
165 | // showMiniBars = S ;// Mostrar barra de porcentagem no mensal/anual?
166 | // showMiniBarsLabels = S ;// Mostrar os números dentro destas barras?
167 | // miniBarWidth = 70 ;// Largura da barra de porcentagem, em pixels
168 |
169 |
170 | // TAGS
171 | //
172 | // showTagReport = S ;// Mostrar o relatório de tags?
173 | // ignoreTags = 'poupança' ;// Ignorar lançamentos com estas tags
174 | // initSelectedTags = 'água' ;// Iniciar já com estas tags marcadas
175 | // initExcludedTags = 'luz' ;// Iniciar já com estas tags riscadas
176 | // checkHideRelatedTags = N ;// Marcar a opção [X] Esconder relacionadas?
177 |
178 |
179 | // FORMATO DA DATA
180 | //
181 | // showLocaleDate = N ;// Mostrar datas no formato regional d/m/a?
182 | //
183 | // Você também pode personalizar o formato regional: usar outros separadores,
184 | // mudar a ordem ou até escolher exatamente quais componentes mostrar. Além
185 | // de símbolos, você pode usar as seguintes letras:
186 | // Y = ano com 4 dígitos b = nome do mês com 3 letras
187 | // y = ano com 2 dígitos B = nome completo do mês
188 | // m = mês
189 | // d = dia
190 | //
191 | // i18nDatabase.pt.dateFormat = 'd.m.Y' ;// Personalizar formato dia-mês-ano
192 | // i18nDatabase.pt.dateFormatMonth = 'B Y' ;// Personalizar formato mês-ano
193 | // i18nDatabase.pt.dateFormatYear = 'Y' ;// Personalizar formato ano
194 |
195 |
196 | // IGNORAR LANÇAMENTOS ANTIGOS E FUTUROS
197 | //
198 | // Se você já usa o MoneyLog há bastante tempo, pode querer simplesmente
199 | // ignorar os lançamentos antigos, dos anos anteriores. Ou ainda, limitar a
200 | // visão de anos futuros para poucos anos, sumindo de sua vista com aquelas
201 | // dezenas de parcelas do financiamento que vai demorar para acabar. Basta
202 | // colocar nas configurações seguintes as datas limite, no passado e/ou no
203 | // futuro, e o MoneyLog vai fingir que não viu nada :)
204 | //
205 | // ignoreDataOlderThan = '2010-01-01' ;// Ignorar lançamentos de 2009, 2008...
206 | // ignoreDataNewerThan = '2020-12-31' ;// Ignorar lançamentos após 2020
207 |
208 |
209 | // ARQUIVOS TXT
210 | //
211 | //
212 | // Se você usa mais de um arquivo TXT, o MoneyLog automaticamente carrega
213 | // todos os arquivos que encontrar em sua pasta. Com essa configuração você
214 | // pode mudar isso e carregar somente um arquivo específico no início.
215 | //
216 | // dataFilesDefault = 'meu-arquivo.txt';
217 | //
218 | //
219 | // Se você quer usar mais de um arquivo TXT, deverá cadastrar todos eles no
220 | // array dataFiles. Podem ser inúmeros, tantos quantos você queira. Veja
221 | // alguns exemplos, separado por ano, por tipo de conta e por tipo de gasto:
222 | //
223 | // dataFiles = ['2012.txt', '2011.txt', '2010.txt'];
224 | //
225 | // dataFiles = ['bb.txt', 'caixa.txt', 'itau.txt', 'dinheiro.txt'];
226 | //
227 | // dataFiles = ['salario.txt', 'carro.txt', 'escola.txt', 'geral.txt'];
228 | //
229 | // Ao iniciar, o MoneyLog sempre carregará o primeiro item da lista. Para
230 | // mudar isso e carregar outro, basta usar esta configuração:
231 | //
232 | // dataFilesDefault = 'carro.txt';
233 | //
234 |
--------------------------------------------------------------------------------
/util/conversor/conversor.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 | Importar dados para o MoneyLog
17 |
18 |
19 |
20 |
23 |
24 |
325 |
326 |
327 |
328 |
329 | Converta lançamentos para o formato do MoneyLog
330 |
331 | Dúvidas? Aprenda como salvar o extrato de seu banco e usar este conversor.
332 |
333 |
338 |
339 |
340 |
341 | De:
342 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 | Para: MoneyLog
360 |
361 |
362 |
363 |
368 |
369 | CONFIRA O RESULTADO. Este é um processo automático, pode haver falhas.
370 |
371 |
372 |
373 |
374 |
375 |
--------------------------------------------------------------------------------
/moneylog.css:
--------------------------------------------------------------------------------
1 | /*
2 | MoneyLog default CSS
3 | by Aurelio Jargas
4 | https://aurelio.net/moneylog/
5 | */
6 |
7 | /* ---------------------------------------------- Reset CSS (from YUI) */
8 |
9 | body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td { margin:0;padding:0; }
10 | table { border-collapse:collapse;border-spacing:0; }
11 | body { font:12px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small; }
12 | select,input,button,textarea { font:99% arial,helvetica,clean,sans-serif; }
13 | table { font-size:inherit;font:100%; }
14 | th,td { border-style:none;padding:0; }
15 | p,blockquote,ul,ol,dl { margin:1em; }
16 | ol,ul,dl { margin-left:2em; }
17 | dl dd { margin-left:1em; }
18 |
19 |
20 | /* ---------------------------------------------- Structure */
21 |
22 | body {
23 | background-color: white; /* content_bg */
24 | color: #333; /* text_color */
25 | }
26 | #container {
27 | width: 100%;
28 | margin: 0 auto;
29 | overflow: hidden;
30 | }
31 | #toolbar {
32 | position: fixed;
33 | top: 57px; /* This is the height of #logo-wrapper */
34 | bottom: 0;
35 | left: 0;
36 | width: 217px;
37 | overflow: auto;
38 | }
39 | #content {
40 | margin-left: 217px; /* See toggleFullScreen, #toolbar */
41 | padding: 30px;
42 | overflow: auto;
43 | }
44 |
45 | /* ---------------------------------------------- Misc */
46 |
47 | label,
48 | .trigger {
49 | cursor: pointer;
50 | }
51 | .number {
52 | text-align: right !important;
53 | white-space: nowrap;
54 | }
55 | .neg { /* Negative numbers */
56 | color: #e33;
57 | }
58 | .hl { /* Highlighted words */
59 | color: black;
60 | background-color: #ddd; /* _light */
61 | }
62 | #tag-report tr:hover td.totals,
63 | tr:hover td,
64 | tr.future:hover td { /* explicit TD to exclude TH */
65 | background-color: #eee; /* hover_bg */
66 | color: black;
67 | }
68 | #toolbar input,
69 | #toolbar label,
70 | #toolbar select {
71 | vertical-align:middle;
72 | }
73 | #toolbar input {
74 | border: 1px solid #bbb; /* element_border */
75 | }
76 |
77 | /* ---------------------------------------------- Error */
78 |
79 | #error {
80 | display: none;
81 | margin: 5em 10%;
82 | padding: 10px;
83 | border: 8px solid red;
84 | background-color: yellow;
85 | color: black;
86 | line-height: 180%;
87 | }
88 |
89 | /* ---------------------------------------------- Logo */
90 |
91 | #logo-wrapper {
92 | position: fixed;
93 | top: 0;
94 | left: 0;
95 | }
96 | #logo {
97 | float: left;
98 | background-color: #EBEBEB;
99 | width: 201px;
100 | height: 57px;
101 | margin: 0;
102 | }
103 | #logo a {
104 | color: #333; /* text_color */
105 | }
106 | #app-name {
107 | font-size: 30px;
108 | line-height: 30px;
109 | padding: 5px 0 0 20px;
110 | }
111 | #website:hover {
112 | text-decoration: underline;
113 | }
114 | #app-flavor {
115 | font-size: 15px;
116 | line-height: 15px;
117 | padding: 2px 0 0 130px;
118 | text-transform: lowercase;
119 | color: black; /* _dark */
120 | }
121 |
122 | /* ---------------------------------------------- Full screen */
123 |
124 | #fullscreen {
125 | font-size: 11px;
126 | background-color: black; /* _dark */
127 | color: white;
128 | width: 15px; /* same as scrollbar width */
129 | float: left;
130 | text-align: center;
131 | height: 57px;
132 | line-height: 55px;
133 | }
134 |
135 | /* ---------------------------------------------- Toolbar */
136 |
137 | #toolbar a,
138 | a.button {
139 | text-decoration: none;
140 | }
141 |
142 | #toolbar hr {
143 | clear: both;
144 | border: 1px solid #ddd; /* toolbar_sep */
145 | border-width: 1px 0 0 0;
146 | margin: 1em 0;
147 | }
148 |
149 | #toolbar-controls-wrapper {
150 | background-color: #FAFAFA;
151 | clear: both;
152 | width: 200px;
153 | }
154 |
155 | #toolbar-controls {
156 | padding: 15px 17px;
157 | }
158 |
159 | /* ---------------------------------------------- Button */
160 |
161 | .button {
162 | display: block;
163 | margin: 0;
164 | text-align: center;
165 | font-weight: normal;
166 | font-size: 100%;
167 | line-height: 200%;
168 | text-transform: lowercase;
169 | border: 1px solid #bbb; /* element_border */
170 | background-color: white;
171 | background-color: #F4F4F4; /* button_bg */
172 | position: relative;
173 | }
174 | .button.active,
175 | a.button:active {
176 | border-color: black; /* _dark */
177 | background-color: black; /* _dark */
178 | color: white;
179 | }
180 | a.button {
181 | color: #333; /* text_color */
182 | }
183 | a.button.active {
184 | color: white;
185 | }
186 | .button.wide {
187 | display: block !important;
188 | float: none !important;
189 | width: 100% !important;
190 | }
191 | .button.naked {
192 | background-color: inherit;
193 | border-style: none;
194 | }
195 |
196 | .widget-box > .button:before {
197 | content: "▶";
198 | position: absolute;
199 | top: 0;
200 | left: 8px; /* The same as .widget-content padding-left */
201 | }
202 | .widget-box > .button.active:before {
203 | content: "▼";
204 | position: absolute;
205 | top: 0;
206 | left: 8px; /* The same as .widget-content padding-left */
207 | }
208 |
209 | /* ---------------------------------------------- [ widgets ] */
210 |
211 | .widget-box {
212 | margin: 1em 0;
213 | }
214 | .widget-box:first-child {
215 | margin-top: 0;
216 | }
217 | .widget-content {
218 | background-color: white;
219 | border: 1px solid #bbb; /* element_border */
220 | border-top-width: 0;
221 | padding: 8px;
222 | line-height: 185%;
223 | }
224 | .widget-content a {
225 | color: #2B97E9; /* cloud_blue */
226 | }
227 | .widget-content a.button {
228 | color: inherit;
229 | }
230 | #about-content a:hover {
231 | text-decoration: underline;
232 | /* Restricted to #about, this breaks Tag Cloud */
233 | }
234 | .widget-content select,
235 | .widget-content table {
236 | width: 100%;
237 | }
238 | .widget-options input {
239 | display: inline;
240 | margin-right: 0.5em;
241 | }
242 |
243 | /* ---------------------------------------------- [file.txt ▼] */
244 |
245 | #storage-content {
246 | display: none; /* JS will show */
247 | }
248 |
249 | #storage-driver,
250 | #source-file {
251 | width: 100%;
252 | margin-bottom: 1em;
253 | }
254 |
255 | #storage-folder {
256 | display: block;
257 | margin: -0.5em 0 0.5em 0;
258 | }
259 | #storage-folder:before {
260 | content: "📁 "; /* U+1F4C1 File Folder */
261 | }
262 |
263 | #source-file-box.mini {
264 | line-height: 150%;
265 | }
266 | #source-file.mini {
267 | width: 140px;
268 | }
269 |
270 | /* ---------------------------------------------- [edit] [reload] */
271 |
272 | #source-reload,
273 | #editor-open {
274 | display: inline-block; /* see showHideEditButton() */
275 | width: 69px;
276 | margin: 0;
277 | }
278 | #editor-open {
279 | margin-right: 5px;
280 | }
281 |
282 | #source-reload.mini { /* ↻ */
283 | float: right;
284 | margin: 0;
285 | padding: 0;
286 | line-height: 150%;
287 | width: 1.5em;
288 | }
289 | #source-reload.mini:hover {
290 | background-color: black;
291 | color: white;
292 | }
293 |
294 | /* ---------------------------------------------- [daily] [monthly] [yearly] */
295 |
296 | #toolbar #report-nav {
297 | text-align: center;
298 | }
299 | #toolbar #report-nav a {
300 | display: inline-block;
301 | width: 50px;
302 | margin: 0 5px 0 0;
303 | }
304 | #toolbar #report-nav #y {
305 | margin-right: 0;
306 | }
307 |
308 | /* ---------------------------------------------- [search ] */
309 |
310 | #search-content {
311 | border-top-width: 1px;
312 | }
313 | #filter {
314 | width: 100%;
315 | border: 1px solid #C9C9C9;
316 | background-color: #F4F4F4; /* button_bg */
317 | padding: 3px 0;
318 | margin-bottom: 5px;
319 | }
320 | #opt-negate-check {
321 | margin-left: 1em;
322 | }
323 |
324 | /* ---------------------------------------------- [X] Options */
325 |
326 | #toolbar label:hover,
327 | #toolbar input:hover + label {
328 | /*font-weight: bold;*/
329 | }
330 | .checkbox-option {
331 | text-align: left;
332 | clear: both;
333 | }
334 | .checkbox-option-extra {
335 | margin-left: 1em;
336 | }
337 | .auto-hide {
338 | display: none; /* appears when clicked, see toggleCheckboxOptionExtra() */
339 | }
340 | .option-disabled {
341 | color: #AAAAAA;
342 | }
343 |
344 | /* ---------------------------------------------- [ view ] */
345 |
346 | #view-options-content {
347 | display: none; /* JS will show */
348 | }
349 | #opt-date-1-month-combo,
350 | #opt-date-2-month-combo,
351 | #opt-date-1-year-combo,
352 | #opt-date-2-year-combo {
353 | float: right;
354 | width: auto;
355 | }
356 | #opt-date-1-year-combo,
357 | #opt-date-2-year-combo {
358 | display: none; /* appears in Yearly report */
359 | }
360 | #opt-value-filter-number {
361 | display: none; /* appears when SELECT item is chosen */
362 | }
363 |
364 | /* ---------------------------------------------- [ tag cloud ] */
365 |
366 | #tag-cloud-content {
367 | display: none; /* JS will show if there are tags */
368 | text-align: center;
369 | }
370 | #tag-cloud-tags a {
371 | padding: 2px 2px;
372 | color: #333; /* text_color */
373 | white-space: nowrap;
374 | }
375 | #tag-cloud-tags a.selected {
376 | background-color: #ddd; /* _light */
377 | color: black;
378 | }
379 | #tag-cloud-tags a.excluded {
380 | text-decoration: line-through;
381 | }
382 | #tag-cloud-options {
383 | display: none; /* JS will show */
384 | }
385 |
386 | /* ---------------------------------------------- [ tag summary ] */
387 |
388 | #tag-summary-content {
389 | display: none; /* JS will show */
390 | }
391 |
392 | /* ---------------------------------------------- [ about ] */
393 |
394 | #about-content {
395 | display: none; /* JS will show */
396 | text-align: center;
397 | }
398 | #about-donate {
399 | font-size: 150%;
400 | }
401 | #about-credits {
402 | display: inline-block;
403 | text-align: left;
404 | }
405 |
406 | /* ---------------------------------------------- Report */
407 |
408 | /* labelNoData */
409 | #report p {
410 | text-align: center;
411 | }
412 |
413 | /* Report table */
414 | .report {
415 | margin: 0 auto; /* do not use width:100% */
416 | }
417 |
418 | /* Table headings are also buttons */
419 | .report th {
420 | text-align: center;
421 | cursor: pointer;
422 | padding: 0.5em;
423 | }
424 | .report th:hover {
425 | background-color: black; /* _dark */
426 | color: white;
427 | }
428 |
429 | /* Column sorting is not working for some columns, so undo formatting */
430 | th.row-count,
431 | table.daily th.balance,
432 | table.overview th.percent {
433 | cursor: auto !important;
434 | }
435 | th.row-count,
436 | table.daily th.balance:hover,
437 | table.overview th.percent:hover {
438 | color: #333 !important; /* text_color */
439 | background-color: white !important; /* content_bg */
440 | }
441 |
442 | /* Generic cell config */
443 | .report td {
444 | border: 1px solid #ddd; /* _light */
445 | border-width: 1px 0;
446 | vertical-align: middle;
447 | }
448 |
449 | /* Column config */
450 | td.row-count {
451 | text-align: center;
452 | font-size: 75%;
453 | border-style: none !important;
454 | background-color: white !important; /* content_bg */
455 | color: silver !important; /* _light_text */
456 | }
457 | td.date {
458 | white-space: nowrap;
459 | }
460 |
461 | /* Future */
462 | tr.future {
463 | background-color: #f8f8f8; /* future_bg */
464 | font-style: italic;
465 | }
466 | tr.future td.row-count {
467 | font-style: normal;
468 | }
469 |
470 | /* Selected row */
471 | tr.selected,
472 | tr.selected:hover td,
473 | tr.selected .neg {
474 | background-color: black; /* _dark */
475 | color: white;
476 | }
477 |
478 | /* Totals rows & cells */
479 | tr.totals,
480 | td.totals {
481 | background-color: #ddd; /* _light */
482 | }
483 | tr.total,
484 | td.total {
485 | font-weight: bold;
486 | }
487 |
488 | /* Rows padding */
489 | .report td {
490 | padding: 6px 10px;
491 | }
492 | .report tr.totals td {
493 | padding: 1px 10px; /* top/bottom: td - 6px */
494 | }
495 |
496 | /* ---------------------------------------------- Report - Daily */
497 |
498 | /* Total row tweaks */
499 | #report table.daily tr.totals {
500 | font-weight: bold;
501 | }
502 | #report table.daily tr.totals table.posneg {
503 | float: right;
504 | font-size: 90%;
505 | font-weight: normal;
506 | }
507 | #report table.daily tr.totals table.posneg td {
508 | padding: 0;
509 | white-space: nowrap;
510 | border-style: none;
511 | }
512 | #report table.daily tr.totals td.monthtotal {
513 | text-align: left;
514 | padding-left: 0;
515 | }
516 | #report table.daily tr.totals td.monthtotal .arrow {
517 | margin-right: 8px;
518 | }
519 |
520 | /* ---------------------------------------------- Report - Monthly/Yearly */
521 |
522 | .report td.rowlabel {
523 | font-weight: bold;
524 | }
525 |
526 | /* ---------------------------------------------- Minibars inside report table */
527 |
528 | td.minibar {
529 | border-style: none !important;
530 | }
531 | div.minibar {
532 | float: left;
533 | }
534 | td.minibar .label {
535 | float: left;
536 | font-size: 75%;
537 | color: white !important;
538 | line-height: 14px;
539 | }
540 |
541 | /* ---------------------------------------------- Charts */
542 |
543 | #charts {
544 | display: none; /* JS will show */
545 | text-align: center;
546 | margin-top: 4em;
547 | }
548 | #chart-content {
549 | overflow: auto;
550 | }
551 | #chart-selector {
552 | margin-bottom: 5px;
553 | }
554 | .posbar {
555 | background-color: #2B97E9; /* bar1_bg cloud_blue */
556 | }
557 | .negbar {
558 | background-color: #f33; /* bar2_bg */
559 | }
560 | table.chart {
561 | margin: 0 auto;
562 | border: 1px solid #bbb; /* element_border */
563 | border-collapse: separate;
564 | border-spacing: 7px; /* space between bars and also border */
565 | }
566 | table.chart td.bar {
567 | text-align: center;
568 | vertical-align: bottom;
569 | }
570 | table.chart td.bar div.bar {
571 | width: 35px; /* must fit 4 digits for the year, i.e. 2012 */
572 | margin: 0 auto;
573 | }
574 | table.chart td.bar .label {
575 | font-size: 11px;
576 | font-style: italic;
577 | }
578 | table.chart tr.label {
579 | font-size: 10px;
580 | line-height: 100%;
581 | text-align: center;
582 | }
583 | table.chart tr:hover td {
584 | background-color: white; /* content_bg */
585 | }
586 |
587 | /* ---------------------------------------------- Tag report */
588 |
589 | #tag-report {
590 | margin-top: 4em;
591 | }
592 | #tag-report th {
593 | text-align: right;
594 | vertical-align: bottom;
595 | padding: 6px 10px; /* same as .report td */
596 | }
597 | #tag-report th.tagname {
598 | text-align: left;
599 | }
600 | #tag-report th i { /* obfuscate year */
601 | font-weight: normal;
602 | font-style: normal;
603 | color: silver; /* _light_text */
604 | }
605 | #tag-report th:hover i {
606 | color: white;
607 | }
608 | #tag-report td.totals {
609 | background-color: inherit;
610 | font-style: italic;
611 | }
612 | #tag-report td.total {
613 | padding-left: 20px; /* separate */
614 | }
615 | #tag-report-options {
616 | display: none; /* JS will show */
617 | text-align: center;
618 | margin-top: 1.5em;
619 | }
620 |
621 | /* ---------------------------------------------- Rows summary */
622 |
623 | #rows-summary {
624 | display: none; /* JS will show */
625 | position: fixed;
626 | right: 0;
627 | bottom: 0;
628 | padding: 5px;
629 | border: 8px solid black; /* _dark */
630 | background-color: #ddd; /* _light */
631 | }
632 | #rows-summary-content td {
633 | padding: 4px 10px;
634 | }
635 | #rows-summary-index {
636 | width: 100%;
637 | margin-bottom: 5px;
638 | }
639 | #rows-summary-reset {
640 | margin-top: 0.5em;
641 | }
642 |
643 | /* ---------------------------------------------- Footer */
644 |
645 | #footer-message {
646 | color: silver; /* _light_text */
647 | text-align: center;
648 | margin-top: 4em;
649 | }
650 |
651 | /* ---------------------------------------------- Editor */
652 |
653 | /* The editor */
654 | #editor { /* fill full window, hiding app interface */
655 | display: none;
656 | position: fixed;
657 | top: 0;
658 | right: 0;
659 | bottom: 0;
660 | left: 0;
661 | background-color: white; /* content_bg */
662 | }
663 | #editor-file-name {
664 | position: fixed;
665 | left: 41px;
666 | top: 21px;
667 | line-height: 29px; /* 50px (wrapper-top) - 21px (top) */
668 | margin: 0;
669 | padding: 0 11px;
670 | letter-spacing: 1px;
671 | color: white; /* content_bg */
672 | background-color: black; /* _dark */
673 | }
674 | #editor-data-wrapper { /* position:fixed so we can set textarea height:~100% */
675 | position: fixed;
676 | top: 50px; /* space for file name */
677 | right: 30px;
678 | bottom: 70px; /* space for the buttons */
679 | left: 30px;
680 | border: 8px solid black; /* _dark */
681 | padding: 15px 0 15px 15px;
682 | }
683 | #editor-data {
684 | width: 100%;
685 | height: 100%;
686 | outline-width: 0; /* disable focus ring */
687 | border-style: none;
688 | margin: 0;
689 | font-family: monospace;
690 | }
691 | #editor-buttons {
692 | position: fixed;
693 | right: 30px;
694 | bottom: 30px;
695 | }
696 | #editor-close,
697 | #editor-save {
698 | display: inline-block;
699 | width: 100px;
700 | }
701 | #editor-close {
702 | margin-right: 3px;
703 | }
704 |
705 | /* ---------------------------------------------- Data */
706 |
707 | /* Always hidden */
708 | #data,
709 | #data-frame {
710 | display: none !important;
711 | }
712 |
713 |
--------------------------------------------------------------------------------
/NEWS.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | NEWS — MoneyLog v5
7 |
8 |
9 | NEWS — MoneyLog v5
10 | March, 2012
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | - New flavors
19 |
- New interface (UI)
20 |
- Translations
21 |
- Mobile
22 |
- Printer ready
23 |
- User data
24 |
- Password
25 |
- Full Screen mode
26 |
- Filters for all reports
27 |
- View widget
28 |
- Tag Cloud widget
29 |
- Tag Summary widget
30 |
- About widget
31 |
- Tag report
32 |
- Rows Summary
33 |
- Date format
34 |
- Date range
35 |
- Charts
36 |
- Misc
37 |
- Config
38 |
- Widgets
39 |
- Test Suite
40 |
41 |
42 |
43 |
44 |
45 |
46 | New flavors
47 |
48 |
49 | - Now the app come in four flavors:
50 |
51 | - MoneyLog Cloud — runs online, get TXT and config files from Dropbox. (by @xupisco)
52 |
- MoneyLog Browser — runs online and offline, saves data to browser localStorage.
53 |
- MoneyLog Portable — runs offline, all-in-one HTML file with app and user data.
54 |
- MoneyLog Beta — runs offline, with local TXT files. This is the default SVN version.
55 |
56 | - These flavors are generated by the scripts named gen-* in SVN/trunk/util/.
57 |
58 |
59 | New interface (UI)
60 |
61 |
62 | - All new user interface. (by @xupisco) r285
63 |
64 | - Toolbar at left side, with collapsable boxes.
65 |
- Reports at right.
66 |
- Help screen is gone.
67 |
- No colors, black & white UI. Each MoneyLog flavor will have its own color theme.
68 |
69 |
70 |
71 | Translations
72 |
73 |
74 | - Added es Spanish (Argentina) translation. (by @g_nemmi and Isadora Pinardi) r137
75 |
- Added ca Catalan translation. (by @pacoriviere) r126
76 |
77 |
78 | Mobile
79 |
80 |
81 | - New mobile UI, for screens with 480px width or less. r459
82 |
- New iOS icon. (by @xupisco) r466
83 |
84 |
85 | Printer ready
86 |
87 |
88 | - New print style, removing colors and undesired elements from interface. (thanks @xupisco) r465
89 |
90 |
91 | User data
92 |
93 |
94 | - New data separator: spaces are now allowed, the TAB is no longer mandatory. DO NOT use spaces inside values. r268 r392
95 |
- Out-of-range days (2000-01-99) will turn to last month day (2000-01-31). r496
96 |
- New config dataFilesDefault to set the default file when using multiple TXT files (local or Dropbox). r260
97 |
- New config ignoreDataOlderThan, to ignore entries older than the specified date. r415
98 |
- New config ignoreDataNewerThan, to ignore entries newer than the specified date. r417
99 |
100 |
101 | Password
102 |
103 |
104 | - New feature: access password. Use the myPassword config. (thanks @bebetasso) r434
105 |
106 |
107 | Full Screen mode
108 |
109 |
110 | - New button for Full Screen mode. r119
111 |
- New config initFullScreen to start app in Full Screen mode. (thanks @xupisco) r324
112 |
113 |
114 | Filters for all reports
115 |
116 |
117 | - Now all filters are also available in Monthly and Yearly reports. (thanks @denilsonsa, @eeev2011) r514
118 |
119 |
120 | View widget
121 |
122 |
123 | - New config showViewWidget to enable/disable the View widget. r387
124 |
- New config initViewWidgetOpen to open/close the View widget. r386
125 |
126 |
127 | Tag Cloud widget
128 |
129 |
130 | - New option in Tag Cloud: [X] Reset. (thanks @wcomnisky) r383
131 |
- New tri-state Tag Cloud: first click select, second exclude (negate), third unselect. The option "[X] Group selected tags" does not affect excluded tags. r451
132 |
- New config showTagCloud to enable/disable the Tag Cloud. r387
133 |
- New config initTagCloudOpen to open/close the Tag Cloud. r386
134 |
- New config initSelectedTags, to select some tags at start up. r444
135 |
- New config initExcludedTags, to exclude some tags at start up. r452
136 |
- New config ignoreTags to ignore all entries with one of the specified tags. (thanks @erickmor) r435
137 |
- The config highlightTags now can also be an array. Useful for tags with spaces. r431
138 |
139 |
140 | Tag Summary widget
141 |
142 |
143 | - New feature: Tag Summary. r194 r511
144 |
- New option in Tag Summary: [X] Sort by value. r429
145 |
- New config TagSummary.config.active to enable/disable the Tag Summary. r387 r511
146 |
- New config TagSummary.config.opened to open/close the Tag Summary. r386 r511
147 |
- New config TagSummary.config.showTagless to show/hide the EMPTY tag. (thanks @denilsonsa) r211 r511
148 |
- New config TagSummary.config.checkSort to check the option [X] Order by value. r430 r511
149 |
150 |
151 | About widget
152 |
153 |
154 | - New About widget. r591
155 |
156 |
157 | Tag report
158 |
159 |
160 | - New feature: Tag Report in monthly and yearly reports. Table headings are clickable for sorting. (thanks @denilsonsa) r524
161 |
- New option in Tag Report: [X] Hide related tags. r527
162 |
- New config checkHideRelatedTags, to check/uncheck the option [X] Hide related tags. r527
163 |
- New config showTagReport, to enable/disable the Tag Report. r533
164 |
165 |
166 | Rows Summary
167 |
168 |
169 | - New feature: click a report row to highlight it. Click again to un-highlight it. r180
170 |
- New feature: Rows Summary. When selecting rows, a popup appears with: sum, max, min, average, count. (thanks @denilsonsa) r207
171 |
- Only show the rows summary when two or more rows are selected. r281
172 |
- Rows Summary now works for the monthly and yearly reports, with a new combo to choose the column: Incoming, Expense, Partial. r342
173 |
- New button to reset the Rows Summary, undoing all user selections in the report. (thanks @denilsonsa) r478
174 |
175 |
176 | Date format
177 |
178 |
179 | - New configs to set locale date: showLocaleDate, i18nDatabase.pt.dateFormat, i18nDatabase.pt.dateFormatMonth, i18nDatabase.pt.dateFormatYear. Change "pt" to "en", "es"…. (thanks @g_nemmi) r113 r352
180 |
- New tokens for locale dates: B = full month name, b = abbreviated month name. r356
181 |
- Now showing locale dates by default. r412
182 |
- Now using month names instead numbers in default locale format. r420
183 |
184 |
185 | Date range
186 |
187 |
188 | - New date filter: combos to choose an initial and final month for the reports. It disables the Recent Only and Future Data options. (thanks @denilsonsa, @adolfont, @magasine) r358
189 |
- Now the new date filter is the default. New config useLegacyDateFilter to bring the old options back. (thanks @denilsonsa) r369
190 |
- New configs checkDateFrom and checkDateUntil, to check/uncheck date filters at startup. r378
191 |
- New config initMonthsOffsetFrom to set the initial selected item for From:. r405
192 |
- New config initMonthsOffsetUntil to set the initial selected item for Until:. r407
193 |
194 |
195 | Charts
196 |
197 |
198 | - Now showing chart bar original value as a tooltip. (by @_Felipe) r144
199 |
- New feature: charts at daily reports. r190
200 |
- New configs to set the initial selected item for each chart type: initChartDaily, initChartMonthly, initChartYearly. r192
201 |
- Fixed two bugs in the chart bar label. (thanks @xupisco) r350
202 |
203 | - When the value was exactly 1000, it was showing 1 instead 1k.
204 |
- When the value was 1 million (or greater), it was showing 1000m instead 1m.
205 |
206 |
207 |
208 | Misc
209 |
210 |
211 | - Faster TXT file loading. (thanks @ricobl) r125
212 |
- Added tooltips (help) for all controls. r165
213 |
- Added favicon. (by @xupisco) r340
214 |
- Set the page TITLE to full app name. (thanks @xupisco) r341
215 |
- Hide the totals rows if there's only one row in the report. r460
216 |
217 |
218 | Config
219 |
220 |
221 | - New sample config file, in Portuguese. r274
222 |
- Renamed some config names from default* to check*: checkMonthPartials, checkRegex, checkNegate. r380
223 |
- New config showBalance, to show/hide the Balance column in all reports. r529
224 |
- New configs for the default report sorting: sortData.d.index, sortData.d.rev, sortData.m.index, sortData.m.rev, sortData.y.index, sortData.y.rev. r523
225 |
- The config oneFile was removed. r288
226 |
- Check the new config guide https://aurelio.net/moneylog/config/
227 |
228 |
229 | Widgets
230 |
231 |
232 | - Added Widget support. See sample in sample/widget-nerd-toy.js. r505
233 |
- Added three new "hello world" sample Widgets. r513
234 |
235 |
236 | Test Suite
237 |
238 |
239 | - New test-suite test/functions.js. Instructions at file header. r549
240 |
241 |
242 |
243 |
244 |
245 |
246 |
--------------------------------------------------------------------------------