Feature complete MassInput
This commit is contained in:
parent
4b2d6d3aa2
commit
aca5d180bc
29
clean.sh
Executable file
29
clean.sh
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
"")
|
||||||
|
exec -- stack clean
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
target=".stack-work-${1}"
|
||||||
|
if [[ ! -d "${target}" ]]; then
|
||||||
|
printf "%s does not exist or is no directory\n" "${target}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -e .stack-work-clean ]]; then
|
||||||
|
printf ".stack-work-clean exists\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
move-back() {
|
||||||
|
mv -v .stack-work "${target}"
|
||||||
|
[[ -d .stack-work-clean ]] && mv -v .stack-work-clean .stack-work
|
||||||
|
}
|
||||||
|
|
||||||
|
mv -v .stack-work .stack-work-clean
|
||||||
|
mv -v "${target}" .stack-work
|
||||||
|
trap move-back EXIT
|
||||||
|
|
||||||
|
stack clean
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@ -307,6 +307,7 @@ data instance ButtonClass UniWorX
|
|||||||
| BCWarning
|
| BCWarning
|
||||||
| BCDanger
|
| BCDanger
|
||||||
| BCLink
|
| BCLink
|
||||||
|
| BCMassInputAdd | BCMassInputDelete
|
||||||
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
|
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
|
||||||
instance Universe (ButtonClass UniWorX)
|
instance Universe (ButtonClass UniWorX)
|
||||||
instance Finite (ButtonClass UniWorX)
|
instance Finite (ButtonClass UniWorX)
|
||||||
|
|||||||
@ -135,23 +135,20 @@ postAdminTestR = do
|
|||||||
let
|
let
|
||||||
-- | Make a form for adding a point/line/plane/hyperplane/... (in this case: cell)
|
-- | Make a form for adding a point/line/plane/hyperplane/... (in this case: cell)
|
||||||
--
|
--
|
||||||
-- This /needs/ to use @nudge@ (for deterministic field naming) and to replace all occurances of @mreq@ with @mpreq@ (no fields should be /actually/ required)
|
-- This /needs/ to replace all occurances of @mreq@ with @mpreq@ (no fields should be /actually/ required)
|
||||||
mkAddForm :: ListPosition -- ^ Approximate position of the add-widget
|
mkAddForm :: ListPosition -- ^ Approximate position of the add-widget
|
||||||
-> Natural -- ^ Dimension Index, outermost dimension ist 0 i.e. if dimension is 3 hyperplane-adders get passed 0, planes get passed 1, lines get 2, and points get 3
|
-> Natural -- ^ Dimension Index, outermost dimension ist 0 i.e. if dimension is 3 hyperplane-adders get passed 0, planes get passed 1, lines get 2, and points get 3
|
||||||
-> ListLength -- ^ Liveliness
|
|
||||||
-> (Text -> Text) -- ^ Nudge deterministic field ids so they're unique
|
-> (Text -> Text) -- ^ Nudge deterministic field ids so they're unique
|
||||||
-> FieldView UniWorX -- ^ Submit-Button for this add-widget
|
-> FieldView UniWorX -- ^ Submit-Button for this add-widget
|
||||||
-> Maybe (Form (ListPosition, Int)) -- ^ Nothing if no further cells should be added; returns index of new cell and data needed to initialize cell
|
-> Maybe (Form (ListLength -> (ListPosition, Int))) -- ^ Nothing iff adding further cells in this position/dimension makes no sense; returns callback to determine index of new cell and data needed to initialize cell
|
||||||
mkAddForm 0 0 listLength nudge submitBtn
|
mkAddForm 0 0 nudge submitBtn = Just $ \csrf -> do
|
||||||
| listLength >= 7 = Nothing
|
(addRes, addView) <- mpreq textField ("" & addName (nudge "text")) Nothing
|
||||||
| otherwise = Just $ \csrf -> do
|
let addRes' = fromMaybe 0 . readMay . Text.filter isDigit <$> addRes
|
||||||
(addRes, addView) <- mpreq textField ("" & addName (nudge "text")) Nothing
|
return ((\dat l -> (fromIntegral l, dat)) <$> addRes', toWidget csrf >> fvInput addView >> fvInput submitBtn)
|
||||||
let addRes' = fromMaybe 0 . readMay . Text.filter isDigit <$> addRes
|
mkAddForm _pos _dim _ _ = error "Dimension and Position is always 0 for our 1-dimensional form"
|
||||||
return ((fromIntegral listLength, ) <$> addRes', toWidget csrf >> fvInput addView >> fvInput submitBtn)
|
|
||||||
mkAddForm _pos _dim _ _ _ = error "Dimension and Position is always 0 for our 1-dimensional form"
|
|
||||||
-- | Make a single massInput-Cell
|
-- | Make a single massInput-Cell
|
||||||
--
|
--
|
||||||
-- This /needs/ to use @nudge@ for deterministic field naming
|
-- This /needs/ to use @nudge@ and deterministic field naming (this allows for correct value-shifting when cells are deleted)
|
||||||
mkCellForm :: ListPosition -- ^ Position of this cell
|
mkCellForm :: ListPosition -- ^ Position of this cell
|
||||||
-> Int -- ^ Data needed to initialize the cell (see return of @mkAddForm@)
|
-> Int -- ^ Data needed to initialize the cell (see return of @mkAddForm@)
|
||||||
-> Maybe Int -- ^ Initial cell result from Argument to `massInput`
|
-> Maybe Int -- ^ Initial cell result from Argument to `massInput`
|
||||||
@ -167,8 +164,11 @@ postAdminTestR = do
|
|||||||
deleteCell l pos
|
deleteCell l pos
|
||||||
| l >= 2 = return . Map.fromSet (\pos' -> bool pos' (succ pos') $ pos' >= pos) $ Set.fromList [0..fromIntegral (l - 2)]
|
| l >= 2 = return . Map.fromSet (\pos' -> bool pos' (succ pos') $ pos' >= pos) $ Set.fromList [0..fromIntegral (l - 2)]
|
||||||
| otherwise = return Map.empty
|
| otherwise = return Map.empty
|
||||||
|
-- | Make a decision on whether an add widget should be allowed to further cells, given the current @liveliness@ (i.e. before performing the addition)
|
||||||
|
allowAdd :: ListPosition -> Natural -> ListLength -> Bool
|
||||||
|
allowAdd _ _ l = l < 7
|
||||||
|
|
||||||
((miResult, (fvInput -> miForm)), miEnc) <- runFormPost . identifyForm ("massinput" :: Text) $ massInput (MassInput mkAddForm mkCellForm deleteCell) "" True Nothing
|
((miResult, (fvInput -> miForm)), miEnc) <- runFormPost . identifyForm ("massinput" :: Text) $ massInput (MassInput mkAddForm mkCellForm deleteCell allowAdd) "" True Nothing
|
||||||
|
|
||||||
|
|
||||||
let locallyDefinedPageHeading = [whamlet|Admin TestPage for Uni2work|]
|
let locallyDefinedPageHeading = [whamlet|Admin TestPage for Uni2work|]
|
||||||
@ -193,7 +193,7 @@ postAdminTestR = do
|
|||||||
$forall err <- errs
|
$forall err <- errs
|
||||||
<li>#{err}
|
<li>#{err}
|
||||||
$of FormSuccess res
|
$of FormSuccess res
|
||||||
<pre>
|
<p style="white-space:pre-wrap; font-family:monospace;">
|
||||||
#{tshow res}
|
#{tshow res}
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
|||||||
@ -24,9 +24,11 @@ import qualified Data.Text as Text
|
|||||||
|
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
import qualified Data.Foldable as Fold
|
||||||
import Data.List (genericLength, genericIndex, iterate)
|
import Data.List (genericLength, genericIndex, iterate)
|
||||||
|
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
|
import Control.Monad.Reader.Class (MonadReader(local))
|
||||||
import Control.Monad.Fix
|
import Control.Monad.Fix
|
||||||
|
|
||||||
|
|
||||||
@ -122,8 +124,8 @@ instance RenderMessage UniWorX (ButtonMassInput coord) where
|
|||||||
instance PathPiece coord => Button UniWorX (ButtonMassInput coord) where
|
instance PathPiece coord => Button UniWorX (ButtonMassInput coord) where
|
||||||
btnValidate _ _ = False
|
btnValidate _ _ = False
|
||||||
|
|
||||||
btnClasses (MassInputAddDimension _ _) = [BCIsButton, BCDefault]
|
btnClasses (MassInputAddDimension _ _) = [BCIsButton, BCDefault, BCMassInputAdd]
|
||||||
btnClasses (MassInputDeleteCell _) = [BCIsButton, BCWarning]
|
btnClasses (MassInputDeleteCell _) = [BCIsButton, BCWarning, BCMassInputDelete]
|
||||||
|
|
||||||
|
|
||||||
data MassInputFieldName coord
|
data MassInputFieldName coord
|
||||||
@ -181,16 +183,16 @@ instance Exception MassInputException
|
|||||||
data MassInput handler liveliness cellData cellResult = MassInput
|
data MassInput handler liveliness cellData cellResult = MassInput
|
||||||
{ miAdd :: BoxCoord liveliness -- Position (dimensions after @dimIx@ are zero)
|
{ miAdd :: BoxCoord liveliness -- Position (dimensions after @dimIx@ are zero)
|
||||||
-> Natural -- Zero-based dimension index @dimIx@
|
-> Natural -- Zero-based dimension index @dimIx@
|
||||||
-> liveliness
|
|
||||||
-> (Text -> Text) -- Nudge deterministic field ids
|
-> (Text -> Text) -- Nudge deterministic field ids
|
||||||
-> FieldView UniWorX -- Submit button
|
-> FieldView UniWorX -- Submit button
|
||||||
-> Maybe (Markup -> MForm handler (FormResult (BoxCoord liveliness, cellData), Widget))
|
-> Maybe (Markup -> MForm handler (FormResult (liveliness -> (BoxCoord liveliness, cellData)), Widget))
|
||||||
, miCell :: BoxCoord liveliness -- Position
|
, miCell :: BoxCoord liveliness -- Position
|
||||||
-> cellData -- Initialisation data
|
-> cellData -- Initialisation data
|
||||||
-> Maybe cellResult -- Previous result
|
-> Maybe cellResult -- Previous result
|
||||||
-> (Text -> Text) -- Nudge deterministic field ids
|
-> (Text -> Text) -- Nudge deterministic field ids
|
||||||
-> (Markup -> MForm handler (FormResult cellResult, Widget))
|
-> (Markup -> MForm handler (FormResult cellResult, Widget))
|
||||||
, miDelete :: liveliness -> BoxCoord liveliness -> MaybeT (MForm handler) (Map (BoxCoord liveliness) (BoxCoord liveliness))
|
, miDelete :: liveliness -> BoxCoord liveliness -> MaybeT (MForm handler) (Map (BoxCoord liveliness) (BoxCoord liveliness))
|
||||||
|
, miAllowAdd :: BoxCoord liveliness -> Natural -> liveliness -> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
massInput :: forall handler cellData cellResult liveliness.
|
massInput :: forall handler cellData cellResult liveliness.
|
||||||
@ -204,7 +206,7 @@ massInput :: forall handler cellData cellResult liveliness.
|
|||||||
-> Bool -- ^ Required?
|
-> Bool -- ^ Required?
|
||||||
-> Maybe (Map (BoxCoord liveliness) (cellData, cellResult))
|
-> Maybe (Map (BoxCoord liveliness) (cellData, cellResult))
|
||||||
-> (Markup -> MForm handler (FormResult (Map (BoxCoord liveliness) (cellData, cellResult)), FieldView UniWorX))
|
-> (Markup -> MForm handler (FormResult (Map (BoxCoord liveliness) (cellData, cellResult)), FieldView UniWorX))
|
||||||
massInput MassInput{..} FieldSettings{..} fvRequired initialResult csrf = do
|
massInput MassInput{..} FieldSettings{..} fvRequired initialResult csrf = mdo
|
||||||
let initialShape = fmap fst <$> initialResult
|
let initialShape = fmap fst <$> initialResult
|
||||||
|
|
||||||
miName <- maybe newFormIdent return fsName
|
miName <- maybe newFormIdent return fsName
|
||||||
@ -223,18 +225,21 @@ massInput MassInput{..} FieldSettings{..} fvRequired initialResult csrf = do
|
|||||||
| otherwise -> throwM MassInputInvalidShape
|
| otherwise -> throwM MassInputInvalidShape
|
||||||
sentLiveliness <- maybe (throwM MassInputInvalidShape) return $ Map.keysSet sentShape' ^? liveCoords :: MForm handler liveliness
|
sentLiveliness <- maybe (throwM MassInputInvalidShape) return $ Map.keysSet sentShape' ^? liveCoords :: MForm handler liveliness
|
||||||
|
|
||||||
let addForm :: [BoxDimension (BoxCoord liveliness)] -> MForm handler (Map (Natural, BoxCoord liveliness) (FormResult (BoxCoord liveliness, cellData), Widget))
|
let addForm :: [BoxDimension (BoxCoord liveliness)] -> MForm handler (Map (Natural, BoxCoord liveliness) (FormResult (Maybe (liveliness -> (BoxCoord liveliness, cellData))), Maybe Widget))
|
||||||
addForm = addForm' boxOrigin . zip [0..]
|
addForm = addForm' boxOrigin . zip [0..]
|
||||||
where
|
where
|
||||||
addForm' _ [] = return Map.empty
|
addForm' _ [] = return Map.empty
|
||||||
addForm' miCoord ((dimIx, _) : remDims) = do
|
addForm' miCoord ((dimIx, _) : remDims) = do
|
||||||
let nudgeAddWidgetName :: Text -> Text
|
let nudgeAddWidgetName :: Text -> Text
|
||||||
nudgeAddWidgetName miAddWidgetField = toPathPiece MassInputAddWidget{..}
|
nudgeAddWidgetName miAddWidgetField = toPathPiece MassInputAddWidget{..}
|
||||||
dimRes <- runMaybeT $ do
|
(btnRes', btnView) <- mopt (buttonField $ MassInputAddDimension dimIx miCoord) ("" & addName MassInputAddButton{..}) Nothing
|
||||||
(btnRes, btnView) <- lift $ mpreq (buttonField $ MassInputAddDimension dimIx miCoord) ("" & addName MassInputAddButton{..}) Nothing
|
let btnRes
|
||||||
(addRes, addView) <- MaybeT . traverse ($ mempty) $ miAdd miCoord dimIx sentLiveliness nudgeAddWidgetName btnView
|
| FormSuccess Nothing <- btnRes' = FormMissing
|
||||||
return (btnRes *> addRes, addView)
|
| FormSuccess (Just x) <- btnRes' = FormSuccess x
|
||||||
let dimRes' = maybe Map.empty (Map.singleton (dimIx, miCoord)) dimRes
|
| otherwise = error "Value of btnRes should only be inspected if FormSuccess" <$ btnRes'
|
||||||
|
addRes' <- over (mapped . _Just . _1) (btnRes *>) . local (bool id (set _1 Nothing) $ is _FormMissing btnRes) . traverse ($ mempty) $
|
||||||
|
miAdd miCoord dimIx nudgeAddWidgetName btnView
|
||||||
|
let dimRes' = Map.singleton (dimIx, miCoord) (maybe (Nothing <$ btnRes) (fmap Just) $ fmap fst addRes', fmap snd addRes')
|
||||||
case remDims of
|
case remDims of
|
||||||
[] -> return dimRes'
|
[] -> return dimRes'
|
||||||
((_, BoxDimension dim) : _) -> do
|
((_, BoxDimension dim) : _) -> do
|
||||||
@ -245,7 +250,8 @@ massInput MassInput{..} FieldSettings{..} fvRequired initialResult csrf = do
|
|||||||
|
|
||||||
addResults <- addForm boxDimensions
|
addResults <- addForm boxDimensions
|
||||||
let addShape
|
let addShape
|
||||||
| [FormSuccess (bCoord, cData)] <- Map.elems . Map.filter (is _FormSuccess) $ fmap fst addResults = Just $ Map.insert bCoord cData sentShape'
|
| [((dimIx, miCoord), FormSuccess (Just mkResult))] <- Map.toList . Map.filter (is $ _FormSuccess . _Just) $ fmap fst addResults
|
||||||
|
= Just $ maybe id (uncurry Map.insert) (mkResult sentLiveliness <$ guard (miAllowAdd miCoord dimIx sentLiveliness)) sentShape'
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
|
|
||||||
addedShape <- if
|
addedShape <- if
|
||||||
@ -257,42 +263,58 @@ massInput MassInput{..} FieldSettings{..} fvRequired initialResult csrf = do
|
|||||||
delForm :: BoxCoord liveliness -> MaybeT (MForm handler) (FormResult (Map (BoxCoord liveliness) (BoxCoord liveliness)), FieldView UniWorX)
|
delForm :: BoxCoord liveliness -> MaybeT (MForm handler) (FormResult (Map (BoxCoord liveliness) (BoxCoord liveliness)), FieldView UniWorX)
|
||||||
delForm miCoord = do
|
delForm miCoord = do
|
||||||
(delRes, delView) <- lift $ mpreq (buttonField $ MassInputDeleteCell miCoord) ("" & addName MassInputDeleteButton{..}) Nothing
|
(delRes, delView) <- lift $ mpreq (buttonField $ MassInputDeleteCell miCoord) ("" & addName MassInputDeleteButton{..}) Nothing
|
||||||
$logDebugS "delForm" . tshow $ fmap toPathPiece delRes
|
-- $logDebugS "delForm" . tshow $ fmap toPathPiece delRes
|
||||||
shapeUpdate <- miDelete addedLiveliness miCoord
|
shapeUpdate <- miDelete addedLiveliness miCoord
|
||||||
guard $ isJust (Map.keysSet shapeUpdate ^? liveCoords :: Maybe liveliness)
|
guard $ isJust (Map.keysSet shapeUpdate ^? liveCoords :: Maybe liveliness)
|
||||||
return (shapeUpdate <$ delRes, delView)
|
return (shapeUpdate <$ delRes, delView)
|
||||||
|
|
||||||
delResults <- fmap (Map.mapMaybe id) . sequence $ Map.fromSet (runMaybeT . delForm) (Map.keysSet addedShape)
|
delResults <- fmap (Map.mapMaybe id) . sequence $ Map.fromSet (runMaybeT . delForm) (Map.keysSet addedShape)
|
||||||
let delShape
|
let
|
||||||
| [FormSuccess shapeUpdate'] <- Map.elems . Map.filter (is _FormSuccess) $ fmap fst delResults = traverse (flip Map.lookup addedShape) shapeUpdate'
|
delShapeUpdate
|
||||||
|
| [FormSuccess shapeUpdate'] <- Map.elems . Map.filter (is _FormSuccess) $ fmap fst delResults = Just shapeUpdate'
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
|
delShape = traverse (flip Map.lookup addedShape) =<< delShapeUpdate
|
||||||
|
|
||||||
|
|
||||||
|
let shapeChanged = Fold.any (isn't _FormMissing . view _1) addResults || Fold.any (is _FormSuccess . view _1) delResults
|
||||||
|
|
||||||
shape <- if
|
shape <- if
|
||||||
| Just s <- delShape -> return s
|
|
||||||
| Just s <- addShape -> return s
|
| Just s <- addShape -> return s
|
||||||
|
| Just s <- delShape -> return s
|
||||||
| otherwise -> return sentShape'
|
| otherwise -> return sentShape'
|
||||||
|
|
||||||
|
$logDebugS "massInput" [st|Current shape: #{tshow (map toPathPiece (Map.keys shape))}|]
|
||||||
|
|
||||||
shapeId <- newIdent
|
shapeId <- newIdent
|
||||||
|
let shapeInput = fieldView shapeField shapeId (toPathPiece shapeName) [] (Right shape) True
|
||||||
|
|
||||||
let
|
let
|
||||||
shapeInput = fieldView shapeField shapeId (toPathPiece shapeName) [] (Right shape) True
|
applyDelShapeUpdate :: Maybe (Env, FileEnv) -> Maybe (Env, FileEnv)
|
||||||
|
applyDelShapeUpdate prevEnv
|
||||||
|
| Just delShapeUpdate' <- delShapeUpdate
|
||||||
|
, Just (env, fEnv) <- prevEnv
|
||||||
|
= let reverseUpdate = Map.fromList . map swap $ Map.toList delShapeUpdate'
|
||||||
|
in Just . (, fEnv) . flip (Map.mapKeysWith mappend) env $ \k -> fromMaybe k $ do
|
||||||
|
cell@MassInputCell{miCoord} <- fromPathPiece k
|
||||||
|
newCoord <- Map.lookup miCoord reverseUpdate
|
||||||
|
return $ toPathPiece cell{ miCoord = newCoord }
|
||||||
|
| otherwise = prevEnv
|
||||||
|
|
||||||
cellResults <- flip Map.traverseWithKey shape $ \miCoord cData -> do
|
cellResults <- flip Map.traverseWithKey shape $ \miCoord cData -> do
|
||||||
let
|
let
|
||||||
nudgeCellName :: Text -> Text
|
nudgeCellName :: Text -> Text
|
||||||
nudgeCellName miCellField = toPathPiece (MassInputCell{..} :: MassInputFieldName (BoxCoord liveliness))
|
nudgeCellName miCellField = toPathPiece (MassInputCell{..} :: MassInputFieldName (BoxCoord liveliness))
|
||||||
(cData, ) <$> miCell miCoord cData (fmap snd . Map.lookup miCoord =<< initialResult) nudgeCellName mempty
|
local (over _1 applyDelShapeUpdate) $ (cData, ) <$> miCell miCoord cData (fmap snd . Map.lookup miCoord =<< initialResult) nudgeCellName mempty
|
||||||
let result :: FormResult (Map (BoxCoord liveliness) (cellData, cellResult))
|
let result :: FormResult (Map (BoxCoord liveliness) (cellData, cellResult))
|
||||||
result
|
result
|
||||||
| isJust addShape || isJust delShape = FormMissing
|
| shapeChanged = FormMissing
|
||||||
| otherwise = traverse (\(cData, (cResult, _)) -> (cData, ) <$> cResult) cellResults
|
| otherwise = traverse (\(cData, (cResult, _)) -> (cData, ) <$> cResult) cellResults
|
||||||
|
|
||||||
liveliness <- maybe (throwM MassInputInvalidShape) return $ Map.keysSet shape ^? liveCoords :: MForm handler liveliness
|
liveliness <- maybe (throwM MassInputInvalidShape) return $ Map.keysSet shape ^? liveCoords :: MForm handler liveliness
|
||||||
|
|
||||||
let miWidget :: BoxCoord liveliness -> [(Natural, BoxDimension (BoxCoord liveliness))] -> Widget
|
let miWidget' :: BoxCoord liveliness -> [(Natural, BoxDimension (BoxCoord liveliness))] -> Widget
|
||||||
miWidget _ [] = mempty
|
miWidget' _ [] = mempty
|
||||||
miWidget miCoord ((dimIx, BoxDimension dim) : remDims) =
|
miWidget' miCoord ((dimIx, BoxDimension dim) : remDims) =
|
||||||
let coords = takeWhile (\c -> review (liveCoord c) liveliness) $ iterate (over dim succ) miCoord
|
let coords = takeWhile (\c -> review (liveCoord c) liveliness) $ iterate (over dim succ) miCoord
|
||||||
cells
|
cells
|
||||||
| [] <- remDims = do
|
| [] <- remDims = do
|
||||||
@ -301,20 +323,18 @@ massInput MassInput{..} FieldSettings{..} fvRequired initialResult csrf = do
|
|||||||
let deleteButton = snd <$> Map.lookup coord delResults
|
let deleteButton = snd <$> Map.lookup coord delResults
|
||||||
return (coord, $(widgetFile "widgets/massinput/cell"))
|
return (coord, $(widgetFile "widgets/massinput/cell"))
|
||||||
| otherwise =
|
| otherwise =
|
||||||
[ (coord, miWidget coord remDims) | coord <- coords ]
|
[ (coord, miWidget' coord remDims) | coord <- coords ]
|
||||||
addWidget = snd <$> Map.lookup (dimIx, miCoord) addResults
|
addWidget = (\(_, mWgt) -> mWgt <* guard (miAllowAdd miCoord dimIx liveliness)) =<< Map.lookup (dimIx, miCoord) addResults
|
||||||
in $(widgetFile "widgets/massinput/row")
|
in $(widgetFile "widgets/massinput/row")
|
||||||
|
|
||||||
|
miWidget = miWidget' boxOrigin $ zip [0..] boxDimensions
|
||||||
|
|
||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
fvId <- maybe newIdent return fsId
|
fvId <- maybe newIdent return fsId
|
||||||
|
|
||||||
let
|
let
|
||||||
fvLabel = toHtml $ mr fsLabel
|
fvLabel = toHtml $ mr fsLabel
|
||||||
fvTooltip = toHtml . mr <$> fsTooltip
|
fvTooltip = toHtml . mr <$> fsTooltip
|
||||||
fvInput = mconcat
|
fvInput = $(widgetFile "widgets/massinput/massinput")
|
||||||
[ toWidget csrf
|
|
||||||
, shapeInput
|
|
||||||
, miWidget boxOrigin $ zip [0..] boxDimensions
|
|
||||||
]
|
|
||||||
fvErrors = Nothing
|
fvErrors = Nothing
|
||||||
in return (result, FieldView{..})
|
in return (result, FieldView{..})
|
||||||
|
|||||||
@ -229,4 +229,30 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Override implicit submit (pressing enter) behaviour to trigger a specified submit button instead of the default
|
||||||
|
window.utils.implicitSubmit = function(input, options) {
|
||||||
|
var submit = options.submit;
|
||||||
|
|
||||||
|
console.log('implicitSubmit', input, submit);
|
||||||
|
|
||||||
|
if (!submit) {
|
||||||
|
throw new Error('window.utils.implicitSubmit(input, options) needs to be passed a submit element via options');
|
||||||
|
}
|
||||||
|
|
||||||
|
var doSubmit = function(event) {
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
event.preventDefault();
|
||||||
|
submit.click();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
input.addEventListener('keypress', doSubmit);
|
||||||
|
|
||||||
|
return {
|
||||||
|
scope: input,
|
||||||
|
destroy: function() {
|
||||||
|
input.removeEventListener('keypress', doSubmit);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
5
templates/widgets/massinput/massinput.hamlet
Normal file
5
templates/widgets/massinput/massinput.hamlet
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
$newline never
|
||||||
|
<div .massinput ##{fvId}>
|
||||||
|
#{csrf}
|
||||||
|
^{shapeInput}
|
||||||
|
^{miWidget}
|
||||||
21
templates/widgets/massinput/massinput.julius
Normal file
21
templates/widgets/massinput/massinput.julius
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var form = document.getElementById(#{String fvId}).closest('form');
|
||||||
|
|
||||||
|
|
||||||
|
var formSubmit = form.querySelector('input[type=submit], button[type=submit]:not(.btn-mass-input-add):not(.btn-mass-input-delete)');
|
||||||
|
var cellInputs = Array.from(form.querySelectorAll('.massinput--cell input:not([type=hidden])'));
|
||||||
|
|
||||||
|
cellInputs.forEach(function(input) {
|
||||||
|
window.utils.setup('implicitSubmit', input, { submit: formSubmit });
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Array.from(form.querySelectorAll('.massinput--add')).forEach(function(wrapper) {
|
||||||
|
var addSubmit = wrapper.querySelector('.btn-mass-input-add');
|
||||||
|
var addInputs = Array.from(wrapper.querySelectorAll('input:not([type=hidden]):not(.btn-mass-input-add)'));
|
||||||
|
|
||||||
|
addInputs.forEach(function(input) {
|
||||||
|
window.utils.setup('implicitSubmit', input, { submit: addSubmit });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user