localstorage for show-hides, sortable tables, more navigation
This commit is contained in:
parent
dd07a1307f
commit
475411bb4a
@ -90,6 +90,7 @@ data MenuTypes
|
|||||||
= NavbarLeft { menuItem :: MenuItem }
|
= NavbarLeft { menuItem :: MenuItem }
|
||||||
| NavbarRight { menuItem :: MenuItem }
|
| NavbarRight { menuItem :: MenuItem }
|
||||||
| NavbarExtra { menuItem :: MenuItem }
|
| NavbarExtra { menuItem :: MenuItem }
|
||||||
|
| NavbarSecondary { menuItem :: MenuItem }
|
||||||
|
|
||||||
-- | A convenient synonym for creating forms.
|
-- | A convenient synonym for creating forms.
|
||||||
type Form x = Html -> MForm (HandlerT UniWorX IO) (FormResult x, Widget)
|
type Form x = Html -> MForm (HandlerT UniWorX IO) (FormResult x, Widget)
|
||||||
@ -277,7 +278,7 @@ instance YesodBreadcrumbs UniWorX where
|
|||||||
|
|
||||||
defaultLinks :: [MenuTypes]
|
defaultLinks :: [MenuTypes]
|
||||||
defaultLinks = -- Define the menu items of the header.
|
defaultLinks = -- Define the menu items of the header.
|
||||||
[ NavbarLeft $ MenuItem
|
[ NavbarRight $ MenuItem
|
||||||
{ menuItemLabel = "Home"
|
{ menuItemLabel = "Home"
|
||||||
, menuItemRoute = HomeR
|
, menuItemRoute = HomeR
|
||||||
, menuItemAccessCallback = return True
|
, menuItemAccessCallback = return True
|
||||||
@ -287,7 +288,7 @@ defaultLinks = -- Define the menu items of the header.
|
|||||||
, menuItemRoute = CourseListR
|
, menuItemRoute = CourseListR
|
||||||
, menuItemAccessCallback = return True
|
, menuItemAccessCallback = return True
|
||||||
}
|
}
|
||||||
, NavbarRight $ MenuItem
|
, NavbarLeft $ MenuItem
|
||||||
{ menuItemLabel = "Users"
|
{ menuItemLabel = "Users"
|
||||||
, menuItemRoute = UsersR
|
, menuItemRoute = UsersR
|
||||||
, menuItemAccessCallback = return True -- Creates a LOOP: (Authorized ==) <$> isAuthorized UsersR False
|
, menuItemAccessCallback = return True -- Creates a LOOP: (Authorized ==) <$> isAuthorized UsersR False
|
||||||
@ -297,12 +298,12 @@ defaultLinks = -- Define the menu items of the header.
|
|||||||
, menuItemRoute = ProfileR
|
, menuItemRoute = ProfileR
|
||||||
, menuItemAccessCallback = isJust <$> maybeAuthPair
|
, menuItemAccessCallback = isJust <$> maybeAuthPair
|
||||||
}
|
}
|
||||||
, NavbarRight $ MenuItem
|
, NavbarSecondary $ MenuItem
|
||||||
{ menuItemLabel = "Login"
|
{ menuItemLabel = "Login"
|
||||||
, menuItemRoute = AuthR LoginR
|
, menuItemRoute = AuthR LoginR
|
||||||
, menuItemAccessCallback = isNothing <$> maybeAuthPair
|
, menuItemAccessCallback = isNothing <$> maybeAuthPair
|
||||||
}
|
}
|
||||||
, NavbarRight $ MenuItem
|
, NavbarSecondary $ MenuItem
|
||||||
{ menuItemLabel = "Logout"
|
{ menuItemLabel = "Logout"
|
||||||
, menuItemRoute = AuthR LogoutR
|
, menuItemRoute = AuthR LogoutR
|
||||||
, menuItemAccessCallback = isJust <$> maybeAuthPair
|
, menuItemAccessCallback = isJust <$> maybeAuthPair
|
||||||
|
|||||||
@ -9,38 +9,38 @@
|
|||||||
|
|
||||||
module Handler.Course where
|
module Handler.Course where
|
||||||
|
|
||||||
import Import
|
import Import
|
||||||
import Handler.Utils
|
import Handler.Utils
|
||||||
|
|
||||||
-- import Data.Time
|
-- import Data.Time
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Function ((&))
|
import Data.Function ((&))
|
||||||
import Yesod.Form.Bootstrap3
|
import Yesod.Form.Bootstrap3
|
||||||
|
|
||||||
import Colonnade hiding (fromMaybe)
|
import Colonnade hiding (fromMaybe)
|
||||||
import Yesod.Colonnade
|
import Yesod.Colonnade
|
||||||
|
|
||||||
import qualified Data.UUID.Cryptographic as UUID
|
import qualified Data.UUID.Cryptographic as UUID
|
||||||
|
|
||||||
|
|
||||||
getCourseListR :: Handler TypedContent
|
getCourseListR :: Handler TypedContent
|
||||||
getCourseListR = redirect TermShowR
|
getCourseListR = redirect TermShowR
|
||||||
|
|
||||||
getCourseListTermR :: TermId -> Handler Html
|
getCourseListTermR :: TermId -> Handler Html
|
||||||
getCourseListTermR tidini = do
|
getCourseListTermR tidini = do
|
||||||
(term,courses) <- runDB $ (,)
|
(term,courses) <- runDB $ (,)
|
||||||
<$> get tidini
|
<$> get tidini
|
||||||
<*> selectList [CourseTermId ==. tidini] [Asc CourseShorthand]
|
<*> selectList [CourseTermId ==. tidini] [Asc CourseShorthand]
|
||||||
when (isNothing term) $ do
|
when (isNothing term) $ do
|
||||||
addMessage "warning" [shamlet| Semester #{toPathPiece tidini} nicht gefunden. |]
|
addMessage "warning" [shamlet| Semester #{toPathPiece tidini} nicht gefunden. |]
|
||||||
redirect TermShowR
|
redirect TermShowR
|
||||||
-- TODO: several runDBs per TableRow are probably too inefficient!
|
-- TODO: several runDBs per TableRow are probably too inefficient!
|
||||||
let colonnadeTerms = mconcat
|
let colonnadeTerms = mconcat
|
||||||
[ headed "Kürzel" $ (\ckv ->
|
[ headed "Kürzel" $ (\ckv ->
|
||||||
let c = entityVal ckv
|
let c = entityVal ckv
|
||||||
shd = courseShorthand c
|
shd = courseShorthand c
|
||||||
tid = courseTermId c
|
tid = courseTermId c
|
||||||
in [whamlet| <a href=@{CourseShowR tid shd}>#{shd} |] )
|
in [whamlet| <a href=@{CourseShowR tid shd}>#{shd} |] )
|
||||||
-- , headed "Institut" $ [shamlet| #{course} |]
|
-- , headed "Institut" $ [shamlet| #{course} |]
|
||||||
, headed "Beginn Anmeldung" $ fromString.(maybe "" formatTimeGerWD).courseRegisterFrom.entityVal
|
, headed "Beginn Anmeldung" $ fromString.(maybe "" formatTimeGerWD).courseRegisterFrom.entityVal
|
||||||
, headed "Ende Anmeldung" $ fromString.(maybe "" formatTimeGerWD).courseRegisterTo.entityVal
|
, headed "Ende Anmeldung" $ fromString.(maybe "" formatTimeGerWD).courseRegisterTo.entityVal
|
||||||
@ -49,60 +49,60 @@ getCourseListTermR tidini = do
|
|||||||
partiNum <- handlerToWidget $ runDB $ count [CourseParticipantCourseId ==. cid]
|
partiNum <- handlerToWidget $ runDB $ count [CourseParticipantCourseId ==. cid]
|
||||||
[whamlet| #{show partiNum} |]
|
[whamlet| #{show partiNum} |]
|
||||||
)
|
)
|
||||||
, headed " " $ (\ckv ->
|
, headed " " $ (\ckv ->
|
||||||
let c = entityVal ckv
|
let c = entityVal ckv
|
||||||
shd = courseShorthand c
|
shd = courseShorthand c
|
||||||
tid = courseTermId c
|
tid = courseTermId c
|
||||||
in do
|
in do
|
||||||
adminLink <- handlerToWidget $ isAuthorized (CourseEditExistR tid shd ) False
|
adminLink <- handlerToWidget $ isAuthorized (CourseEditExistR tid shd ) False
|
||||||
-- if (adminLink==Authorized) then linkButton "Ändern" BCWarning (CourseEditExistR tid shd) else ""
|
-- if (adminLink==Authorized) then linkButton "Ändern" BCWarning (CourseEditExistR tid shd) else ""
|
||||||
[whamlet|
|
[whamlet|
|
||||||
$if adminLink == Authorized
|
$if adminLink == Authorized
|
||||||
<a href=@{CourseEditExistR tid shd}>
|
<a href=@{CourseEditExistR tid shd}>
|
||||||
editieren
|
editieren
|
||||||
|]
|
|]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
let pageLinks =
|
let pageLinks =
|
||||||
[ NavbarLeft $ MenuItem
|
[ NavbarLeft $ MenuItem
|
||||||
{ menuItemLabel = "Neuer Kurs"
|
{ menuItemLabel = "Neuer Kurs"
|
||||||
, menuItemRoute = CourseEditR
|
, menuItemRoute = CourseEditR
|
||||||
, menuItemAccessCallback = (== Authorized) <$> isAuthorized CourseEditR False
|
, menuItemAccessCallback = (== Authorized) <$> isAuthorized CourseEditR False
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
let coursesTable = encodeWidgetTable tableSortable colonnadeTerms courses
|
||||||
defaultLinkLayout pageLinks $ do
|
defaultLinkLayout pageLinks $ do
|
||||||
-- defaultLayout $ do
|
-- defaultLayout $ do
|
||||||
setTitle "Semesterkurse"
|
setTitle "Semesterkurse"
|
||||||
linkButton "Neuen Kurs anlegen" BCPrimary CourseEditR
|
$(widgetFile "courses")
|
||||||
encodeWidgetTable tableDefault colonnadeTerms courses -- (map entityVal courses)
|
|
||||||
|
|
||||||
getCourseShowR :: TermId -> Text -> Handler Html
|
getCourseShowR :: TermId -> Text -> Handler Html
|
||||||
getCourseShowR tid csh = do
|
getCourseShowR tid csh = do
|
||||||
mbAid <- maybeAuthId
|
mbAid <- maybeAuthId
|
||||||
(courseEnt,(schoolMB,participants,mbRegistered)) <- runDB $ do
|
(courseEnt,(schoolMB,participants,mbRegistered)) <- runDB $ do
|
||||||
courseEnt@(Entity cid course) <- getBy404 $ CourseTermShort tid csh
|
courseEnt@(Entity cid course) <- getBy404 $ CourseTermShort tid csh
|
||||||
dependent <- (,,)
|
dependent <- (,,)
|
||||||
<$> get (courseSchoolId course) -- join
|
<$> get (courseSchoolId course) -- join
|
||||||
<*> count [CourseParticipantCourseId ==. cid] -- join
|
<*> count [CourseParticipantCourseId ==. cid] -- join
|
||||||
<*> (case mbAid of -- TODO: Someone please refactor this late-night mess here!
|
<*> (case mbAid of -- TODO: Someone please refactor this late-night mess here!
|
||||||
Nothing -> return False
|
Nothing -> return False
|
||||||
(Just aid) -> do
|
(Just aid) -> do
|
||||||
regL <- getBy (UniqueCourseParticipant cid aid)
|
regL <- getBy (UniqueCourseParticipant cid aid)
|
||||||
return $ isJust regL)
|
return $ isJust regL)
|
||||||
return $ (courseEnt,dependent)
|
return $ (courseEnt,dependent)
|
||||||
let course = entityVal courseEnt
|
let course = entityVal courseEnt
|
||||||
(regWidget, regEnctype) <- generateFormPost $ identifyForm "registerBtn" $ registerButton $ mbRegistered
|
(regWidget, regEnctype) <- generateFormPost $ identifyForm "registerBtn" $ registerButton $ mbRegistered
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitle $ [shamlet| #{toPathPiece tid} - #{csh}|]
|
setTitle $ [shamlet| #{toPathPiece tid} - #{csh}|]
|
||||||
$(widgetFile "course")
|
$(widgetFile "course")
|
||||||
|
|
||||||
registerButton :: Bool -> Form ()
|
registerButton :: Bool -> Form ()
|
||||||
registerButton registered = renderAForm FormStandard $
|
registerButton registered = renderAForm FormStandard $
|
||||||
pure () <* bootstrapSubmit regMsg
|
pure () <* bootstrapSubmit regMsg
|
||||||
where
|
where
|
||||||
msg = if registered then "Abmelden" else "Anmelden"
|
msg = if registered then "Abmelden" else "Anmelden"
|
||||||
regMsg = msg :: BootstrapSubmit Text
|
regMsg = msg :: BootstrapSubmit Text
|
||||||
|
|
||||||
postCourseShowR :: TermId -> Text -> Handler Html
|
postCourseShowR :: TermId -> Text -> Handler Html
|
||||||
postCourseShowR tid csh = do
|
postCourseShowR tid csh = do
|
||||||
aid <- requireAuthId
|
aid <- requireAuthId
|
||||||
@ -110,30 +110,30 @@ postCourseShowR tid csh = do
|
|||||||
(Entity cid _) <- getBy404 $ CourseTermShort tid csh
|
(Entity cid _) <- getBy404 $ CourseTermShort tid csh
|
||||||
registered <- isJust <$> (getBy $ UniqueCourseParticipant cid aid)
|
registered <- isJust <$> (getBy $ UniqueCourseParticipant cid aid)
|
||||||
return (cid, registered)
|
return (cid, registered)
|
||||||
((regResult,_), _) <- runFormPost $ identifyForm "registerBtn" $ registerButton registered
|
((regResult,_), _) <- runFormPost $ identifyForm "registerBtn" $ registerButton registered
|
||||||
case regResult of
|
case regResult of
|
||||||
(FormSuccess _)
|
(FormSuccess _)
|
||||||
| registered -> do
|
| registered -> do
|
||||||
runDB $ deleteBy $ UniqueCourseParticipant cid aid
|
runDB $ deleteBy $ UniqueCourseParticipant cid aid
|
||||||
addMessage "info" "Sie wurden abgemeldet."
|
addMessage "info" "Sie wurden abgemeldet."
|
||||||
| otherwise -> do
|
| otherwise -> do
|
||||||
actTime <- liftIO $ getCurrentTime
|
actTime <- liftIO $ getCurrentTime
|
||||||
regOk <- runDB $ insertUnique $ CourseParticipant cid aid actTime
|
regOk <- runDB $ insertUnique $ CourseParticipant cid aid actTime
|
||||||
when (isJust regOk) $ addMessage "success" "Erfolgreich angemeldet!"
|
when (isJust regOk) $ addMessage "success" "Erfolgreich angemeldet!"
|
||||||
(_other) -> return () -- TODO check this!
|
(_other) -> return () -- TODO check this!
|
||||||
-- redirect or not?! I guess not, since we want GET now
|
-- redirect or not?! I guess not, since we want GET now
|
||||||
getCourseShowR tid csh
|
getCourseShowR tid csh
|
||||||
|
|
||||||
getCourseEditR :: Handler Html
|
getCourseEditR :: Handler Html
|
||||||
getCourseEditR = do
|
getCourseEditR = do
|
||||||
-- TODO: Defaults für Semester hier ermitteln und übergeben
|
-- TODO: Defaults für Semester hier ermitteln und übergeben
|
||||||
courseEditHandler Nothing
|
courseEditHandler Nothing
|
||||||
|
|
||||||
postCourseEditR :: Handler Html
|
postCourseEditR :: Handler Html
|
||||||
postCourseEditR = courseEditHandler Nothing
|
postCourseEditR = courseEditHandler Nothing
|
||||||
|
|
||||||
getCourseEditExistR :: TermId -> Text -> Handler Html
|
getCourseEditExistR :: TermId -> Text -> Handler Html
|
||||||
getCourseEditExistR tid csh = do
|
getCourseEditExistR tid csh = do
|
||||||
course <- runDB $ getBy $ CourseTermShort tid csh
|
course <- runDB $ getBy $ CourseTermShort tid csh
|
||||||
courseEditHandler course
|
courseEditHandler course
|
||||||
|
|
||||||
@ -143,28 +143,28 @@ getCourseEditExistIDR cID = do
|
|||||||
courseID <- UUID.decrypt cIDKey cID
|
courseID <- UUID.decrypt cIDKey cID
|
||||||
courseEditHandler =<< runDB (getEntity courseID)
|
courseEditHandler =<< runDB (getEntity courseID)
|
||||||
|
|
||||||
|
|
||||||
courseEditHandler :: Maybe (Entity Course) -> Handler Html
|
courseEditHandler :: Maybe (Entity Course) -> Handler Html
|
||||||
courseEditHandler course = do
|
courseEditHandler course = do
|
||||||
aid <- requireAuthId
|
aid <- requireAuthId
|
||||||
((result, formWidget), formEnctype) <- runFormPost $ newCourseForm $ courseToForm <$> course
|
((result, formWidget), formEnctype) <- runFormPost $ newCourseForm $ courseToForm <$> course
|
||||||
action <- lookupPostParam "formaction"
|
action <- lookupPostParam "formaction"
|
||||||
case (result,action) of
|
case (result,action) of
|
||||||
(FormSuccess res, fAct)
|
(FormSuccess res, fAct)
|
||||||
| fAct == formActionDelete
|
| fAct == formActionDelete
|
||||||
, Just cid <- cfCourseId res -> do
|
, Just cid <- cfCourseId res -> do
|
||||||
runDB $ deleteCascade cid -- TODO Sicherheitsabfrage einbauen!
|
runDB $ deleteCascade cid -- TODO Sicherheitsabfrage einbauen!
|
||||||
let cti = toPathPiece $ cfTerm res
|
let cti = toPathPiece $ cfTerm res
|
||||||
addMessage "info" [shamlet| Kurs #{cti}/#{cfShort res} wurde gelöscht!|]
|
addMessage "info" [shamlet| Kurs #{cti}/#{cfShort res} wurde gelöscht!|]
|
||||||
redirect $ CourseListTermR $ cfTerm res
|
redirect $ CourseListTermR $ cfTerm res
|
||||||
| fAct == formActionSave
|
| fAct == formActionSave
|
||||||
, Just cid <- cfCourseId res -> do
|
, Just cid <- cfCourseId res -> do
|
||||||
let tid = cfTerm res
|
let tid = cfTerm res
|
||||||
actTime <- liftIO getCurrentTime
|
actTime <- liftIO getCurrentTime
|
||||||
updateokay <- runDB $ do
|
updateokay <- runDB $ do
|
||||||
exists <- getBy $ CourseTermShort tid $ cfShort res
|
exists <- getBy $ CourseTermShort tid $ cfShort res
|
||||||
let upokay = isNothing exists
|
let upokay = isNothing exists
|
||||||
when upokay $ update cid
|
when upokay $ update cid
|
||||||
[ CourseName =. cfName res
|
[ CourseName =. cfName res
|
||||||
, CourseDescription =. cfDesc res
|
, CourseDescription =. cfDesc res
|
||||||
, CourseLinkExternal =. cfLink res
|
, CourseLinkExternal =. cfLink res
|
||||||
@ -179,17 +179,17 @@ courseEditHandler course = do
|
|||||||
]
|
]
|
||||||
return upokay
|
return upokay
|
||||||
let cti = toPathPiece $ cfTerm res
|
let cti = toPathPiece $ cfTerm res
|
||||||
if updateokay
|
if updateokay
|
||||||
then do
|
then do
|
||||||
addMessage "info" [shamlet| Kurs #{cti}/#{cfShort res} wurde geändert. |]
|
addMessage "info" [shamlet| Kurs #{cti}/#{cfShort res} wurde geändert. |]
|
||||||
redirect $ CourseListTermR $ cfTerm res
|
redirect $ CourseListTermR $ cfTerm res
|
||||||
else do
|
else do
|
||||||
addMessage "danger" [shamlet| Kurs #{cti}/#{cfShort res} konnte nicht geändert werden.
|
addMessage "danger" [shamlet| Kurs #{cti}/#{cfShort res} konnte nicht geändert werden.
|
||||||
\ Es gibt bereits einen anderen Kurs mit diesem Kürzel in diesem Semester.|]
|
\ Es gibt bereits einen anderen Kurs mit diesem Kürzel in diesem Semester.|]
|
||||||
| fAct == formActionSave
|
| fAct == formActionSave
|
||||||
, Nothing <- cfCourseId res -> do
|
, Nothing <- cfCourseId res -> do
|
||||||
actTime <- liftIO getCurrentTime
|
actTime <- liftIO getCurrentTime
|
||||||
insertOkay <- runDB $ insertUnique $ Course
|
insertOkay <- runDB $ insertUnique $ Course
|
||||||
{ courseName = cfName res
|
{ courseName = cfName res
|
||||||
, courseDescription = cfDesc res
|
, courseDescription = cfDesc res
|
||||||
, courseLinkExternal = cfLink res
|
, courseLinkExternal = cfLink res
|
||||||
@ -204,17 +204,17 @@ courseEditHandler course = do
|
|||||||
, courseChanged = actTime
|
, courseChanged = actTime
|
||||||
, courseCreatedBy = aid
|
, courseCreatedBy = aid
|
||||||
, courseChangedBy = aid
|
, courseChangedBy = aid
|
||||||
}
|
}
|
||||||
case insertOkay of
|
case insertOkay of
|
||||||
(Just cid) -> do
|
(Just cid) -> do
|
||||||
runDB $ insert_ $ Lecturer aid cid
|
runDB $ insert_ $ Lecturer aid cid
|
||||||
let cti = toPathPiece $ cfTerm res
|
let cti = toPathPiece $ cfTerm res
|
||||||
addMessage "info" [shamlet|Kurs #{cti}/#{cfShort res} wurde angelegt.|]
|
addMessage "info" [shamlet|Kurs #{cti}/#{cfShort res} wurde angelegt.|]
|
||||||
redirect $ CourseListTermR $ cfTerm res
|
redirect $ CourseListTermR $ cfTerm res
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
let cti = toPathPiece $ cfTerm res
|
let cti = toPathPiece $ cfTerm res
|
||||||
addMessage "danger" [shamlet|Es gibt bereits einen Kurs #{cfShort res} in Semester #{cti}.|]
|
addMessage "danger" [shamlet|Es gibt bereits einen Kurs #{cfShort res} in Semester #{cti}.|]
|
||||||
(FormFailure _,_) -> addMessage "warning" "Bitte Eingabe korrigieren."
|
(FormFailure _,_) -> addMessage "warning" "Bitte Eingabe korrigieren."
|
||||||
_other -> return ()
|
_other -> return ()
|
||||||
let formTitle = "Kurs editieren/anlegen" :: Text
|
let formTitle = "Kurs editieren/anlegen" :: Text
|
||||||
let actionUrl = CourseEditR
|
let actionUrl = CourseEditR
|
||||||
@ -222,28 +222,28 @@ courseEditHandler course = do
|
|||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitle [shamlet| #{formTitle} |]
|
setTitle [shamlet| #{formTitle} |]
|
||||||
$(widgetFile "formPage")
|
$(widgetFile "formPage")
|
||||||
|
|
||||||
|
|
||||||
data CourseForm = CourseForm
|
data CourseForm = CourseForm
|
||||||
{ cfCourseId :: Maybe CourseId -- Maybe CryptoUUIDCourse
|
{ cfCourseId :: Maybe CourseId -- Maybe CryptoUUIDCourse
|
||||||
, cfName :: Text
|
, cfName :: Text
|
||||||
, cfDesc :: Maybe Html
|
, cfDesc :: Maybe Html
|
||||||
, cfLink :: Maybe Text
|
, cfLink :: Maybe Text
|
||||||
, cfShort :: Text
|
, cfShort :: Text
|
||||||
, cfTerm :: TermId
|
, cfTerm :: TermId
|
||||||
, cfSchool :: SchoolId
|
, cfSchool :: SchoolId
|
||||||
, cfCapacity :: Maybe Int
|
, cfCapacity :: Maybe Int
|
||||||
, cfHasReg :: Bool
|
, cfHasReg :: Bool
|
||||||
, cfRegFrom :: Maybe UTCTime
|
, cfRegFrom :: Maybe UTCTime
|
||||||
, cfRegTo :: Maybe UTCTime
|
, cfRegTo :: Maybe UTCTime
|
||||||
}
|
}
|
||||||
|
|
||||||
instance Show CourseForm where
|
instance Show CourseForm where
|
||||||
show cf = T.unpack (cfShort cf) ++ ' ':(show $ cfCourseId cf)
|
show cf = T.unpack (cfShort cf) ++ ' ':(show $ cfCourseId cf)
|
||||||
|
|
||||||
|
|
||||||
courseToForm :: Entity Course -> CourseForm
|
courseToForm :: Entity Course -> CourseForm
|
||||||
courseToForm cEntity = CourseForm
|
courseToForm cEntity = CourseForm
|
||||||
{ cfCourseId = Just $ entityKey cEntity
|
{ cfCourseId = Just $ entityKey cEntity
|
||||||
, cfName = courseName course
|
, cfName = courseName course
|
||||||
, cfDesc = courseDescription course
|
, cfDesc = courseDescription course
|
||||||
@ -253,26 +253,26 @@ courseToForm cEntity = CourseForm
|
|||||||
, cfSchool = courseSchoolId course
|
, cfSchool = courseSchoolId course
|
||||||
, cfCapacity = courseCapacity course
|
, cfCapacity = courseCapacity course
|
||||||
, cfHasReg = courseHasRegistration course
|
, cfHasReg = courseHasRegistration course
|
||||||
, cfRegFrom = courseRegisterFrom course
|
, cfRegFrom = courseRegisterFrom course
|
||||||
, cfRegTo = courseRegisterTo course
|
, cfRegTo = courseRegisterTo course
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
course = entityVal cEntity
|
course = entityVal cEntity
|
||||||
|
|
||||||
newCourseForm :: Maybe CourseForm -> Form CourseForm
|
newCourseForm :: Maybe CourseForm -> Form CourseForm
|
||||||
newCourseForm template = identForm FIDcourse $ \html -> do
|
newCourseForm template = identForm FIDcourse $ \html -> do
|
||||||
-- mopt hiddenField
|
-- mopt hiddenField
|
||||||
-- cidKey <- getsYesod appCryptoIDKey
|
-- cidKey <- getsYesod appCryptoIDKey
|
||||||
-- courseId <- runMaybeT $ do
|
-- courseId <- runMaybeT $ do
|
||||||
-- cid <- cfCourseId template
|
-- cid <- cfCourseId template
|
||||||
-- UUID.encrypt cidKey cid
|
-- UUID.encrypt cidKey cid
|
||||||
(result, widget) <- flip (renderAForm FormStandard) html $ CourseForm
|
(result, widget) <- flip (renderAForm FormStandard) html $ CourseForm
|
||||||
-- <$> pure cid -- $ join $ cfCourseId <$> template -- why doesnt this work?
|
-- <$> pure cid -- $ join $ cfCourseId <$> template -- why doesnt this work?
|
||||||
<$> aopt hiddenField "KursId" (cfCourseId <$> template)
|
<$> aopt hiddenField "KursId" (cfCourseId <$> template)
|
||||||
<*> areq textField (fsb "Name") (cfName <$> template)
|
<*> areq textField (fsb "Name") (cfName <$> template)
|
||||||
<*> aopt htmlField (fsb "Beschreibung") (cfDesc <$> template)
|
<*> aopt htmlField (fsb "Beschreibung") (cfDesc <$> template)
|
||||||
<*> aopt urlField (fsb "Homepage") (cfLink <$> template)
|
<*> aopt urlField (fsb "Homepage") (cfLink <$> template)
|
||||||
<*> areq textField (fsb "Kürzel"
|
<*> areq textField (fsb "Kürzel"
|
||||||
-- & addAttr "disabled" "disabled"
|
-- & addAttr "disabled" "disabled"
|
||||||
& setTooltip "Muss innerhalb des Semesters eindeutig sein")
|
& setTooltip "Muss innerhalb des Semesters eindeutig sein")
|
||||||
(cfShort <$> template)
|
(cfShort <$> template)
|
||||||
@ -282,9 +282,9 @@ newCourseForm template = identForm FIDcourse $ \html -> do
|
|||||||
<*> areq checkBoxField (fsb "Anmeldung") (cfHasReg <$> template)
|
<*> areq checkBoxField (fsb "Anmeldung") (cfHasReg <$> template)
|
||||||
<*> aopt utcTimeField (fsb "Anmeldung von:") (cfRegFrom <$> template)
|
<*> aopt utcTimeField (fsb "Anmeldung von:") (cfRegFrom <$> template)
|
||||||
<*> aopt utcTimeField (fsb "Anmeldung bis:") (cfRegTo <$> template)
|
<*> aopt utcTimeField (fsb "Anmeldung bis:") (cfRegTo <$> template)
|
||||||
-- <* bootstrapSubmit (bsSubmit (show cid))
|
-- <* bootstrapSubmit (bsSubmit (show cid))
|
||||||
return $ case result of
|
return $ case result of
|
||||||
FormSuccess courseResult
|
FormSuccess courseResult
|
||||||
| errorMsgs <- validateCourse courseResult
|
| errorMsgs <- validateCourse courseResult
|
||||||
, not $ null errorMsgs ->
|
, not $ null errorMsgs ->
|
||||||
(FormFailure errorMsgs,
|
(FormFailure errorMsgs,
|
||||||
@ -293,18 +293,18 @@ newCourseForm template = identForm FIDcourse $ \html -> do
|
|||||||
<h4> Fehler:
|
<h4> Fehler:
|
||||||
<ul>
|
<ul>
|
||||||
$forall errmsg <- errorMsgs
|
$forall errmsg <- errorMsgs
|
||||||
<li> #{errmsg}
|
<li> #{errmsg}
|
||||||
^{widget}
|
^{widget}
|
||||||
|]
|
|]
|
||||||
)
|
)
|
||||||
_ -> (result, widget)
|
_ -> (result, widget)
|
||||||
-- where
|
-- where
|
||||||
-- cid :: Maybe CourseId
|
-- cid :: Maybe CourseId
|
||||||
-- cid = join $ cfCourseId <$> template
|
-- cid = join $ cfCourseId <$> template
|
||||||
|
|
||||||
|
|
||||||
validateCourse :: CourseForm -> [Text]
|
validateCourse :: CourseForm -> [Text]
|
||||||
validateCourse (CourseForm{..}) =
|
validateCourse (CourseForm{..}) =
|
||||||
[ msg | (False, msg) <-
|
[ msg | (False, msg) <-
|
||||||
[
|
[
|
||||||
( cfRegFrom <= cfRegTo
|
( cfRegFrom <= cfRegTo
|
||||||
@ -324,5 +324,3 @@ validateCourse (CourseForm{..}) =
|
|||||||
, "Anmeldungen aktivieren oder Anmeldezeitraum löschen"
|
, "Anmeldungen aktivieren oder Anmeldezeitraum löschen"
|
||||||
)
|
)
|
||||||
] ]
|
] ]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
module Handler.Term where
|
module Handler.Term where
|
||||||
|
|
||||||
import Import
|
import Import
|
||||||
import Handler.Utils
|
import Handler.Utils
|
||||||
|
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Yesod.Form.Bootstrap3
|
import Yesod.Form.Bootstrap3
|
||||||
|
|
||||||
import Colonnade hiding (bool)
|
import Colonnade hiding (bool)
|
||||||
import Yesod.Colonnade
|
import Yesod.Colonnade
|
||||||
@ -27,74 +27,74 @@ getTermShowR = do
|
|||||||
-- term <- runDB $ E.select . E.from $ \(term) -> do
|
-- term <- runDB $ E.select . E.from $ \(term) -> do
|
||||||
-- E.orderBy [E.desc $ term E.^. TermStart ]
|
-- E.orderBy [E.desc $ term E.^. TermStart ]
|
||||||
-- return term
|
-- return term
|
||||||
--
|
--
|
||||||
termData <- runDB $ E.select . E.from $ \term -> do
|
termData <- runDB $ E.select . E.from $ \term -> do
|
||||||
E.orderBy [E.desc $ term E.^. TermStart ]
|
E.orderBy [E.desc $ term E.^. TermStart ]
|
||||||
let courseCount :: E.SqlExpr (E.Value Int)
|
let courseCount :: E.SqlExpr (E.Value Int)
|
||||||
courseCount = E.sub_select . E.from $ \course -> do
|
courseCount = E.sub_select . E.from $ \course -> do
|
||||||
E.where_ $ term E.^. TermId E.==. course E.^. CourseTermId
|
E.where_ $ term E.^. TermId E.==. course E.^. CourseTermId
|
||||||
return E.countRows
|
return E.countRows
|
||||||
return (term, courseCount)
|
return (term, courseCount)
|
||||||
selectRep $ do
|
selectRep $ do
|
||||||
provideRep $ return $ toJSON $ map fst termData
|
provideRep $ return $ toJSON $ map fst termData
|
||||||
provideRep $ do
|
provideRep $ do
|
||||||
let colonnadeTerms = mconcat
|
let colonnadeTerms = mconcat
|
||||||
[ headed "Kürzel" $ \(Entity tid Term{..},_) -> do
|
[ headed "Kürzel" $ \(Entity tid Term{..},_) -> do
|
||||||
-- Scrap this if to slow, create term edit page instead
|
-- Scrap this if to slow, create term edit page instead
|
||||||
adminLink <- handlerToWidget $ isAuthorized (TermEditExistR tid) False
|
adminLink <- handlerToWidget $ isAuthorized (TermEditExistR tid) False
|
||||||
[whamlet|
|
[whamlet|
|
||||||
$if adminLink == Authorized
|
$if adminLink == Authorized
|
||||||
<a href=@{TermEditExistR tid}>
|
<a href=@{TermEditExistR tid}>
|
||||||
#{termToText termName}
|
#{termToText termName}
|
||||||
$else
|
$else
|
||||||
#{termToText termName}
|
#{termToText termName}
|
||||||
|]
|
|]
|
||||||
, headed "Beginn Vorlesungen" $ \(Entity _ Term{..},_) ->
|
, headed "Beginn Vorlesungen" $ \(Entity _ Term{..},_) ->
|
||||||
fromString $ formatTimeGerWD termLectureStart
|
fromString $ formatTimeGerWD termLectureStart
|
||||||
, headed "Ende Vorlesungen" $ \(Entity _ Term{..},_) ->
|
, headed "Ende Vorlesungen" $ \(Entity _ Term{..},_) ->
|
||||||
fromString $ formatTimeGerWD termLectureEnd
|
fromString $ formatTimeGerWD termLectureEnd
|
||||||
, headed "Aktiv" $ \(Entity _ Term{..},_) ->
|
, headed "Aktiv" $ \(Entity _ Term{..},_) ->
|
||||||
bool "" tickmark termActive
|
bool "" tickmark termActive
|
||||||
, headed "Kursliste" $ \(Entity tid Term{..}, E.Value numCourses) ->
|
, headed "Kursliste" $ \(Entity tid Term{..}, E.Value numCourses) ->
|
||||||
[whamlet|
|
[whamlet|
|
||||||
<a href=@{CourseListTermR tid}>
|
<a href=@{CourseListTermR tid}>
|
||||||
#{show numCourses} Kurse
|
#{show numCourses} Kurse
|
||||||
|]
|
|]
|
||||||
, headed "Semesteranfang" $ \(Entity _ Term{..},_) ->
|
, headed "Semesteranfang" $ \(Entity _ Term{..},_) ->
|
||||||
fromString $ formatTimeGerWD termStart
|
fromString $ formatTimeGerWD termStart
|
||||||
, headed "Semesterende" $ \(Entity _ Term{..},_) ->
|
, headed "Semesterende" $ \(Entity _ Term{..},_) ->
|
||||||
fromString $ formatTimeGerWD termEnd
|
fromString $ formatTimeGerWD termEnd
|
||||||
, headed "Feiertage im Semester" $ \(Entity _ Term{..},_) ->
|
, headed "Feiertage im Semester" $ \(Entity _ Term{..},_) ->
|
||||||
fromString $ (intercalate ", ") $ map formatTimeGerWD termHolidays
|
fromString $ (intercalate ", ") $ map formatTimeGerWD termHolidays
|
||||||
]
|
]
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitle "Freigeschaltete Semester"
|
setTitle "Freigeschaltete Semester"
|
||||||
encodeWidgetTable tableDefault colonnadeTerms termData
|
encodeWidgetTable tableSortable colonnadeTerms termData
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
getTermEditR :: Handler Html
|
getTermEditR :: Handler Html
|
||||||
getTermEditR = do
|
getTermEditR = do
|
||||||
-- TODO: Defaults für Semester hier ermitteln und übergeben
|
-- TODO: Defaults für Semester hier ermitteln und übergeben
|
||||||
termEditHandler Nothing
|
termEditHandler Nothing
|
||||||
|
|
||||||
postTermEditR :: Handler Html
|
postTermEditR :: Handler Html
|
||||||
postTermEditR = termEditHandler Nothing
|
postTermEditR = termEditHandler Nothing
|
||||||
|
|
||||||
getTermEditExistR :: TermId -> Handler Html
|
getTermEditExistR :: TermId -> Handler Html
|
||||||
getTermEditExistR tid = do
|
getTermEditExistR tid = do
|
||||||
term <- runDB $ get tid
|
term <- runDB $ get tid
|
||||||
termEditHandler term
|
termEditHandler term
|
||||||
|
|
||||||
|
|
||||||
termEditHandler :: Maybe Term -> Handler Html
|
termEditHandler :: Maybe Term -> Handler Html
|
||||||
termEditHandler term = do
|
termEditHandler term = do
|
||||||
((result, formWidget), formEnctype) <- runFormPost $ newTermForm term
|
((result, formWidget), formEnctype) <- runFormPost $ newTermForm term
|
||||||
case result of
|
case result of
|
||||||
(FormSuccess res) -> do
|
(FormSuccess res) -> do
|
||||||
-- term <- runDB $ get $ TermKey termName
|
-- term <- runDB $ get $ TermKey termName
|
||||||
runDB $ repsert (TermKey $ termName res) res
|
runDB $ repsert (TermKey $ termName res) res
|
||||||
let tid = termToText $ termName res
|
let tid = termToText $ termName res
|
||||||
let msg = "Semester " `T.append` tid `T.append` " erfolgreich editiert."
|
let msg = "Semester " `T.append` tid `T.append` " erfolgreich editiert."
|
||||||
addMessage "success" [shamlet| #{msg} |]
|
addMessage "success" [shamlet| #{msg} |]
|
||||||
redirect TermShowR
|
redirect TermShowR
|
||||||
(FormMissing ) -> return ()
|
(FormMissing ) -> return ()
|
||||||
@ -104,7 +104,7 @@ termEditHandler term = do
|
|||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitle [shamlet| #{formTitle} |]
|
setTitle [shamlet| #{formTitle} |]
|
||||||
$(widgetFile "formPage")
|
$(widgetFile "formPage")
|
||||||
|
|
||||||
newTermForm :: Maybe Term -> Form Term
|
newTermForm :: Maybe Term -> Form Term
|
||||||
newTermForm template html = do
|
newTermForm template html = do
|
||||||
(result, widget) <- flip (renderAForm FormStandard) html $ Term
|
(result, widget) <- flip (renderAForm FormStandard) html $ Term
|
||||||
@ -116,8 +116,8 @@ newTermForm template html = do
|
|||||||
<*> areq dayField (bfs ("Ende Vorlesungen" :: Text)) (termLectureEnd <$> template)
|
<*> areq dayField (bfs ("Ende Vorlesungen" :: Text)) (termLectureEnd <$> template)
|
||||||
<*> areq checkBoxField (bfs ("Aktiv" :: Text)) (termActive <$> template)
|
<*> areq checkBoxField (bfs ("Aktiv" :: Text)) (termActive <$> template)
|
||||||
<* submitButton
|
<* submitButton
|
||||||
return $ case result of
|
return $ case result of
|
||||||
FormSuccess termResult
|
FormSuccess termResult
|
||||||
| errorMsgs <- validateTerm termResult
|
| errorMsgs <- validateTerm termResult
|
||||||
, not $ null errorMsgs ->
|
, not $ null errorMsgs ->
|
||||||
(FormFailure errorMsgs,
|
(FormFailure errorMsgs,
|
||||||
@ -126,13 +126,13 @@ newTermForm template html = do
|
|||||||
<h4> Fehler:
|
<h4> Fehler:
|
||||||
<ul>
|
<ul>
|
||||||
$forall errmsg <- errorMsgs
|
$forall errmsg <- errorMsgs
|
||||||
<li> #{errmsg}
|
<li> #{errmsg}
|
||||||
^{widget}
|
^{widget}
|
||||||
|]
|
|]
|
||||||
)
|
)
|
||||||
_ -> (result, widget)
|
_ -> (result, widget)
|
||||||
{-
|
{-
|
||||||
where
|
where
|
||||||
set :: Text -> FieldSettings site
|
set :: Text -> FieldSettings site
|
||||||
set = bfs
|
set = bfs
|
||||||
-}
|
-}
|
||||||
|
|||||||
@ -41,5 +41,5 @@ getUsersR = do
|
|||||||
-- ++ map (\school -> headed (text2widget $ schoolName $ entityVal school) (\u -> "xx")) schools
|
-- ++ map (\school -> headed (text2widget $ schoolName $ entityVal school) (\u -> "xx")) schools
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitle "Comprehensive User List"
|
setTitle "Comprehensive User List"
|
||||||
let userList = encodeWidgetTable tableDefault colonnadeUsers users
|
let userList = encodeWidgetTable tableSortable colonnadeUsers users
|
||||||
$(widgetFile "users")
|
$(widgetFile "users")
|
||||||
|
|||||||
@ -23,12 +23,15 @@ import Data.Either
|
|||||||
|
|
||||||
-- Table design
|
-- Table design
|
||||||
tableDefault :: Attribute
|
tableDefault :: Attribute
|
||||||
tableDefault = customAttribute "class" "table table-striped table-hover"
|
tableDefault = customAttribute "class" "table table-striped table-hover"
|
||||||
|
|
||||||
|
tableSortable :: Attribute
|
||||||
|
tableSortable = customAttribute "class" "js-sortable"
|
||||||
|
|
||||||
-- Colonnade Tools
|
-- Colonnade Tools
|
||||||
numberColonnade :: (IsString c) => Colonnade Headed Int c
|
numberColonnade :: (IsString c) => Colonnade Headed Int c
|
||||||
numberColonnade = headed "Nr" (fromString.show)
|
numberColonnade = headed "Nr" (fromString.show)
|
||||||
|
|
||||||
pairColonnade :: (Functor h) => Colonnade h a c -> Colonnade h b c -> Colonnade h (a,b) c
|
pairColonnade :: (Functor h) => Colonnade h a c -> Colonnade h b c -> Colonnade h (a,b) c
|
||||||
pairColonnade a b = mconcat [ lmap fst a, lmap snd b]
|
pairColonnade a b = mconcat [ lmap fst a, lmap snd b]
|
||||||
|
|
||||||
@ -39,8 +42,8 @@ encodeHeadedWidgetTableNumbered attrs colo tdata =
|
|||||||
encodeWidgetTable attrs (mconcat [numberCol, lmap snd colo]) (zip [1..] tdata)
|
encodeWidgetTable attrs (mconcat [numberCol, lmap snd colo]) (zip [1..] tdata)
|
||||||
where
|
where
|
||||||
numberCol :: Colonnade Headed (Int,a) (WidgetT site IO ())
|
numberCol :: Colonnade Headed (Int,a) (WidgetT site IO ())
|
||||||
numberCol = headed "Nr" (fromString.show.fst)
|
numberCol = headed "Nr" (fromString.show.fst)
|
||||||
|
|
||||||
headedRowSelector :: ( PathPiece b
|
headedRowSelector :: ( PathPiece b
|
||||||
, Eq b
|
, Eq b
|
||||||
)
|
)
|
||||||
@ -74,7 +77,7 @@ headedRowSelector toExternal fromExternal attrs colonnade tdata = do
|
|||||||
selectionIdent <- newFormIdent
|
selectionIdent <- newFormIdent
|
||||||
|
|
||||||
(selectionResults, selectionBoxes) <- fmap unzip . forM externalIds $ \ident -> mopt (checkbox ident) ("" { fsName = Just selectionIdent }) Nothing
|
(selectionResults, selectionBoxes) <- fmap unzip . forM externalIds $ \ident -> mopt (checkbox ident) ("" { fsName = Just selectionIdent }) Nothing
|
||||||
|
|
||||||
let
|
let
|
||||||
selColonnade :: Colonnade Headed Int (Cell UniWorX)
|
selColonnade :: Colonnade Headed Int (Cell UniWorX)
|
||||||
selColonnade = headed "Markiert" $ cell . fvInput . (selectionBoxes !!)
|
selColonnade = headed "Markiert" $ cell . fvInput . (selectionBoxes !!)
|
||||||
|
|||||||
6
templates/courses.hamlet
Normal file
6
templates/courses.hamlet
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<div>
|
||||||
|
<h1>Kursübersicht für Semester #{termToText $ unTermKey tidini}
|
||||||
|
^{coursesTable}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a href=@{CourseEditR}>Neuen Kurs anlegen
|
||||||
@ -19,7 +19,3 @@
|
|||||||
|
|
||||||
<!-- actual content -->
|
<!-- actual content -->
|
||||||
^{widget}
|
^{widget}
|
||||||
|
|
||||||
<!-- footer -->
|
|
||||||
<footer>
|
|
||||||
#{appCopyright $ appSettings master}
|
|
||||||
|
|||||||
@ -28,12 +28,14 @@
|
|||||||
--blackbase: #1A2A36;
|
--blackbase: #1A2A36;
|
||||||
--fontbase: #34303a;
|
--fontbase: #34303a;
|
||||||
--fontsec: #5b5861;
|
--fontsec: #5b5861;
|
||||||
|
--primarybase: #4C7A9C;
|
||||||
|
|
||||||
|
|
||||||
/* THEME INDEPENDENT COLORS */
|
/* THEME INDEPENDENT COLORS */
|
||||||
--errorbase: red;
|
--errorbase: red;
|
||||||
--warningbase: #fe7700;
|
--warningbase: #fe7700;
|
||||||
--validbase: #2dcc35;
|
--validbase: #2dcc35;
|
||||||
|
--infobase: var(--darkbase);
|
||||||
|
|
||||||
|
|
||||||
/* FONTS */
|
/* FONTS */
|
||||||
@ -100,12 +102,23 @@ h4 {
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
table {
|
||||||
|
margin: 21px 0;
|
||||||
|
/*width: 100%;*/
|
||||||
|
}
|
||||||
th, td {
|
th, td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 0 2px 0 4px;
|
padding: 0 13px 0 7px;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
th:first-child,
|
||||||
|
td:first-child {
|
||||||
|
padding-left: 0;
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
border-left: 2px solid var(--greybase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* LAYOUT */
|
/* LAYOUT */
|
||||||
.main {
|
.main {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -115,6 +128,7 @@ th, td {
|
|||||||
|
|
||||||
.main__aside {
|
.main__aside {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
flex-shrink: 0;
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
padding-left: 4vw;
|
padding-left: 4vw;
|
||||||
background-color: var(--darkbase);
|
background-color: var(--darkbase);
|
||||||
@ -144,3 +158,57 @@ th, td {
|
|||||||
outline: 5px auto var(--lightbase);
|
outline: 5px auto var(--lightbase);
|
||||||
outline: 5px auto -webkit-focus-ring-color;
|
outline: 5px auto -webkit-focus-ring-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* GENERAL BUTTON STYLES */
|
||||||
|
input[type="submit"],
|
||||||
|
input[type="button"],
|
||||||
|
button,
|
||||||
|
.btn {
|
||||||
|
outline: 0;
|
||||||
|
border: 0;
|
||||||
|
box-shadow: 0;
|
||||||
|
background-color: var(--lightbase);
|
||||||
|
color: white;
|
||||||
|
padding: 10px 17px;
|
||||||
|
min-width: 100px;
|
||||||
|
transition: all .1s;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
input.btn-primary,
|
||||||
|
button.btn-primary,
|
||||||
|
.btn.btn-primary {
|
||||||
|
background-color: var(--primarybase);
|
||||||
|
}
|
||||||
|
|
||||||
|
input.btn-info,
|
||||||
|
button.btn-info,
|
||||||
|
.btn.btn-info {
|
||||||
|
background-color: var(--infobase)
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"][disabled],
|
||||||
|
input[type="button"][disabled],
|
||||||
|
button[disabled],
|
||||||
|
.btn[disabled] {
|
||||||
|
opacity: 0.3;
|
||||||
|
background-color: var(--greybase);
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"]:not([disabled]):hover,
|
||||||
|
input[type="button"]:not([disabled]):hover,
|
||||||
|
button:not([disabled]):hover,
|
||||||
|
.btn:not([disabled]):hover {
|
||||||
|
background-color: var(--lighterbase);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"].btn-info:hover,
|
||||||
|
input[type="button"].btn-info:hover,
|
||||||
|
button.btn-info:hover,
|
||||||
|
.btn.btn-info:hover {
|
||||||
|
background-color: var(--greybase)
|
||||||
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
<a href=@{SubmissionListR}>Dateien hochladen und abrufen
|
<a href=@{SubmissionListR}>Dateien hochladen und abrufen
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<div .js-show-hide.js-show-hide--collapsed>
|
<div .js-show-hide data-collapsed=true>
|
||||||
<h2 .js-show-hide__toggle>Tabellen
|
<h2 .js-show-hide__toggle>Tabellen
|
||||||
<table .js-sortable>
|
<table .js-sortable>
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
@ -16,12 +16,31 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
var toggle = toggles[el.dataset.index];
|
var toggle = toggles[el.dataset.index];
|
||||||
toggle.collapsed = !toggle.collapsed;
|
toggle.collapsed = !toggle.collapsed;
|
||||||
toggle.parent.classList.toggle('js-show-hide--collapsed', toggle.collapsed);
|
toggle.parent.classList.toggle('js-show-hide--collapsed', toggle.collapsed);
|
||||||
|
updateLocalStorage();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateLocalStorage(id) {
|
||||||
|
let jsonToggles = JSON.stringify(toggles.map(t => {
|
||||||
|
return {id: t.index, collapsed: t.collapsed};
|
||||||
|
}));
|
||||||
|
window.localStorage.setItem('showHidesToggles', jsonToggles);
|
||||||
|
}
|
||||||
|
|
||||||
|
function collapsedStateInLocalStorage(id, fallBack) {
|
||||||
|
let lsData = JSON.parse(window.localStorage.getItem('showHidesToggles'));
|
||||||
|
if (lsData[id]) {
|
||||||
|
return lsData[id].collapsed;
|
||||||
|
}
|
||||||
|
return fallBack;
|
||||||
|
}
|
||||||
|
|
||||||
elements.forEach(function(el, i) {
|
elements.forEach(function(el, i) {
|
||||||
el.dataset.index = i;
|
el.dataset.index = i;
|
||||||
var coll = el.parentElement.classList.contains('js-show-hide--collapsed');
|
var coll = collapsedStateInLocalStorage(i, el.parentElement.dataset.collapsed === 'true');
|
||||||
|
if (coll) {
|
||||||
|
el.parentElement.classList.add('js-show-hide--collapsed')
|
||||||
|
}
|
||||||
Array.from(el.parentElement.children).forEach(function(el) {
|
Array.from(el.parentElement.children).forEach(function(el) {
|
||||||
if (!el.classList.contains('js-show-hide__toggle')) {
|
if (!el.classList.contains('js-show-hide__toggle')) {
|
||||||
el.classList.add('js-show-hide__target');
|
el.classList.add('js-show-hide__target');
|
||||||
|
|||||||
@ -13,8 +13,8 @@ table.js-sortable th.sorted-asc::after,
|
|||||||
table.js-sortable th.sorted-desc::after {
|
table.js-sortable th.sorted-desc::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 15px;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
transform: translateY(-100%);
|
transform: translateY(-100%);
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<div .asidenav>
|
<div .asidenav>
|
||||||
<div .asidenav__box>
|
<div .asidenav__box>
|
||||||
<h3 .asidenav__box-title>NavbarLefts
|
|
||||||
<ul .asidenav__list>
|
<ul .asidenav__list>
|
||||||
$forall menuType <- menuTypes
|
$forall menuType <- menuTypes
|
||||||
$case menuType
|
$case menuType
|
||||||
@ -8,6 +7,7 @@
|
|||||||
<li .asidenav__list-item :Just route == mcurrentRoute:.asidenav__list-item--active>
|
<li .asidenav__list-item :Just route == mcurrentRoute:.asidenav__list-item--active>
|
||||||
<a .asidenav__link href=@{route}>#{label}
|
<a .asidenav__link href=@{route}>#{label}
|
||||||
$of _
|
$of _
|
||||||
|
|
||||||
<div .asidenav__box>
|
<div .asidenav__box>
|
||||||
<h3 .asidenav__box-title>WiSe 17/18
|
<h3 .asidenav__box-title>WiSe 17/18
|
||||||
<ul .asidenav__list>
|
<ul .asidenav__list>
|
||||||
|
|||||||
@ -134,7 +134,7 @@
|
|||||||
var nextInput = document.createElement('input');
|
var nextInput = document.createElement('input');
|
||||||
var remover = document.createElement('div');
|
var remover = document.createElement('div');
|
||||||
cont.classList.add('file-input__container');
|
cont.classList.add('file-input__container');
|
||||||
desc.classList.add('file-input__label');
|
desc.classList.add('file-input__label', 'btn');
|
||||||
remover.classList.add('file-input__remover');
|
remover.classList.add('file-input__remover');
|
||||||
nextInput.setAttribute('name', name);
|
nextInput.setAttribute('name', name);
|
||||||
nextInput.setAttribute('type', 'file');
|
nextInput.setAttribute('type', 'file');
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* GENERAL STYLES FOR FORMS */
|
/* GENERAL STYLES FOR FORMS */
|
||||||
|
|
||||||
/* FORMS */
|
/* TEXT INPUTS */
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
input[type="url"],
|
input[type="url"],
|
||||||
@ -27,36 +27,9 @@ input[type="email"]:focus {
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="submit"],
|
/* BUTTON STYLE SEE default-layout.lucius */
|
||||||
input[type="button"],
|
|
||||||
button {
|
|
||||||
outline: 0;
|
|
||||||
border: 0;
|
|
||||||
box-shadow: 0;
|
|
||||||
background-color: var(--lightbase);
|
|
||||||
color: white;
|
|
||||||
padding: 10px 17px;
|
|
||||||
min-width: 100px;
|
|
||||||
transition: all .1s;
|
|
||||||
font-size: 16px;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="submit"][disabled],
|
|
||||||
input[type="button"][disabled],
|
|
||||||
button[disabled] {
|
|
||||||
opacity: 0.3;
|
|
||||||
background-color: var(--greybase);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="submit"]:not([disabled]):hover,
|
|
||||||
input[type="button"]:not([disabled]):hover,
|
|
||||||
button:not([disabled]):hover {
|
|
||||||
background-color: var(--lighterbase);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* TEXTAREAS */
|
||||||
textarea {
|
textarea {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
@ -75,7 +48,7 @@ textarea:focus {
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-bottom-color: var(--lightbase);
|
border-bottom-color: var(--lightbase);
|
||||||
}
|
}
|
||||||
|
/* FORM GROUPS */
|
||||||
.form-group {
|
.form-group {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -267,12 +240,13 @@ input[type="file"] {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.file-input__label {
|
.file-input__label {
|
||||||
background-color: var(--lighterbase);
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: 40px;
|
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
.file-input__label.btn {
|
||||||
|
padding: 5px 13px;
|
||||||
|
}
|
||||||
.file-input__label::after,
|
.file-input__label::after,
|
||||||
.file-input__label::before {
|
.file-input__label::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@ -3,12 +3,12 @@
|
|||||||
<ul .navbar__list.list--inline>
|
<ul .navbar__list.list--inline>
|
||||||
$forall menuType <- menuTypes
|
$forall menuType <- menuTypes
|
||||||
$case menuType
|
$case menuType
|
||||||
$of NavbarLeft (MenuItem label route _)
|
|
||||||
<li .navbar__list-item :Just route == mcurrentRoute:.navbar__list-item--active>
|
|
||||||
<a .navbar__link href=@{route}>#{label}
|
|
||||||
$of NavbarRight (MenuItem label route _)
|
$of NavbarRight (MenuItem label route _)
|
||||||
<li .navbar__list-item :Just route == mcurrentRoute:.navbar__list-item--active>
|
<li .navbar__list-item :Just route == mcurrentRoute:.navbar__list-item--active>
|
||||||
<a .navbar__link href=@{route}>#{label}
|
<a .navbar__link href=@{route}>#{label}
|
||||||
|
$of NavbarSecondary (MenuItem label route _)
|
||||||
|
<li .navbar__list-item.navbar__list-item--secondary :Just route == mcurrentRoute:.navbar__list-item--active>
|
||||||
|
<a .navbar__link href=@{route}>#{label}
|
||||||
$of _
|
$of _
|
||||||
|
|
||||||
<div .navbar__pushdown>
|
<div .navbar__pushdown>
|
||||||
|
|||||||
@ -25,12 +25,22 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar__list-item--secondary {
|
||||||
|
margin-left: 20px;
|
||||||
|
background-color: var(--fontsec);
|
||||||
|
}
|
||||||
|
.navbar__list-item--secondary + .navbar__list-item--secondary {
|
||||||
|
margin-left: 0;
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar__list-item--active > .navbar__link {
|
.navbar__list-item--active > .navbar__link {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
color: var(--darkbase);
|
color: var(--darkbase);
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar .navbar__list-item > .navbar__link:hover {
|
.navbar .navbar__list-item > .navbar__link:hover {
|
||||||
|
color: var(--whitebase);
|
||||||
background-color: var(--darkbase);
|
background-color: var(--darkbase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user