web: UI cleanup

This commit is contained in:
Jakub Zárybnický 2018-06-17 14:31:10 +02:00
parent c952ab881b
commit 5f6da96baa
10 changed files with 82 additions and 181 deletions

View File

@ -12,7 +12,7 @@ import Import
import Hledger
import Hledger.Cli.CliOptions
import Hledger.Web.WebOptions
import Widget.AddForm (addForm)
import Widget.AddForm (addModal)
import Widget.Common (accountQuery, mixedAmountAsHtml)
-- | The formatted journal view, with sidebar.
@ -27,7 +27,6 @@ getJournalR = do
acctlink a = (RegisterR, [("q", accountQuery a)])
(_, items) = journalTransactionsReport (reportopts_ $ cliopts_ opts) j m
(addView, addEnctype) <- generateFormPost (addForm j today)
defaultLayout $ do
setTitle "journal - hledger-web"
$(widgetFile "journal")

View File

@ -17,8 +17,8 @@ import Text.Hamlet (hamletFile)
import Hledger
import Hledger.Cli.CliOptions
import Hledger.Web.WebOptions
import Widget.AddForm (addForm)
import Widget.Common (mixedAmountAsHtml, numberTransactionsReportItems)
import Widget.AddForm (addModal)
import Widget.Common (mixedAmountAsHtml)
-- | The main journal/account register view, with accounts sidebar.
getRegisterR :: Handler Html
@ -31,13 +31,6 @@ getRegisterR = do
let r@(balancelabel,items) = accountTransactionsReport (reportopts_ $ cliopts_ opts) j m $ fromMaybe Any $ inAccountQuery qopts
balancelabel' = if isJust (inAccount qopts) then balancelabel else "Total"
evenodd x = if even x then "even" else "odd" :: Text
datetransition newm newd
| newm = "newmonth"
| newd = "newday"
| otherwise = "" :: Text
(addView, addEnctype) <- generateFormPost (addForm j today)
defaultLayout $ do
setTitle "register - hledger-web"
$(widgetFile "register")

View File

@ -2,10 +2,12 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
module Widget.AddForm
( addForm
, addModal
) where
import Control.Monad.State.Strict (evalStateT)
@ -26,6 +28,27 @@ import Settings (widgetFile)
-- XXX <select> which journal to add to
addModal ::
( MonadWidget m
, r ~ Route (HandlerSite m)
, m ~ WidgetFor (HandlerSite m)
, RenderMessage (HandlerSite m) FormMessage
)
=> r -> Journal -> Day -> m ()
addModal addR j today = do
(addView, addEnctype) <- generateFormPost (addForm j today)
[whamlet|
<div .modal.fade #addmodal tabindex="-1" role="dialog" aria-labelledby="addLabel" aria-hidden="true">
<div .modal-dialog .modal-lg>
<div .modal-content>
<div .modal-header>
<button type="button" .close data-dismiss="modal" aria-hidden="true">&times;
<h3 .modal-title #addLabel>Add a transaction
<div .modal-body>
<form#addform.form action=@{addR} method=POST enctype=#{addEnctype}>
^{addView}
|]
addForm ::
(site ~ HandlerSite m, RenderMessage site FormMessage, MonadHandler m)
=> Journal

View File

@ -1,4 +1,3 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
@ -10,7 +9,6 @@ module Widget.Common
, balanceReportAsHtml
, helplink
, mixedAmountAsHtml
, numberTransactionsReportItems
, fromFormSuccess
, writeValidJournal
, journalFile404
@ -18,11 +16,9 @@ module Widget.Common
import Data.Default (def)
import Data.Foldable (find, for_)
import Data.List (mapAccumL)
import Data.Semigroup ((<>))
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time.Calendar (Day, toGregorian)
import System.FilePath (takeFileName)
import Text.Blaze ((!), textValue)
import qualified Text.Blaze.Html5 as H
@ -50,7 +46,6 @@ writeValidJournal f txt =
liftIO (readJournal def (Just f) txt) >>= \case
Left e -> return (Left e)
Right _ -> do
-- And write to the file
_ <- liftIO (writeFileWithBackupIfChanged f txt)
return (Right ())
@ -102,19 +97,6 @@ accountQuery = ("inacct:" <>) . quoteIfSpaced
accountOnlyQuery :: AccountName -> Text
accountOnlyQuery = ("inacctonly:" <>) . quoteIfSpaced
numberTransactionsReportItems :: [TransactionsReportItem] -> [(Int, Bool, Bool, TransactionsReportItem)]
numberTransactionsReportItems = snd . mapAccumL number (0, nulldate)
where
number :: (Int, Day) -> TransactionsReportItem -> ((Int, Day), (Int, Bool, Bool, TransactionsReportItem))
number (!n, !prevd) i@(t, _, _, _, _, _) = ((n', d), (n', newday, newmonth, i))
where
n' = n + 1
d = tdate t
newday = d /= prevd
newmonth = dm /= prevdm || dy /= prevdy
(dy, dm, _) = toGregorian d
(prevdy, prevdm, _) = toGregorian prevd
mixedAmountAsHtml :: MixedAmount -> HtmlUrl a
mixedAmountAsHtml b _ =
for_ (lines (showMixedAmountWithoutPrice b)) $ \t -> do

View File

@ -20,37 +20,6 @@
/*------------------------------------------------------------------------------------------*/
/* 4. typeahead styles */
/*
.typeahead,
.tt-query,
.tt-hint {
width: 396px;
height: 30px;
padding: 8px 12px;
font-size: 24px;
line-height: 30px;
border: 2px solid #ccc;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
outline: none;
}
.typeahead {
background-color: #fff;
}
.typeahead:focus {
border: 2px solid #0097cf;
}
.tt-query {
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
*/
.tt-hint {
color: #bbb;
}
@ -200,24 +169,6 @@ ul {
whitespace: nowrap;
}
#main-content {
/*
-webkit-transition: width 0.3s ease, margin 0.3s ease;
-moz-transition: width 0.3s ease, margin 0.3s ease;
-o-transition: width 0.3s ease, margin 0.3s ease;
transition: width 0.3s ease, margin 0.3s ease;
*/
}
#sidebar-menu {
/*
-webkit-transition: width 0.3s ease, margin 0.3s ease,opacity 0.3s ease,height 1s ease 1s;
-moz-transition: width 0.3s ease, margin 0.3s ease,opacity 0.3s ease,height 1s ease 1s;
-o-transition: width 0.3s ease, margin 0.3s ease,opacity 0.3s ease,height 1s ease 1s;
transition: width 0.3s ease, margin 0.3s ease,opacity 0.3s ease,height 1s ease 1s;
*/
}
.col-any-0 {
width:0 !important;
height:0 !important;
@ -229,10 +180,6 @@ ul {
font-size:large;
}
#searchbar {
width: 100% !important;
}
@media screen and (max-width: 768px) {
.row-offcanvas {
position: relative;

View File

@ -4,9 +4,13 @@
// STARTUP
$(document).ready(function() {
// cache the input element as a variable
// for minor performance benefits
var dateEl = $('#dateWrap');
// date picker
// http://bootstrap-datepicker.readthedocs.io/en/latest/options.html
var dateEl = $('#dateWrap').datepicker({
showOnFocus: false,
autoclose: true,
format: 'yyyy-mm-dd'
});;
// ensure add form always focuses its first field
$('#addmodal')
@ -18,21 +22,6 @@ $(document).ready(function() {
dateEl.datepicker('hide');
});
// show add form if ?add=1
if ($.url.param('add')) { addformShow(true); }
// date picker
// http://bootstrap-datepicker.readthedocs.io/en/latest/options.html
dateEl.datepicker({
showOnFocus: false,
autoclose: true,
format: 'yyyy-mm-dd'
});
// sidebar account hover handlers
$('#sidebar td a').mouseenter(function(){ $(this).parent().addClass('mouseover'); });
$('#sidebar td').mouseleave(function(){ $(this).removeClass('mouseover'); });
// keyboard shortcuts
// 'body' seems to hold focus better than document in FF
$('body').bind('keydown', 'h', function(){ $('#helpmodal').modal('toggle'); return false; });
@ -42,12 +31,12 @@ $(document).ready(function() {
$('body').bind('keydown', 'a', function(){ addformShow(); return false; });
$('body').bind('keydown', 'n', function(){ addformShow(); return false; });
$('body').bind('keydown', 'f', function(){ $('#searchform input').focus(); return false; });
$('body, #addform input, #addform select').bind('keydown', 'ctrl++', addformAddPosting);
$('body, #addform input, #addform select').bind('keydown', 'ctrl+shift+=', addformAddPosting);
$('body, #addform input, #addform select').bind('keydown', 'ctrl+=', addformAddPosting);
$('body, #addform input, #addform select').bind('keydown', 'ctrl+-', addformDeletePosting);
$('.amount-input:last').keypress(addformAddPosting);
// highlight the entry from the url hash
if (window.location.hash && $(window.location.hash)[0]) {
$(window.location.hash).addClass('highlighted');
@ -173,49 +162,38 @@ function focus($el) {
// Insert another posting row in the add form.
function addformAddPosting() {
$('.amount-input:last').off('keypress');
// do nothing if it's not currently visible
if (!$('#addform').is(':visible')) return;
// save a copy of last row
var lastrow = $('#addform .form-group:last').clone();
if (!$('#addform').is(':visible')) {
return;
}
// replace the submit button with an amount field, clear and renumber it, add the keybindings
var prevLastRow = $('.amount-input:last');
prevLastRow.off('keypress');
// Clone the currently last row
$('#addform .account-postings').append(prevLastRow.clone());
var num = $('#addform .account-group').length;
// insert the new last row
$('#addform .account-postings').append(lastrow);
// TODO: Enable typehead on dynamically created inputs
var $acctinput = $('.account-input:last');
var $amntinput = $('.amount-input:last');
// clear and renumber the field, add keybindings
$acctinput
// XXX Enable typehead on dynamically created inputs
$('.amount-input:last')
.val('')
.prop('name', 'account')
.prop('placeholder', 'Account ' + (num + 1));
//lastrow.find('input') // not :last this time
$acctinput
.bind('keydown', 'ctrl+shift+=', addformAddPosting)
.bind('keydown', 'ctrl+=', addformAddPosting)
.bind('keydown', 'ctrl+-', addformDeletePosting);
$amntinput
.val('')
.prop('name','amount')
.prop('placeholder','Amount ' + (num + 1))
.prop('placeholder','Amount ' + num)
.keypress(addformAddPosting);
$acctinput
$('.account-input:last')
.val('')
.prop('placeholder', 'Account ' + num)
.bind('keydown', 'ctrl++', addformAddPosting)
.bind('keydown', 'ctrl+shift+=', addformAddPosting)
.bind('keydown', 'ctrl+=', addformAddPosting)
.bind('keydown', 'ctrl+-', addformDeletePosting);
}
// Remove the add form's last posting row, if empty, keeping at least two.
function addformDeletePosting() {
var num = $('#addform .account-group').length;
if (num <= 2) return;
if ($('#addform .account-group').length <= 2) {
return;
}
// remember if the last row's field or button had focus
var focuslost =
$('.account-input:last').is(':focus')

View File

@ -11,13 +11,10 @@
<table .main-menu .table>
^{accounts}
<div .col-xs-12.#{mainShowmd}.#{mainShowsm}>
<div#main-content .col-xs-12.#{mainShowmd}.#{mainShowsm}>
$maybe m <- msg
<div #message .alert.alert-info>#{m}
<div .row>
<form#searchform .form-inline method=GET>
<div .form-group .col-md-12 .col-sm-12 .col-xs-12>
<div #searchbar .input-group>
<form#searchform.input-group method=GET>
<input .form-control name=q value=#{q} placeholder="Search"
title="Enter hledger search patterns to filter the data below">
<div .input-group-btn>
@ -26,10 +23,11 @@
<span .glyphicon .glyphicon-remove-circle>
<button .btn .btn-default type=submit title="Apply search terms">
<span .glyphicon .glyphicon-search>
<button .btn .btn-default type=button data-toggle="modal" data-target="#helpmodal"
title="Show search and general help">?
<a href="@{ManageR}" .btn.btn-default title="Manage journal files">
<span .glyphicon .glyphicon-wrench>
<button .btn .btn-default type=button data-toggle="modal" data-target="#helpmodal"
title="Show search and general help">
<span .glyphicon .glyphicon-question-sign>
^{widget}
<div .modal.fade #helpmodal tabindex="-1" role="dialog" aria-labelledby="helpLabel" aria-hidden="true">

View File

@ -16,7 +16,7 @@
<td .date nowrap>#{show (tdate torig)}
<td .description colspan=2>#{textElideRight 60 (tdescription torig)}
<td .amount style="text-align:right;">
$if not split || not (isZeroMixedAmount amt)
$if not split && not (isZeroMixedAmount amt)
\^{mixedAmountAsHtml amt}
$forall Posting { paccount = acc, pamount = amt } <- tpostings torig
@ -30,12 +30,4 @@
<td .amount .nonhead style="text-align:right;">
^{mixedAmountAsHtml amt}
<div .modal #addmodal tabindex="-1" role="dialog" aria-labelledby="addLabel" aria-hidden="true">
<div .modal-dialog .modal-lg>
<div .modal-content>
<div .modal-header>
<button type="button" .close data-dismiss="modal" aria-hidden="true">&times;
<h3 .modal-title #addLabel>Add a transaction
<div .modal-body>
<form#addform.form action=@{AddR} method=POST enctype=#{addEnctype}>
^{addView}
^{addModal AddR j today}

View File

@ -11,14 +11,12 @@
<tbody>
$forall (path, _) <- jfiles j
<tr>
<td>
<td style="vertical-align:middle">
#{path}
<td style="text-align:right">
<a href=@{EditR path}>
<a.btn.btn-default href=@{EditR path}>
Edit
&nbsp;&nbsp;
<a href=@{UploadR path}>
<a.btn.btn-default href=@{UploadR path}>
Upload
&nbsp;&nbsp;
<a href=@{DownloadR path}>
<a.btn.btn-default href=@{DownloadR path}>
Download

View File

@ -5,7 +5,7 @@
^{registerChartHtml $ transactionsReportByCommodity r}
<div.table-responsive>
<table.registerreport .table .table-striped .table-condensed>
<table .table.table-striped.table-condensed>
<thead>
<tr>
<th style="text-align:left;">
@ -18,9 +18,8 @@
#{balancelabel'}
<tbody>
$forall (n, newd, newm, (torig, tacct, split, acct, amt, bal)) <- numberTransactionsReportItems items
<tr ##{tindex torig} .item.#{evenodd n}.#{datetransition newm newd}
title="#{show torig}" style="vertical-align:top;">
$forall (torig, tacct, split, acct, amt, bal) <- items
<tr ##{tindex torig} .item title="#{show torig}" style="vertical-align:top;">
<td .date>
<a href="@{JournalR}#transaction-#{tindex torig}">
#{show (tdate tacct)}
@ -28,15 +27,7 @@
<td .account>#{elideRight 40 acct}
<td .amount style="text-align:right; white-space:nowrap;">
$if not split || not (isZeroMixedAmount amt)
\^{mixedAmountAsHtml amt}
^{mixedAmountAsHtml amt}
<td .balance style="text-align:right;">^{mixedAmountAsHtml bal}
<div .modal #addmodal tabindex="-1" role="dialog" aria-labelledby="addLabel" aria-hidden="true">
<div .modal-dialog .modal-lg>
<div .modal-content>
<div .modal-header>
<button type="button" .close data-dismiss="modal" aria-hidden="true">&times;
<h3 .modal-title #addLabel>Add a transaction
<div .modal-body>
<form#addform.form action=@{AddR} method=POST enctype=#{addEnctype}>
^{addView}
^{addModal AddR j today}