Start on implementation
This commit is contained in:
parent
e9c69e6cfb
commit
c0edc87926
@ -7,6 +7,7 @@ module Handler.Utils.Form.MassInput
|
|||||||
|
|
||||||
import Import
|
import Import
|
||||||
import Utils.Form
|
import Utils.Form
|
||||||
|
import Handler.Utils.Form (secretJsonField)
|
||||||
|
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
|
|
||||||
@ -18,23 +19,28 @@ import Text.Blaze (Markup)
|
|||||||
|
|
||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
|
|
||||||
|
import qualified Data.Set as Set
|
||||||
|
import qualified Data.Map as Map
|
||||||
import Data.List (genericLength, genericIndex)
|
import Data.List (genericLength, genericIndex)
|
||||||
|
|
||||||
|
|
||||||
data BoxDimension x = forall n. Enum n => BoxDimension (Lens' x n)
|
data BoxDimension x = forall n. (Enum n, Num n) => BoxDimension (Lens' x n)
|
||||||
|
|
||||||
class (PathPiece x, ToJSONKey x, FromJSONKey x, Eq x, Ord x) => IsBoxCoord x where
|
class (PathPiece x, ToJSONKey x, FromJSONKey x, Eq x, Ord x) => IsBoxCoord x where
|
||||||
boxDimensions :: [BoxDimension x]
|
boxDimensions :: [BoxDimension x]
|
||||||
boxOrigin :: x
|
boxOrigin :: x
|
||||||
|
|
||||||
boxDimension :: IsBoxCoord x => Natural -> Maybe (BoxDimension x)
|
boxDimension :: IsBoxCoord x => Natural -> BoxDimension x
|
||||||
boxDimension n
|
boxDimension n
|
||||||
| n < genericLength dims = Just $ genericIndex dims n
|
| n < genericLength dims = genericIndex dims n
|
||||||
| otherwise = Nothing
|
| otherwise = error "boxDimension: insufficient dimensions"
|
||||||
where
|
where
|
||||||
dims = boxDimensions
|
dims = boxDimensions
|
||||||
|
|
||||||
|
zeroDimension :: IsBoxCoord x => Natural -> x -> x
|
||||||
|
zeroDimension (boxDimension -> BoxDimension dim) = set dim $ boxOrigin ^. dim
|
||||||
|
|
||||||
class (ToJSON a, FromJSON a, IsBoxCoord (BoxCoord a), Lattice a, BoundedJoinSemiLattice a) => Liveliness a where
|
class (IsBoxCoord (BoxCoord a), Lattice a, BoundedJoinSemiLattice a) => Liveliness a where
|
||||||
type BoxCoord a :: *
|
type BoxCoord a :: *
|
||||||
liveCoords :: Prism' (Set (BoxCoord a)) a
|
liveCoords :: Prism' (Set (BoxCoord a)) a
|
||||||
liveCoord :: BoxCoord a -> Prism' Bool a
|
liveCoord :: BoxCoord a -> Prism' Bool a
|
||||||
@ -73,17 +79,37 @@ instance PathPiece coord => Button UniWorX (ButtonMassInput coord) where
|
|||||||
|
|
||||||
|
|
||||||
data MassInputFieldName coord
|
data MassInputFieldName coord
|
||||||
= MassInputCell coord Text
|
= MassInputShape { miName :: Text }
|
||||||
|
| MassInputAddWidget { miName :: Text, miCoord :: coord, miAddWidgetField :: Text }
|
||||||
|
| MassInputCell { miName :: Text, miCoord :: coord, miCellField :: Text }
|
||||||
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
|
|
||||||
instance IsBoxCoord coord => PathPiece (MassInputFieldName coord) where
|
instance IsBoxCoord coord => PathPiece (MassInputFieldName coord) where
|
||||||
toPathPiece = \case
|
toPathPiece = \case
|
||||||
MassInputCell (toPathPiece -> coord) name -> coord <> "__" <> name
|
MassInputShape{..} -> [st|#{miName}__shape|]
|
||||||
|
MassInputAddWidget{..} -> [st|#{miName}__#{toPathPiece miCoord}__#{miAddWidgetField}|]
|
||||||
|
MassInputCell{..} -> [st|#{miName}__#{toPathPiece miCoord}__#{miCellField}|]
|
||||||
|
|
||||||
fromPathPiece t = do
|
fromPathPiece t = do
|
||||||
(coordT, Text.stripPrefix "__" -> Just name) <- return $ Text.breakOn "__" t
|
(miName, Text.stripPrefix "__" -> Just t') <- return $ Text.breakOn "__" t
|
||||||
coord <- fromPathPiece coordT
|
choice
|
||||||
return $ MassInputCell coord name
|
[ do
|
||||||
|
guard $ t' == "shape"
|
||||||
|
return MassInputShape{..}
|
||||||
|
, do
|
||||||
|
(coordT, Text.stripPrefix "__" -> Just miCellField) <- return $ Text.breakOn "__" t'
|
||||||
|
miCoord <- fromPathPiece coordT
|
||||||
|
return MassInputAddWidget{..}
|
||||||
|
, do
|
||||||
|
(coordT, Text.stripPrefix "__" -> Just miCellField) <- return $ Text.breakOn "__" t'
|
||||||
|
miCoord <- fromPathPiece coordT
|
||||||
|
return MassInputCell{..}
|
||||||
|
]
|
||||||
|
|
||||||
|
data MassInputException = MassInputInvalidShape
|
||||||
|
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
|
|
||||||
|
instance Exception MassInputException
|
||||||
|
|
||||||
massInput :: forall handler cellData cellResult liveliness.
|
massInput :: forall handler cellData cellResult liveliness.
|
||||||
( MonadHandler handler, HandlerSite handler ~ UniWorX
|
( MonadHandler handler, HandlerSite handler ~ UniWorX
|
||||||
@ -93,14 +119,43 @@ massInput :: forall handler cellData cellResult liveliness.
|
|||||||
=> ( Natural -- ^ Zero-based dimension index
|
=> ( Natural -- ^ Zero-based dimension index
|
||||||
-> liveliness -- ^ Currently live positions
|
-> liveliness -- ^ Currently live positions
|
||||||
-> (Text -> Text) -- ^ Nudge deterministic field ids
|
-> (Text -> Text) -- ^ Nudge deterministic field ids
|
||||||
-> (Markup -> MForm handler (FormResult (cellData, BoxCoord liveliness), Widget))
|
-> (Markup -> MForm handler (FormResult (BoxCoord liveliness, cellData), Widget))
|
||||||
) -- ^ Generate a cell-addition widget
|
) -- ^ Generate a cell-addition widget
|
||||||
-> ( BoxCoord liveliness
|
-> ( BoxCoord liveliness
|
||||||
-> cellData
|
-> cellData
|
||||||
|
-> Maybe cellResult
|
||||||
-> (Text -> Text) -- ^ Nudge deterministic field ids
|
-> (Text -> Text) -- ^ Nudge deterministic field ids
|
||||||
-> (Markup -> MForm handler (FormResult cellResult, Widget))
|
-> (Markup -> MForm handler (FormResult cellResult, Widget))
|
||||||
) -- ^ Cell-Widget
|
) -- ^ Cell-Widget
|
||||||
-> FieldSettings UniWorX
|
-> FieldSettings UniWorX
|
||||||
-> MForm handler (FormResult (Map (BoxCoord liveliness) cellResult), FieldView UniWorX)
|
-> Maybe (Map (BoxCoord liveliness) (cellData, cellResult))
|
||||||
massInput mkAddWidget mkCellWidget FieldSettings{..} = do
|
-> MForm handler (FormResult (Map (BoxCoord liveliness) (cellData, cellResult)), Widget)
|
||||||
error "massInput: not implemented"
|
massInput _mkAddWidget mkCellWidget FieldSettings{..} initialResult = do
|
||||||
|
miName <- maybe newFormIdent return fsName
|
||||||
|
let
|
||||||
|
shapeName :: MassInputFieldName (BoxCoord liveliness)
|
||||||
|
shapeName = MassInputShape{..}
|
||||||
|
(shape', _shapeWdgt) <- mreq secretJsonField ("" & addName shapeName) $ fmap fst <$> initialResult
|
||||||
|
shape <- if
|
||||||
|
| FormSuccess s <- shape' -> return s
|
||||||
|
| Just (fmap fst -> iS) <- initialResult -> return iS
|
||||||
|
| Just iS <- Set.empty ^? liveCoords -> return iS
|
||||||
|
| otherwise -> throwM MassInputInvalidShape
|
||||||
|
cellResults <- forM shape $ \(miCoord, cData) -> do
|
||||||
|
let
|
||||||
|
nudgeCellName :: Text -> Text
|
||||||
|
nudgeCellName miCellField = toPathPiece MassInputCell{..}
|
||||||
|
(cData, ) <$> mkCellWidget miCoord cData (fmap snd . Map.lookup miCoord =<< initialResult) nudgeCellName mempty
|
||||||
|
liveliness <- maybe (throwM MassInputInvalidShape) return $ Map.keysSet shape ^? liveCoords
|
||||||
|
let result :: FormResult (Map (BoxCoord liveliness) (cellData, cellResult))
|
||||||
|
result = traverse (\(cData, (cResult, _)) -> (cData, ) <$> cResult) cellResults
|
||||||
|
miWidget :: [BoxDimension (BoxCoord liveliness)] -> Widget
|
||||||
|
miWidget = miWidget' nudgeAddWidgetName 0 liveliness
|
||||||
|
nudgeAddWidgetName :: Text -> Text
|
||||||
|
nudgeAddWidgetName miAddWidgetField = toPathPiece MassInputAddWidget{..}
|
||||||
|
return (result, miWidget boxDimensions)
|
||||||
|
where
|
||||||
|
miWidget' :: (Text -> Text) -> Natural -> liveliness -> [BoxDimension (BoxCoord liveliness)] -> Widget
|
||||||
|
miWidget' nudge dimIx liveliness [] = mempty
|
||||||
|
miWidget' nudge dimIx liveliness (BoxDimension dim : remDims)
|
||||||
|
= error "not implemented"
|
||||||
|
|||||||
@ -508,6 +508,12 @@ mconcatMapM f = foldM (\x my -> mappend x <$> my) mempty . map f . Fold.toList
|
|||||||
mconcatForM :: (Monoid b, Monad m, Foldable f) => f a -> (a -> m b) -> m b
|
mconcatForM :: (Monoid b, Monad m, Foldable f) => f a -> (a -> m b) -> m b
|
||||||
mconcatForM = flip mconcatMapM
|
mconcatForM = flip mconcatMapM
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
-- Alternative --
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
choice :: forall f mono a. (Alternative f, MonoFoldable mono, Element mono ~ f a) => mono -> f a
|
||||||
|
choice = foldr (<|>) empty
|
||||||
|
|
||||||
--------------
|
--------------
|
||||||
-- Sessions --
|
-- Sessions --
|
||||||
|
|||||||
@ -108,8 +108,8 @@ addClass = addAttr "class"
|
|||||||
addClasses :: [Text] -> FieldSettings site -> FieldSettings site
|
addClasses :: [Text] -> FieldSettings site -> FieldSettings site
|
||||||
addClasses = addAttrs "class"
|
addClasses = addAttrs "class"
|
||||||
|
|
||||||
addName :: Text -> FieldSettings site -> FieldSettings site
|
addName :: PathPiece p => p -> FieldSettings site -> FieldSettings site
|
||||||
addName nm fs = fs { fsName = Just nm }
|
addName nm fs = fs { fsName = Just $ toPathPiece nm }
|
||||||
|
|
||||||
addNameClass :: Text -> Text -> FieldSettings site -> FieldSettings site
|
addNameClass :: Text -> Text -> FieldSettings site -> FieldSettings site
|
||||||
addNameClass gName gClass fs = fs { fsName = Just gName, fsAttrs = ("class",gClass) : fsAttrs fs }
|
addNameClass gName gClass fs = fs { fsName = Just gName, fsAttrs = ("class",gClass) : fsAttrs fs }
|
||||||
|
|||||||
Reference in New Issue
Block a user