Merge branch 'master' into staging
This commit is contained in:
commit
69c2e95d83
1
models
1
models
@ -12,6 +12,7 @@ User json
|
||||
UserAdmin
|
||||
user UserId
|
||||
school SchoolId
|
||||
UniqueUserAdmin user school
|
||||
UserLecturer
|
||||
user UserId
|
||||
school SchoolId
|
||||
|
||||
@ -459,7 +459,6 @@ instance Yesod UniWorX where
|
||||
defaultLayout widget = do
|
||||
master <- getYesod
|
||||
mmsgs <- getMessages
|
||||
messageRender <- getMessageRender -- needed, since there is no i18n interpolation in Julius
|
||||
|
||||
mcurrentRoute <- getCurrentRoute
|
||||
|
||||
@ -493,10 +492,10 @@ instance Yesod UniWorX where
|
||||
in (c, courseRoute, ) <$> filterM (menuItemAccessCallback . menuItem) (pageActions courseRoute)
|
||||
|
||||
let highlight :: Route UniWorX -> Bool -- highlight last route in breadcrumbs, favorites taking priority
|
||||
highlight = let crumbs = mcons mcurrentRoute $ fst <$> parents
|
||||
actFav = List.intersect (snd3 <$> favourites) crumbs
|
||||
highRs = if null actFav then crumbs else actFav
|
||||
in \r -> r `elem` highRs
|
||||
highlight = let crumbs = mcons mcurrentRoute $ fst <$> reverse parents
|
||||
navItems = map snd3 favourites ++ map (menuItemRoute . menuItem) menuTypes
|
||||
highR = find (`elem` navItems) . uncurry (++) $ partition (`elem` map snd3 favourites) crumbs
|
||||
in \r -> Just r == highR
|
||||
favouriteTerms :: [TermIdentifier]
|
||||
favouriteTerms = Set.toDescList $ foldMap (\(Course{..}, _, _) -> Set.singleton $ unTermKey courseTerm) favourites
|
||||
favouriteTerm :: TermIdentifier -> [(Course, Route UniWorX, [MenuTypes])]
|
||||
@ -655,7 +654,7 @@ submissionList tid csh shn uid = E.select . E.from $ \(course `E.InnerJoin` shee
|
||||
|
||||
defaultLinks :: [MenuTypes]
|
||||
defaultLinks = -- Define the menu items of the header.
|
||||
[ NavbarRight $ MenuItem
|
||||
[ NavbarAside $ MenuItem
|
||||
{ menuItemLabel = "Home"
|
||||
, menuItemIcon = Just "home"
|
||||
, menuItemRoute = HomeR
|
||||
|
||||
@ -13,6 +13,7 @@ import Import
|
||||
import Handler.Utils
|
||||
|
||||
import qualified Data.Map as Map
|
||||
import qualified Data.Set as Set
|
||||
|
||||
import qualified Database.Esqueleto as E
|
||||
|
||||
@ -41,7 +42,7 @@ getUsersR = do
|
||||
E.orderBy [E.asc $ school E.^. SchoolShorthand]
|
||||
return $ school E.^. SchoolShorthand
|
||||
return [whamlet|
|
||||
<ul>
|
||||
<ul .list--inline .list--comma-separated>
|
||||
$forall (E.Value sh) <- schools
|
||||
<li>#{sh}
|
||||
|]
|
||||
@ -54,7 +55,7 @@ getUsersR = do
|
||||
E.orderBy [E.asc $ school E.^. SchoolShorthand]
|
||||
return $ school E.^. SchoolShorthand
|
||||
return [whamlet|
|
||||
<ul>
|
||||
<ul .list--inline .list--comma-separated>
|
||||
$forall (E.Value sh) <- schools
|
||||
<li>#{sh}
|
||||
|]
|
||||
@ -95,7 +96,15 @@ postAdminHijackUserR cID = do
|
||||
case hijackRes of
|
||||
FormSuccess uid'
|
||||
| uid' == uid -> do
|
||||
User{..} <- runDB $ get404 uid
|
||||
myUid <- requireAuthId
|
||||
User{..} <- runDB $ do
|
||||
otherSchoolsAdmin <- Set.fromList . map (userAdminSchool . entityVal) <$> selectList [UserAdminUser ==. uid] []
|
||||
otherSchoolsLecturer <- Set.fromList . map (userLecturerSchool . entityVal) <$> selectList [UserLecturerUser ==. uid] []
|
||||
mySchools <- Set.fromList . map (userAdminSchool . entityVal) <$> selectList [UserAdminUser ==. myUid] []
|
||||
when (not $ (otherSchoolsAdmin `Set.union` otherSchoolsLecturer) `Set.isSubsetOf` mySchools) $
|
||||
permissionDenied "Cannot escalate admin status to additional schools"
|
||||
|
||||
get404 uid
|
||||
setCredsRedirect $ Creds "dummy" (userPlugin <> ":" <> userIdent) []
|
||||
| otherwise -> error "This should be impossible by definition of `hijackUserForm`"
|
||||
FormFailure errs -> toTypedContent <$> mapM_ (addMessage "error" . toHtml) errs
|
||||
|
||||
@ -8,10 +8,10 @@
|
||||
Der Handler sollte jeweils aktuelle Beispiele für alle möglichen Funktionalitäten enthalten, so dass man immer weiß, wo man nachschlagen kann.
|
||||
|
||||
|
||||
<div .container>
|
||||
<div .container.js-show-hide>
|
||||
<h2 .js-show-hide__toggle>Teilweise funktionierende Abschnitte
|
||||
|
||||
<ul>
|
||||
<ul .js-show-hide__target>
|
||||
<li .list-group-item>
|
||||
<a href=@{UsersR}>Benutzer Verwaltung
|
||||
|
||||
|
||||
@ -115,10 +115,6 @@ ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.list--inline > li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-weight: 600;
|
||||
}
|
||||
@ -214,14 +210,14 @@ h4 {
|
||||
@media (max-width: 768px) {
|
||||
|
||||
.main__content-body {
|
||||
padding: 0 20px 60px;
|
||||
padding: 30px 20px 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 425px) {
|
||||
|
||||
.main__content-body {
|
||||
padding: 0 10px 60px;
|
||||
padding: 20px 10px 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,6 +418,22 @@ input[type="button"].btn-info:hover,
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
/* LIST MODIFIERS */
|
||||
.list--inline > li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.list--comma-separated > li {
|
||||
|
||||
&::after {
|
||||
content: ', ';
|
||||
}
|
||||
|
||||
&:last-of-type::after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* DEFINITION LIST */
|
||||
.deflist {
|
||||
display: grid;
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
autoDecay = parseInt(dataDecay, 10);
|
||||
}
|
||||
closeEl.classList.add('alert__close');
|
||||
closeEl.innerText = #{String (messageRender MsgCloseAlert)};
|
||||
closeEl.addEventListener('click', function(event) {
|
||||
alertEl.classList.add('alert--invisible');
|
||||
});
|
||||
|
||||
@ -72,6 +72,7 @@
|
||||
|
||||
.alert {
|
||||
margin-left: 80px;
|
||||
max-width: 420px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,29 +8,45 @@
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
var elements = Array.from(document.querySelectorAll('.js-show-hide__toggle')),
|
||||
toggles = [];
|
||||
var LSNAME = 'SHOW_HIDE';
|
||||
|
||||
function addEventHandler(el) {
|
||||
el.addEventListener('click', function elClickListener() {
|
||||
var toggle = toggles[el.dataset.index];
|
||||
toggle.collapsed = !toggle.collapsed;
|
||||
toggle.parent.classList.toggle('js-show-hide--collapsed', toggle.collapsed);
|
||||
var newState = el.parentElement.classList.toggle('js-show-hide--collapsed');
|
||||
updateLSState(el.dataset.shIndex || null, newState);
|
||||
});
|
||||
}
|
||||
|
||||
elements.forEach(function(el, i) {
|
||||
el.dataset.index = i;
|
||||
var coll = el.dataset.collapsed === 'true';
|
||||
if (coll) {
|
||||
el.parentElement.classList.add('js-show-hide--collapsed')
|
||||
function updateLSState(index, state) {
|
||||
if (!index) {
|
||||
return false;
|
||||
}
|
||||
Array.from(el.parentElement.children).forEach(function(el) {
|
||||
if (!el.classList.contains('js-show-hide__toggle')) {
|
||||
el.classList.add('js-show-hide__target');
|
||||
}
|
||||
});
|
||||
toggles.push({index: i, collapsed: coll, parent: el.parentElement});
|
||||
addEventHandler(el);
|
||||
var lsData = fromLocalStorage();
|
||||
lsData[index] = state;
|
||||
window.localStorage.setItem(LSNAME, JSON.stringify(lsData));
|
||||
}
|
||||
|
||||
function collapsedStateInLocalStorage(index) {
|
||||
return fromLocalStorage()[index] || null;
|
||||
}
|
||||
|
||||
function fromLocalStorage() {
|
||||
return JSON.parse(window.localStorage.getItem(LSNAME)) || {};
|
||||
}
|
||||
|
||||
Array
|
||||
.from(document.querySelectorAll('.js-show-hide__toggle'))
|
||||
.forEach(function(el) {
|
||||
var index = el.dataset.shIndex || null;
|
||||
el.parentElement.classList.toggle(
|
||||
'js-show-hide--collapsed',
|
||||
collapsedStateInLocalStorage(index) || el.dataset.collapsed === 'true'
|
||||
);
|
||||
Array.from(el.parentElement.children).forEach(function(el) {
|
||||
if (!el.classList.contains('js-show-hide__toggle')) {
|
||||
el.classList.add('js-show-hide__target');
|
||||
}
|
||||
});
|
||||
addEventHandler(el);
|
||||
});
|
||||
});
|
||||
|
||||
@ -2,14 +2,14 @@ $newline never
|
||||
<aside .main__aside>
|
||||
<div .asidenav>
|
||||
$forall tid@TermIdentifier{..} <- favouriteTerms
|
||||
<div .asidenav__box>
|
||||
<h3 .asidenav__box-title.js-show-hide__toggle>
|
||||
<div .asidenav__box.js-show-hide>
|
||||
<h3 .asidenav__box-title.js-show-hide__toggle data-sh-index="#{display season}-#{year}">
|
||||
$case season
|
||||
$of Winter
|
||||
_{MsgWinterTermShort year}
|
||||
$of Summer
|
||||
_{MsgSummerTermShort year}
|
||||
<ul .asidenav__list>
|
||||
<ul .asidenav__list.js-show-hide__target>
|
||||
$forall (Course{..}, courseRoute, pageActions) <- favouriteTerm tid
|
||||
<li .asidenav__list-item :highlight courseRoute:.asidenav__list-item--active>
|
||||
<a .asidenav__link-wrapper href=@{courseRoute}>
|
||||
|
||||
@ -19,15 +19,21 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
var asidenavEl = document.querySelector('.main__aside');
|
||||
var mainEl = document.querySelector('.main__content');
|
||||
var mainContentEl = document.querySelector('.main__content');
|
||||
|
||||
asidenavEl.style.height = `${mainEl.clientHeight + 75}px`;
|
||||
|
||||
window.addEventListener('resize', function() {
|
||||
function adjustHeight() {
|
||||
window.requestAnimationFrame(function() {
|
||||
asidenavEl.style.height = `${mainEl.clientHeight + 75}px`;
|
||||
asidenavEl.style.height = mainContentEl.clientHeight + 'px';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// unbeknownst to the user (below the fold), this happes slightly delayed
|
||||
// because of dynamic changes to the styles inside the main__content
|
||||
setTimeout(function() {
|
||||
adjustHeight();
|
||||
}, 10);
|
||||
|
||||
window.addEventListener('resize', adjustHeight);
|
||||
|
||||
window.utils.aside(asidenavEl);
|
||||
|
||||
|
||||
@ -16,6 +16,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
.main__aside {
|
||||
min-height: calc(100% - var(--header-height-collapsed));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 425px) {
|
||||
|
||||
.main__aside {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user