mirror of
https://github.com/simonmichael/hledger.git
synced 2024-09-20 10:47:29 +03:00
web: 1. move templates back into main code 2. begin adding content titles
This commit is contained in:
parent
3fcff17f8f
commit
35f145f03d
@ -60,12 +60,12 @@ data QueryOpt = QueryOptInAcctOnly AccountName -- ^ show an account register fo
|
|||||||
-- | QueryOptEffectiveDate -- ^ show effective dates instead of actual dates
|
-- | QueryOptEffectiveDate -- ^ show effective dates instead of actual dates
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq)
|
||||||
|
|
||||||
-- | The account we are currently focussed on, if any.
|
-- | The account we are currently focussed on, if any, and whether subaccounts are included.
|
||||||
-- Just looks at the first query option.
|
-- Just looks at the first query option.
|
||||||
inAccount :: [QueryOpt] -> Maybe AccountName
|
inAccount :: [QueryOpt] -> Maybe (AccountName,Bool)
|
||||||
inAccount [] = Nothing
|
inAccount [] = Nothing
|
||||||
inAccount (QueryOptInAcctOnly a:_) = Just a
|
inAccount (QueryOptInAcctOnly a:_) = Just (a,False)
|
||||||
inAccount (QueryOptInAcct a:_) = Just a
|
inAccount (QueryOptInAcct a:_) = Just (a,True)
|
||||||
|
|
||||||
-- | A matcher for the account(s) we are currently focussed on, if any.
|
-- | A matcher for the account(s) we are currently focussed on, if any.
|
||||||
-- Just looks at the first query option.
|
-- Just looks at the first query option.
|
||||||
|
@ -39,7 +39,7 @@ body { backgroun
|
|||||||
/*------------------------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------------------------*/
|
||||||
/* 2. font families & sizes */
|
/* 2. font families & sizes */
|
||||||
/* overspecified for cross-browser robustness */
|
/* overspecified for cross-browser robustness */
|
||||||
body { font-family:helvetica,arial,"sans serif"; }
|
body { font-family:helvetica,arial,sans-serif; }
|
||||||
pre { font-family:courier,"courier new",monospace; }
|
pre { font-family:courier,"courier new",monospace; }
|
||||||
input.textinput, .dhx_combo_input, .dhx_combo_list { font-size:small; }
|
input.textinput, .dhx_combo_input, .dhx_combo_list { font-size:small; }
|
||||||
#editform textarea { font-family:courier,"courier new",monospace; font-size:small; }
|
#editform textarea { font-family:courier,"courier new",monospace; font-size:small; }
|
||||||
@ -57,6 +57,7 @@ input.textinput, .dhx_combo_input, .dhx_combo_list { font-size:small; }
|
|||||||
.showall { font-size:small; }
|
.showall { font-size:small; }
|
||||||
/* #addformlink { font-size:small; } */
|
/* #addformlink { font-size:small; } */
|
||||||
/* #editformlink { font-size:small; } */
|
/* #editformlink { font-size:small; } */
|
||||||
|
#contenttitle { font-size:1.2em; }
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------------------------*/
|
||||||
/* 3. layout */
|
/* 3. layout */
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
<script type=text/javascript>
|
|
||||||
$(document).ready(function() {
|
|
||||||
/* render chart */
|
|
||||||
/* if ($('#register-chart')) */
|
|
||||||
$.plot($('#register-chart'),
|
|
||||||
[
|
|
||||||
[
|
|
||||||
$forall i <- items
|
|
||||||
[#{dayToJsTimestamp $ ariDate i}, #{ariBalance i}],
|
|
||||||
]
|
|
||||||
],
|
|
||||||
{
|
|
||||||
xaxis: {
|
|
||||||
mode: "time",
|
|
||||||
timeformat: "%y/%m/%d"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
<div#register-chart style="width:600px;height:100px; margin-bottom:1em;"
|
|
||||||
|
|
||||||
<table.registerreport
|
|
||||||
<tr.headings
|
|
||||||
<th.date align=left>Date
|
|
||||||
<th.description align=left>Description
|
|
||||||
<th.account align=left>
|
|
||||||
Accounts
|
|
||||||
<!-- \ #
|
|
||||||
<a#all-postings-toggle-link.togglelink href="#" title="Toggle all split postings">[+/-] -->
|
|
||||||
<th.amount align=right>Amount
|
|
||||||
<th.balance align=right>#{balancelabel}
|
|
||||||
|
|
||||||
$forall i <- numberAccountRegisterReportItems items
|
|
||||||
^{itemAsHtml vd i}
|
|
@ -1,24 +0,0 @@
|
|||||||
<tr.item.#{evenodd}.#{firstposting}.#{datetransition}
|
|
||||||
<td.date>#{date}
|
|
||||||
<td.description title="#{show t}">#{elideRight 30 desc}
|
|
||||||
<td.account title="#{show t}"
|
|
||||||
$if True
|
|
||||||
<a
|
|
||||||
#{elideRight 40 acct}
|
|
||||||
|
|
||||||
<a.postings-toggle-link.togglelink href="#" title="Toggle postings"
|
|
||||||
[+/-]
|
|
||||||
$else
|
|
||||||
<a href="@?{acctquery}" title="Go to #{acct}">#{elideRight 40 acct}
|
|
||||||
<td.amount align=right>
|
|
||||||
$if showamt
|
|
||||||
#{mixedAmountAsHtml amt}
|
|
||||||
<td.balance align=right>#{mixedAmountAsHtml bal}
|
|
||||||
$if True
|
|
||||||
$forall p <- tpostings t
|
|
||||||
<tr.item.#{evenodd}.posting.#{displayclass}
|
|
||||||
<td.date
|
|
||||||
<td.description
|
|
||||||
<td.account> <a href="@?{accountUrl here $ paccount p}" title="Show transactions in #{paccount p}">#{elideRight 40 $ paccount p}
|
|
||||||
<td.amount align=right>#{mixedAmountAsHtml $ pamount p}
|
|
||||||
<td.balance align=right>
|
|
@ -1,50 +0,0 @@
|
|||||||
<script type=text/javascript>
|
|
||||||
$(document).ready(function() {
|
|
||||||
/* dhtmlxcombo setup */
|
|
||||||
window.dhx_globalImgPath="../static/";
|
|
||||||
var desccombo = new dhtmlXCombo("description");
|
|
||||||
var acct1combo = new dhtmlXCombo("account1");
|
|
||||||
var acct2combo = new dhtmlXCombo("account2");
|
|
||||||
desccombo.enableFilteringMode(true);
|
|
||||||
acct1combo.enableFilteringMode(true);
|
|
||||||
acct2combo.enableFilteringMode(true);
|
|
||||||
desccombo.setSize(300);
|
|
||||||
acct1combo.setSize(300);
|
|
||||||
acct2combo.setSize(300);
|
|
||||||
/* desccombo.enableOptionAutoHeight(true, 20); */
|
|
||||||
/* desccombo.setOptionHeight(200); */
|
|
||||||
});
|
|
||||||
<form#addform method=POST style=display:none;
|
|
||||||
<table.form
|
|
||||||
<tr
|
|
||||||
<td colspan=4
|
|
||||||
<table
|
|
||||||
<tr#descriptionrow
|
|
||||||
<td
|
|
||||||
Date:
|
|
||||||
<td
|
|
||||||
<input.textinput size=15 name=date value=#{date}
|
|
||||||
<td style=padding-left:1em;
|
|
||||||
Description:
|
|
||||||
<td
|
|
||||||
<select id=description name=description
|
|
||||||
<option
|
|
||||||
$forall d <- descriptions
|
|
||||||
<option value=#{d}>#{d}
|
|
||||||
<tr.helprow
|
|
||||||
<td
|
|
||||||
<td
|
|
||||||
<span.help>#{datehelp} #
|
|
||||||
<td
|
|
||||||
<td
|
|
||||||
<span.help>#{deschelp}
|
|
||||||
^{postingfields vd 1}
|
|
||||||
^{postingfields vd 2}
|
|
||||||
<tr#addbuttonrow
|
|
||||||
<td colspan=4
|
|
||||||
<input type=hidden name=action value=add
|
|
||||||
<input type=submit name=submit value="add transaction"
|
|
||||||
$if manyfiles
|
|
||||||
\ to: ^{journalselect $ files $ j vd}
|
|
||||||
\ or #
|
|
||||||
<a href onclick="return addformToggle(event)">cancel
|
|
@ -1,15 +0,0 @@
|
|||||||
<tr#postingrow
|
|
||||||
<td align=right>#{acctlabel}:
|
|
||||||
<td
|
|
||||||
<select id=#{acctvar} name=#{acctvar}
|
|
||||||
<option
|
|
||||||
$forall a <- acctnames
|
|
||||||
<option value=#{a} :shouldselect a:selected>#{a}
|
|
||||||
^{amtfield}
|
|
||||||
<tr.helprow
|
|
||||||
<td
|
|
||||||
<td
|
|
||||||
<span.help>#{accthelp}
|
|
||||||
<td
|
|
||||||
<td
|
|
||||||
<span.help>#{amthelp}
|
|
@ -1,4 +0,0 @@
|
|||||||
<td style=padding-left:1em;
|
|
||||||
Amount:
|
|
||||||
<td
|
|
||||||
<input.textinput size=15 name=#{amtvar} value=""
|
|
@ -1,32 +0,0 @@
|
|||||||
<div#accountsheading
|
|
||||||
<a#accounts-toggle-link.togglelink href="#" title="Toggle sidebar">[+/-]
|
|
||||||
<div#accounts
|
|
||||||
<table.balancereport>
|
|
||||||
<tr
|
|
||||||
<td.add colspan=3
|
|
||||||
<br>
|
|
||||||
<a#addformlink href onclick="return addformToggle(event)" title="Add a new transaction to the journal">Add a transaction..
|
|
||||||
|
|
||||||
<tr.item :allaccts:.inacct
|
|
||||||
<td.journal colspan=3
|
|
||||||
<br>
|
|
||||||
<a href=@{RegisterR} title="Show all transactions">General journal
|
|
||||||
<span.hoverlinks
|
|
||||||
|
|
||||||
<a href=@{JournalR} title="Show journal source text">source</a>
|
|
||||||
|
|
||||||
<a#editformlink href onclick="return editformToggle(event)" title="Edit the journal">edit
|
|
||||||
|
|
||||||
<tr
|
|
||||||
<td colspan=3
|
|
||||||
<br>
|
|
||||||
Accounts
|
|
||||||
|
|
||||||
$forall i <- items
|
|
||||||
^{itemAsHtml vd i}
|
|
||||||
|
|
||||||
<tr.totalrule>
|
|
||||||
<td colspan=2>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<td align=right>#{mixedAmountAsHtml total}
|
|
@ -1,14 +0,0 @@
|
|||||||
<tr.item.#{inacctclass}
|
|
||||||
<td.account.#{depthclass}
|
|
||||||
#{indent}
|
|
||||||
<a href="@?{acctquery}" title="Show transactions in this account, including subaccounts">#{adisplay}
|
|
||||||
<span.hoverlinks
|
|
||||||
$if hassubs
|
|
||||||
|
|
||||||
<a href="@?{acctonlyquery}" title="Show transactions in this account only">only
|
|
||||||
<!--
|
|
||||||
|
|
||||||
<a href="@?{acctsonlyquery}" title="Focus on this account and sub-accounts and hide others">-others -->
|
|
||||||
|
|
||||||
<td.balance align=right>#{mixedAmountAsHtml abal}
|
|
||||||
<td.numpostings align=right title="#{numpostings} transactions in this account">(#{numpostings})
|
|
@ -1,2 +0,0 @@
|
|||||||
body
|
|
||||||
font-family: sans-serif
|
|
@ -1,16 +0,0 @@
|
|||||||
!!!
|
|
||||||
<html
|
|
||||||
<head
|
|
||||||
<title>#{pageTitle pc}
|
|
||||||
^{pageHead pc}
|
|
||||||
<meta http-equiv=Content-Type content="text/html; charset=utf-8"
|
|
||||||
<script type=text/javascript src=@{StaticR jquery_js}
|
|
||||||
<script type=text/javascript src=@{StaticR jquery_url_js}
|
|
||||||
<script type=text/javascript src=@{StaticR jquery_flot_js}
|
|
||||||
<!--[if lte IE 8]><script language="javascript" type="text/javascript" src="excanvas.min.js"></script><![endif]-->
|
|
||||||
<script type=text/javascript src=@{StaticR dhtmlxcommon_js}
|
|
||||||
<script type=text/javascript src=@{StaticR dhtmlxcombo_js}
|
|
||||||
<script type=text/javascript src=@{StaticR hledger_js}
|
|
||||||
<link rel=stylesheet type=text/css media=all href=@{StaticR style_css}
|
|
||||||
<body
|
|
||||||
^{pageBody pc}
|
|
@ -1,21 +0,0 @@
|
|||||||
<form#editform method=POST style=display:none;
|
|
||||||
<table.form
|
|
||||||
$if manyfiles
|
|
||||||
<tr
|
|
||||||
<td colspan=2
|
|
||||||
Editing ^{journalselect $ files j}
|
|
||||||
<tr
|
|
||||||
<td colspan=2
|
|
||||||
<!-- XXX textarea ids are unquoted journal file paths here, not valid html -->
|
|
||||||
$forall f <- files j
|
|
||||||
<textarea id=#{fst f}_textarea name=text rows=25 cols=80 style=display:none; disabled=disabled
|
|
||||||
#{snd f}
|
|
||||||
<tr#addbuttonrow
|
|
||||||
<td
|
|
||||||
<span.help>^{formathelp}
|
|
||||||
<td align=right
|
|
||||||
<span.help Are you sure ? This will overwrite the journal. #
|
|
||||||
<input type=hidden name=action value=edit
|
|
||||||
<input type=submit name=submit value="save journal"
|
|
||||||
\ or #
|
|
||||||
<a href onclick="return editformToggle(event)">cancel
|
|
@ -1,4 +0,0 @@
|
|||||||
<a#editformlink href onclick="return editformToggle(event)" title="Toggle journal edit form">edit
|
|
||||||
\ | #
|
|
||||||
<a#addformlink href onclick="return addformToggle(event)" title="Toggle transaction add form">add
|
|
||||||
<a#importformlink href onclick="return importformToggle(event)" style="display:none;">import transactions
|
|
@ -1 +0,0 @@
|
|||||||
<a href=#{u} target=hledgerhelp>#{label}
|
|
@ -1,9 +0,0 @@
|
|||||||
<form#importform method=POST style=display:none;
|
|
||||||
<table.form
|
|
||||||
<tr
|
|
||||||
<td
|
|
||||||
<input type=file name=file
|
|
||||||
<input type=hidden name=action value=import
|
|
||||||
<input type=submit name=submit value="import from file"
|
|
||||||
\ or #
|
|
||||||
<a href onclick="return importformToggle(event)" cancel
|
|
@ -1,11 +0,0 @@
|
|||||||
^{topbar vd}
|
|
||||||
<div#content
|
|
||||||
<div#sidebar
|
|
||||||
^{sidecontent}
|
|
||||||
<div#main.journal
|
|
||||||
<div#maincontent
|
|
||||||
^{searchform vd}
|
|
||||||
^{maincontent}
|
|
||||||
^{addform vd}
|
|
||||||
^{editform vd}
|
|
||||||
^{importform}
|
|
@ -1,7 +0,0 @@
|
|||||||
<div.journal
|
|
||||||
^{editlinks}
|
|
||||||
<div#maincontent
|
|
||||||
^{maincontent}
|
|
||||||
^{addform vd}
|
|
||||||
^{editform vd}
|
|
||||||
^{importform}
|
|
@ -1,3 +0,0 @@
|
|||||||
<table.journalreport>
|
|
||||||
$forall i <- numbered items
|
|
||||||
^{itemAsHtml vd i}
|
|
@ -1,3 +0,0 @@
|
|||||||
<tr.item.#{evenodd}>
|
|
||||||
<td.transaction>
|
|
||||||
<pre>#{txn}
|
|
@ -1,3 +0,0 @@
|
|||||||
<select id=journalselect name=journal onchange="editformJournalSelect(event)"
|
|
||||||
$forall f <- journalfiles
|
|
||||||
<option value=#{fst f}>#{fst f}
|
|
@ -1 +0,0 @@
|
|||||||
<a##{s}link.#{style} href=@?{u} title="#{title}">#{s}
|
|
@ -1,6 +0,0 @@
|
|||||||
<div#navlinks
|
|
||||||
^{journallink}
|
|
||||||
\ | #
|
|
||||||
^{registerlink}
|
|
||||||
\ | #
|
|
||||||
^{editlinks}
|
|
@ -1,10 +0,0 @@
|
|||||||
<table.registerreport
|
|
||||||
<tr.headings
|
|
||||||
<th.date align=left>Date
|
|
||||||
<th.description align=left>Description
|
|
||||||
<th.account align=left>Account
|
|
||||||
<th.amount align=right>Amount
|
|
||||||
<th.balance align=right>#{balancelabel}
|
|
||||||
|
|
||||||
$forall i <- numberPostingRegisterReportItems items
|
|
||||||
^{itemAsHtml vd i}
|
|
@ -1,6 +0,0 @@
|
|||||||
<tr.item.#{evenodd}.#{firstposting}.#{datetransition}
|
|
||||||
<td.date>#{date}
|
|
||||||
<td.description title="#{desc}">#{elideRight 30 desc}
|
|
||||||
<td.account><a href="@?{acctquery}" title="#{acct}">#{elideRight 40 acct}
|
|
||||||
<td.amount align=right>#{mixedAmountAsHtml $ pamount posting}
|
|
||||||
<td.balance align=right>#{mixedAmountAsHtml b}
|
|
@ -1,11 +0,0 @@
|
|||||||
^{topbar vd}
|
|
||||||
<div#content
|
|
||||||
<div#sidebar
|
|
||||||
^{sidecontent}
|
|
||||||
<div#main.register
|
|
||||||
<div#maincontent
|
|
||||||
^{searchform vd}
|
|
||||||
^{maincontent}
|
|
||||||
^{addform vd}
|
|
||||||
^{editform vd}
|
|
||||||
^{importform}
|
|
@ -1,7 +0,0 @@
|
|||||||
<div.register
|
|
||||||
^{editlinks}
|
|
||||||
<div#maincontent
|
|
||||||
^{maincontent}
|
|
||||||
^{addform vd}
|
|
||||||
^{editform vd}
|
|
||||||
^{importform}
|
|
@ -1,35 +0,0 @@
|
|||||||
<div#searchformdiv
|
|
||||||
<form#searchform.form method=GET
|
|
||||||
<table
|
|
||||||
<tr
|
|
||||||
<td
|
|
||||||
Search:
|
|
||||||
\ #
|
|
||||||
<td
|
|
||||||
<input name=q size=70 value=#{q}
|
|
||||||
<input type=submit value="Search"
|
|
||||||
$if filtering
|
|
||||||
\ #
|
|
||||||
<span.showall
|
|
||||||
<a href=@{here}>clear search
|
|
||||||
\ #
|
|
||||||
<a#search-help-link href="#" title="Toggle search help">help
|
|
||||||
<tr
|
|
||||||
<td
|
|
||||||
<td
|
|
||||||
<div#search-help.help style="display:none;"
|
|
||||||
Leave blank to see general journal (all transactions), or #
|
|
||||||
click account links to see transactions under that account.
|
|
||||||
<br>
|
|
||||||
Transactions/postings may additionally be filtered by:
|
|
||||||
<br>
|
|
||||||
acct:REGEXP (target account), #
|
|
||||||
desc:REGEXP (description), #
|
|
||||||
date:PERIODEXP (date), #
|
|
||||||
edate:PERIODEXP (effective date), #
|
|
||||||
<br>
|
|
||||||
status:BOOL (cleared status), #
|
|
||||||
real:BOOL (real/virtual-ness), #
|
|
||||||
empty:BOOL (posting amount = 0).
|
|
||||||
<br>
|
|
||||||
not: to negate, enclose space-containing patterns in quotes, multiple filters are AND'ed.
|
|
@ -1,9 +0,0 @@
|
|||||||
<div#topbar
|
|
||||||
<a.topleftlink href=#{hledgerorgurl} title="More about hledger"
|
|
||||||
hledger-web
|
|
||||||
<br />
|
|
||||||
#{version}
|
|
||||||
<a.toprightlink href=#{manualurl} target=hledgerhelp title="User manual">manual
|
|
||||||
<h1>#{title}
|
|
||||||
$maybe m <- msg
|
|
||||||
<div#message>#{m}
|
|
@ -16,9 +16,10 @@ module App
|
|||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.Trans.Class (lift)
|
import Control.Monad.Trans.Class (lift)
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
|
import qualified Data.ByteString.Lazy as L
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import qualified Data.ByteString.Lazy as L
|
import Text.Hamlet hiding (hamletFile)
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
import Yesod.Helpers.Static
|
import Yesod.Helpers.Static
|
||||||
|
|
||||||
@ -78,8 +79,25 @@ instance Yesod App where
|
|||||||
-- mmsg <- getMessage
|
-- mmsg <- getMessage
|
||||||
pc <- widgetToPageContent $ do
|
pc <- widgetToPageContent $ do
|
||||||
widget
|
widget
|
||||||
addCassius $(Settings.cassiusFile "default-layout")
|
-- addCassius $(Settings.cassiusFile "default-layout")
|
||||||
hamletToRepHtml $(Settings.hamletFile "default-layout")
|
hamletToRepHtml [$hamlet|
|
||||||
|
!!!
|
||||||
|
<html
|
||||||
|
<head
|
||||||
|
<title>#{pageTitle pc}
|
||||||
|
^{pageHead pc}
|
||||||
|
<meta http-equiv=Content-Type content="text/html; charset=utf-8"
|
||||||
|
<script type=text/javascript src=@{StaticR jquery_js}
|
||||||
|
<script type=text/javascript src=@{StaticR jquery_url_js}
|
||||||
|
<script type=text/javascript src=@{StaticR jquery_flot_js}
|
||||||
|
<!--[if lte IE 8]><script language="javascript" type="text/javascript" src="excanvas.min.js"></script><![endif]-->
|
||||||
|
<script type=text/javascript src=@{StaticR dhtmlxcommon_js}
|
||||||
|
<script type=text/javascript src=@{StaticR dhtmlxcombo_js}
|
||||||
|
<script type=text/javascript src=@{StaticR hledger_js}
|
||||||
|
<link rel=stylesheet type=text/css media=all href=@{StaticR style_css}
|
||||||
|
<body
|
||||||
|
^{pageBody pc}
|
||||||
|
|]
|
||||||
|
|
||||||
-- -- This is done to provide an optimization for serving static files from
|
-- -- This is done to provide an optimization for serving static files from
|
||||||
-- -- a separate domain. Please see the staticroot setting in Settings.hs
|
-- -- a separate domain. Please see the staticroot setting in Settings.hs
|
||||||
|
@ -48,36 +48,32 @@ getRootR = redirect RedirectTemporary defaultroute where defaultroute = Register
|
|||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
-- main views
|
-- main views
|
||||||
|
|
||||||
-- | The main journal view, with accounts sidebar.
|
-- | The journal entries view, with accounts sidebar.
|
||||||
getJournalR :: Handler RepHtml
|
getJournalR :: Handler RepHtml
|
||||||
getJournalR = do
|
getJournalR = do
|
||||||
vd@VD{opts=opts,m=m,am=am,j=j} <- getViewData
|
vd@VD{opts=opts,m=m,am=am,j=j} <- getViewData
|
||||||
let sidecontent = balanceReportAsHtml opts vd $ balanceReport2 opts am j
|
let
|
||||||
|
sidecontent = balanceReportAsHtml opts vd $ balanceReport2 opts am j
|
||||||
|
title = "Journal entries" ++ if m /= MatchAny then ", filtered" else "" :: String
|
||||||
maincontent = journalReportAsHtml opts vd $ journalReport opts nullfilterspec $ filterJournalTransactions2 m j
|
maincontent = journalReportAsHtml opts vd $ journalReport opts nullfilterspec $ filterJournalTransactions2 m j
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitle "hledger-web journal"
|
setTitle "hledger-web journal"
|
||||||
addHamlet $(Settings.hamletFile "journal")
|
addHamlet [$hamlet|
|
||||||
|
^{topbar vd}
|
||||||
|
<div#content
|
||||||
|
<div#sidebar
|
||||||
|
^{sidecontent}
|
||||||
|
<div#main.journal
|
||||||
|
<h2#contenttitle>#{title}
|
||||||
|
^{searchform vd}
|
||||||
|
<div#maincontent
|
||||||
|
^{maincontent}
|
||||||
|
^{addform vd}
|
||||||
|
^{editform vd}
|
||||||
|
^{importform}
|
||||||
|
|]
|
||||||
|
|
||||||
postJournalR :: Handler RepPlain
|
-- | The journal entries view with no sidebar.
|
||||||
postJournalR = handlePost
|
|
||||||
|
|
||||||
-- | The main register view, with accounts sidebar.
|
|
||||||
getRegisterR :: Handler RepHtml
|
|
||||||
getRegisterR = do
|
|
||||||
vd@VD{opts=opts,qopts=qopts,m=m,am=am,j=j} <- getViewData
|
|
||||||
let sidecontent = balanceReportAsHtml opts vd $ balanceReport2 opts am j
|
|
||||||
maincontent =
|
|
||||||
case inAccountMatcher qopts of Just m' -> accountRegisterReportAsHtml opts vd $ accountRegisterReport opts j m m'
|
|
||||||
Nothing -> accountRegisterReportAsHtml opts vd $ journalRegisterReport opts j m
|
|
||||||
editform' = editform vd
|
|
||||||
defaultLayout $ do
|
|
||||||
setTitle "hledger-web register"
|
|
||||||
addHamlet $(Settings.hamletFile "register")
|
|
||||||
|
|
||||||
postRegisterR :: Handler RepPlain
|
|
||||||
postRegisterR = handlePost
|
|
||||||
|
|
||||||
-- | A simple journal view, like hledger print (with editing.)
|
|
||||||
getJournalOnlyR :: Handler RepHtml
|
getJournalOnlyR :: Handler RepHtml
|
||||||
getJournalOnlyR = do
|
getJournalOnlyR = do
|
||||||
vd@VD{opts=opts,m=m,j=j} <- getViewData
|
vd@VD{opts=opts,m=m,j=j} <- getViewData
|
||||||
@ -85,24 +81,54 @@ getJournalOnlyR = do
|
|||||||
setTitle "hledger-web journal only"
|
setTitle "hledger-web journal only"
|
||||||
addHamlet $ journalReportAsHtml opts vd $ journalReport opts nullfilterspec $ filterJournalTransactions2 m j
|
addHamlet $ journalReportAsHtml opts vd $ journalReport opts nullfilterspec $ filterJournalTransactions2 m j
|
||||||
|
|
||||||
postJournalOnlyR :: Handler RepPlain
|
-- | The main journal/account register view, with accounts sidebar.
|
||||||
postJournalOnlyR = handlePost
|
getRegisterR :: Handler RepHtml
|
||||||
|
getRegisterR = do
|
||||||
|
vd@VD{opts=opts,qopts=qopts,m=m,am=am,j=j} <- getViewData
|
||||||
|
let sidecontent = balanceReportAsHtml opts vd $ balanceReport2 opts am j
|
||||||
|
-- XXX like registerReportAsHtml
|
||||||
|
inacct = inAccount qopts
|
||||||
|
-- injournal = isNothing inacct
|
||||||
|
filtering = m /= MatchAny
|
||||||
|
-- showlastcolumn = if injournal && not filtering then False else True
|
||||||
|
title = case inacct of
|
||||||
|
Nothing -> "Journal"++filter
|
||||||
|
Just (a,subs) -> "Transactions in "++a++andsubs++filter
|
||||||
|
where andsubs = if subs then " (and subaccounts)" else ""
|
||||||
|
where
|
||||||
|
filter = if filtering then ", filtered" else ""
|
||||||
|
maincontent =
|
||||||
|
case inAccountMatcher qopts of Just m' -> registerReportAsHtml opts vd $ accountRegisterReport opts j m m'
|
||||||
|
Nothing -> registerReportAsHtml opts vd $ journalRegisterReport opts j m
|
||||||
|
defaultLayout $ do
|
||||||
|
setTitle "hledger-web register"
|
||||||
|
addHamlet [$hamlet|
|
||||||
|
^{topbar vd}
|
||||||
|
<div#content
|
||||||
|
<div#sidebar
|
||||||
|
^{sidecontent}
|
||||||
|
<div#main.register
|
||||||
|
<h2#contenttitle>#{title}
|
||||||
|
^{searchform vd}
|
||||||
|
<div#maincontent
|
||||||
|
^{maincontent}
|
||||||
|
^{addform vd}
|
||||||
|
^{editform vd}
|
||||||
|
^{importform}
|
||||||
|
|]
|
||||||
|
|
||||||
-- | A simple postings view, like hledger register (with editing.)
|
-- | The register view with no sidebar.
|
||||||
getRegisterOnlyR :: Handler RepHtml
|
getRegisterOnlyR :: Handler RepHtml
|
||||||
getRegisterOnlyR = do
|
getRegisterOnlyR = do
|
||||||
vd@VD{opts=opts,qopts=qopts,m=m,j=j} <- getViewData
|
vd@VD{opts=opts,qopts=qopts,m=m,j=j} <- getViewData
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitle "hledger-web register only"
|
setTitle "hledger-web register only"
|
||||||
addHamlet $
|
addHamlet $
|
||||||
case inAccountMatcher qopts of Just m' -> accountRegisterReportAsHtml opts vd $ accountRegisterReport opts j m m'
|
case inAccountMatcher qopts of Just m' -> registerReportAsHtml opts vd $ accountRegisterReport opts j m m'
|
||||||
Nothing -> accountRegisterReportAsHtml opts vd $ journalRegisterReport opts j m
|
Nothing -> registerReportAsHtml opts vd $ journalRegisterReport opts j m
|
||||||
|
|
||||||
postRegisterOnlyR :: Handler RepPlain
|
-- | A simple accounts view. This one is json-capable, returning the chart
|
||||||
postRegisterOnlyR = handlePost
|
-- of accounts as json if the Accept header specifies json.
|
||||||
|
|
||||||
-- | A simple accounts view, like hledger balance. If the Accept header
|
|
||||||
-- specifies json, returns the chart of accounts as json.
|
|
||||||
getAccountsR :: Handler RepHtmlJson
|
getAccountsR :: Handler RepHtmlJson
|
||||||
getAccountsR = do
|
getAccountsR = do
|
||||||
vd@VD{opts=opts,m=m,am=am,j=j} <- getViewData
|
vd@VD{opts=opts,m=m,am=am,j=j} <- getViewData
|
||||||
@ -113,34 +139,75 @@ getAccountsR = do
|
|||||||
json = jsonMap [("accounts", toJSON $ journalAccountNames j')]
|
json = jsonMap [("accounts", toJSON $ journalAccountNames j')]
|
||||||
defaultLayoutJson html json
|
defaultLayoutJson html json
|
||||||
|
|
||||||
-- | Return the chart of accounts as json, without needing a special Accept header.
|
-- | A json-only version of "getAccountsR", does not require the special Accept header.
|
||||||
getAccountsJsonR :: Handler RepJson
|
getAccountsJsonR :: Handler RepJson
|
||||||
getAccountsJsonR = do
|
getAccountsJsonR = do
|
||||||
VD{m=m,j=j} <- getViewData
|
VD{m=m,j=j} <- getViewData
|
||||||
let j' = filterJournalPostings2 m j
|
let j' = filterJournalPostings2 m j
|
||||||
jsonToRepJson $ jsonMap [("accounts", toJSON $ journalAccountNames j')]
|
jsonToRepJson $ jsonMap [("accounts", toJSON $ journalAccountNames j')]
|
||||||
|
|
||||||
-- helpers
|
----------------------------------------------------------------------
|
||||||
|
-- view helpers
|
||||||
|
|
||||||
accountQuery :: AccountName -> String
|
-- | Render a "BalanceReport" as HTML.
|
||||||
accountQuery a = "inacct:" ++ quoteIfSpaced a -- (accountNameToAccountRegex a)
|
|
||||||
|
|
||||||
accountOnlyQuery :: AccountName -> String
|
|
||||||
accountOnlyQuery a = "inacctonly:" ++ quoteIfSpaced a -- (accountNameToAccountRegex a)
|
|
||||||
|
|
||||||
-- accountUrl :: AppRoute -> AccountName -> (AppRoute,[(String,ByteString)])
|
|
||||||
accountUrl r a = (r, [("q",pack $ accountQuery a)])
|
|
||||||
|
|
||||||
-- | Render a balance report as HTML.
|
|
||||||
balanceReportAsHtml :: [Opt] -> ViewData -> BalanceReport -> Hamlet AppRoute
|
balanceReportAsHtml :: [Opt] -> ViewData -> BalanceReport -> Hamlet AppRoute
|
||||||
balanceReportAsHtml _ vd@VD{here=here,m=m,q=q,qopts=qopts,j=j} (items',total) = $(Settings.hamletFile "balancereport")
|
balanceReportAsHtml _ vd@VD{qopts=qopts,j=j} (items',total) =
|
||||||
|
[$hamlet|
|
||||||
|
<div#accountsheading
|
||||||
|
<a#accounts-toggle-link.togglelink href="#" title="Toggle sidebar">[+/-]
|
||||||
|
<div#accounts
|
||||||
|
<table.balancereport>
|
||||||
|
<tr
|
||||||
|
<td.add colspan=3
|
||||||
|
<br>
|
||||||
|
<a#addformlink href onclick="return addformToggle(event)" title="Add a new transaction to the journal">Add a transaction..
|
||||||
|
|
||||||
|
<tr.item :allaccts:.inacct
|
||||||
|
<td.journal colspan=3
|
||||||
|
<br>
|
||||||
|
<a href=@{RegisterR} title="Show all transactions in journal format">Journal
|
||||||
|
<span.hoverlinks
|
||||||
|
|
||||||
|
<a href=@{JournalR} title="Show raw journal entries">entries</a>
|
||||||
|
|
||||||
|
<a#editformlink href onclick="return editformToggle(event)" title="Edit the journal">edit
|
||||||
|
|
||||||
|
<tr
|
||||||
|
<td colspan=3
|
||||||
|
<br>
|
||||||
|
Accounts
|
||||||
|
|
||||||
|
$forall i <- items
|
||||||
|
^{itemAsHtml vd i}
|
||||||
|
|
||||||
|
<tr.totalrule>
|
||||||
|
<td colspan=2>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<td align=right>#{mixedAmountAsHtml total}
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
l = journalToLedger nullfilterspec j
|
l = journalToLedger nullfilterspec j
|
||||||
inacctmatcher = inAccountMatcher qopts
|
inacctmatcher = inAccountMatcher qopts
|
||||||
allaccts = isNothing inacctmatcher
|
allaccts = isNothing inacctmatcher
|
||||||
items = items' -- maybe items' (\m -> filter (matchesAccount m . \(a,_,_,_)->a) items') showacctmatcher
|
items = items' -- maybe items' (\m -> filter (matchesAccount m . \(a,_,_,_)->a) items') showacctmatcher
|
||||||
itemAsHtml :: ViewData -> BalanceReportItem -> Hamlet AppRoute
|
itemAsHtml :: ViewData -> BalanceReportItem -> Hamlet AppRoute
|
||||||
itemAsHtml VD{here=here,q=q} (acct, adisplay, aindent, abal) = $(Settings.hamletFile "balancereportitem")
|
itemAsHtml _ (acct, adisplay, aindent, abal) = [$hamlet|
|
||||||
|
<tr.item.#{inacctclass}
|
||||||
|
<td.account.#{depthclass}
|
||||||
|
#{indent}
|
||||||
|
<a href="@?{acctquery}" title="Show transactions in this account, including subaccounts">#{adisplay}
|
||||||
|
<span.hoverlinks
|
||||||
|
$if hassubs
|
||||||
|
|
||||||
|
<a href="@?{acctonlyquery}" title="Show transactions in this account only">only
|
||||||
|
<!--
|
||||||
|
|
||||||
|
<a href="@?{acctsonlyquery}" title="Focus on this account and sub-accounts and hide others">-others -->
|
||||||
|
|
||||||
|
<td.balance align=right>#{mixedAmountAsHtml abal}
|
||||||
|
<td.numpostings align=right title="#{numpostings} transactions in this account">(#{numpostings})
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
hassubs = not $ null $ ledgerSubAccounts l $ ledgerAccount l acct
|
hassubs = not $ null $ ledgerSubAccounts l $ ledgerAccount l acct
|
||||||
numpostings = length $ apostings $ ledgerAccount l acct
|
numpostings = length $ apostings $ ledgerAccount l acct
|
||||||
@ -152,22 +219,110 @@ balanceReportAsHtml _ vd@VD{here=here,m=m,q=q,qopts=qopts,j=j} (items',total) =
|
|||||||
acctquery = (RegisterR, [("q", pack $ accountQuery acct)])
|
acctquery = (RegisterR, [("q", pack $ accountQuery acct)])
|
||||||
acctonlyquery = (RegisterR, [("q", pack $ accountOnlyQuery acct)])
|
acctonlyquery = (RegisterR, [("q", pack $ accountOnlyQuery acct)])
|
||||||
|
|
||||||
-- | Render a journal report as HTML.
|
accountQuery :: AccountName -> String
|
||||||
|
accountQuery a = "inacct:" ++ quoteIfSpaced a -- (accountNameToAccountRegex a)
|
||||||
|
|
||||||
|
accountOnlyQuery :: AccountName -> String
|
||||||
|
accountOnlyQuery a = "inacctonly:" ++ quoteIfSpaced a -- (accountNameToAccountRegex a)
|
||||||
|
|
||||||
|
-- accountUrl :: AppRoute -> AccountName -> (AppRoute,[(String,ByteString)])
|
||||||
|
accountUrl r a = (r, [("q",pack $ accountQuery a)])
|
||||||
|
|
||||||
|
-- | Render a "JournalReport" as HTML.
|
||||||
journalReportAsHtml :: [Opt] -> ViewData -> JournalReport -> Hamlet AppRoute
|
journalReportAsHtml :: [Opt] -> ViewData -> JournalReport -> Hamlet AppRoute
|
||||||
journalReportAsHtml _ vd items = $(Settings.hamletFile "journalreport")
|
journalReportAsHtml _ vd items = [$hamlet|
|
||||||
|
<table.journalreport>
|
||||||
|
$forall i <- numbered items
|
||||||
|
^{itemAsHtml vd i}
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
itemAsHtml :: ViewData -> (Int, JournalReportItem) -> Hamlet AppRoute
|
itemAsHtml :: ViewData -> (Int, JournalReportItem) -> Hamlet AppRoute
|
||||||
itemAsHtml _ (n, t) = $(Settings.hamletFile "journalreportitem")
|
itemAsHtml _ (n, t) = [$hamlet|
|
||||||
|
<tr.item.#{evenodd}>
|
||||||
|
<td.transaction>
|
||||||
|
<pre>#{txn}
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
evenodd = if even n then "even" else "odd" :: String
|
evenodd = if even n then "even" else "odd" :: String
|
||||||
txn = trimnl $ showTransaction t where trimnl = reverse . dropWhile (=='\n') . reverse
|
txn = trimnl $ showTransaction t where trimnl = reverse . dropWhile (=='\n') . reverse
|
||||||
|
|
||||||
-- Account-specific transaction register, when an account is focussed.
|
-- Render an "AccountRegisterReport" as html, for the journal/account register views.
|
||||||
accountRegisterReportAsHtml :: [Opt] -> ViewData -> AccountRegisterReport -> Hamlet AppRoute
|
registerReportAsHtml :: [Opt] -> ViewData -> AccountRegisterReport -> Hamlet AppRoute
|
||||||
accountRegisterReportAsHtml _ vd (balancelabel,items) = $(Settings.hamletFile "accountregisterreport")
|
registerReportAsHtml _ vd@VD{m=m,qopts=qopts} (balancelabel,items) = [$hamlet|
|
||||||
|
$if showlastcolumn
|
||||||
|
<script type=text/javascript>
|
||||||
|
$(document).ready(function() {
|
||||||
|
/* render chart */
|
||||||
|
/* if ($('#register-chart')) */
|
||||||
|
$.plot($('#register-chart'),
|
||||||
|
[
|
||||||
|
[
|
||||||
|
$forall i <- items
|
||||||
|
[#{dayToJsTimestamp $ ariDate i}, #{ariBalance i}],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
{
|
||||||
|
xaxis: {
|
||||||
|
mode: "time",
|
||||||
|
timeformat: "%y/%m/%d"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
<div#register-chart style="width:600px;height:100px; margin-bottom:1em;"
|
||||||
|
|
||||||
|
<table.registerreport
|
||||||
|
<tr.headings
|
||||||
|
<th.date align=left>Date
|
||||||
|
<th.description align=left>Description
|
||||||
|
<th.account align=left>
|
||||||
|
$if injournal
|
||||||
|
Accounts
|
||||||
|
$else
|
||||||
|
To/From Account
|
||||||
|
<!-- \ #
|
||||||
|
<a#all-postings-toggle-link.togglelink href="#" title="Toggle all split postings">[+/-] -->
|
||||||
|
<th.amount align=right>Amount
|
||||||
|
$if showlastcolumn
|
||||||
|
<th.balance align=right>#{balancelabel}
|
||||||
|
|
||||||
|
$forall i <- numberAccountRegisterReportItems items
|
||||||
|
^{itemAsHtml vd i}
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
|
inacct = inAccount qopts
|
||||||
|
filtering = m /= MatchAny
|
||||||
|
injournal = isNothing inacct
|
||||||
|
showlastcolumn = if injournal && not filtering then False else True
|
||||||
itemAsHtml :: ViewData -> (Int, Bool, Bool, Bool, AccountRegisterReportItem) -> Hamlet AppRoute
|
itemAsHtml :: ViewData -> (Int, Bool, Bool, Bool, AccountRegisterReportItem) -> Hamlet AppRoute
|
||||||
itemAsHtml VD{here=here,p=p} (n, newd, newm, newy, (t, t', split, acct, amt, bal)) = $(Settings.hamletFile "accountregisterreportitem")
|
itemAsHtml VD{here=here,p=p} (n, newd, newm, _, (t, _, split, acct, amt, bal)) = [$hamlet|
|
||||||
|
<tr.item.#{evenodd}.#{firstposting}.#{datetransition}
|
||||||
|
<td.date>#{date}
|
||||||
|
<td.description title="#{show t}">#{elideRight 30 desc}
|
||||||
|
<td.account title="#{show t}"
|
||||||
|
$if True
|
||||||
|
<a
|
||||||
|
#{elideRight 40 acct}
|
||||||
|
|
||||||
|
<a.postings-toggle-link.togglelink href="#" title="Toggle postings"
|
||||||
|
[+/-]
|
||||||
|
$else
|
||||||
|
<a href="@?{acctquery}" title="Go to #{acct}">#{elideRight 40 acct}
|
||||||
|
<td.amount align=right>
|
||||||
|
$if showamt
|
||||||
|
#{mixedAmountAsHtml amt}
|
||||||
|
$if showlastcolumn
|
||||||
|
<td.balance align=right>#{mixedAmountAsHtml bal}
|
||||||
|
$if True
|
||||||
|
$forall p <- tpostings t
|
||||||
|
<tr.item.#{evenodd}.posting.#{displayclass}
|
||||||
|
<td.date
|
||||||
|
<td.description
|
||||||
|
<td.account> <a href="@?{accountUrl here $ paccount p}" title="Show transactions in #{paccount p}">#{elideRight 40 $ paccount p}
|
||||||
|
<td.amount align=right>#{mixedAmountAsHtml $ pamount p}
|
||||||
|
$if showlastcolumn
|
||||||
|
<td.balance align=right>
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
evenodd = if even n then "even" else "odd" :: String
|
evenodd = if even n then "even" else "odd" :: String
|
||||||
datetransition | newm = "newmonth"
|
datetransition | newm = "newmonth"
|
||||||
@ -200,6 +355,21 @@ mixedAmountAsHtml b = preEscapedString $ addclass $ intercalate "<br>" $ lines $
|
|||||||
c = case isNegativeMixedAmount b of Just True -> "negative amount"
|
c = case isNegativeMixedAmount b of Just True -> "negative amount"
|
||||||
_ -> "positive amount"
|
_ -> "positive amount"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- post handlers
|
||||||
|
|
||||||
|
postJournalR :: Handler RepPlain
|
||||||
|
postJournalR = handlePost
|
||||||
|
|
||||||
|
postRegisterR :: Handler RepPlain
|
||||||
|
postRegisterR = handlePost
|
||||||
|
|
||||||
|
postJournalOnlyR :: Handler RepPlain
|
||||||
|
postJournalOnlyR = handlePost
|
||||||
|
|
||||||
|
postRegisterOnlyR :: Handler RepPlain
|
||||||
|
postRegisterOnlyR = handlePost
|
||||||
|
|
||||||
-- | Handle a post from any of the edit forms.
|
-- | Handle a post from any of the edit forms.
|
||||||
handlePost :: Handler RepPlain
|
handlePost :: Handler RepPlain
|
||||||
handlePost = do
|
handlePost = do
|
||||||
@ -314,7 +484,7 @@ handleEdit = do
|
|||||||
redirect RedirectTemporary JournalR)
|
redirect RedirectTemporary JournalR)
|
||||||
jE
|
jE
|
||||||
|
|
||||||
-- | Handle post from the journal import form.
|
-- | Handle a post from the journal import form.
|
||||||
handleImport :: Handler RepPlain
|
handleImport :: Handler RepPlain
|
||||||
handleImport = do
|
handleImport = do
|
||||||
setMessage "can't handle file upload yet"
|
setMessage "can't handle file upload yet"
|
||||||
@ -337,51 +507,168 @@ handleImport = do
|
|||||||
|
|
||||||
-- | Global toolbar/heading area.
|
-- | Global toolbar/heading area.
|
||||||
topbar :: ViewData -> Hamlet AppRoute
|
topbar :: ViewData -> Hamlet AppRoute
|
||||||
topbar VD{j=j,msg=msg,today=today} = $(Settings.hamletFile "topbar")
|
topbar VD{j=j,msg=msg} = [$hamlet|
|
||||||
|
<div#topbar
|
||||||
|
<a.topleftlink href=#{hledgerorgurl} title="More about hledger"
|
||||||
|
hledger-web
|
||||||
|
<br />
|
||||||
|
#{version}
|
||||||
|
<a.toprightlink href=#{manualurl} target=hledgerhelp title="User manual">manual
|
||||||
|
<h1>#{title}
|
||||||
|
$maybe m <- msg
|
||||||
|
<div#message>#{m}
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
title = takeFileName $ journalFilePath j
|
title = takeFileName $ journalFilePath j
|
||||||
|
|
||||||
-- -- | Links to navigate between the main views.
|
|
||||||
-- navlinks :: ViewData -> Hamlet AppRoute
|
|
||||||
-- navlinks vd = $(Settings.hamletFile "navlinks")
|
|
||||||
-- where
|
|
||||||
-- journallink = navlink vd "transactions" JournalR
|
|
||||||
-- registerlink = navlink vd "postings" RegisterR
|
|
||||||
|
|
||||||
-- | Navigation link, preserving parameters and possibly highlighted.
|
-- | Navigation link, preserving parameters and possibly highlighted.
|
||||||
navlink :: ViewData -> String -> AppRoute -> String -> Hamlet AppRoute
|
navlink :: ViewData -> String -> AppRoute -> String -> Hamlet AppRoute
|
||||||
navlink VD{here=here,q=q} s dest title = $(Settings.hamletFile "navlink")
|
navlink VD{here=here,q=q} s dest title = [$hamlet|
|
||||||
|
<a##{s}link.#{style} href=@?{u} title="#{title}">#{s}
|
||||||
|
|]
|
||||||
where u = (dest, if null q then [] else [("q", pack q)])
|
where u = (dest, if null q then [] else [("q", pack q)])
|
||||||
style | dest == here = "navlinkcurrent"
|
style | dest == here = "navlinkcurrent"
|
||||||
| otherwise = "navlink" :: Text
|
| otherwise = "navlink" :: Text
|
||||||
|
|
||||||
-- | Links to the various journal editing forms.
|
-- | Links to the various journal editing forms.
|
||||||
editlinks :: Hamlet AppRoute
|
editlinks :: Hamlet AppRoute
|
||||||
editlinks = $(Settings.hamletFile "editlinks")
|
editlinks = [$hamlet|
|
||||||
|
<a#editformlink href onclick="return editformToggle(event)" title="Toggle journal edit form">edit
|
||||||
|
\ | #
|
||||||
|
<a#addformlink href onclick="return addformToggle(event)" title="Toggle transaction add form">add
|
||||||
|
<a#importformlink href onclick="return importformToggle(event)" style="display:none;">import transactions
|
||||||
|
|]
|
||||||
|
|
||||||
-- | Link to a topic in the manual.
|
-- | Link to a topic in the manual.
|
||||||
helplink :: String -> String -> Hamlet AppRoute
|
helplink :: String -> String -> Hamlet AppRoute
|
||||||
helplink topic label = $(Settings.hamletFile "helplink")
|
helplink topic label = [$hamlet|
|
||||||
|
<a href=#{u} target=hledgerhelp>#{label}
|
||||||
|
|]
|
||||||
where u = manualurl ++ if null topic then "" else '#':topic
|
where u = manualurl ++ if null topic then "" else '#':topic
|
||||||
|
|
||||||
-- | Search form for entering custom queries to filter journal data.
|
-- | Search form for entering custom queries to filter journal data.
|
||||||
searchform :: ViewData -> Hamlet AppRoute
|
searchform :: ViewData -> Hamlet AppRoute
|
||||||
searchform VD{here=here,q=q} = $(Settings.hamletFile "searchform")
|
searchform VD{here=here,q=q} = [$hamlet|
|
||||||
|
<div#searchformdiv
|
||||||
|
<form#searchform.form method=GET
|
||||||
|
<table
|
||||||
|
<tr
|
||||||
|
<td
|
||||||
|
Search:
|
||||||
|
\ #
|
||||||
|
<td
|
||||||
|
<input name=q size=70 value=#{q}
|
||||||
|
<input type=submit value="Search"
|
||||||
|
$if filtering
|
||||||
|
\ #
|
||||||
|
<span.showall
|
||||||
|
<a href=@{here}>clear search
|
||||||
|
\ #
|
||||||
|
<a#search-help-link href="#" title="Toggle search help">help
|
||||||
|
<tr
|
||||||
|
<td
|
||||||
|
<td
|
||||||
|
<div#search-help.help style="display:none;"
|
||||||
|
Leave blank to see journal (all transactions), or click account links to see transactions under that account.
|
||||||
|
<br>
|
||||||
|
Transactions/postings may additionally be filtered by:
|
||||||
|
<br>
|
||||||
|
acct:REGEXP (target account), #
|
||||||
|
desc:REGEXP (description), #
|
||||||
|
date:PERIODEXP (date), #
|
||||||
|
edate:PERIODEXP (effective date), #
|
||||||
|
<br>
|
||||||
|
status:BOOL (cleared status), #
|
||||||
|
real:BOOL (real/virtual-ness), #
|
||||||
|
empty:BOOL (posting amount = 0).
|
||||||
|
<br>
|
||||||
|
not: to negate, enclose space-containing patterns in quotes, multiple filters are AND'ed.
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
filtering = not $ null q
|
filtering = not $ null q
|
||||||
|
|
||||||
-- | Add transaction form.
|
-- | Add transaction form.
|
||||||
addform :: ViewData -> Hamlet AppRoute
|
addform :: ViewData -> Hamlet AppRoute
|
||||||
addform vd@VD{qopts=qopts} = $(Settings.hamletFile "addform")
|
addform vd@VD{qopts=qopts} = [$hamlet|
|
||||||
|
<script type=text/javascript>
|
||||||
|
$(document).ready(function() {
|
||||||
|
/* dhtmlxcombo setup */
|
||||||
|
window.dhx_globalImgPath="../static/";
|
||||||
|
var desccombo = new dhtmlXCombo("description");
|
||||||
|
var acct1combo = new dhtmlXCombo("account1");
|
||||||
|
var acct2combo = new dhtmlXCombo("account2");
|
||||||
|
desccombo.enableFilteringMode(true);
|
||||||
|
acct1combo.enableFilteringMode(true);
|
||||||
|
acct2combo.enableFilteringMode(true);
|
||||||
|
desccombo.setSize(300);
|
||||||
|
acct1combo.setSize(300);
|
||||||
|
acct2combo.setSize(300);
|
||||||
|
/* desccombo.enableOptionAutoHeight(true, 20); */
|
||||||
|
/* desccombo.setOptionHeight(200); */
|
||||||
|
});
|
||||||
|
|
||||||
|
<form#addform method=POST style=display:none;
|
||||||
|
<h2#contenttitle>#{title}
|
||||||
|
<table.form
|
||||||
|
<tr
|
||||||
|
<td colspan=4
|
||||||
|
<table
|
||||||
|
<tr#descriptionrow
|
||||||
|
<td
|
||||||
|
Date:
|
||||||
|
<td
|
||||||
|
<input.textinput size=15 name=date value=#{date}
|
||||||
|
<td style=padding-left:1em;
|
||||||
|
Description:
|
||||||
|
<td
|
||||||
|
<select id=description name=description
|
||||||
|
<option
|
||||||
|
$forall d <- descriptions
|
||||||
|
<option value=#{d}>#{d}
|
||||||
|
<tr.helprow
|
||||||
|
<td
|
||||||
|
<td
|
||||||
|
<span.help>#{datehelp} #
|
||||||
|
<td
|
||||||
|
<td
|
||||||
|
<span.help>#{deschelp}
|
||||||
|
^{postingfields vd 1}
|
||||||
|
^{postingfields vd 2}
|
||||||
|
<tr#addbuttonrow
|
||||||
|
<td colspan=4
|
||||||
|
<input type=hidden name=action value=add
|
||||||
|
<input type=submit name=submit value="add transaction"
|
||||||
|
$if manyfiles
|
||||||
|
\ to: ^{journalselect $ files $ j vd}
|
||||||
|
\ or #
|
||||||
|
<a href onclick="return addformToggle(event)">cancel
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
|
title = "Add transaction" :: String
|
||||||
datehelp = "eg: 2010/7/20" :: String
|
datehelp = "eg: 2010/7/20" :: String
|
||||||
deschelp = "eg: supermarket (optional)" :: String
|
deschelp = "eg: supermarket (optional)" :: String
|
||||||
date = "today" :: String
|
date = "today" :: String
|
||||||
descriptions = sort $ nub $ map tdescription $ jtxns $ j vd
|
descriptions = sort $ nub $ map tdescription $ jtxns $ j vd
|
||||||
manyfiles = (length $ files $ j vd) > 1
|
manyfiles = (length $ files $ j vd) > 1
|
||||||
postingfields VD{j=j} n = $(Settings.hamletFile "addformpostingfields")
|
postingfields VD{j=j} n = [$hamlet|
|
||||||
|
<tr#postingrow
|
||||||
|
<td align=right>#{acctlabel}:
|
||||||
|
<td
|
||||||
|
<select id=#{acctvar} name=#{acctvar}
|
||||||
|
<option
|
||||||
|
$forall a <- acctnames
|
||||||
|
<option value=#{a} :shouldselect a:selected>#{a}
|
||||||
|
^{amtfield}
|
||||||
|
<tr.helprow
|
||||||
|
<td
|
||||||
|
<td
|
||||||
|
<span.help>#{accthelp}
|
||||||
|
<td
|
||||||
|
<td
|
||||||
|
<span.help>#{amthelp}
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
shouldselect a = n == 2 && Just a == inAccount qopts
|
shouldselect a = n == 2 && maybe False ((a==).fst) (inAccount qopts)
|
||||||
numbered = (++ show n)
|
numbered = (++ show n)
|
||||||
acctvar = numbered "account"
|
acctvar = numbered "account"
|
||||||
amtvar = numbered "amount"
|
amtvar = numbered "amount"
|
||||||
@ -389,7 +676,12 @@ addform vd@VD{qopts=qopts} = $(Settings.hamletFile "addform")
|
|||||||
(acctlabel, accthelp, amtfield, amthelp)
|
(acctlabel, accthelp, amtfield, amthelp)
|
||||||
| n == 1 = ("To account"
|
| n == 1 = ("To account"
|
||||||
,"eg: expenses:food"
|
,"eg: expenses:food"
|
||||||
,$(Settings.hamletFile "addformpostingfieldsamount")
|
,[$hamlet|
|
||||||
|
<td style=padding-left:1em;
|
||||||
|
Amount:
|
||||||
|
<td
|
||||||
|
<input.textinput size=15 name=#{amtvar} value=""
|
||||||
|
|]
|
||||||
,"eg: $6"
|
,"eg: $6"
|
||||||
)
|
)
|
||||||
| otherwise = ("From account" :: String
|
| otherwise = ("From account" :: String
|
||||||
@ -400,25 +692,61 @@ addform vd@VD{qopts=qopts} = $(Settings.hamletFile "addform")
|
|||||||
|
|
||||||
-- | Edit journal form.
|
-- | Edit journal form.
|
||||||
editform :: ViewData -> Hamlet AppRoute
|
editform :: ViewData -> Hamlet AppRoute
|
||||||
editform VD{j=j} = $(Settings.hamletFile "editform")
|
editform VD{j=j} = [$hamlet|
|
||||||
|
<form#editform method=POST style=display:none;
|
||||||
|
<table.form
|
||||||
|
$if manyfiles
|
||||||
|
<tr
|
||||||
|
<td colspan=2
|
||||||
|
Editing ^{journalselect $ files j}
|
||||||
|
<tr
|
||||||
|
<td colspan=2
|
||||||
|
<!-- XXX textarea ids are unquoted journal file paths here, not valid html -->
|
||||||
|
$forall f <- files j
|
||||||
|
<textarea id=#{fst f}_textarea name=text rows=25 cols=80 style=display:none; disabled=disabled
|
||||||
|
#{snd f}
|
||||||
|
<tr#addbuttonrow
|
||||||
|
<td
|
||||||
|
<span.help>^{formathelp}
|
||||||
|
<td align=right
|
||||||
|
<span.help Are you sure ? This will overwrite the journal. #
|
||||||
|
<input type=hidden name=action value=edit
|
||||||
|
<input type=submit name=submit value="save journal"
|
||||||
|
\ or #
|
||||||
|
<a href onclick="return editformToggle(event)">cancel
|
||||||
|
|]
|
||||||
where
|
where
|
||||||
manyfiles = (length $ files j) > 1
|
manyfiles = (length $ files j) > 1
|
||||||
formathelp = helplink "file-format" "file format help"
|
formathelp = helplink "file-format" "file format help"
|
||||||
|
|
||||||
-- | Import journal form.
|
-- | Import journal form.
|
||||||
importform :: Hamlet AppRoute
|
importform :: Hamlet AppRoute
|
||||||
importform = $(Settings.hamletFile "importform")
|
importform = [$hamlet|
|
||||||
|
<form#importform method=POST style=display:none;
|
||||||
|
<table.form
|
||||||
|
<tr
|
||||||
|
<td
|
||||||
|
<input type=file name=file
|
||||||
|
<input type=hidden name=action value=import
|
||||||
|
<input type=submit name=submit value="import from file"
|
||||||
|
\ or #
|
||||||
|
<a href onclick="return importformToggle(event)" cancel
|
||||||
|
|]
|
||||||
|
|
||||||
journalselect :: [(FilePath,String)] -> Hamlet AppRoute
|
journalselect :: [(FilePath,String)] -> Hamlet AppRoute
|
||||||
journalselect journalfiles = $(Settings.hamletFile "journalselect")
|
journalselect journalfiles = [$hamlet|
|
||||||
|
<select id=journalselect name=journal onchange="editformJournalSelect(event)"
|
||||||
----------------------------------------------------------------------
|
$forall f <- journalfiles
|
||||||
-- utilities
|
<option value=#{fst f}>#{fst f}
|
||||||
|
|]
|
||||||
|
|
||||||
nulltemplate :: Hamlet AppRoute
|
nulltemplate :: Hamlet AppRoute
|
||||||
nulltemplate = [$hamlet||]
|
nulltemplate = [$hamlet||]
|
||||||
|
|
||||||
-- | A bundle of data useful for handlers and their templates.
|
----------------------------------------------------------------------
|
||||||
|
-- utilities
|
||||||
|
|
||||||
|
-- | A bundle of data useful for hledger-web request handlers and templates.
|
||||||
data ViewData = VD {
|
data ViewData = VD {
|
||||||
opts :: [Opt] -- ^ command-line options at startup
|
opts :: [Opt] -- ^ command-line options at startup
|
||||||
,q :: String -- ^ current q parameter, the query expression
|
,q :: String -- ^ current q parameter, the query expression
|
||||||
@ -448,7 +776,7 @@ mkvd = VD {
|
|||||||
,msg = Nothing
|
,msg = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | Gather data useful for a hledger-web request handler and its templates.
|
-- | Gather useful data for handlers and templates.
|
||||||
getViewData :: Handler ViewData
|
getViewData :: Handler ViewData
|
||||||
getViewData = do
|
getViewData = do
|
||||||
app <- getYesod
|
app <- getYesod
|
||||||
|
@ -111,7 +111,7 @@ toJuliusFile x = datadir++"templates/" ++ x ++ ".julius"
|
|||||||
toLuciusFile x = datadir++"templates/" ++ x ++ ".lucius"
|
toLuciusFile x = datadir++"templates/" ++ x ++ ".lucius"
|
||||||
|
|
||||||
hamletFile :: FilePath -> Q Exp
|
hamletFile :: FilePath -> Q Exp
|
||||||
hamletFile = H.hamletFile . toHamletFile -- debug variant not used, http://www.yesodweb.com/book/faq#q1
|
hamletFile = H.hamletFile . toHamletFile
|
||||||
|
|
||||||
cassiusFile :: FilePath -> Q Exp
|
cassiusFile :: FilePath -> Q Exp
|
||||||
#ifdef PRODUCTION
|
#ifdef PRODUCTION
|
||||||
|
Loading…
Reference in New Issue
Block a user