Merge branch 'master' into 'live'
iframe-based dynamic modals Closes #226, #217, and #223 See merge request !91
This commit is contained in:
commit
f4df3b110e
3
.gitignore
vendored
3
.gitignore
vendored
@ -30,5 +30,4 @@ src/Handler/Course.SnapCustom.hs
|
|||||||
/instance
|
/instance
|
||||||
.stack-work-*
|
.stack-work-*
|
||||||
.directory
|
.directory
|
||||||
tags
|
tags
|
||||||
.vscode
|
|
||||||
35
.vscode/tasks.json
vendored
Normal file
35
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "./build.sh",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "silent",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "dedicated",
|
||||||
|
"showReuseMessage": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "start",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "./start.sh",
|
||||||
|
"group": "build",
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "silent",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "dedicated",
|
||||||
|
"showReuseMessage": false
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -10,3 +10,8 @@ $# Ignoriere rekursiv alle Ordner __MACOSX und ihren Inhalt
|
|||||||
|
|
||||||
$# Ignoriere rekursiv alle Dateien .DS_Store (Mac OS)
|
$# Ignoriere rekursiv alle Dateien .DS_Store (Mac OS)
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
|
|
||||||
|
$# Ignoriere VI-Style-Backup-Files
|
||||||
|
**/*~
|
||||||
|
$# Ignoriere Emacs-Style-Backup-Files
|
||||||
|
**/.#*#
|
||||||
@ -346,7 +346,7 @@ MailSheetActiveIntro courseName@Text termDesc@Text sheetName@SheetName: Sie kön
|
|||||||
|
|
||||||
MailSubjectSheetSoonInactive csh@CourseShorthand sheetName@SheetName: #{sheetName} in #{csh} kann nur noch kurze Zeit abgegeben werden
|
MailSubjectSheetSoonInactive csh@CourseShorthand sheetName@SheetName: #{sheetName} in #{csh} kann nur noch kurze Zeit abgegeben werden
|
||||||
MailSheetSoonInactiveIntro courseName@Text termDesc@Text sheetName@SheetName: Abgabefirst für #{sheetName} im Kurs #{courseName} (#{termDesc}) endet in Kürze.
|
MailSheetSoonInactiveIntro courseName@Text termDesc@Text sheetName@SheetName: Abgabefirst für #{sheetName} im Kurs #{courseName} (#{termDesc}) endet in Kürze.
|
||||||
MailSubjectSheetInactive csh@CourseShorthand sheetName@SheetName: Abgabfristt für #{sheetName} in #{csh} abgelaufen
|
MailSubjectSheetInactive csh@CourseShorthand sheetName@SheetName: Abgabfrist für #{sheetName} in #{csh} abgelaufen
|
||||||
MailSheetInactiveIntro courseName@Text termDesc@Text sheetName@SheetName: Die Abgabefirst für #{sheetName} im Kurs #{courseName} (#{termDesc}) beendet.
|
MailSheetInactiveIntro courseName@Text termDesc@Text sheetName@SheetName: Die Abgabefirst für #{sheetName} im Kurs #{courseName} (#{termDesc}) beendet.
|
||||||
MailCorrectionsAssignedIntro courseName@Text termDesc@Text sheetName@SheetName n@Int: #{display n} Abgaben wurden Ihnen zur Korrektur für #{sheetName} im Kurs #{courseName} (#{termDesc}) zugeteilt.
|
MailCorrectionsAssignedIntro courseName@Text termDesc@Text sheetName@SheetName n@Int: #{display n} Abgaben wurden Ihnen zur Korrektur für #{sheetName} im Kurs #{courseName} (#{termDesc}) zugeteilt.
|
||||||
MailEditNotifications: Benachrichtigungen ein-/ausschalten
|
MailEditNotifications: Benachrichtigungen ein-/ausschalten
|
||||||
|
|||||||
24
routes
24
routes
@ -10,20 +10,20 @@
|
|||||||
-- Admins always have access to entities within their assigned schools.
|
-- Admins always have access to entities within their assigned schools.
|
||||||
--
|
--
|
||||||
-- Access Tags:
|
-- Access Tags:
|
||||||
-- !free -- free for all
|
-- !free -- free for all
|
||||||
-- !lecturer -- lecturer for this course (or the school, if route is not connected to a course)
|
-- !lecturer -- lecturer for this course (or the school, if route is not connected to a course)
|
||||||
-- !corrector -- corrector for this sheet (or the submission, if route is connected to a submission, or the course, if route is not connected to a sheet, or any course, if route is not connected to a course)
|
-- !corrector -- corrector for this sheet (or the submission, if route is connected to a submission, or the course, if route is not connected to a sheet, or any course, if route is not connected to a course)
|
||||||
-- !registered -- participant for this course (no effect outside of courses)
|
-- !registered -- participant for this course (no effect outside of courses)
|
||||||
-- !owner -- part of the group of owners of this submission
|
-- !owner -- part of the group of owners of this submission
|
||||||
-- !capacity -- course this route is associated with has at least one unit of participant capacity
|
-- !capacity -- course this route is associated with has at least one unit of participant capacity
|
||||||
--
|
--
|
||||||
-- !materials -- only if course allows all materials to be free (no meaning outside of courses)
|
-- !materials -- only if course allows all materials to be free (no meaning outside of courses)
|
||||||
-- !time -- access depends on time somehow
|
-- !time -- access depends on time somehow
|
||||||
-- !isRead -- only if it is read-only access (i.e. GET but not POST)
|
-- !isRead -- only if it is read-only access (i.e. GET but not POST)
|
||||||
-- !isWrite -- only if it is write access (i.e. POST only) why needed???
|
-- !isWrite -- only if it is write access (i.e. POST only) why needed???
|
||||||
--
|
|
||||||
-- !deprecated -- like free, but logs and gives a warning; entirely disabled in production
|
|
||||||
--
|
--
|
||||||
|
-- !deprecated -- like free, but logs and gives a warning; entirely disabled in production
|
||||||
|
-- !development -- like free, but only for development builds
|
||||||
|
|
||||||
/static StaticR Static appStatic !free
|
/static StaticR Static appStatic !free
|
||||||
/auth AuthR Auth getAuth !free
|
/auth AuthR Auth getAuth !free
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import Auth.PWHash
|
|||||||
import Auth.Dummy
|
import Auth.Dummy
|
||||||
import Jobs.Types
|
import Jobs.Types
|
||||||
|
|
||||||
|
import Handler.Utils.Templates (siteModalId, modalParameter)
|
||||||
|
|
||||||
import qualified Network.Wai as W (pathInfo)
|
import qualified Network.Wai as W (pathInfo)
|
||||||
|
|
||||||
import Yesod.Default.Util (addStaticContentExternal)
|
import Yesod.Default.Util (addStaticContentExternal)
|
||||||
@ -697,8 +699,14 @@ siteLayout headingOverride widget = do
|
|||||||
master <- getYesod
|
master <- getYesod
|
||||||
let AppSettings { appUserDefaults = UserDefaultConf{..}, .. } = appSettings master
|
let AppSettings { appUserDefaults = UserDefaultConf{..}, .. } = appSettings master
|
||||||
|
|
||||||
applySystemMessages
|
isModal <- isJust <$> siteModalId
|
||||||
mmsgs <- getMessages
|
$logDebugS "siteLayout" $ "isModal = " <> tshow isModal
|
||||||
|
|
||||||
|
mmsgs <- if
|
||||||
|
| isModal -> return []
|
||||||
|
| otherwise -> do
|
||||||
|
applySystemMessages
|
||||||
|
getMessages
|
||||||
|
|
||||||
mcurrentRoute <- getCurrentRoute
|
mcurrentRoute <- getCurrentRoute
|
||||||
|
|
||||||
|
|||||||
@ -180,8 +180,7 @@ getSheetListR tid ssh csh = do
|
|||||||
mkRoute = do
|
mkRoute = do
|
||||||
cid' <- mkCid
|
cid' <- mkCid
|
||||||
return $ CSubmissionR tid ssh csh sheetName cid' CorrectionR
|
return $ CSubmissionR tid ssh csh sheetName cid' CorrectionR
|
||||||
protoCell = anchorCellM mkRoute $(widgetFile "widgets/rating")
|
in anchorCellM mkRoute $(widgetFile "widgets/rating")
|
||||||
in protoCell & cellContents %~ (<* tell (sheetTypeSum sheetType submissionRatingPoints))
|
|
||||||
, sortable Nothing -- (Just "percent")
|
, sortable Nothing -- (Just "percent")
|
||||||
(i18nCell MsgRatingPercent)
|
(i18nCell MsgRatingPercent)
|
||||||
$ \(Entity _ Sheet{sheetType=sType}, _, mbSub) -> case mbSub of
|
$ \(Entity _ Sheet{sheetType=sType}, _, mbSub) -> case mbSub of
|
||||||
@ -196,23 +195,7 @@ getSheetListR tid ssh csh = do
|
|||||||
]
|
]
|
||||||
psValidator = def
|
psValidator = def
|
||||||
& defaultSorting [("submission-since", SortAsc)]
|
& defaultSorting [("submission-since", SortAsc)]
|
||||||
------------------------------------------------------
|
((), table) <- dbTable psValidator $ DBTable
|
||||||
-- ISSUE #223
|
|
||||||
-- The following line does not work; something is wrong with the tell in line 189 above.
|
|
||||||
-- (SheetTypeSummary{..}, table) <- dbTable psValidator $ DBTable
|
|
||||||
--
|
|
||||||
-- If fixed, remove the following workaround code:
|
|
||||||
SheetTypeSummary{..} <- do
|
|
||||||
rows <- runDB $ E.select $ E.from $ \(sheet `E.LeftOuterJoin` (submission `E.InnerJoin` submissionUser)) -> do
|
|
||||||
E.on $ submission E.?. SubmissionId E.==. submissionUser E.?. SubmissionUserSubmission
|
|
||||||
E.on $ (E.just $ sheet E.^. SheetId) E.==. submission E.?. SubmissionSheet
|
|
||||||
E.&&. submissionUser E.?. SubmissionUserUser E.==. E.val muid
|
|
||||||
E.where_ $ sheet E.^. SheetCourse E.==. E.val cid
|
|
||||||
return (sheet E.^. SheetType, submission E.?. SubmissionRatingPoints)
|
|
||||||
return $ foldMap (\(E.Value sheetType, E.Value mbPts) -> sheetTypeSum sheetType (join mbPts)) rows
|
|
||||||
(_, table) <- dbTable psValidator $ DBTable
|
|
||||||
-- END ISSUE #223
|
|
||||||
-----------------------------------------------------
|
|
||||||
{ dbtSQLQuery = sheetData
|
{ dbtSQLQuery = sheetData
|
||||||
, dbtColonnade = sheetCol
|
, dbtColonnade = sheetCol
|
||||||
, dbtProj = \DBRow{ dbrOutput = dbrOutput@(Entity _ Sheet{..}, _, _) }
|
, dbtProj = \DBRow{ dbrOutput = dbrOutput@(Entity _ Sheet{..}, _, _) }
|
||||||
@ -245,6 +228,15 @@ getSheetListR tid ssh csh = do
|
|||||||
, dbtStyle = def
|
, dbtStyle = def
|
||||||
, dbtIdent = "sheets" :: Text
|
, dbtIdent = "sheets" :: Text
|
||||||
}
|
}
|
||||||
|
-- Collect summary over all Sheets, not just the ones shown due to pagination:
|
||||||
|
SheetTypeSummary{..} <- do
|
||||||
|
rows <- runDB $ E.select $ E.from $ \(sheet `E.LeftOuterJoin` (submission `E.InnerJoin` submissionUser)) -> do
|
||||||
|
E.on $ submission E.?. SubmissionId E.==. submissionUser E.?. SubmissionUserSubmission
|
||||||
|
E.on $ (E.just $ sheet E.^. SheetId) E.==. submission E.?. SubmissionSheet
|
||||||
|
E.&&. submissionUser E.?. SubmissionUserUser E.==. E.val muid
|
||||||
|
E.where_ $ sheet E.^. SheetCourse E.==. E.val cid
|
||||||
|
return (sheet E.^. SheetType, submission E.?. SubmissionRatingPoints)
|
||||||
|
return $ foldMap (\(E.Value sheetType, E.Value mbPts) -> sheetTypeSum sheetType (join mbPts)) rows
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
$(widgetFile "sheetList")
|
$(widgetFile "sheetList")
|
||||||
$(widgetFile "widgets/sheetTypeSummary")
|
$(widgetFile "widgets/sheetTypeSummary")
|
||||||
|
|||||||
@ -47,22 +47,27 @@ import System.FilePath
|
|||||||
-- numberOfSubmissionEditDates = 3 -- for debugging only, should be 1 in production.
|
-- numberOfSubmissionEditDates = 3 -- for debugging only, should be 1 in production.
|
||||||
|
|
||||||
|
|
||||||
makeSubmissionForm :: Maybe SubmissionId -> UploadMode -> SheetGroup -> [UserEmail] -> Form (Maybe (Source Handler File), [UserEmail])
|
makeSubmissionForm :: Maybe SubmissionId -> UploadMode -> SheetGroup -> NonEmpty UserEmail -> Form (Maybe (Source Handler File), NonEmpty UserEmail)
|
||||||
makeSubmissionForm msmid uploadMode grouping buddies = identForm FIDsubmission $ \html -> do
|
makeSubmissionForm msmid uploadMode grouping (self :| buddies) = identForm FIDsubmission $ \html -> do
|
||||||
let
|
let
|
||||||
fileUploadForm = case uploadMode of
|
fileUploadForm = case uploadMode of
|
||||||
NoUpload -> pure Nothing
|
NoUpload -> pure Nothing
|
||||||
(Upload unpackZips) -> (bool (\f fs _ -> Just <$> areq f fs Nothing) aopt $ isJust msmid) (zipFileField unpackZips) (fsm $ bool MsgSubmissionFile MsgSubmissionArchive unpackZips) Nothing
|
(Upload unpackZips) -> (bool (\f fs _ -> Just <$> areq f fs Nothing) aopt $ isJust msmid) (zipFileField unpackZips) (fsm $ bool MsgSubmissionFile MsgSubmissionArchive unpackZips) Nothing
|
||||||
flip (renderAForm FormStandard) html $ (,)
|
flip (renderAForm FormStandard) html $ (,)
|
||||||
<$> fileUploadForm
|
<$> fileUploadForm
|
||||||
<*> (catMaybes <$> sequenceA [bool aforced' aopt editableBuddies ciField (fslpI (MsgSubmissionMember g) "user@campus.lmu.de" ) buddy
|
<*> ( (:|)
|
||||||
| g <- [1..(max (fromIntegral groupNr) $ length buddies)] -- groupNr might have decreased meanwhile
|
-- #227 Part I: change aforced to areq if the user is the lecturer or an admin (lecturer can upload for students)
|
||||||
| buddy <- map (Just . Just) buddies ++ repeat Nothing -- show current buddies
|
<$> aforced ciField (fslpI (MsgSubmissionMember 1) "user@campus.lmu.de" ) self
|
||||||
])
|
<*> (catMaybes <$> sequenceA [bool aforced' aopt editableBuddies ciField (fslpI (MsgSubmissionMember g) "user@campus.lmu.de" ) buddy
|
||||||
|
| g <- [2..(fromIntegral groupNr)]
|
||||||
|
| buddy <- map (Just . Just) buddies ++ repeat Nothing -- show current buddies
|
||||||
|
])
|
||||||
|
)
|
||||||
<* submitButton
|
<* submitButton
|
||||||
where
|
where
|
||||||
(groupNr, editableBuddies)
|
(groupNr, editableBuddies)
|
||||||
| Arbitrary{..} <- grouping = (pred maxParticipants, True) -- pred to account for the person submitting
|
| Arbitrary{..} <- grouping = (maxParticipants, True)
|
||||||
|
| RegisteredGroups <- grouping = (fromIntegral $ length buddies, False)
|
||||||
| otherwise = (0, False)
|
| otherwise = (0, False)
|
||||||
|
|
||||||
aforced' f fs (Just (Just v)) = Just <$> aforced f fs v
|
aforced' f fs (Just (Just v)) = Just <$> aforced f fs v
|
||||||
@ -95,7 +100,7 @@ getSubmissionOwnR tid ssh csh shn = do
|
|||||||
|
|
||||||
submissionHelper :: TermId -> SchoolId -> CourseShorthand -> SheetName -> SubmissionMode -> Handler Html
|
submissionHelper :: TermId -> SchoolId -> CourseShorthand -> SheetName -> SubmissionMode -> Handler Html
|
||||||
submissionHelper tid ssh csh shn (SubmissionMode mcid) = do
|
submissionHelper tid ssh csh shn (SubmissionMode mcid) = do
|
||||||
uid <- requireAuthId
|
(Entity uid userData) <- requireAuth
|
||||||
msmid <- traverse decrypt mcid
|
msmid <- traverse decrypt mcid
|
||||||
actionUrl <- Data.Maybe.fromJust <$> getCurrentRoute
|
actionUrl <- Data.Maybe.fromJust <$> getCurrentRoute
|
||||||
maySubmit <- (== Authorized) <$> isAuthorized actionUrl True -- affects visibility of Edit-Dates, Submission-Button, etc.
|
maySubmit <- (== Authorized) <$> isAuthorized actionUrl True -- affects visibility of Edit-Dates, Submission-Button, etc.
|
||||||
@ -141,7 +146,7 @@ submissionHelper tid ssh csh shn (SubmissionMode mcid) = do
|
|||||||
invalidArgsI [MsgSubmissionWrongSheet]
|
invalidArgsI [MsgSubmissionWrongSheet]
|
||||||
-- fetch buddies from current submission
|
-- fetch buddies from current submission
|
||||||
(Any isOwner, buddies) <- do
|
(Any isOwner, buddies) <- do
|
||||||
submittors <- E.select . E.from $ \(submissionUser `E.InnerJoin` user) -> do
|
submitters <- E.select . E.from $ \(submissionUser `E.InnerJoin` user) -> do
|
||||||
E.on (submissionUser E.^. SubmissionUserUser E.==. user E.^. UserId)
|
E.on (submissionUser E.^. SubmissionUserUser E.==. user E.^. UserId)
|
||||||
E.where_ $ submissionUser E.^. SubmissionUserSubmission E.==. E.val smid
|
E.where_ $ submissionUser E.^. SubmissionUserSubmission E.==. E.val smid
|
||||||
E.orderBy [E.asc $ user E.^. UserEmail]
|
E.orderBy [E.asc $ user E.^. UserEmail]
|
||||||
@ -149,7 +154,7 @@ submissionHelper tid ssh csh shn (SubmissionMode mcid) = do
|
|||||||
let breakUserFromBuddies (E.Value userID, E.Value email)
|
let breakUserFromBuddies (E.Value userID, E.Value email)
|
||||||
| uid == userID = (Any True , [])
|
| uid == userID = (Any True , [])
|
||||||
| otherwise = (Any False, [email])
|
| otherwise = (Any False, [email])
|
||||||
return $ foldMap breakUserFromBuddies submittors
|
return $ foldMap breakUserFromBuddies submitters
|
||||||
|
|
||||||
lastEdits <- do
|
lastEdits <- do
|
||||||
raw <- E.select . E.from $ \(user `E.InnerJoin` submissionEdit) -> do
|
raw <- E.select . E.from $ \(user `E.InnerJoin` submissionEdit) -> do
|
||||||
@ -163,13 +168,14 @@ submissionHelper tid ssh csh shn (SubmissionMode mcid) = do
|
|||||||
return (userName, submissionEdit E.^. SubmissionEditTime)
|
return (userName, submissionEdit E.^. SubmissionEditTime)
|
||||||
forM raw $ \(E.Value name, E.Value time) -> (name, ) <$> formatTime SelFormatDateTime time
|
forM raw $ \(E.Value name, E.Value time) -> (name, ) <$> formatTime SelFormatDateTime time
|
||||||
return (csheet,buddies,lastEdits)
|
return (csheet,buddies,lastEdits)
|
||||||
((res,formWidget), formEnctype) <- runFormPost $ makeSubmissionForm msmid sheetUploadMode sheetGrouping buddies
|
((res,formWidget), formEnctype) <- runFormPost $ makeSubmissionForm msmid sheetUploadMode sheetGrouping (userEmail userData :| buddies)
|
||||||
mCID <- runDBJobs $ do
|
mCID <- runDBJobs $ do
|
||||||
res' <- case res of
|
res' <- case res of
|
||||||
FormMissing -> return FormMissing
|
FormMissing -> return FormMissing
|
||||||
(FormFailure failmsgs) -> return $ FormFailure failmsgs
|
(FormFailure failmsgs) -> return $ FormFailure failmsgs
|
||||||
(FormSuccess (mFiles,[])) -> return $ FormSuccess (mFiles,[]) -- Type change
|
-- #227 Part II: no longer ignore submitter, if the user is lecturer or admin (allow lecturers to submit for their students)
|
||||||
(FormSuccess (mFiles,gEMails@(_:_))) -- Validate AdHoc Group Members
|
(FormSuccess (mFiles,_submitter:|[])) -> return $ FormSuccess (mFiles,[]) -- Type change
|
||||||
|
(FormSuccess (mFiles,_submitter:|gEMails@(_:_))) -- Validate AdHoc Group Members
|
||||||
| Arbitrary{..} <- sheetGrouping -> do
|
| Arbitrary{..} <- sheetGrouping -> do
|
||||||
-- , length gEMails < maxParticipants -> do -- < since submitting user is already accounted for
|
-- , length gEMails < maxParticipants -> do -- < since submitting user is already accounted for
|
||||||
let prep :: [(E.Value UserEmail, (E.Value UserId, E.Value Bool, E.Value Bool))] -> Map (CI Text) (Maybe (UserId, Bool, Bool))
|
let prep :: [(E.Value UserEmail, (E.Value UserId, E.Value Bool, E.Value Bool))] -> Map (CI Text) (Maybe (UserId, Bool, Bool))
|
||||||
|
|||||||
@ -7,6 +7,12 @@ import Import.NoFoundation
|
|||||||
lipsum :: WidgetT site IO ()
|
lipsum :: WidgetT site IO ()
|
||||||
lipsum = $(widgetFile "widgets/lipsum")
|
lipsum = $(widgetFile "widgets/lipsum")
|
||||||
|
|
||||||
|
modalParameter :: Text
|
||||||
|
modalParameter = "_modal"
|
||||||
|
|
||||||
|
siteModalId :: MonadHandler m => m (Maybe Text)
|
||||||
|
siteModalId = lookupGetParam modalParameter
|
||||||
|
|
||||||
modal :: WidgetT site IO () -> Either (Route site) (WidgetT site IO ()) -> WidgetT site IO ()
|
modal :: WidgetT site IO () -> Either (Route site) (WidgetT site IO ()) -> WidgetT site IO ()
|
||||||
modal modalTrigger modalContent = do
|
modal modalTrigger modalContent = do
|
||||||
let modalDynamic = isLeft modalContent
|
let modalDynamic = isLeft modalContent
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
<!-- navigation -->
|
$if not isModal
|
||||||
^{navbar}
|
<!-- navigation -->
|
||||||
|
^{navbar}
|
||||||
|
|
||||||
<div .main>
|
<div .main>
|
||||||
|
|
||||||
<!-- secondary navigation at the side -->
|
$if not isModal
|
||||||
^{asidenav}
|
<!-- secondary navigation at the side -->
|
||||||
|
^{asidenav}
|
||||||
|
|
||||||
<div .main__content>
|
<div .main__content>
|
||||||
|
|
||||||
<!-- breadcrumbs -->
|
$if not isModal
|
||||||
$if not $ Just HomeR == mcurrentRoute
|
<!-- breadcrumbs -->
|
||||||
^{breadcrumbsWgt}
|
$if not $ Just HomeR == mcurrentRoute
|
||||||
|
^{breadcrumbsWgt}
|
||||||
|
|
||||||
<div .main__content-body>
|
<div .main__content-body>
|
||||||
|
|
||||||
@ -20,17 +23,17 @@
|
|||||||
<a .breadcrumbs__link href="@{fst back}">#{snd back} -->
|
<a .breadcrumbs__link href="@{fst back}">#{snd back} -->
|
||||||
^{headline}
|
^{headline}
|
||||||
|
|
||||||
<!-- prime page actions -->
|
$if not isModal
|
||||||
^{pageactionprime}
|
<!-- prime page actions -->
|
||||||
|
^{pageactionprime}
|
||||||
|
|
||||||
<!-- alerts -->
|
<!-- alerts -->
|
||||||
<div .alerts>
|
<div .alerts>
|
||||||
$forall (status, msg) <- mmsgs
|
$forall (status, msg) <- mmsgs
|
||||||
$with status2 <- bool status "info" (status == "")
|
$with status2 <- bool status "info" (status == "")
|
||||||
<div class="alert alert-#{status2}">
|
<div class="alert alert-#{status2}">
|
||||||
<div .alert__content>
|
<div .alert__content>
|
||||||
#{msg}
|
#{msg}
|
||||||
|
|
||||||
<!-- actual content -->
|
<!-- actual content -->
|
||||||
|
|
||||||
^{widget}
|
^{widget}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
var overlay = document.createElement('div');
|
var overlay = document.createElement('div');
|
||||||
var closer = document.createElement('div');
|
var closer = document.createElement('div');
|
||||||
var trigger = document.querySelector('#' + modal.dataset.trigger);
|
var trigger = document.querySelector('#' + modal.dataset.trigger);
|
||||||
var origParent = modal.parentNode;
|
// var origParent = modal.parentNode;
|
||||||
|
|
||||||
function open(event) {
|
function open(event) {
|
||||||
// disable modals for narrow screens
|
// disable modals for narrow screens
|
||||||
@ -16,8 +16,8 @@
|
|||||||
}
|
}
|
||||||
modal.classList.add('modal--open');
|
modal.classList.add('modal--open');
|
||||||
overlay.classList.add('modal__overlay');
|
overlay.classList.add('modal__overlay');
|
||||||
document.body.insertBefore(modal, null);
|
// document.body.insertBefore(modal, null);
|
||||||
document.body.insertBefore(overlay, modal);
|
document.body.insertBefore(overlay, modal);
|
||||||
overlay.classList.add('modal__overlay--open');
|
overlay.classList.add('modal__overlay--open');
|
||||||
|
|
||||||
if (modal.dataset.closeable === 'true') {
|
if (modal.dataset.closeable === 'true') {
|
||||||
@ -39,13 +39,15 @@
|
|||||||
function close(event) {
|
function close(event) {
|
||||||
if (typeof event === 'undefined' || event.target === closer || event.target === overlay) {
|
if (typeof event === 'undefined' || event.target === closer || event.target === overlay) {
|
||||||
overlay.remove();
|
overlay.remove();
|
||||||
origParent.insertBefore(modal, null);
|
// origParent.insertBefore(modal, null);
|
||||||
modal.classList.remove('modal--open');
|
modal.classList.remove('modal--open');
|
||||||
closer.removeEventListener('click', close, false);
|
closer.removeEventListener('click', close, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
|
document.body.insertBefore(modal, null);
|
||||||
|
|
||||||
// every modal can be openend via document-wide event, see openOnEvent
|
// every modal can be openend via document-wide event, see openOnEvent
|
||||||
document.addEventListener('modal-open', openOnEvent, false);
|
document.addEventListener('modal-open', openOnEvent, false);
|
||||||
// if modal has trigger assigned to it open modal on click
|
// if modal has trigger assigned to it open modal on click
|
||||||
@ -55,24 +57,48 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (modal.dataset.dynamic === 'True') {
|
if (modal.dataset.dynamic === 'True') {
|
||||||
|
// var dynamicContentURL = trigger.getAttribute('href');
|
||||||
|
// console.log(dynamicContentURL);
|
||||||
|
// if (dynamicContentURL.length > 0) {
|
||||||
|
// fetch(dynamicContentURL, {
|
||||||
|
// credentials: 'same-origin',
|
||||||
|
// }).then(function(response) {
|
||||||
|
// return response.text();
|
||||||
|
// }).then(function(body) {
|
||||||
|
// var modalContent = document.createElement('div');
|
||||||
|
// modalContent.innerHTML = body;
|
||||||
|
// var main = modalContent.querySelector('.main__content-body');
|
||||||
|
// if (main) {
|
||||||
|
// modal.appendChild(main);
|
||||||
|
// } else {
|
||||||
|
// replaceMe.innerHTML = body;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
var dynamicContentURL = trigger.getAttribute('href');
|
var dynamicContentURL = trigger.getAttribute('href');
|
||||||
console.log(dynamicContentURL);
|
console.log(dynamicContentURL);
|
||||||
if (dynamicContentURL.length > 0) {
|
var frame = document.createElement('iframe');
|
||||||
fetch(dynamicContentURL, {
|
frame.setAttribute('id', "frame-" + modal.getAttribute('id'));
|
||||||
credentials: 'same-origin',
|
modal.insertBefore(frame, null);
|
||||||
}).then(function(response) {
|
|
||||||
return response.text();
|
frame.onload = function() {
|
||||||
}).then(function(body) {
|
frame.style.visibility = 'hidden';
|
||||||
var modalContent = document.createElement('div');
|
frame.style.height = '0';
|
||||||
modalContent.innerHTML = body;
|
|
||||||
var main = modalContent.querySelector('.main__content-body');
|
var doc = frame.contentDocument ? frame.contentDocument : frame.contentWindow.document;
|
||||||
if (main) {
|
var body = doc.body, html = doc.documentElement;
|
||||||
modal.appendChild(main);
|
var height = Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight );
|
||||||
} else {
|
|
||||||
replaceMe.innerHTML = body;
|
frame.style.height = "calc(" + (height + "px") + " + 1em)";
|
||||||
}
|
frame.style.visibility = 'visible';
|
||||||
});
|
|
||||||
|
doc.querySelectorAll("form").forEach(function(form) {
|
||||||
|
form.setAttribute("target", "_top");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame.setAttribute('src', dynamicContentURL + "?" + #{String modalParameter});
|
||||||
}
|
}
|
||||||
// tell further modals, that this one already got initialized
|
// tell further modals, that this one already got initialized
|
||||||
modal.classList.add('js-modal-initialized');
|
modal.classList.add('js-modal-initialized');
|
||||||
|
|||||||
@ -14,15 +14,23 @@
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
padding-right: 65px;
|
padding-right: 65px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
opacity: 0;
|
|
||||||
transition: all .15s ease;
|
transition: all .15s ease;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
&.modal--open {
|
&.modal--open {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
z-index: 200;
|
z-index: 200;
|
||||||
transform: translate(-50%, -50%) scale(1, 1);
|
transform: translate(-50%, -50%) scale(1, 1);
|
||||||
pointer-events: all;
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
height: calc(60vh);
|
||||||
|
width: 100%;
|
||||||
|
border-style: none;
|
||||||
|
scroll: auto;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,10 +58,11 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
opacity: 0;
|
|
||||||
transition: all .2s ease;
|
transition: all .2s ease;
|
||||||
|
display: none;
|
||||||
|
|
||||||
&.modal__overlay--open {
|
&.modal__overlay--open {
|
||||||
|
display: block;
|
||||||
z-index: 199;
|
z-index: 199;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
background-color: rgba(0, 0, 0, 0.4);
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
|||||||
Reference in New Issue
Block a user