web: stay in add form when there are errors

This commit is contained in:
Simon Michael 2015-02-23 23:22:02 +00:00
parent 8bde2fd212
commit e76cc6ee47
6 changed files with 29 additions and 25 deletions

View File

@ -25,6 +25,7 @@ import Settings (staticRoot, widgetFile, Extra (..))
import Settings (staticDir) import Settings (staticDir)
import Text.Jasmine (minifym) import Text.Jasmine (minifym)
#endif #endif
import Text.Blaze.Html.Renderer.String (renderHtml)
import Text.Hamlet (hamletFile) import Text.Hamlet (hamletFile)
import Hledger.Web.Options import Hledger.Web.Options
@ -104,7 +105,7 @@ instance Yesod App where
defaultLayout widget = do defaultLayout widget = do
master <- getYesod master <- getYesod
mmsg <- getMessage vd@VD{..} <- getViewData
-- We break up the default layout into two components: -- We break up the default layout into two components:
-- default-layout is the contents of the body tag, and -- default-layout is the contents of the body tag, and
@ -140,7 +141,6 @@ instance Yesod App where
$(widgetFile "default-layout") $(widgetFile "default-layout")
staticRootUrl <- (staticRoot . settings) <$> getYesod staticRootUrl <- (staticRoot . settings) <$> getYesod
vd@VD{..} <- getViewData
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet") withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
-- This is done to provide an optimization for serving static files from -- This is done to provide an optimization for serving static files from
@ -232,8 +232,9 @@ getViewData :: Handler ViewData
getViewData = do getViewData = do
app <- getYesod app <- getYesod
let opts@WebOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} = appOpts app let opts@WebOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} = appOpts app
(j, err) <- getCurrentJournal app copts{reportopts_=ropts{no_elide_=True}} (j, merr) <- getCurrentJournal app copts{reportopts_=ropts{no_elide_=True}}
msg <- getMessageOr err lastmsg <- getLastMessage
let msg = maybe lastmsg (Just . toHtml) merr
Just here <- getCurrentRoute Just here <- getCurrentRoute
today <- liftIO getCurrentDay today <- liftIO getCurrentDay
q <- getParameterOrNull "q" q <- getParameterOrNull "q"
@ -275,11 +276,10 @@ getViewData = do
getParameterOrNull :: String -> Handler String getParameterOrNull :: String -> Handler String
getParameterOrNull p = unpack `fmap` fromMaybe "" <$> lookupGetParam (pack p) getParameterOrNull p = unpack `fmap` fromMaybe "" <$> lookupGetParam (pack p)
-- | Get the message set by the last request, or the newer message provided, if any. -- | Get the message that was set by the last request, in a
getMessageOr :: Maybe String -> Handler (Maybe Html) -- referentially transparent manner (allowing multiple reads).
getMessageOr mnewmsg = do getLastMessage :: Handler (Maybe Html)
oldmsg <- getMessage getLastMessage = cached getMessage
return $ maybe oldmsg (Just . toHtml) mnewmsg
-- add form dialog, part of the default template -- add form dialog, part of the default template
@ -334,7 +334,7 @@ addform _ vd@VD{..} = [hamlet|
<table style="width:100%;"> <table style="width:100%;">
<tr#descriptionrow> <tr#descriptionrow>
<td> <td>
<input #date .typeahead .form-control .input-lg type=text size=15 name=date placeholder="Date" value=#{date}> <input #date .typeahead .form-control .input-lg type=text size=15 name=date placeholder="Date" value=#{defdate}>
<td> <td>
<input #description .typeahead .form-control .input-lg type=text size=40 name=description placeholder="Description"> <input #description .typeahead .form-control .input-lg type=text size=40 name=description placeholder="Description">
$forall n <- postingnums $forall n <- postingnums
@ -344,7 +344,7 @@ addform _ vd@VD{..} = [hamlet|
Tab in last field for <a .small href="#" onclick="addformAddPosting(); return false;">more</a> (or ctrl +, ctrl -) Tab in last field for <a .small href="#" onclick="addformAddPosting(); return false;">more</a> (or ctrl +, ctrl -)
|] |]
where where
date = "today" :: String defdate = "today" :: String
dates = ["today","yesterday","tomorrow"] :: [String] dates = ["today","yesterday","tomorrow"] :: [String]
descriptions = sort $ nub $ map tdescription $ jtxns j descriptions = sort $ nub $ map tdescription $ jtxns j
accts = sort $ journalAccountNamesUsed j accts = sort $ journalAccountNamesUsed j

View File

@ -61,9 +61,9 @@ postAddForm = do
<*> iopt textField "description" <*> iopt textField "description"
<*> iopt (check validateJournalFile textField) "journal" <*> iopt (check validateJournalFile textField) "journal"
case formresult of ok <- case formresult of
FormMissing -> showErrors ["there is no form data"::String] FormMissing -> showErrors ["there is no form data"::String] >> return False
FormFailure errs -> showErrors errs FormFailure errs -> showErrors errs >> return False
FormSuccess dat -> do FormSuccess dat -> do
let AddForm{ let AddForm{
addFormDate =date addFormDate =date
@ -107,7 +107,7 @@ postAddForm = do
,tpostings=[nullposting{paccount=acct, pamount=Mixed [amt]} | (acct,amt) <- zip accts amts] ,tpostings=[nullposting{paccount=acct, pamount=Mixed [amt]} | (acct,amt) <- zip accts amts]
}) })
case etxn of case etxn of
Left errs -> showErrors errs Left errs -> showErrors errs >> return False
Right t -> do Right t -> do
-- 3. all fields look good and form a balanced transaction; append it to the file -- 3. all fields look good and form a balanced transaction; append it to the file
liftIO $ do ensureJournalFileExists journalfile liftIO $ do ensureJournalFileExists journalfile
@ -116,5 +116,6 @@ postAddForm = do
txnTieKnot -- XXX move into balanceTransaction txnTieKnot -- XXX move into balanceTransaction
t t
setMessage [shamlet|<span>Transaction added.|] setMessage [shamlet|<span>Transaction added.|]
return True
redirect (JournalR) -- , [("add","1")]) if ok then redirect JournalR else redirect (JournalR, [("add","1")])

View File

@ -55,8 +55,6 @@ topbar VD{..} = [hamlet|
<nav class="navbar" role="navigation"> <nav class="navbar" role="navigation">
<div#topbar> <div#topbar>
<h1>#{title} <h1>#{title}
$maybe m' <- msg
<div#message>#{m'}
|] |]
where where
title = takeFileName $ journalFilePath j title = takeFileName $ journalFilePath j

View File

@ -6,7 +6,7 @@
$(document).ready(function() { $(document).ready(function() {
// show add form if ?add=1 // show add form if ?add=1
if ($.url.param('add')) { addformShow(); } if ($.url.param('add')) { addformShow(showmsg=true); }
// sidebar account hover handlers // sidebar account hover handlers
$('#sidebar td a').mouseenter(function(){ $(this).parent().addClass('mouseover'); }); $('#sidebar td a').mouseenter(function(){ $(this).parent().addClass('mouseover'); });
@ -126,8 +126,8 @@ function registerChartClick(ev, pos, item) {
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// ADD FORM // ADD FORM
function addformShow() { function addformShow(showmsg=false) {
addformReset(); addformReset(showmsg);
$('#addmodal') $('#addmodal')
.on('shown.bs.modal', function (e) { .on('shown.bs.modal', function (e) {
addformFocus(); addformFocus();
@ -136,13 +136,14 @@ function addformShow() {
} }
// Make sure the add form is empty and clean for display. // Make sure the add form is empty and clean for display.
function addformReset() { function addformReset(showmsg=false) {
if ($('form#addform').length > 0) { if ($('form#addform').length > 0) {
if (!showmsg) $('div#message').html('');
$('form#addform')[0].reset(); $('form#addform')[0].reset();
$('input#date').val('today');
// reset typehead state (though not fetched completions) // reset typehead state (though not fetched completions)
$('.typeahead').typeahead('val', ''); $('.typeahead').typeahead('val', '');
$('.tt-dropdown-menu').hide(); $('.tt-dropdown-menu').hide();
$('input#date').val('today');
} }
} }

View File

@ -100,4 +100,7 @@ $newline never
<button type="button" .close data-dismiss="modal" aria-hidden="true">&times; <button type="button" .close data-dismiss="modal" aria-hidden="true">&times;
<h3 .modal-title #addLabel>Add a transaction <h3 .modal-title #addLabel>Add a transaction
<div .modal-body> <div .modal-body>
$maybe m <- msg
$if isPrefixOf "Errors" (renderHtml m)
<div #message>#{m}
^{addform staticRootUrl vd} ^{addform staticRootUrl vd}

View File

@ -1,3 +1,4 @@
$maybe msg <- mmsg $maybe m <- msg
<div #message>#{msg} $if not $ isPrefixOf "Errors" (renderHtml m)
<div #message>#{m}
^{widget} ^{widget}