parent
02e8825cba
commit
3820b45b3e
@ -3,44 +3,41 @@ import { Utility } from '../../core/utility';
|
|||||||
const FORM_ERROR_REMOVER_INITIALIZED_CLASS = 'form-error-remover--initialized';
|
const FORM_ERROR_REMOVER_INITIALIZED_CLASS = 'form-error-remover--initialized';
|
||||||
const FORM_ERROR_REMOVER_INPUTS_SELECTOR = 'input:not([type="hidden"]), textarea, select';
|
const FORM_ERROR_REMOVER_INPUTS_SELECTOR = 'input:not([type="hidden"]), textarea, select';
|
||||||
|
|
||||||
const FORM_GROUP_SELECTOR = '.form-group';
|
const FORM_GROUP_WITH_ERRORS_CLASSES = ['form-group--has-error', 'standalone-field--has-error'];
|
||||||
const FORM_GROUP_WITH_ERRORS_CLASS = 'form-group--has-error';
|
const FORM_GROUP_SELECTOR = FORM_GROUP_WITH_ERRORS_CLASSES.map(c => '.' + c).join(', ');
|
||||||
|
|
||||||
@Utility({
|
@Utility({
|
||||||
selector: 'form',
|
selector: FORM_GROUP_SELECTOR,
|
||||||
})
|
})
|
||||||
export class FormErrorRemover {
|
export class FormErrorRemover {
|
||||||
|
|
||||||
|
_element;
|
||||||
|
|
||||||
constructor(element) {
|
constructor(element) {
|
||||||
if (!element) {
|
if (!element)
|
||||||
throw new Error('Form Error Remover utility needs to be passed an element!');
|
throw new Error('Form Error Remover utility needs to be passed an element!');
|
||||||
}
|
|
||||||
|
|
||||||
if (element.classList.contains(FORM_ERROR_REMOVER_INITIALIZED_CLASS)) {
|
if (element.classList.contains(FORM_ERROR_REMOVER_INITIALIZED_CLASS))
|
||||||
return false;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// find form groups
|
if (FORM_GROUP_WITH_ERRORS_CLASSES.every(c => !element.classList.contains(c)))
|
||||||
const formGroups = Array.from(element.querySelectorAll(FORM_GROUP_SELECTOR));
|
return;
|
||||||
|
|
||||||
formGroups.forEach((formGroup) => {
|
this._element = element;
|
||||||
if (!formGroup.classList.contains(FORM_GROUP_WITH_ERRORS_CLASS)) {
|
|
||||||
return;
|
this._element.classList.add(FORM_ERROR_REMOVER_INITIALIZED_CLASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputElements = Array.from(formGroup.querySelectorAll(FORM_ERROR_REMOVER_INPUTS_SELECTOR));
|
start() {
|
||||||
if (!inputElements) {
|
if (!this._element)
|
||||||
return false;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
inputElements.forEach((inputElement) => {
|
const inputElements = Array.from(this._element.querySelectorAll(FORM_ERROR_REMOVER_INPUTS_SELECTOR));
|
||||||
inputElement.addEventListener('input', () => {
|
|
||||||
formGroup.classList.remove(FORM_GROUP_WITH_ERRORS_CLASS);
|
inputElements.forEach((inputElement) => {
|
||||||
});
|
inputElement.addEventListener('input', () => {
|
||||||
|
FORM_GROUP_WITH_ERRORS_CLASSES.forEach(c => { this._element.classList.remove(c); });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// mark initialized
|
|
||||||
element.classList.add(FORM_ERROR_REMOVER_INITIALIZED_CLASS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,10 +78,32 @@
|
|||||||
font-weight: 600
|
font-weight: 600
|
||||||
color: var(--color-error)
|
color: var(--color-error)
|
||||||
margin: 7px 0
|
margin: 7px 0
|
||||||
|
white-space: pre-wrap
|
||||||
|
|
||||||
.form-error
|
.form-error
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
|
.standalone-field
|
||||||
|
display: inline-flex
|
||||||
|
|
||||||
|
&__error
|
||||||
|
display: none
|
||||||
|
align-self: center
|
||||||
|
flex: 0 0 auto
|
||||||
|
|
||||||
|
.tooltip__content
|
||||||
|
font-weight: 600
|
||||||
|
color: var(--color-error)
|
||||||
|
white-space: pre-wrap
|
||||||
|
|
||||||
|
&--has-error
|
||||||
|
input, textarea
|
||||||
|
border-color: var(--color-error) !important
|
||||||
|
|
||||||
|
.standalone-field__error
|
||||||
|
display: block
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 768px)
|
@media (max-width: 768px)
|
||||||
.form-group
|
.form-group
|
||||||
grid-template-columns: 1fr
|
grid-template-columns: 1fr
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
CampusIdentPlaceholder: Vorname.Nachname@campus.lmu.de
|
CampusIdentPlaceholder: Vorname.Nachname@campus.lmu.de
|
||||||
CampusIdent: Campus-Kennung
|
CampusIdent: Campus-Kennung
|
||||||
CampusPassword: Passwort
|
CampusPassword: Passwort
|
||||||
CampusPasswordPlaceholder: Passwort
|
CampusPasswordPlaceholder: Passwort
|
||||||
CampusSubmit: Abschicken
|
|
||||||
CampusInvalidCredentials: Ungültige Logindaten
|
|
||||||
@ -1,6 +1,4 @@
|
|||||||
CampusIdentPlaceholder: First.Last@campus.lmu.de
|
CampusIdentPlaceholder: First.Last@campus.lmu.de
|
||||||
CampusIdent: Campus account
|
CampusIdent: Campus account
|
||||||
CampusPassword: Password
|
CampusPassword: Password
|
||||||
CampusPasswordPlaceholder: Password
|
CampusPasswordPlaceholder: Password
|
||||||
CampusSubmit: Send
|
|
||||||
CampusInvalidCredentials: Invalid login
|
|
||||||
@ -91,6 +91,7 @@ TermEndDay: Letzter Tag
|
|||||||
TermEndDayTooltip: Üblicherweise immer 30. September oder 31. März
|
TermEndDayTooltip: Üblicherweise immer 30. September oder 31. März
|
||||||
TermHolidays: Feiertage
|
TermHolidays: Feiertage
|
||||||
TermHolidayPlaceholder: Feiertag
|
TermHolidayPlaceholder: Feiertag
|
||||||
|
TermHolidayMissing: Feiertag wird benötigt
|
||||||
TermLectureStart: Beginn Vorlesungen
|
TermLectureStart: Beginn Vorlesungen
|
||||||
TermLectureEnd: Ende Vorlesungen
|
TermLectureEnd: Ende Vorlesungen
|
||||||
TermLectureEndTooltip: Meistens dauer das Sommersemester 14 Wochen und das Wintersemester 15 Wochen.
|
TermLectureEndTooltip: Meistens dauer das Sommersemester 14 Wochen und das Wintersemester 15 Wochen.
|
||||||
@ -257,6 +258,7 @@ CourseFormSectionRegistration: Anmeldung zum Kurs
|
|||||||
CourseFormSectionAdministration: Verwaltung
|
CourseFormSectionAdministration: Verwaltung
|
||||||
|
|
||||||
CourseLecturers: Kursverwalter
|
CourseLecturers: Kursverwalter
|
||||||
|
CourseLecturerEmail: E-Mail
|
||||||
CourseLecturer: Dozent
|
CourseLecturer: Dozent
|
||||||
CourseAssistant: Assistent
|
CourseAssistant: Assistent
|
||||||
CourseLecturerAlreadyAdded: Dieser Nutzer ist bereits als Kursverwalter eingetragen
|
CourseLecturerAlreadyAdded: Dieser Nutzer ist bereits als Kursverwalter eingetragen
|
||||||
@ -775,6 +777,8 @@ CampusUserInvalidSex: Konnte anhand des Campus-Logins kein Geschlecht ermitteln
|
|||||||
CorrectorNormal: Normal
|
CorrectorNormal: Normal
|
||||||
CorrectorMissing: Abwesend
|
CorrectorMissing: Abwesend
|
||||||
CorrectorExcused: Entschuldigt
|
CorrectorExcused: Entschuldigt
|
||||||
|
SheetCorrectorState: Status
|
||||||
|
SheetCorrectorProportion: Anteil
|
||||||
CorrectorStateTip: Abwesende Korrektoren bekommen bei späteren Übungsblättern mehr Korrekturen zum Ausgleich zugewiesen. Entschuldigte Korrektoren müssen nicht nacharbeiten.
|
CorrectorStateTip: Abwesende Korrektoren bekommen bei späteren Übungsblättern mehr Korrekturen zum Ausgleich zugewiesen. Entschuldigte Korrektoren müssen nicht nacharbeiten.
|
||||||
|
|
||||||
DayIsAHoliday tid@TermId name@Text date@Text: "#{name}" (#{date}) ist ein Feiertag
|
DayIsAHoliday tid@TermId name@Text date@Text: "#{name}" (#{date}) ist ein Feiertag
|
||||||
@ -843,6 +847,7 @@ NoStudyField: Kein Studienfach
|
|||||||
StudyFeatureType:
|
StudyFeatureType:
|
||||||
StudyFeatureValid: Aktiv
|
StudyFeatureValid: Aktiv
|
||||||
StudyFeatureUpdate: Abgeglichen
|
StudyFeatureUpdate: Abgeglichen
|
||||||
|
StudyTermsParentMissing: Elter wird benötigt
|
||||||
|
|
||||||
DegreeKey: Abschlussschlüssel
|
DegreeKey: Abschlussschlüssel
|
||||||
DegreeName: Abschluss
|
DegreeName: Abschluss
|
||||||
@ -1510,6 +1515,7 @@ SubmissionUserInviteExplanation: Sie wurden eingeladen, Mitabgebende(r) bei eine
|
|||||||
ExamOfficeUserInviteHeading displayName@Text: Zugriff auf Ihre Prüfungsleistungen durch #{displayName}
|
ExamOfficeUserInviteHeading displayName@Text: Zugriff auf Ihre Prüfungsleistungen durch #{displayName}
|
||||||
ExamOfficeUserInviteExplanation: Um Ihre Prüfungsleistungen ordnungsgemäß anrechnen zu können (z.B. im finalen Transcript of Records für Erasmus-Studierende) werden sie eingeladen der hierfür zuständigen Stelle Einsicht zu gewähren.
|
ExamOfficeUserInviteExplanation: Um Ihre Prüfungsleistungen ordnungsgemäß anrechnen zu können (z.B. im finalen Transcript of Records für Erasmus-Studierende) werden sie eingeladen der hierfür zuständigen Stelle Einsicht zu gewähren.
|
||||||
ExamOfficeUserInvitationAccepted: Einsicht erfolgreich gewährt
|
ExamOfficeUserInvitationAccepted: Einsicht erfolgreich gewährt
|
||||||
|
ExamOfficeUserEmail: E-Mail
|
||||||
|
|
||||||
InvitationAction: Aktion
|
InvitationAction: Aktion
|
||||||
InvitationActionTip: Abgelehnte Einladungen können nicht mehr angenommen werden
|
InvitationActionTip: Abgelehnte Einladungen können nicht mehr angenommen werden
|
||||||
@ -1576,6 +1582,7 @@ TutorialRegGroupTip: Studenten können sich in jeweils maximal einem Tutorium pr
|
|||||||
TutorialRoomPlaceholder: Raum
|
TutorialRoomPlaceholder: Raum
|
||||||
TutorialTutors: Tutoren
|
TutorialTutors: Tutoren
|
||||||
TutorialTutorAlreadyAdded: Ein Tutor mit dieser E-Mail ist bereits für dieses Tutorium eingetragen
|
TutorialTutorAlreadyAdded: Ein Tutor mit dieser E-Mail ist bereits für dieses Tutorium eingetragen
|
||||||
|
TutorEmail: E-Mail
|
||||||
|
|
||||||
OccurrenceNoneScheduled: (Noch) keine planmäßigen Termine
|
OccurrenceNoneScheduled: (Noch) keine planmäßigen Termine
|
||||||
OccurrenceNoneExceptions: (Noch) keine Termin-Ausnahmen
|
OccurrenceNoneExceptions: (Noch) keine Termin-Ausnahmen
|
||||||
@ -1701,6 +1708,7 @@ ExamNoSuchOccurrence: Termin/Raum existiert nicht (mehr)
|
|||||||
ExamOccurrences: Termine
|
ExamOccurrences: Termine
|
||||||
ExamRooms: Räume
|
ExamRooms: Räume
|
||||||
ExamTimes: Termine
|
ExamTimes: Termine
|
||||||
|
ExamRoomRoom: Raum
|
||||||
ExamRoomAlreadyExists: Prüfung ist bereits eingetragen
|
ExamRoomAlreadyExists: Prüfung ist bereits eingetragen
|
||||||
ExamRoomName: Interne Bezeichnung
|
ExamRoomName: Interne Bezeichnung
|
||||||
ExamRoomCapacity: Kapazität
|
ExamRoomCapacity: Kapazität
|
||||||
@ -1724,6 +1732,7 @@ ExamFormParts: Teile
|
|||||||
ExamCorrectors: Korrektoren
|
ExamCorrectors: Korrektoren
|
||||||
ExamCorrectorsTip: Hier eingetragene Korrektoren können zwischen Beginn der Prüfung und "Bewertung abgeschlossen ab" Ergebnisse für alle Teilprüfungen und alle Teilnehmer im System hinterlegen.
|
ExamCorrectorsTip: Hier eingetragene Korrektoren können zwischen Beginn der Prüfung und "Bewertung abgeschlossen ab" Ergebnisse für alle Teilprüfungen und alle Teilnehmer im System hinterlegen.
|
||||||
ExamCorrectorAlreadyAdded: Ein Korrektor mit dieser E-Mail ist bereits für diese Prüfung eingetragen
|
ExamCorrectorAlreadyAdded: Ein Korrektor mit dieser E-Mail ist bereits für diese Prüfung eingetragen
|
||||||
|
ExamCorrectorEmail: E-Mail
|
||||||
|
|
||||||
ExamPart: Teilprüfung/Aufgabe
|
ExamPart: Teilprüfung/Aufgabe
|
||||||
ExamParts: Teilprüfungen/Aufgaben
|
ExamParts: Teilprüfungen/Aufgaben
|
||||||
@ -2109,6 +2118,7 @@ SchoolShort: Kürzel
|
|||||||
SchoolName: Name
|
SchoolName: Name
|
||||||
SchoolLdapOrganisations: Assoziierte LDAP-Fragmente
|
SchoolLdapOrganisations: Assoziierte LDAP-Fragmente
|
||||||
SchoolLdapOrganisationsTip: Beim Login via LDAP werden dem Nutzer alle Institute zugeordnet deren assoziierte LDAP-Fragmente im Eintrag des Nutzer gefunden werden
|
SchoolLdapOrganisationsTip: Beim Login via LDAP werden dem Nutzer alle Institute zugeordnet deren assoziierte LDAP-Fragmente im Eintrag des Nutzer gefunden werden
|
||||||
|
SchoolLdapOrganisationMissing: LDAP-Fragment wird benötigt
|
||||||
|
|
||||||
SchoolUpdated ssh@SchoolId: #{ssh} erfolgreich angepasst
|
SchoolUpdated ssh@SchoolId: #{ssh} erfolgreich angepasst
|
||||||
SchoolTitle ssh@SchoolId: Institut „#{ssh}“
|
SchoolTitle ssh@SchoolId: Institut „#{ssh}“
|
||||||
@ -2428,6 +2438,7 @@ ExternalExamExamOfficeSchoolsTip: Prüfungsbeauftragte von Instituten, die Sie h
|
|||||||
ExternalExamStaff: Assoziierte Personen
|
ExternalExamStaff: Assoziierte Personen
|
||||||
ExternalExamStaffTip: Assoziierte Personen werden den Prüfungsbeauftragten und Teilnehmern angezeigt und dürfen Leistungen für die Prüfung hinterlegen.
|
ExternalExamStaffTip: Assoziierte Personen werden den Prüfungsbeauftragten und Teilnehmern angezeigt und dürfen Leistungen für die Prüfung hinterlegen.
|
||||||
ExternalExamStaffAlreadyAdded: Person wurde bereits der Prüfung hinzugefügt
|
ExternalExamStaffAlreadyAdded: Person wurde bereits der Prüfung hinzugefügt
|
||||||
|
ExternalExamStaffEmail: E-Mail
|
||||||
ExternalExamUserMustBeStaff: Sie selbst müssen stets assoziierte Person sein, für die externen Prüfungen, die Sie anlegen
|
ExternalExamUserMustBeStaff: Sie selbst müssen stets assoziierte Person sein, für die externen Prüfungen, die Sie anlegen
|
||||||
ExternalExamCourseExists: Der angegebene Kurs existiert im System. Prüfungen sollten daher direkt beim Kurs (statt extern) hinterlegt werden.
|
ExternalExamCourseExists: Der angegebene Kurs existiert im System. Prüfungen sollten daher direkt beim Kurs (statt extern) hinterlegt werden.
|
||||||
ExternalExamExists coursen@CourseName examn@ExamName: Prüfung „#{examn}“ für Kurs „#{coursen}“ existiert bereits.
|
ExternalExamExists coursen@CourseName examn@ExamName: Prüfung „#{examn}“ für Kurs „#{coursen}“ existiert bereits.
|
||||||
@ -2530,13 +2541,17 @@ CourseOption tid@TermId ssh@SchoolId coursen@CourseName: #{tid} - #{ssh} - #{cou
|
|||||||
BearerTokenUsageWarning: Mit diesem Interface können quesi beliebige Rechte als Tokens kodiert und somit ohne wesentliche weitere Beschränkung frei übertragen werden. Benutzen Sie dieses Interface nur, wenn Sie von einem erfahrenen Entwickler über die Auswirkungen des konkreten Tokens, dass sie ausstellen möchten, beraten wurden!
|
BearerTokenUsageWarning: Mit diesem Interface können quesi beliebige Rechte als Tokens kodiert und somit ohne wesentliche weitere Beschränkung frei übertragen werden. Benutzen Sie dieses Interface nur, wenn Sie von einem erfahrenen Entwickler über die Auswirkungen des konkreten Tokens, dass sie ausstellen möchten, beraten wurden!
|
||||||
BearerTokenAuthorityGroups: Token-Authorität (Gruppen)
|
BearerTokenAuthorityGroups: Token-Authorität (Gruppen)
|
||||||
BearerTokenAuthorityGroupsTip: Die primären Benutzer aller angegebenen Gruppen müssen Zugriff auf eine Route haben, damit das Token den Zugriff auf diese Route erlaubt.
|
BearerTokenAuthorityGroupsTip: Die primären Benutzer aller angegebenen Gruppen müssen Zugriff auf eine Route haben, damit das Token den Zugriff auf diese Route erlaubt.
|
||||||
|
BearerTokenAuthorityGroupMissing: Gruppe wird benötigt
|
||||||
BearerTokenAuthorityUsers: Token-Authorität (Benutzer)
|
BearerTokenAuthorityUsers: Token-Authorität (Benutzer)
|
||||||
BearerTokenAuthorityUsersTip: Alle angegebenen Benutzer müssen Zugriff auf eine Route haben, damit das Token den Zugriff auf diese Route erlaubt. Der Aussteller muss, bei mit diesem Benutzerinterface erzeugten Tokens, auch Zugriff auf die Route haben (er wird automatisch der Menge von Token-Authoritäten hinzugefügt).
|
BearerTokenAuthorityUsersTip: Alle angegebenen Benutzer müssen Zugriff auf eine Route haben, damit das Token den Zugriff auf diese Route erlaubt. Der Aussteller muss, bei mit diesem Benutzerinterface erzeugten Tokens, auch Zugriff auf die Route haben (er wird automatisch der Menge von Token-Authoritäten hinzugefügt).
|
||||||
BearerTokenAuthorityUnknownUser email@UserEmail: Ein Nutzer mit E-Mail #{email} ist dem System nicht bekannt
|
BearerTokenAuthorityUnknownUser email@UserEmail: Ein Nutzer mit E-Mail #{email} ist dem System nicht bekannt
|
||||||
BearerTokenRoutes: Erlaubte Routen
|
BearerTokenRoutes: Erlaubte Routen
|
||||||
BearerTokenRoutesTip: Wenn die Token-Validität nach Routen eingeschränkt und keine Routen angegeben werden, ist das Token nirgends gültig.
|
BearerTokenRoutesTip: Wenn die Token-Validität nach Routen eingeschränkt und keine Routen angegeben werden, ist das Token nirgends gültig.
|
||||||
|
BearerTokenRouteMissing: Route wird benötigt
|
||||||
BearerTokenRestrictions: Routen-spezifische Einschränkungen
|
BearerTokenRestrictions: Routen-spezifische Einschränkungen
|
||||||
BearerTokenRestrictRoutes: Token-Validität nach Routen einschränken
|
BearerTokenRestrictRoutes: Token-Validität nach Routen einschränken
|
||||||
|
BearerTokenRestrictRoute: Route
|
||||||
|
BearerTokenRestrictValue: Einschränkung
|
||||||
BearerTokenAdditionalAuth: Zusätzliche Authorisierung
|
BearerTokenAdditionalAuth: Zusätzliche Authorisierung
|
||||||
BearerTokenAdditionalAuthTip: Wird hier nichts angegeben, werden keine Einschränkungen daran gesetzt, wer das Token verwenden kann. Es reicht dann der Besitz.
|
BearerTokenAdditionalAuthTip: Wird hier nichts angegeben, werden keine Einschränkungen daran gesetzt, wer das Token verwenden kann. Es reicht dann der Besitz.
|
||||||
BearerTokenOverrideExpiration: Ablaufzeitpunkt überschreiben
|
BearerTokenOverrideExpiration: Ablaufzeitpunkt überschreiben
|
||||||
@ -2564,4 +2579,7 @@ TestDownloadMaxSize: Maximale Dateigröße
|
|||||||
TestDownloadMode: Modus
|
TestDownloadMode: Modus
|
||||||
TestDownloadDirect: Direkte Generierung
|
TestDownloadDirect: Direkte Generierung
|
||||||
TestDownloadInTransaction: Generierung während Datenbank-Transaktion
|
TestDownloadInTransaction: Generierung während Datenbank-Transaktion
|
||||||
TestDownloadFromDatabase: Generierung während Download aus Datenbank
|
TestDownloadFromDatabase: Generierung während Download aus Datenbank
|
||||||
|
|
||||||
|
ValueRequiredLabeledSimple fieldLabel@Text: #{fieldLabel} wird benötigt
|
||||||
|
ValueRequiredLabeledMultiWord fieldLabel@Text: „#{fieldLabel}“ wird benötigt
|
||||||
@ -2563,3 +2563,6 @@ TestDownloadMode: Mode
|
|||||||
TestDownloadDirect: Direct generation
|
TestDownloadDirect: Direct generation
|
||||||
TestDownloadInTransaction: Generate during database transaction
|
TestDownloadInTransaction: Generate during database transaction
|
||||||
TestDownloadFromDatabase: Generate while streaming from database
|
TestDownloadFromDatabase: Generate while streaming from database
|
||||||
|
|
||||||
|
ValueRequiredLabeledSimple fieldLabel: #{fieldLabel} is required
|
||||||
|
ValueRequiredLabeledMultiWord fieldLabel: “#{fieldLabel}” is required
|
||||||
@ -18,14 +18,15 @@ data DummyMessage = MsgDummyIdent
|
|||||||
|
|
||||||
|
|
||||||
dummyForm :: ( RenderMessage (HandlerSite m) FormMessage
|
dummyForm :: ( RenderMessage (HandlerSite m) FormMessage
|
||||||
|
, RenderMessage (HandlerSite m) (ValueRequired (HandlerSite m))
|
||||||
, RenderMessage (HandlerSite m) DummyMessage
|
, RenderMessage (HandlerSite m) DummyMessage
|
||||||
, YesodPersist (HandlerSite m)
|
, YesodPersist (HandlerSite m)
|
||||||
, SqlBackendCanRead (YesodPersistBackend (HandlerSite m))
|
, SqlBackendCanRead (YesodPersistBackend (HandlerSite m))
|
||||||
, MonadHandler m
|
, MonadHandler m
|
||||||
) => AForm m (CI Text)
|
) => WForm m (FormResult (CI Text))
|
||||||
dummyForm = wFormToAForm $ do
|
dummyForm = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
aFormToWForm $ areq (ciField & addDatalist userList) (fslpI MsgDummyIdent (mr MsgDummyIdentPlaceholder) & noAutocomplete & addName PostLoginDummy) Nothing
|
wreq (ciField & addDatalist userList) (fslpI MsgDummyIdent (mr MsgDummyIdentPlaceholder) & noAutocomplete & addName PostLoginDummy) Nothing
|
||||||
where
|
where
|
||||||
userList = fmap mkOptionList . runDB $ withReaderT projectBackend (map toOption <$> selectList [] [Asc UserIdent] :: ReaderT SqlBackend _ [Option UserIdent])
|
userList = fmap mkOptionList . runDB $ withReaderT projectBackend (map toOption <$> selectList [] [Asc UserIdent] :: ReaderT SqlBackend _ [Option UserIdent])
|
||||||
toOption (Entity _ User{..}) = Option userDisplayName userIdent (CI.original userIdent)
|
toOption (Entity _ User{..}) = Option userDisplayName userIdent (CI.original userIdent)
|
||||||
@ -36,6 +37,7 @@ dummyLogin :: forall site.
|
|||||||
, SqlBackendCanRead (YesodPersistBackend site)
|
, SqlBackendCanRead (YesodPersistBackend site)
|
||||||
, RenderMessage site AFormMessage
|
, RenderMessage site AFormMessage
|
||||||
, RenderMessage site DummyMessage
|
, RenderMessage site DummyMessage
|
||||||
|
, RenderMessage site (ValueRequired site)
|
||||||
, Button site ButtonSubmit
|
, Button site ButtonSubmit
|
||||||
) => AuthPlugin site
|
) => AuthPlugin site
|
||||||
dummyLogin = AuthPlugin{..}
|
dummyLogin = AuthPlugin{..}
|
||||||
@ -44,8 +46,8 @@ dummyLogin = AuthPlugin{..}
|
|||||||
apName = "dummy"
|
apName = "dummy"
|
||||||
|
|
||||||
apDispatch :: forall m. MonadAuthHandler site m => Text -> [Text] -> m TypedContent
|
apDispatch :: forall m. MonadAuthHandler site m => Text -> [Text] -> m TypedContent
|
||||||
apDispatch "POST" [] = liftSubHandler $ do
|
apDispatch method [] | encodeUtf8 method == methodPost = liftSubHandler $ do
|
||||||
((loginRes, _), _) <- runFormPost $ renderAForm FormStandard dummyForm
|
((loginRes, _), _) <- runFormPost $ renderWForm FormStandard dummyForm
|
||||||
tp <- getRouteToParent
|
tp <- getRouteToParent
|
||||||
case loginRes of
|
case loginRes of
|
||||||
FormFailure errs -> do
|
FormFailure errs -> do
|
||||||
@ -55,15 +57,16 @@ dummyLogin = AuthPlugin{..}
|
|||||||
addMessageI Warning MsgDummyNoFormData
|
addMessageI Warning MsgDummyNoFormData
|
||||||
redirect $ tp LoginR
|
redirect $ tp LoginR
|
||||||
FormSuccess ident ->
|
FormSuccess ident ->
|
||||||
setCredsRedirect $ Creds "dummy" (CI.original ident) []
|
setCredsRedirect $ Creds apName (CI.original ident) []
|
||||||
|
apDispatch _ [] = badMethod
|
||||||
apDispatch _ _ = notFound
|
apDispatch _ _ = notFound
|
||||||
|
|
||||||
apLogin :: (Route Auth -> Route site) -> WidgetFor site ()
|
apLogin :: (Route Auth -> Route site) -> WidgetFor site ()
|
||||||
apLogin toMaster = do
|
apLogin toMaster = do
|
||||||
(login, loginEnctype) <- handlerToWidget . generateFormPost $ renderAForm FormStandard dummyForm
|
(login, loginEnctype) <- handlerToWidget . generateFormPost $ renderWForm FormStandard dummyForm
|
||||||
let loginForm = wrapForm login FormSettings
|
let loginForm = wrapForm login FormSettings
|
||||||
{ formMethod = POST
|
{ formMethod = POST
|
||||||
, formAction = Just . SomeRoute . toMaster $ PluginR "dummy" []
|
, formAction = Just . SomeRoute . toMaster $ PluginR apName []
|
||||||
, formEncoding = loginEnctype
|
, formEncoding = loginEnctype
|
||||||
, formAttrs = [("uw-no-navigate-away-prompt","")]
|
, formAttrs = [("uw-no-navigate-away-prompt","")]
|
||||||
, formSubmit = FormSubmit
|
, formSubmit = FormSubmit
|
||||||
|
|||||||
@ -34,8 +34,6 @@ data CampusMessage = MsgCampusIdentPlaceholder
|
|||||||
| MsgCampusIdent
|
| MsgCampusIdent
|
||||||
| MsgCampusPassword
|
| MsgCampusPassword
|
||||||
| MsgCampusPasswordPlaceholder
|
| MsgCampusPasswordPlaceholder
|
||||||
| MsgCampusSubmit
|
|
||||||
| MsgCampusInvalidCredentials
|
|
||||||
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
|
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
|
||||||
|
|
||||||
|
|
||||||
@ -152,18 +150,15 @@ campusUserMatr' pool mode
|
|||||||
|
|
||||||
|
|
||||||
campusForm :: ( RenderMessage (HandlerSite m) FormMessage
|
campusForm :: ( RenderMessage (HandlerSite m) FormMessage
|
||||||
|
, RenderMessage (HandlerSite m) (ValueRequired (HandlerSite m))
|
||||||
, RenderMessage (HandlerSite m) CampusMessage
|
, RenderMessage (HandlerSite m) CampusMessage
|
||||||
, MonadHandler m
|
, MonadHandler m
|
||||||
) => WForm m (FormResult CampusLogin)
|
) => WForm m (FormResult CampusLogin)
|
||||||
campusForm = do
|
campusForm = do
|
||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
|
aFormToWForm $ CampusLogin
|
||||||
ident <- wreq ciField (fslpI MsgCampusIdent (mr MsgCampusIdentPlaceholder) & addAttr "autofocus" "") Nothing
|
<$> areq ciField (fslpI MsgCampusIdent (mr MsgCampusIdentPlaceholder) & addAttr "autofocus" "") Nothing
|
||||||
password <- wreq passwordField (fslpI MsgCampusPassword (mr MsgCampusPasswordPlaceholder)) Nothing
|
<*> areq passwordField (fslpI MsgCampusPassword (mr MsgCampusPasswordPlaceholder)) Nothing
|
||||||
|
|
||||||
return $ CampusLogin
|
|
||||||
<$> ident
|
|
||||||
<*> password
|
|
||||||
|
|
||||||
apLdap :: Text
|
apLdap :: Text
|
||||||
apLdap = "LDAP"
|
apLdap = "LDAP"
|
||||||
@ -172,6 +167,7 @@ campusLogin :: forall site.
|
|||||||
( YesodAuth site
|
( YesodAuth site
|
||||||
, RenderMessage site CampusMessage
|
, RenderMessage site CampusMessage
|
||||||
, RenderMessage site AFormMessage
|
, RenderMessage site AFormMessage
|
||||||
|
, RenderMessage site (ValueRequired site)
|
||||||
, Button site ButtonSubmit
|
, Button site ButtonSubmit
|
||||||
) => Failover (LdapConf, LdapPool) -> FailoverMode -> AuthPlugin site
|
) => Failover (LdapConf, LdapPool) -> FailoverMode -> AuthPlugin site
|
||||||
campusLogin pool mode = AuthPlugin{..}
|
campusLogin pool mode = AuthPlugin{..}
|
||||||
@ -180,38 +176,37 @@ campusLogin pool mode = AuthPlugin{..}
|
|||||||
apName = apLdap
|
apName = apLdap
|
||||||
|
|
||||||
apDispatch :: forall m. MonadAuthHandler site m => Text -> [Text] -> m TypedContent
|
apDispatch :: forall m. MonadAuthHandler site m => Text -> [Text] -> m TypedContent
|
||||||
apDispatch "POST" [] = liftSubHandler $ do
|
apDispatch method [] | encodeUtf8 method == methodPost = liftSubHandler $ do
|
||||||
((loginRes, _), _) <- runFormPost $ renderWForm FormStandard campusForm
|
((loginRes, _), _) <- runFormPost $ renderWForm FormStandard campusForm
|
||||||
tp <- getRouteToParent
|
tp <- getRouteToParent
|
||||||
case loginRes of
|
|
||||||
FormFailure errs -> do
|
resp <- formResultMaybe loginRes $ \CampusLogin{ campusIdent = CI.original -> campusIdent, ..} -> Just <$> do
|
||||||
forM_ errs $ addMessage Error . toHtml
|
ldapResult <- withLdapFailover _2 pool mode $ \(conf@LdapConf{..}, ldap) -> liftIO $ do
|
||||||
redirect $ tp LoginR
|
Ldap.bind ldap ldapDn ldapPassword
|
||||||
FormMissing -> redirect $ tp LoginR
|
searchResults <- findUser conf ldap campusIdent [ldapUserPrincipalName]
|
||||||
FormSuccess CampusLogin{ campusIdent = CI.original -> campusIdent, ..} -> do
|
case searchResults of
|
||||||
ldapResult <- withLdapFailover _2 pool mode $ \(conf@LdapConf{..}, ldap) -> liftIO $ do
|
[Ldap.SearchEntry (Ldap.Dn userDN) userAttrs]
|
||||||
Ldap.bind ldap ldapDn ldapPassword
|
| [principalName] <- fold [ v | (k, v) <- userAttrs, k == ldapUserPrincipalName ]
|
||||||
searchResults <- findUser conf ldap campusIdent [ldapUserPrincipalName]
|
, Right credsIdent <- Text.decodeUtf8' principalName
|
||||||
case searchResults of
|
-> Right (userDN, credsIdent) <$ Ldap.bind ldap (Ldap.Dn credsIdent) (Ldap.Password $ Text.encodeUtf8 campusPassword)
|
||||||
[Ldap.SearchEntry (Ldap.Dn userDN) userAttrs]
|
other -> return $ Left other
|
||||||
| [principalName] <- fold [ v | (k, v) <- userAttrs, k == ldapUserPrincipalName ]
|
case ldapResult of
|
||||||
, Right credsIdent <- Text.decodeUtf8' principalName
|
Left err
|
||||||
-> Right (userDN, credsIdent) <$ Ldap.bind ldap (Ldap.Dn credsIdent) (Ldap.Password $ Text.encodeUtf8 campusPassword)
|
| LdapError (Ldap.ResponseError (Ldap.ResponseErrorCode _ Ldap.InvalidCredentials _ _)) <- err
|
||||||
other -> return $ Left other
|
-> do
|
||||||
case ldapResult of
|
$logDebugS "LDAP" "Invalid credentials"
|
||||||
Left err
|
loginErrorMessageI LoginR Msg.InvalidLogin
|
||||||
| LdapError (Ldap.ResponseError (Ldap.ResponseErrorCode _ Ldap.InvalidCredentials _ _)) <- err
|
| otherwise -> do
|
||||||
-> do
|
$logErrorS "LDAP" $ "Error during login: " <> tshow err
|
||||||
$logDebugS "LDAP" "Invalid credentials"
|
loginErrorMessageI LoginR Msg.AuthError
|
||||||
loginErrorMessageI LoginR Msg.InvalidLogin
|
Right (Right (userDN, credsIdent)) ->
|
||||||
| otherwise -> do
|
setCredsRedirect $ Creds apName credsIdent [("DN", userDN)]
|
||||||
$logErrorS "LDAP" $ "Error during login: " <> tshow err
|
Right (Left searchResults) -> do
|
||||||
loginErrorMessageI LoginR Msg.AuthError
|
$logWarnS "LDAP" $ "Could not extract principal name: " <> tshow searchResults
|
||||||
Right (Right (userDN, credsIdent)) ->
|
loginErrorMessageI LoginR Msg.AuthError
|
||||||
setCredsRedirect $ Creds apName credsIdent [("DN", userDN)]
|
|
||||||
Right (Left searchResults) -> do
|
maybe (redirect $ tp LoginR) return resp
|
||||||
$logWarnS "LDAP" $ "Could not extract principal name: " <> tshow searchResults
|
apDispatch _ [] = badMethod
|
||||||
loginErrorMessageI LoginR Msg.AuthError
|
|
||||||
apDispatch _ _ = notFound
|
apDispatch _ _ = notFound
|
||||||
|
|
||||||
apLogin :: (Route Auth -> Route site) -> WidgetFor site ()
|
apLogin :: (Route Auth -> Route site) -> WidgetFor site ()
|
||||||
|
|||||||
@ -28,11 +28,12 @@ data PWHashMessage = MsgPWHashIdent
|
|||||||
|
|
||||||
|
|
||||||
hashForm :: ( RenderMessage (HandlerSite m) FormMessage
|
hashForm :: ( RenderMessage (HandlerSite m) FormMessage
|
||||||
|
, RenderMessage (HandlerSite m) (ValueRequired (HandlerSite m))
|
||||||
, RenderMessage (HandlerSite m) PWHashMessage
|
, RenderMessage (HandlerSite m) PWHashMessage
|
||||||
, MonadHandler m
|
, MonadHandler m
|
||||||
) => AForm m HashLogin
|
) => WForm m (FormResult HashLogin)
|
||||||
hashForm = wFormToAForm $ do
|
hashForm = do
|
||||||
mr <- getMessageRender
|
MsgRenderer mr <- getMsgRenderer
|
||||||
aFormToWForm $ HashLogin
|
aFormToWForm $ HashLogin
|
||||||
<$> areq ciField (fslpI MsgPWHashIdent (mr MsgPWHashIdentPlaceholder)) Nothing
|
<$> areq ciField (fslpI MsgPWHashIdent (mr MsgPWHashIdentPlaceholder)) Nothing
|
||||||
<*> areq passwordField (fslpI MsgPWHashPassword (mr MsgPWHashPasswordPlaceholder)) Nothing
|
<*> areq passwordField (fslpI MsgPWHashPassword (mr MsgPWHashPasswordPlaceholder)) Nothing
|
||||||
@ -45,6 +46,7 @@ hashLogin :: forall site.
|
|||||||
, PersistRecordBackend User (YesodPersistBackend site)
|
, PersistRecordBackend User (YesodPersistBackend site)
|
||||||
, RenderMessage site PWHashMessage
|
, RenderMessage site PWHashMessage
|
||||||
, RenderMessage site AFormMessage
|
, RenderMessage site AFormMessage
|
||||||
|
, RenderMessage site (ValueRequired site)
|
||||||
, Button site ButtonSubmit
|
, Button site ButtonSubmit
|
||||||
) => PWHashAlgorithm -> AuthPlugin site
|
) => PWHashAlgorithm -> AuthPlugin site
|
||||||
hashLogin pwHashAlgo = AuthPlugin{..}
|
hashLogin pwHashAlgo = AuthPlugin{..}
|
||||||
@ -53,31 +55,30 @@ hashLogin pwHashAlgo = AuthPlugin{..}
|
|||||||
apName = "PWHash"
|
apName = "PWHash"
|
||||||
|
|
||||||
apDispatch :: forall m. MonadAuthHandler site m => Text -> [Text] -> m TypedContent
|
apDispatch :: forall m. MonadAuthHandler site m => Text -> [Text] -> m TypedContent
|
||||||
apDispatch "POST" [] = liftSubHandler $ do
|
apDispatch method [] | encodeUtf8 method == methodPost = liftSubHandler $ do
|
||||||
((loginRes, _), _) <- runFormPost $ renderAForm FormStandard hashForm
|
((loginRes, _), _) <- runFormPost $ renderWForm FormStandard hashForm
|
||||||
tp <- getRouteToParent
|
tp <- getRouteToParent
|
||||||
case loginRes of
|
|
||||||
FormFailure errs -> do
|
resp <- formResultMaybe loginRes $ \HashLogin{..} -> Just <$> do
|
||||||
forM_ errs $ addMessage Error . toHtml
|
user <- liftHandler . runDB . getBy $ UniqueAuthentication hashIdent
|
||||||
redirect $ tp LoginR
|
case user of
|
||||||
FormMissing -> redirect $ tp LoginR
|
Just (Entity _ User{ userAuthentication = AuthPWHash{..}, userIdent = CI.original -> userIdent })
|
||||||
FormSuccess HashLogin{..} -> do
|
| verifyPasswordWith pwHashAlgo (2^) (encodeUtf8 hashPassword) (encodeUtf8 authPWHash) -> -- (2^) is magic.
|
||||||
user <- liftHandler . runDB . getBy $ UniqueAuthentication hashIdent
|
setCredsRedirect $ Creds apName userIdent []
|
||||||
case user of
|
other -> do
|
||||||
Just (Entity _ User{ userAuthentication = AuthPWHash{..}, userIdent = CI.original -> userIdent })
|
$logDebugS "PWHash" $ tshow other
|
||||||
| verifyPasswordWith pwHashAlgo (2^) (encodeUtf8 hashPassword) (encodeUtf8 authPWHash) -> -- (2^) is magic.
|
loginErrorMessageI LoginR Msg.InvalidLogin
|
||||||
setCredsRedirect $ Creds apName userIdent []
|
|
||||||
other -> do
|
maybe (redirect $ tp LoginR) return resp
|
||||||
$logDebugS "PWHash" $ tshow other
|
apDispatch _ [] = badMethod
|
||||||
loginErrorMessageI LoginR Msg.InvalidLogin
|
|
||||||
apDispatch _ _ = notFound
|
apDispatch _ _ = notFound
|
||||||
|
|
||||||
apLogin :: (Route Auth -> Route site) -> WidgetFor site ()
|
apLogin :: (Route Auth -> Route site) -> WidgetFor site ()
|
||||||
apLogin toMaster = do
|
apLogin toMaster = do
|
||||||
(login, loginEnctype) <- handlerToWidget . generateFormPost $ renderAForm FormStandard hashForm
|
(login, loginEnctype) <- handlerToWidget . generateFormPost $ renderWForm FormStandard hashForm
|
||||||
let loginForm = wrapForm login FormSettings
|
let loginForm = wrapForm login FormSettings
|
||||||
{ formMethod = POST
|
{ formMethod = POST
|
||||||
, formAction = Just . SomeRoute . toMaster $ PluginR "PWHash" []
|
, formAction = Just . SomeRoute . toMaster $ PluginR apName []
|
||||||
, formEncoding = loginEnctype
|
, formEncoding = loginEnctype
|
||||||
, formAttrs = [("uw-no-navigate-away-prompt","")]
|
, formAttrs = [("uw-no-navigate-away-prompt","")]
|
||||||
, formSubmit = FormSubmit
|
, formSubmit = FormSubmit
|
||||||
|
|||||||
@ -81,8 +81,6 @@ import Utils.Metrics
|
|||||||
|
|
||||||
import Text.Cassius (cassiusFile)
|
import Text.Cassius (cassiusFile)
|
||||||
|
|
||||||
import Yesod.Form.I18n.German
|
|
||||||
import Yesod.Form.I18n.English
|
|
||||||
import qualified Yesod.Auth.Message as Auth
|
import qualified Yesod.Auth.Message as Auth
|
||||||
|
|
||||||
import qualified Data.Conduit.List as C
|
import qualified Data.Conduit.List as C
|
||||||
@ -239,15 +237,7 @@ appLanguagesOpts = do
|
|||||||
}
|
}
|
||||||
langOptions = map mkOption $ toList appLanguages
|
langOptions = map mkOption $ toList appLanguages
|
||||||
return $ mkOptionList langOptions
|
return $ mkOptionList langOptions
|
||||||
|
|
||||||
-- This instance is required to use forms. You can modify renderMessage to
|
|
||||||
-- achieve customized and internationalized form validation messages.
|
|
||||||
instance RenderMessage UniWorX FormMessage where
|
|
||||||
renderMessage _ ls = case lang of
|
|
||||||
("en" : _) -> englishFormMessage
|
|
||||||
_other -> germanFormMessage
|
|
||||||
where lang = Text.splitOn "-" $ selectLanguage' appLanguages ls
|
|
||||||
|
|
||||||
instance RenderMessage UniWorX WeekDay where
|
instance RenderMessage UniWorX WeekDay where
|
||||||
renderMessage _ ls wDay = pack . fst $ wDays (getTimeLocale' ls) !! (fromEnum wDay `mod` 7)
|
renderMessage _ ls wDay = pack . fst $ wDays (getTimeLocale' ls) !! (fromEnum wDay `mod` 7)
|
||||||
|
|
||||||
@ -256,6 +246,7 @@ newtype ShortWeekDay = ShortWeekDay { longWeekDay :: WeekDay }
|
|||||||
instance RenderMessage UniWorX ShortWeekDay where
|
instance RenderMessage UniWorX ShortWeekDay where
|
||||||
renderMessage _ ls (ShortWeekDay wDay) = pack . snd $ wDays (getTimeLocale' ls) !! (fromEnum wDay `mod` 7)
|
renderMessage _ ls (ShortWeekDay wDay) = pack . snd $ wDays (getTimeLocale' ls) !! (fromEnum wDay `mod` 7)
|
||||||
|
|
||||||
|
|
||||||
-- Access Control
|
-- Access Control
|
||||||
newtype InvalidAuthTag = InvalidAuthTag Text
|
newtype InvalidAuthTag = InvalidAuthTag Text
|
||||||
deriving (Eq, Ord, Show, Read, Generic, Typeable)
|
deriving (Eq, Ord, Show, Read, Generic, Typeable)
|
||||||
|
|||||||
@ -34,6 +34,9 @@ import Utils.Form
|
|||||||
|
|
||||||
import GHC.Exts (IsList(..))
|
import GHC.Exts (IsList(..))
|
||||||
|
|
||||||
|
import Yesod.Form.I18n.German
|
||||||
|
import Yesod.Form.I18n.English
|
||||||
|
|
||||||
|
|
||||||
appLanguages :: NonEmpty Lang
|
appLanguages :: NonEmpty Lang
|
||||||
appLanguages = "de-de-formal" :| ["en-eu"]
|
appLanguages = "de-de-formal" :| ["en-eu"]
|
||||||
@ -324,3 +327,26 @@ instance RenderMessage UniWorX UniWorXMessages where
|
|||||||
|
|
||||||
uniworxMessages :: [UniWorXMessage] -> UniWorXMessages
|
uniworxMessages :: [UniWorXMessage] -> UniWorXMessages
|
||||||
uniworxMessages = UniWorXMessages . map SomeMessage
|
uniworxMessages = UniWorXMessages . map SomeMessage
|
||||||
|
|
||||||
|
|
||||||
|
-- This instance is required to use forms. You can modify renderMessage to
|
||||||
|
-- achieve customized and internationalized form validation messages.
|
||||||
|
instance RenderMessage UniWorX FormMessage where
|
||||||
|
renderMessage _ ls | lang == "en" = englishFormMessage
|
||||||
|
| otherwise = germanFormMessage
|
||||||
|
where lang = selectLanguage' ("de" :| ["en"]) ls
|
||||||
|
|
||||||
|
instance RenderMessage UniWorX (ValueRequired UniWorX) where
|
||||||
|
renderMessage foundation ls (ValueRequired label')
|
||||||
|
| [w] <- Text.words label
|
||||||
|
, let w' = Text.strip w
|
||||||
|
, not $ Text.null w'
|
||||||
|
= mr $ MsgValueRequiredLabeledSimple w'
|
||||||
|
| Text.null $ Text.strip label
|
||||||
|
= mr MsgValueRequired
|
||||||
|
| otherwise
|
||||||
|
= mr . MsgValueRequiredLabeledMultiWord $ Text.strip label
|
||||||
|
where
|
||||||
|
label = mr label'
|
||||||
|
mr :: forall msg. RenderMessage UniWorX msg => msg -> Text
|
||||||
|
mr = renderMessage foundation ls
|
||||||
|
|||||||
@ -250,7 +250,7 @@ postAdminFeaturesR = do
|
|||||||
-> DBRow r
|
-> DBRow r
|
||||||
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
||||||
textInputCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
textInputCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
||||||
(\row _mkUnique -> bimap (fmap $ set lensRes . assertM (not . Text.null)) fvInput
|
(\row _mkUnique -> bimap (fmap $ set lensRes . assertM (not . Text.null)) fvWidget
|
||||||
<$> mopt (textField & cfStrip) "" (Just $ row ^. lensDefault)
|
<$> mopt (textField & cfStrip) "" (Just $ row ^. lensDefault)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ postAdminFeaturesR = do
|
|||||||
-> DBRow r
|
-> DBRow r
|
||||||
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
||||||
checkboxCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
checkboxCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
||||||
( \row _mkUnique -> bimap (fmap $ set lensRes) fvInput
|
( \row _mkUnique -> bimap (fmap $ set lensRes) fvWidget
|
||||||
<$> mpopt checkBoxField "" (Just $ row ^. lensDefault)
|
<$> mpopt checkBoxField "" (Just $ row ^. lensDefault)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -272,7 +272,7 @@ postAdminFeaturesR = do
|
|||||||
-- -> DBRow r
|
-- -> DBRow r
|
||||||
-- -> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
-- -> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
||||||
-- termKeyCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
-- termKeyCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
||||||
-- ( \row _mkUnique -> (\(res, fieldView) -> (set lensRes <$> res, fvInput fieldView))
|
-- ( \row _mkUnique -> (\(res, fieldView) -> (set lensRes <$> res, fvWidget fieldView))
|
||||||
-- <$> mopt (intField & isoField (from _StudyTermsId)) "" (Just $ row ^. lensDefault)
|
-- <$> mopt (intField & isoField (from _StudyTermsId)) "" (Just $ row ^. lensDefault)
|
||||||
-- )
|
-- )
|
||||||
|
|
||||||
@ -283,10 +283,11 @@ postAdminFeaturesR = do
|
|||||||
-> DBRow r
|
-> DBRow r
|
||||||
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
||||||
parentsCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
parentsCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
||||||
( \row mkUnique -> bimap (fmap $ set lensRes . Set.fromList) fvInput
|
( \row mkUnique -> bimap (fmap $ set lensRes . Set.fromList) fvWidget
|
||||||
<$> massInputList
|
<$> massInputList
|
||||||
(intField & isoField (from _StudyTermsId))
|
(intField & isoField (from _StudyTermsId))
|
||||||
(const "")
|
(const "")
|
||||||
|
MsgStudyTermsParentMissing
|
||||||
(Just . SomeRoute . (AdminFeaturesR :#:))
|
(Just . SomeRoute . (AdminFeaturesR :#:))
|
||||||
(mkUnique ("parents" :: Text))
|
(mkUnique ("parents" :: Text))
|
||||||
""
|
""
|
||||||
@ -302,7 +303,7 @@ postAdminFeaturesR = do
|
|||||||
-> DBRow r
|
-> DBRow r
|
||||||
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
||||||
degreeCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
degreeCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
||||||
( \row _mkUnique -> bimap (fmap $ set lensRes) fvInput
|
( \row _mkUnique -> bimap (fmap $ set lensRes) fvWidget
|
||||||
<$> mopt degreeField "" (Just $ row ^. lensDefault)
|
<$> mopt degreeField "" (Just $ row ^. lensDefault)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -313,7 +314,7 @@ postAdminFeaturesR = do
|
|||||||
-> DBRow r
|
-> DBRow r
|
||||||
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
||||||
fieldTypeCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
fieldTypeCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
||||||
( \row _mkUnique -> bimap (fmap $ set lensRes) fvInput
|
( \row _mkUnique -> bimap (fmap $ set lensRes) fvWidget
|
||||||
<$> mopt (selectField optionsFinite) "" (Just $ row ^. lensDefault)
|
<$> mopt (selectField optionsFinite) "" (Just $ row ^. lensDefault)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -157,7 +157,7 @@ postAdminTestR = do
|
|||||||
(addRes, addView) <- mpreq textField ("" & addName (nudge "text")) Nothing -- Any old field; for demonstration
|
(addRes, addView) <- mpreq textField ("" & addName (nudge "text")) Nothing -- Any old field; for demonstration
|
||||||
let addRes' = fromMaybe 0 . readMay . Text.filter isDigit <$> addRes -- Do something semi-interesting on the result of the @textField@ to demonstrate that further processing can be done
|
let addRes' = fromMaybe 0 . readMay . Text.filter isDigit <$> addRes -- Do something semi-interesting on the result of the @textField@ to demonstrate that further processing can be done
|
||||||
addRes'' = addRes' <&> \dat prev -> FormSuccess (Map.singleton (maybe 0 (succ . fst) $ Map.lookupMax prev) dat) -- Construct the callback to determine new cell positions and data within @FormResult@ as required, nested @FormResult@ allows aborting the add depending on previous data
|
addRes'' = addRes' <&> \dat prev -> FormSuccess (Map.singleton (maybe 0 (succ . fst) $ Map.lookupMax prev) dat) -- Construct the callback to determine new cell positions and data within @FormResult@ as required, nested @FormResult@ allows aborting the add depending on previous data
|
||||||
return (addRes'', toWidget csrf >> fvInput addView >> fvInput submitBtn)
|
return (addRes'', toWidget csrf >> fvWidget addView >> fvWidget submitBtn)
|
||||||
mkAddForm _pos _dim _ _ = error "Dimension and Position is always 0 for our 1-dimensional form"
|
mkAddForm _pos _dim _ _ = error "Dimension and Position is always 0 for our 1-dimensional form"
|
||||||
|
|
||||||
-- | Make a single massInput-Cell
|
-- | Make a single massInput-Cell
|
||||||
@ -170,7 +170,7 @@ postAdminTestR = do
|
|||||||
-> Form Int
|
-> Form Int
|
||||||
mkCellForm _pos cData initial nudge csrf = do -- Extremely simple cell
|
mkCellForm _pos cData initial nudge csrf = do -- Extremely simple cell
|
||||||
(intRes, intView) <- mreq intField ("" & addName (nudge "int")) $ initial <|> Just cData
|
(intRes, intView) <- mreq intField ("" & addName (nudge "int")) $ initial <|> Just cData
|
||||||
return (intRes, toWidget csrf >> fvInput intView)
|
return (intRes, toWidget csrf >> fvWidget intView)
|
||||||
-- | How does the shape (`ListLength`) change if a certain cell is deleted?
|
-- | How does the shape (`ListLength`) change if a certain cell is deleted?
|
||||||
deleteCell :: Map ListPosition Int -- ^ Current shape, including initialisation data
|
deleteCell :: Map ListPosition Int -- ^ Current shape, including initialisation data
|
||||||
-> ListPosition -- ^ Coordinate to delete
|
-> ListPosition -- ^ Coordinate to delete
|
||||||
@ -185,7 +185,7 @@ postAdminTestR = do
|
|||||||
|
|
||||||
-- The actual call to @massInput@ is comparatively simple:
|
-- The actual call to @massInput@ is comparatively simple:
|
||||||
|
|
||||||
((miResult, fvInput -> miForm), miEnc) <- runFormPost . identifyForm ("massinput" :: Text) $ massInput (MassInput mkAddForm mkCellForm deleteCell allowAdd (\_ _ _ -> Set.empty) buttonAction defaultMiLayout ("massinput" :: Text)) "" True Nothing
|
((miResult, fvWidget -> miForm), miEnc) <- runFormPost . identifyForm ("massinput" :: Text) $ massInput (MassInput mkAddForm mkCellForm deleteCell allowAdd (\_ _ _ -> Set.empty) buttonAction defaultMiLayout ("massinput" :: Text)) "" True Nothing
|
||||||
|
|
||||||
|
|
||||||
testDownloadWidget <- testDownload
|
testDownloadWidget <- testDownload
|
||||||
|
|||||||
@ -31,13 +31,13 @@ bearerTokenForm = do
|
|||||||
muid <- maybeAuthId
|
muid <- maybeAuthId
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
|
|
||||||
btfAuthorityGroups <- aFormToWForm $ HashSet.fromList . map Left <$> massInputListA pathPieceField (const "") (\p -> Just . SomeRoute $ AdminTokensR :#: p) ("token-groups" :: Text) (fslI MsgBearerTokenAuthorityGroups & setTooltip MsgBearerTokenAuthorityGroupsTip) False Nothing
|
btfAuthorityGroups <- aFormToWForm $ HashSet.fromList . map Left <$> massInputListA pathPieceField (const "") MsgBearerTokenAuthorityGroupMissing (\p -> Just . SomeRoute $ AdminTokensR :#: p) ("token-groups" :: Text) (fslI MsgBearerTokenAuthorityGroups & setTooltip MsgBearerTokenAuthorityGroupsTip) False Nothing
|
||||||
btfAuthorityUsers <- fmap (fmap . ofoldMap $ HashSet.singleton . Right) <$> wopt (checkMap (foldMapM $ fmap Set.singleton . left MsgBearerTokenAuthorityUnknownUser) (Set.map Right) $ multiUserField False Nothing) (fslpI MsgBearerTokenAuthorityUsers (mr MsgLdapIdentificationOrEmail) & setTooltip MsgBearerTokenAuthorityUsersTip) (Just $ Set.singleton <$> muid)
|
btfAuthorityUsers <- fmap (fmap . ofoldMap $ HashSet.singleton . Right) <$> wopt (checkMap (foldMapM $ fmap Set.singleton . left MsgBearerTokenAuthorityUnknownUser) (Set.map Right) $ multiUserField False Nothing) (fslpI MsgBearerTokenAuthorityUsers (mr MsgLdapIdentificationOrEmail) & setTooltip MsgBearerTokenAuthorityUsersTip) (Just $ Set.singleton <$> muid)
|
||||||
let btfAuthority' :: FormResult (HashSet (Either UserGroupName UserId))
|
let btfAuthority' :: FormResult (HashSet (Either UserGroupName UserId))
|
||||||
btfAuthority'
|
btfAuthority'
|
||||||
= (<>) <$> btfAuthorityGroups <*> ((hoistMaybe =<< btfAuthorityUsers) <|> pure HashSet.empty)
|
= (<>) <$> btfAuthorityGroups <*> ((hoistMaybe =<< btfAuthorityUsers) <|> pure HashSet.empty)
|
||||||
|
|
||||||
let btfRoutesForm = HashSet.fromList <$> massInputListA routeField (const "") (\p -> Just . SomeRoute $ AdminTokensR :#: p) ("token-routes" :: Text) (fslI MsgBearerTokenRoutes & setTooltip MsgBearerTokenRoutesTip) True Nothing
|
let btfRoutesForm = HashSet.fromList <$> massInputListA routeField (const "") MsgBearerTokenRouteMissing (\p -> Just . SomeRoute $ AdminTokensR :#: p) ("token-routes" :: Text) (fslI MsgBearerTokenRoutes & setTooltip MsgBearerTokenRoutesTip) True Nothing
|
||||||
btfRoutes' <- optionalActionW btfRoutesForm (fslI MsgBearerTokenRestrictRoutes) (Just True)
|
btfRoutes' <- optionalActionW btfRoutesForm (fslI MsgBearerTokenRestrictRoutes) (Just True)
|
||||||
|
|
||||||
let btfRestrictForm = massInputAccumEditW miAdd' miCell' (\p -> Just . SomeRoute $ AdminTokensR :#: p) miLayout' ("token-restrictions" :: Text) (fslI MsgBearerTokenRestrictions) False Nothing
|
let btfRestrictForm = massInputAccumEditW miAdd' miCell' (\p -> Just . SomeRoute $ AdminTokensR :#: p) miLayout' ("token-restrictions" :: Text) (fslI MsgBearerTokenRestrictions) False Nothing
|
||||||
@ -48,8 +48,8 @@ bearerTokenForm = do
|
|||||||
-> Either (FieldView UniWorX) (Route UniWorX, Value)
|
-> Either (FieldView UniWorX) (Route UniWorX, Value)
|
||||||
-> Form (Route UniWorX, Value)
|
-> Form (Route UniWorX, Value)
|
||||||
miForm nudge mode csrf = do
|
miForm nudge mode csrf = do
|
||||||
(routeRes, routeView) <- mpreq routeField ("" & addName (nudge "route")) (mode ^? _Right . _1)
|
(routeRes, routeView) <- mpreq routeField (fslI MsgBearerTokenRestrictRoute & addName (nudge "route")) (mode ^? _Right . _1)
|
||||||
(restrRes, restrView) <- mpreq (checkMap (left Text.pack . Aeson.eitherDecode . encodeUtf8 . fromStrict . unTextarea) (Textarea . toStrict . decodeUtf8 . Aeson.encodePretty) textareaField) ("" & addName (nudge "restr")) (mode ^? _Right . _2)
|
(restrRes, restrView) <- mpreq (checkMap (left Text.pack . Aeson.eitherDecode . encodeUtf8 . fromStrict . unTextarea) (Textarea . toStrict . decodeUtf8 . Aeson.encodePretty) textareaField) (fslI MsgBearerTokenRestrictValue & addName (nudge "restr")) (mode ^? _Right . _2)
|
||||||
|
|
||||||
return ((,) <$> routeRes <*> restrRes, case mode of
|
return ((,) <$> routeRes <*> restrRes, case mode of
|
||||||
Left btn -> $(widgetFile "widgets/massinput/token-restrictions/add")
|
Left btn -> $(widgetFile "widgets/massinput/token-restrictions/add")
|
||||||
|
|||||||
@ -217,14 +217,14 @@ colPseudonyms = sortable Nothing (i18nCell MsgPseudonyms) $ \DBRow{ dbrOutput=(_
|
|||||||
colRatedField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (DBFormResult SubmissionId (Bool, a, b) CorrectionTableData)))
|
colRatedField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (DBFormResult SubmissionId (Bool, a, b) CorrectionTableData)))
|
||||||
colRatedField = sortable Nothing (i18nCell MsgRatingDone) $ formCell id
|
colRatedField = sortable Nothing (i18nCell MsgRatingDone) $ formCell id
|
||||||
(\DBRow{ dbrOutput=(Entity subId _, _, _, _, _, _, _, _) } -> return subId)
|
(\DBRow{ dbrOutput=(Entity subId _, _, _, _, _, _, _, _) } -> return subId)
|
||||||
(\DBRow{ dbrOutput=(Entity _ (submissionRatingDone -> done), _, _, _, _, _, _, _) } mkUnique -> over (_1.mapped) (_1 .~) . over _2 fvInput <$> mreq checkBoxField (fsUniq mkUnique "rated") (Just done))
|
(\DBRow{ dbrOutput=(Entity _ (submissionRatingDone -> done), _, _, _, _, _, _, _) } mkUnique -> over (_1.mapped) (_1 .~) . over _2 fvWidget <$> mreq checkBoxField (fsUniq mkUnique "rated") (Just done))
|
||||||
|
|
||||||
colPointsField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (DBFormResult SubmissionId (a, Maybe Points, b) CorrectionTableData)))
|
colPointsField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (DBFormResult SubmissionId (a, Maybe Points, b) CorrectionTableData)))
|
||||||
colPointsField = sortable (Just "rating") (i18nCell MsgColumnRatingPoints) $ formCell id
|
colPointsField = sortable (Just "rating") (i18nCell MsgColumnRatingPoints) $ formCell id
|
||||||
(\DBRow{ dbrOutput=(Entity subId _, _, _, _, _, _, _, _) } -> return subId)
|
(\DBRow{ dbrOutput=(Entity subId _, _, _, _, _, _, _, _) } -> return subId)
|
||||||
(\DBRow{ dbrOutput=(Entity _ Submission{..}, Entity _ Sheet{..}, _, _, _, _, _, _) } mkUnique -> case sheetType of
|
(\DBRow{ dbrOutput=(Entity _ Submission{..}, Entity _ Sheet{..}, _, _, _, _, _, _) } mkUnique -> case sheetType of
|
||||||
NotGraded -> over (_1.mapped) (_2 .~) <$> pure (FormSuccess Nothing, mempty)
|
NotGraded -> over (_1.mapped) (_2 .~) <$> pure (FormSuccess Nothing, mempty)
|
||||||
_other -> over (_1.mapped) (_2 .~) . over _2 fvInput <$> mopt (pointsFieldMax $ preview (_grading . _maxPoints) sheetType) (fsUniq mkUnique "points") (Just submissionRatingPoints)
|
_other -> over (_1.mapped) (_2 .~) . over _2 fvWidget <$> mopt (pointsFieldMax $ preview (_grading . _maxPoints) sheetType) (fsUniq mkUnique "points") (Just submissionRatingPoints)
|
||||||
)
|
)
|
||||||
|
|
||||||
colMaxPointsField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (DBFormResult SubmissionId (a, Maybe Points, b) CorrectionTableData)))
|
colMaxPointsField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (DBFormResult SubmissionId (a, Maybe Points, b) CorrectionTableData)))
|
||||||
@ -233,7 +233,7 @@ colMaxPointsField = sortable (Just "sheet-type") (i18nCell MsgSheetType) $ i18nC
|
|||||||
colCommentField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (DBFormResult SubmissionId (a, b, Maybe Text) CorrectionTableData)))
|
colCommentField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (DBFormResult SubmissionId (a, b, Maybe Text) CorrectionTableData)))
|
||||||
colCommentField = sortable (Just "comment") (i18nCell MsgRatingComment) $ fmap (cellAttrs <>~ [("style","width:60%")]) $ formCell id
|
colCommentField = sortable (Just "comment") (i18nCell MsgRatingComment) $ fmap (cellAttrs <>~ [("style","width:60%")]) $ formCell id
|
||||||
(\DBRow{ dbrOutput=(Entity subId _, _, _, _, _, _, _, _) } -> return subId)
|
(\DBRow{ dbrOutput=(Entity subId _, _, _, _, _, _, _, _) } -> return subId)
|
||||||
(\DBRow{ dbrOutput=(Entity _ Submission{..}, _, _, _, _, _, _, _) } mkUnique -> over (_1.mapped) ((_3 .~) . assertM (not . null) . fmap (Text.strip . unTextarea)) . over _2 fvInput <$> mopt textareaField (fsUniq mkUnique "comment") (Just $ Textarea <$> submissionRatingComment))
|
(\DBRow{ dbrOutput=(Entity _ Submission{..}, _, _, _, _, _, _, _) } mkUnique -> over (_1.mapped) ((_3 .~) . assertM (not . null) . fmap (Text.strip . unTextarea)) . over _2 fvWidget <$> mopt textareaField (fsUniq mkUnique "comment") (Just $ Textarea <$> submissionRatingComment))
|
||||||
|
|
||||||
colLastEdit :: IsDBTable m a => Colonnade Sortable CorrectionTableData (DBCell m a)
|
colLastEdit :: IsDBTable m a => Colonnade Sortable CorrectionTableData (DBCell m a)
|
||||||
colLastEdit = sortable (Just "last-edit") (i18nCell MsgLastEdit) $
|
colLastEdit = sortable (Just "last-edit") (i18nCell MsgLastEdit) $
|
||||||
|
|||||||
@ -128,7 +128,7 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
|
|||||||
|
|
||||||
let miAdd :: ListPosition -> Natural -> (Text -> Text) -> FieldView UniWorX -> Maybe (Form (Map ListPosition (Either UserEmail UserId) -> FormResult (Map ListPosition (Either UserEmail UserId))))
|
let miAdd :: ListPosition -> Natural -> (Text -> Text) -> FieldView UniWorX -> Maybe (Form (Map ListPosition (Either UserEmail UserId) -> FormResult (Map ListPosition (Either UserEmail UserId))))
|
||||||
miAdd _ _ nudge btn = Just $ \csrf -> do
|
miAdd _ _ nudge btn = Just $ \csrf -> do
|
||||||
(addRes, addView) <- mpreq (multiUserInvitationField $ MUILookupAnyUser Nothing) ("" & addName (nudge "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
(addRes, addView) <- mpreq (multiUserInvitationField $ MUILookupAnyUser Nothing) (fslI MsgCourseLecturerEmail & addName (nudge "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
||||||
let addRes'' = addRes <&> \newDat oldDat -> if
|
let addRes'' = addRes <&> \newDat oldDat -> if
|
||||||
| existing <- newDat `Set.intersection` Set.fromList (Map.elems oldDat)
|
| existing <- newDat `Set.intersection` Set.fromList (Map.elems oldDat)
|
||||||
, not $ Set.null existing
|
, not $ Set.null existing
|
||||||
@ -140,7 +140,7 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
|
|||||||
|
|
||||||
miCell :: ListPosition -> Either UserEmail UserId -> Maybe (Maybe LecturerType) -> (Text -> Text) -> Form (Maybe LecturerType)
|
miCell :: ListPosition -> Either UserEmail UserId -> Maybe (Maybe LecturerType) -> (Text -> Text) -> Form (Maybe LecturerType)
|
||||||
miCell _ (Right lid) defType nudge = \csrf -> do
|
miCell _ (Right lid) defType nudge = \csrf -> do
|
||||||
(lrwRes,lrwView) <- mreq (selectField optionsFinite) ("" & addName (nudge "lecturer-type")) (join defType)
|
(lrwRes,lrwView) <- mreq (selectField optionsFinite) (fslI MsgLecturerType & addName (nudge "lecturer-type")) (join defType)
|
||||||
User{userEmail, userDisplayName, userSurname} <- liftHandler . runDB $ get404 lid
|
User{userEmail, userDisplayName, userSurname} <- liftHandler . runDB $ get404 lid
|
||||||
let lrwView' = $(widgetFile "course/lecturerMassInput/cellKnown")
|
let lrwView' = $(widgetFile "course/lecturerMassInput/cellKnown")
|
||||||
return (Just <$> lrwRes,lrwView')
|
return (Just <$> lrwRes,lrwView')
|
||||||
|
|||||||
@ -103,7 +103,7 @@ courseUserProfileSection (Entity cid Course{..}) (Entity uid User{ userShowSex =
|
|||||||
((regFieldRes, regFieldView), regFieldEnctype) <- lift . runFormPost . identifyForm FIDcRegField $ \csrf ->
|
((regFieldRes, regFieldView), regFieldEnctype) <- lift . runFormPost . identifyForm FIDcRegField $ \csrf ->
|
||||||
let currentField :: Maybe (Maybe StudyFeaturesId)
|
let currentField :: Maybe (Maybe StudyFeaturesId)
|
||||||
currentField = courseParticipantField . entityVal <$> mRegistration
|
currentField = courseParticipantField . entityVal <$> mRegistration
|
||||||
in over _2 ((toWidget csrf <>) . fvInput) <$> mreq (studyFeaturesFieldFor Nothing True (maybeToList $ join currentField) $ Just uid) ("" & addAutosubmit) currentField
|
in over _2 ((toWidget csrf <>) . fvWidget) <$> mreq (studyFeaturesFieldFor Nothing True (maybeToList $ join currentField) $ Just uid) ("" & addAutosubmit) currentField
|
||||||
|
|
||||||
let registrationFieldFrag :: Text
|
let registrationFieldFrag :: Text
|
||||||
registrationFieldFrag = "registration-field"
|
registrationFieldFrag = "registration-field"
|
||||||
|
|||||||
@ -77,7 +77,7 @@ examAutoOccurrenceAcceptForm :: Maybe ExamAutoOccurrenceAcceptForm -> Form ExamA
|
|||||||
examAutoOccurrenceAcceptForm confirmData = identifyForm FIDExamAutoOccurrenceConfirm $ \html -> do
|
examAutoOccurrenceAcceptForm confirmData = identifyForm FIDExamAutoOccurrenceConfirm $ \html -> do
|
||||||
(confirmDataRes, confirmDataView) <- mreq secretJsonField "" confirmData
|
(confirmDataRes, confirmDataView) <- mreq secretJsonField "" confirmData
|
||||||
(acceptRes, acceptView) <- buttonForm' [BtnExamAutoOccurrenceAccept] mempty
|
(acceptRes, acceptView) <- buttonForm' [BtnExamAutoOccurrenceAccept] mempty
|
||||||
return (acceptRes *> confirmDataRes, toWidget html <> fvInput confirmDataView <> acceptView)
|
return (acceptRes *> confirmDataRes, toWidget html <> fvWidget confirmDataView <> acceptView)
|
||||||
|
|
||||||
|
|
||||||
examAutoOccurrenceCalculateWidget :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Widget
|
examAutoOccurrenceCalculateWidget :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Widget
|
||||||
|
|||||||
@ -114,7 +114,7 @@ examCorrectorsForm mPrev = wFormToAForm $ do
|
|||||||
|
|
||||||
miAdd' :: (Text -> Text) -> FieldView UniWorX -> Form ([Either UserEmail UserId] -> FormResult [Either UserEmail UserId])
|
miAdd' :: (Text -> Text) -> FieldView UniWorX -> Form ([Either UserEmail UserId] -> FormResult [Either UserEmail UserId])
|
||||||
miAdd' nudge submitView csrf = do
|
miAdd' nudge submitView csrf = do
|
||||||
(addRes, addView) <- mpreq (multiUserInvitationField . MUILookupAnyUser $ Just corrUserSuggestions) ("" & addName (nudge "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
(addRes, addView) <- mpreq (multiUserInvitationField . MUILookupAnyUser $ Just corrUserSuggestions) (fslI MsgExamCorrectorEmail & addName (nudge "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
||||||
let
|
let
|
||||||
addRes'
|
addRes'
|
||||||
| otherwise
|
| otherwise
|
||||||
@ -160,12 +160,12 @@ examOccurrenceForm prev = wFormToAForm $ do
|
|||||||
where
|
where
|
||||||
examOccurrenceForm' nudge mPrev csrf = do
|
examOccurrenceForm' nudge mPrev csrf = do
|
||||||
(eofIdRes, eofIdView) <- mopt hiddenField ("" & addName (nudge "id")) (Just $ eofId =<< mPrev)
|
(eofIdRes, eofIdView) <- mopt hiddenField ("" & addName (nudge "id")) (Just $ eofId =<< mPrev)
|
||||||
(eofNameRes, eofNameView) <- mpreq (textField & cfStrip & cfCI) ("" & addName (nudge "name")) (eofName <$> mPrev)
|
(eofNameRes, eofNameView) <- mpreq (textField & cfStrip & cfCI) (fslI MsgExamRoomName & addName (nudge "name")) (eofName <$> mPrev)
|
||||||
(eofRoomRes, eofRoomView) <- mpreq (textField & cfStrip) ("" & addName (nudge "room")) (eofRoom <$> mPrev)
|
(eofRoomRes, eofRoomView) <- mpreq (textField & cfStrip) (fslI MsgExamRoomRoom & addName (nudge "room")) (eofRoom <$> mPrev)
|
||||||
(eofCapacityRes, eofCapacityView) <- mpreq (natFieldI MsgExamRoomCapacityNegative) ("" & addName (nudge "capacity")) (eofCapacity <$> mPrev)
|
(eofCapacityRes, eofCapacityView) <- mpreq (natFieldI MsgExamRoomCapacityNegative) (fslI MsgExamRoomCapacity & addName (nudge "capacity")) (eofCapacity <$> mPrev)
|
||||||
(eofStartRes, eofStartView) <- mpreq utcTimeField ("" & addName (nudge "start")) (eofStart <$> mPrev)
|
(eofStartRes, eofStartView) <- mpreq utcTimeField (fslI MsgExamRoomStart & addName (nudge "start")) (eofStart <$> mPrev)
|
||||||
(eofEndRes, eofEndView) <- mopt utcTimeField ("" & addName (nudge "end")) (eofEnd <$> mPrev)
|
(eofEndRes, eofEndView) <- mopt utcTimeField (fslI MsgExamRoomEnd & addName (nudge "end")) (eofEnd <$> mPrev)
|
||||||
(eofDescRes, eofDescView) <- mopt htmlFieldSmall ("" & addName (nudge "description")) (eofDescription <$> mPrev)
|
(eofDescRes, eofDescView) <- mopt htmlFieldSmall (fslI MsgExamRoomDescription & addName (nudge "description")) (eofDescription <$> mPrev)
|
||||||
|
|
||||||
return ( ExamOccurrenceForm
|
return ( ExamOccurrenceForm
|
||||||
<$> eofIdRes
|
<$> eofIdRes
|
||||||
@ -201,11 +201,11 @@ examPartsForm prev = wFormToAForm $ do
|
|||||||
fmap (fmap Set.fromList) . massInputAccumEditW miAdd' miCell' miButtonAction' miLayout' miIdent' (fslI MsgExamParts) False $ Set.toList <$> prev
|
fmap (fmap Set.fromList) . massInputAccumEditW miAdd' miCell' miButtonAction' miLayout' miIdent' (fslI MsgExamParts) False $ Set.toList <$> prev
|
||||||
where
|
where
|
||||||
examPartForm' nudge mPrev csrf = do
|
examPartForm' nudge mPrev csrf = do
|
||||||
(epfIdRes, epfIdView) <- mopt hiddenField ("" & addName (nudge "id")) (Just $ epfId =<< mPrev)
|
(epfIdRes, epfIdView) <- mopt hiddenField ("" & addName (nudge "id")) (Just $ epfId =<< mPrev)
|
||||||
(epfNumberRes, epfNumberView) <- mpreq (isoField (from _ExamPartNumber) $ textField & cfStrip & cfCI) ("" & addName (nudge "number") & addPlaceholder "1, 6a, 3.1.4, ...") (epfNumber <$> mPrev)
|
(epfNumberRes, epfNumberView) <- mpreq (isoField (from _ExamPartNumber) $ textField & cfStrip & cfCI) (fslI MsgExamPartNumber & addName (nudge "number") & addPlaceholder "1, 6a, 3.1.4, ...") (epfNumber <$> mPrev)
|
||||||
(epfNameRes, epfNameView) <- mopt (textField & cfStrip & cfCI) ("" & addName (nudge "name")) (epfName <$> mPrev)
|
(epfNameRes, epfNameView) <- mopt (textField & cfStrip & cfCI) (fslI MsgExamPartName & addName (nudge "name")) (epfName <$> mPrev)
|
||||||
(epfMaxPointsRes, epfMaxPointsView) <- mopt pointsField ("" & addName (nudge "max-points")) (epfMaxPoints <$> mPrev)
|
(epfMaxPointsRes, epfMaxPointsView) <- mopt pointsField (fslI MsgExamPartMaxPoints & addName (nudge "max-points")) (epfMaxPoints <$> mPrev)
|
||||||
(epfWeightRes, epfWeightView) <- mpreq (checkBool (>= 0) MsgExamPartWeightNegative rationalField) ("" & addName (nudge "weight")) (epfWeight <$> mPrev <|> Just 1)
|
(epfWeightRes, epfWeightView) <- mpreq (checkBool (>= 0) MsgExamPartWeightNegative rationalField) (fslI MsgExamPartWeight & addName (nudge "weight")) (epfWeight <$> mPrev <|> Just 1)
|
||||||
|
|
||||||
return ( ExamPartForm
|
return ( ExamPartForm
|
||||||
<$> epfIdRes
|
<$> epfIdRes
|
||||||
|
|||||||
@ -95,7 +95,7 @@ makeExamOfficeUsersForm template = renderWForm FormStandard $ do
|
|||||||
-> Form ([Either UserEmail UserId] -> FormResult [Either UserEmail UserId])
|
-> Form ([Either UserEmail UserId] -> FormResult [Either UserEmail UserId])
|
||||||
miAdd' nudge btn csrf = do
|
miAdd' nudge btn csrf = do
|
||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
(addRes, addView) <- mpreq (multiUserInvitationField $ MUILookupAnyUser Nothing) ("" & addName (nudge "users") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
(addRes, addView) <- mpreq (multiUserInvitationField $ MUILookupAnyUser Nothing) (fslI MsgExamOfficeUserEmail & addName (nudge "users") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
||||||
let
|
let
|
||||||
res' :: FormResult ([Either UserEmail UserId] -> FormResult [Either UserEmail UserId])
|
res' :: FormResult ([Either UserEmail UserId] -> FormResult [Either UserEmail UserId])
|
||||||
res' = addRes <&> \newUsers oldUsers -> if
|
res' = addRes <&> \newUsers oldUsers -> if
|
||||||
|
|||||||
@ -72,11 +72,12 @@ externalExamForm template = validateForm validateExternalExam $ \html -> do
|
|||||||
miIdent = "external-exams-school"
|
miIdent = "external-exams-school"
|
||||||
fSettings = fslI MsgExternalExamExamOfficeSchools & setTooltip MsgExternalExamExamOfficeSchoolsTip
|
fSettings = fslI MsgExternalExamExamOfficeSchools & setTooltip MsgExternalExamExamOfficeSchoolsTip
|
||||||
fRequired = False
|
fRequired = False
|
||||||
|
staffForm :: Route UniWorX -> Maybe [Either UserEmail UserId] -> AForm Handler [Either UserEmail UserId]
|
||||||
staffForm cRoute = massInputAccumA miAdd miCell miButtonAction miLayout miIdent fSettings fRequired
|
staffForm cRoute = massInputAccumA miAdd miCell miButtonAction miLayout miIdent fSettings fRequired
|
||||||
where
|
where
|
||||||
miAdd mkUnique submitView csrf = do
|
miAdd mkUnique submitView csrf = do
|
||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
(usersRes, addView) <- mpreq (multiUserInvitationField $ MUILookupAnyUser Nothing) ("" & addName (mkUnique "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
(usersRes, addView) <- mpreq (multiUserInvitationField $ MUILookupAnyUser Nothing) (fslI MsgExternalExamStaffEmail & addName (mkUnique "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
||||||
let
|
let
|
||||||
usersRes' = usersRes <&> \newDat oldDat -> if
|
usersRes' = usersRes <&> \newDat oldDat -> if
|
||||||
| existing <- newDat `Set.intersection` Set.fromList oldDat
|
| existing <- newDat `Set.intersection` Set.fromList oldDat
|
||||||
|
|||||||
@ -68,7 +68,7 @@ mkSchoolForm :: Maybe SchoolId -> Maybe SchoolForm -> Form SchoolForm
|
|||||||
mkSchoolForm mSsh template = renderAForm FormStandard $ SchoolForm
|
mkSchoolForm mSsh template = renderAForm FormStandard $ SchoolForm
|
||||||
<$> maybe (\f fs -> areq f fs (sfShorthand <$> template)) (\ssh f fs -> aforced f fs (unSchoolKey ssh)) mSsh (textField & cfStrip & cfCI) (fslI MsgSchoolShort)
|
<$> maybe (\f fs -> areq f fs (sfShorthand <$> template)) (\ssh f fs -> aforced f fs (unSchoolKey ssh)) mSsh (textField & cfStrip & cfCI) (fslI MsgSchoolShort)
|
||||||
<*> areq (textField & cfStrip & cfCI) (fslI MsgSchoolName) (sfName <$> template)
|
<*> areq (textField & cfStrip & cfCI) (fslI MsgSchoolName) (sfName <$> template)
|
||||||
<*> (Set.fromList . mapMaybe (fmap CI.mk . assertM' (not . Text.null) . Text.strip . CI.original) <$> massInputListA (ciField & addDatalist ldapOrgs) (const "") (const Nothing) ("ldap-organisations" :: Text) (fslI MsgSchoolLdapOrganisations & setTooltip MsgSchoolLdapOrganisationsTip) False (Set.toList . sfOrgUnits <$> template))
|
<*> (Set.fromList . mapMaybe (fmap CI.mk . assertM' (not . Text.null) . Text.strip . CI.original) <$> massInputListA (ciField & addDatalist ldapOrgs) (const "") MsgSchoolLdapOrganisationMissing (const Nothing) ("ldap-organisations" :: Text) (fslI MsgSchoolLdapOrganisations & setTooltip MsgSchoolLdapOrganisationsTip) False (Set.toList . sfOrgUnits <$> template))
|
||||||
where
|
where
|
||||||
ldapOrgs :: HandlerFor UniWorX (OptionList (CI Text))
|
ldapOrgs :: HandlerFor UniWorX (OptionList (CI Text))
|
||||||
ldapOrgs = fmap (mkOptionList . map (\t -> Option (CI.original t) t (CI.original t)) . Set.toAscList) . runDB $
|
ldapOrgs = fmap (mkOptionList . map (\t -> Option (CI.original t) t (CI.original t)) . Set.toAscList) . runDB $
|
||||||
|
|||||||
@ -420,7 +420,7 @@ getSShowR tid ssh csh shn = do
|
|||||||
Entity _ SheetPseudonym{sheetPseudonymPseudonym} <- MaybeT . runDB . getBy $ UniqueSheetPseudonymUser sid uid
|
Entity _ SheetPseudonym{sheetPseudonymPseudonym} <- MaybeT . runDB . getBy $ UniqueSheetPseudonymUser sid uid
|
||||||
return $ review _PseudonymText sheetPseudonymPseudonym
|
return $ review _PseudonymText sheetPseudonymPseudonym
|
||||||
(generateWidget, generateEnctype) <- generateFormPost $ \csrf ->
|
(generateWidget, generateEnctype) <- generateFormPost $ \csrf ->
|
||||||
over _2 ((toWidget csrf <>) . fvInput) <$> mreq (buttonField BtnGenerate) "" Nothing
|
over _2 ((toWidget csrf <>) . fvWidget) <$> mreq (buttonField BtnGenerate) "" Nothing
|
||||||
let generateForm = wrapForm generateWidget def
|
let generateForm = wrapForm generateWidget def
|
||||||
{ formAction = Just . SomeRoute $ CSheetR tid ssh csh shn SPseudonymR
|
{ formAction = Just . SomeRoute $ CSheetR tid ssh csh shn SPseudonymR
|
||||||
, formEncoding = generateEnctype
|
, formEncoding = generateEnctype
|
||||||
@ -760,9 +760,9 @@ correctorForm loads' = wFormToAForm $ do
|
|||||||
-> (Text -> Text)
|
-> (Text -> Text)
|
||||||
-> Form (CorrectorState, Load)
|
-> Form (CorrectorState, Load)
|
||||||
miCell _ userIdent initRes nudge csrf = do
|
miCell _ userIdent initRes nudge csrf = do
|
||||||
(stateRes, stateView) <- mreq (selectField optionsFinite) ("" & addName (nudge "state")) $ (fst <$> initRes) <|> Just CorrectorNormal
|
(stateRes, stateView) <- mreq (selectField optionsFinite) (fslI MsgSheetCorrectorState & addName (nudge "state")) $ (fst <$> initRes) <|> Just CorrectorNormal
|
||||||
(byTutRes, byTutView) <- mreq checkBoxField ("" & addName (nudge "bytut")) $ (isJust . byTutorial . snd <$> initRes) <|> Just False
|
(byTutRes, byTutView) <- mreq checkBoxField ("" & addName (nudge "bytut")) $ (isJust . byTutorial . snd <$> initRes) <|> Just False
|
||||||
(propRes, propView) <- mreq (checkBool (>= 0) MsgProportionNegative $ rationalField) ("" & addName (nudge "prop")) $ (byProportion . snd <$> initRes) <|> Just 0
|
(propRes, propView) <- mreq (checkBool (>= 0) MsgProportionNegative $ rationalField) (fslI MsgSheetCorrectorProportion & addName (nudge "prop")) $ (byProportion . snd <$> initRes) <|> Just 0
|
||||||
let
|
let
|
||||||
res :: FormResult (CorrectorState, Load)
|
res :: FormResult (CorrectorState, Load)
|
||||||
res = (,) <$> stateRes <*> (Load <$> tutRes' <*> propRes)
|
res = (,) <$> stateRes <*> (Load <$> tutRes' <*> propRes)
|
||||||
|
|||||||
@ -243,6 +243,7 @@ newTermForm template = validateForm validateTerm $ \html -> do
|
|||||||
holidayForm = massInputListA
|
holidayForm = massInputListA
|
||||||
dayField
|
dayField
|
||||||
(const $ "" & addPlaceholder (mr MsgTermHolidayPlaceholder))
|
(const $ "" & addPlaceholder (mr MsgTermHolidayPlaceholder))
|
||||||
|
MsgTermHolidayMissing
|
||||||
(const Nothing)
|
(const Nothing)
|
||||||
("holidays" :: Text)
|
("holidays" :: Text)
|
||||||
(fslI MsgTermHolidays)
|
(fslI MsgTermHolidays)
|
||||||
|
|||||||
@ -40,7 +40,7 @@ tutorialForm cid template html = do
|
|||||||
where
|
where
|
||||||
miAdd' :: (Text -> Text) -> FieldView UniWorX -> Form ([Either UserEmail UserId] -> FormResult [Either UserEmail UserId])
|
miAdd' :: (Text -> Text) -> FieldView UniWorX -> Form ([Either UserEmail UserId] -> FormResult [Either UserEmail UserId])
|
||||||
miAdd' nudge submitView csrf = do
|
miAdd' nudge submitView csrf = do
|
||||||
(addRes, addView) <- mpreq (multiUserInvitationField . MUILookupAnyUser . Just $ tutUserSuggestions uid) ("" & addName (nudge "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
(addRes, addView) <- mpreq (multiUserInvitationField . MUILookupAnyUser . Just $ tutUserSuggestions uid) (fslI MsgTutorEmail & addName (nudge "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
||||||
let
|
let
|
||||||
addRes'
|
addRes'
|
||||||
| otherwise
|
| otherwise
|
||||||
|
|||||||
@ -42,7 +42,7 @@ import qualified Data.HashSet as HashSet
|
|||||||
hijackUserForm :: Form ()
|
hijackUserForm :: Form ()
|
||||||
hijackUserForm csrf = do
|
hijackUserForm csrf = do
|
||||||
(btnResult, btnView) <- mopt (buttonField BtnHijack) "" Nothing
|
(btnResult, btnView) <- mopt (buttonField BtnHijack) "" Nothing
|
||||||
return (btnResult >>= guard . is _Just, mconcat [toWidget csrf, fvInput btnView])
|
return (btnResult >>= guard . is _Just, mconcat [toWidget csrf, fvWidget btnView])
|
||||||
|
|
||||||
-- In case of refactoring, use this:
|
-- In case of refactoring, use this:
|
||||||
-- instance HasEntity (DBRow (Entity User)) User where
|
-- instance HasEntity (DBRow (Entity User)) User where
|
||||||
|
|||||||
@ -73,7 +73,7 @@ confirmForm' drRecords confirmString mmsg = addDeleteTargets . identifyForm FIDD
|
|||||||
addDeleteTargets :: Form a -> Form a
|
addDeleteTargets :: Form a -> Form a
|
||||||
addDeleteTargets form csrf = do
|
addDeleteTargets form csrf = do
|
||||||
(_, fvTargets) <- mreq secretJsonField ("" & addName (toPathPiece PostDeleteTarget)) (Just drRecords)
|
(_, fvTargets) <- mreq secretJsonField ("" & addName (toPathPiece PostDeleteTarget)) (Just drRecords)
|
||||||
over _2 (mappend $ fvInput fvTargets) <$> form csrf
|
over _2 (mappend $ fvWidget fvTargets) <$> form csrf
|
||||||
|
|
||||||
|
|
||||||
postDeleteR :: ( DeleteCascade record SqlBackend )
|
postDeleteR :: ( DeleteCascade record SqlBackend )
|
||||||
|
|||||||
@ -635,9 +635,9 @@ uploadModeForm prev = multiActionA actions (fslI MsgSheetUploadMode) (classifyUp
|
|||||||
|
|
||||||
sFileForm :: (Text -> Text) -> Maybe UploadSpecificFile -> Form UploadSpecificFile
|
sFileForm :: (Text -> Text) -> Maybe UploadSpecificFile -> Form UploadSpecificFile
|
||||||
sFileForm nudge mPrevUF csrf = do
|
sFileForm nudge mPrevUF csrf = do
|
||||||
(labelRes, labelView) <- mpreq textField ("" & addName (nudge "label")) $ specificFileLabel <$> mPrevUF
|
(labelRes, labelView) <- mpreq textField (fslI MsgUploadSpecificFileLabel & addName (nudge "label")) $ specificFileLabel <$> mPrevUF
|
||||||
(nameRes, nameView) <- mpreq textField ("" & addName (nudge "name")) $ specificFileName <$> mPrevUF
|
(nameRes, nameView) <- mpreq textField (fslI MsgUploadSpecificFileName & addName (nudge "name")) $ specificFileName <$> mPrevUF
|
||||||
(reqRes, reqView) <- mpreq checkBoxField ("" & addName (nudge "required")) $ specificFileRequired <$> mPrevUF
|
(reqRes, reqView) <- mpreq checkBoxField (fslI MsgUploadSpecificFileRequired & addName (nudge "required")) $ specificFileRequired <$> mPrevUF
|
||||||
|
|
||||||
return ( UploadSpecificFile <$> labelRes <*> nameRes <*> reqRes
|
return ( UploadSpecificFile <$> labelRes <*> nameRes <*> reqRes
|
||||||
, $(widgetFile "widgets/massinput/uploadSpecificFiles/form")
|
, $(widgetFile "widgets/massinput/uploadSpecificFiles/form")
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import Utils.Form
|
|||||||
import Handler.Utils.Form.MassInput.Liveliness
|
import Handler.Utils.Form.MassInput.Liveliness
|
||||||
import Handler.Utils.Form.MassInput.TH
|
import Handler.Utils.Form.MassInput.TH
|
||||||
|
|
||||||
import Text.Blaze (Markup)
|
import Text.Blaze (Markup, toMarkup)
|
||||||
|
|
||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
|
|
||||||
@ -426,7 +426,9 @@ massInput MassInput{ miIdent = toPathPiece -> miIdent, ..} FieldSettings{..} fvR
|
|||||||
fvLabel = toHtml $ mr fsLabel
|
fvLabel = toHtml $ mr fsLabel
|
||||||
fvTooltip = toHtml . mr <$> fsTooltip
|
fvTooltip = toHtml . mr <$> fsTooltip
|
||||||
fvInput = $(widgetFile "widgets/massinput/massinput")
|
fvInput = $(widgetFile "widgets/massinput/massinput")
|
||||||
fvErrors = Nothing
|
fvErrors = case result of
|
||||||
|
FormFailure errs | not $ null errs -> Just . mconcat . intersperse [shamlet|<br />|] $ map toMarkup errs
|
||||||
|
_other -> Nothing
|
||||||
in return (result, FieldView{..})
|
in return (result, FieldView{..})
|
||||||
|
|
||||||
defaultMiLayout :: forall liveliness cellData cellResult.
|
defaultMiLayout :: forall liveliness cellData cellResult.
|
||||||
@ -455,24 +457,26 @@ listMiLayout lLength _ cellWdgts delButtons addWdgts = $(widgetFile "widgets/mas
|
|||||||
|
|
||||||
|
|
||||||
-- | Wrapper around `massInput` for the common case, that we just want an arbitrary list of single fields without any constraints
|
-- | Wrapper around `massInput` for the common case, that we just want an arbitrary list of single fields without any constraints
|
||||||
massInputList :: forall handler cellResult ident.
|
massInputList :: forall handler cellResult ident msg.
|
||||||
( MonadHandler handler, HandlerSite handler ~ UniWorX
|
( MonadHandler handler, HandlerSite handler ~ UniWorX
|
||||||
, MonadThrow handler
|
, MonadThrow handler
|
||||||
, PathPiece ident
|
, PathPiece ident
|
||||||
|
, RenderMessage UniWorX msg
|
||||||
)
|
)
|
||||||
=> Field handler cellResult
|
=> Field handler cellResult
|
||||||
-> (ListPosition -> FieldSettings UniWorX)
|
-> (ListPosition -> FieldSettings UniWorX)
|
||||||
|
-> msg
|
||||||
-> (forall p. PathPiece p => p -> Maybe (SomeRoute UniWorX))
|
-> (forall p. PathPiece p => p -> Maybe (SomeRoute UniWorX))
|
||||||
-> ident
|
-> ident
|
||||||
-> FieldSettings UniWorX
|
-> FieldSettings UniWorX
|
||||||
-> Bool
|
-> Bool
|
||||||
-> Maybe [cellResult]
|
-> Maybe [cellResult]
|
||||||
-> (Markup -> MForm handler (FormResult [cellResult], FieldView UniWorX))
|
-> (Markup -> MForm handler (FormResult [cellResult], FieldView UniWorX))
|
||||||
massInputList field fieldSettings miButtonAction miIdent miSettings miRequired miPrevResult = over (mapped . _1 . mapped) (map snd . Map.elems) . massInput
|
massInputList field fieldSettings onMissing miButtonAction miIdent miSettings miRequired miPrevResult = over (mapped . _1 . mapped) (map snd . Map.elems) . massInput
|
||||||
MassInput { miAdd = \_ _ _ submitBtn -> Just $ \csrf ->
|
MassInput { miAdd = \_ _ _ submitBtn -> Just $ \csrf ->
|
||||||
return (FormSuccess $ \pRes -> FormSuccess $ Map.singleton (maybe 0 succ . fmap fst $ Map.lookupMax pRes) (), toWidget csrf >> fvInput submitBtn)
|
return (FormSuccess $ \pRes -> FormSuccess $ Map.singleton (maybe 0 succ . fmap fst $ Map.lookupMax pRes) (), toWidget csrf >> fvWidget submitBtn)
|
||||||
, miCell = \pos () iRes nudge csrf ->
|
, miCell = \pos () iRes nudge csrf ->
|
||||||
over _2 (\FieldView{..} -> $(widgetFile "widgets/massinput/list/cell")) <$> mreq field (fieldSettings pos & addName (nudge "field")) iRes
|
over _2 (\fv -> $(widgetFile "widgets/massinput/list/cell")) <$> mreqMsg field (fieldSettings pos & addName (nudge "field")) onMissing iRes
|
||||||
, miDelete = miDeleteList
|
, miDelete = miDeleteList
|
||||||
, miAllowAdd = \_ _ _ -> True
|
, miAllowAdd = \_ _ _ -> True
|
||||||
, miAddEmpty = \_ _ _ -> Set.empty
|
, miAddEmpty = \_ _ _ -> Set.empty
|
||||||
@ -484,20 +488,22 @@ massInputList field fieldSettings miButtonAction miIdent miSettings miRequired m
|
|||||||
miRequired
|
miRequired
|
||||||
(Map.fromList . zip [0..] . map ((), ) <$> miPrevResult)
|
(Map.fromList . zip [0..] . map ((), ) <$> miPrevResult)
|
||||||
|
|
||||||
massInputListA :: forall handler cellResult ident.
|
massInputListA :: forall handler cellResult ident msg.
|
||||||
( MonadHandler handler, HandlerSite handler ~ UniWorX
|
( MonadHandler handler, HandlerSite handler ~ UniWorX
|
||||||
, MonadThrow handler
|
, MonadThrow handler
|
||||||
, PathPiece ident
|
, PathPiece ident
|
||||||
|
, RenderMessage UniWorX msg
|
||||||
)
|
)
|
||||||
=> Field handler cellResult
|
=> Field handler cellResult
|
||||||
-> (ListPosition -> FieldSettings UniWorX)
|
-> (ListPosition -> FieldSettings UniWorX)
|
||||||
|
-> msg
|
||||||
-> (forall p. PathPiece p => p -> Maybe (SomeRoute UniWorX))
|
-> (forall p. PathPiece p => p -> Maybe (SomeRoute UniWorX))
|
||||||
-> ident
|
-> ident
|
||||||
-> FieldSettings UniWorX
|
-> FieldSettings UniWorX
|
||||||
-> Bool
|
-> Bool
|
||||||
-> Maybe [cellResult]
|
-> Maybe [cellResult]
|
||||||
-> AForm handler [cellResult]
|
-> AForm handler [cellResult]
|
||||||
massInputListA field fieldSettings miButtonAction miIdent miSettings miRequired miPrevResult = formToAForm . fmap (over _2 pure) $ massInputList field fieldSettings miButtonAction miIdent miSettings miRequired miPrevResult mempty
|
massInputListA field fieldSettings onMissing miButtonAction miIdent miSettings miRequired miPrevResult = formToAForm . fmap (over _2 pure) $ massInputList field fieldSettings onMissing miButtonAction miIdent miSettings miRequired miPrevResult mempty
|
||||||
|
|
||||||
|
|
||||||
-- | Wrapper around `massInput` for the common case, that we just want a list of data with no option to modify it except deletion and addition
|
-- | Wrapper around `massInput` for the common case, that we just want a list of data with no option to modify it except deletion and addition
|
||||||
|
|||||||
@ -1598,4 +1598,4 @@ dbSelect resLens selLens genIndex = Colonnade.singleton (headednessPure $ mempty
|
|||||||
where
|
where
|
||||||
genForm _ mkUnique = do
|
genForm _ mkUnique = do
|
||||||
(selResult, selWidget) <- mreq checkBoxField (fsUniq mkUnique "select") (Just False)
|
(selResult, selWidget) <- mreq checkBoxField (fsUniq mkUnique "select") (Just False)
|
||||||
return (set selLens <$> selResult, [whamlet|^{fvInput selWidget}|])
|
return (set selLens <$> selResult, [whamlet|^{fvWidget selWidget}|])
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import ClassyPrelude.Yesod as Import
|
|||||||
, embed
|
, embed
|
||||||
, try, embed, catches, handle, catch, bracket, bracketOnError, bracket_, catchJust, finally, handleJust, mask, mask_, onException, tryJust, uninterruptibleMask, uninterruptibleMask_
|
, try, embed, catches, handle, catch, bracket, bracketOnError, bracket_, catchJust, finally, handleJust, mask, mask_, onException, tryJust, uninterruptibleMask, uninterruptibleMask_
|
||||||
, htmlField, fileField
|
, htmlField, fileField
|
||||||
|
, mreq, areq, wreq -- Use `mreqMsg`, `areqMsg`, `wreqMsg`
|
||||||
)
|
)
|
||||||
|
|
||||||
import UnliftIO.Async.Utils as Import
|
import UnliftIO.Async.Utils as Import
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
module Utils.Form where
|
module Utils.Form where
|
||||||
|
|
||||||
import ClassyPrelude.Yesod hiding (addMessage, addMessageI, cons, Proxy(..), identifyForm, addClass)
|
import ClassyPrelude.Yesod hiding (addMessage, addMessageI, cons, Proxy(..), identifyForm, addClass, mreq, areq, wreq)
|
||||||
import qualified Yesod.Form.Functions as Yesod
|
import qualified Yesod.Form.Functions as Yesod
|
||||||
import Yesod.Core.Instances ()
|
import Yesod.Core.Instances ()
|
||||||
import Settings
|
import Settings
|
||||||
@ -409,7 +409,7 @@ buttonForm' btns csrf = do
|
|||||||
$newline never
|
$newline never
|
||||||
#{csrf}
|
#{csrf}
|
||||||
$forall bView <- fViews
|
$forall bView <- fViews
|
||||||
^{fvInput bView}
|
^{fvWidget bView}
|
||||||
|])
|
|])
|
||||||
|
|
||||||
withButtonForm' :: (MonadHandler m, Button (HandlerSite m) btn)
|
withButtonForm' :: (MonadHandler m, Button (HandlerSite m) btn)
|
||||||
@ -932,6 +932,9 @@ formSection formSectionTitle = do
|
|||||||
, fvInput = mempty
|
, fvInput = mempty
|
||||||
})
|
})
|
||||||
|
|
||||||
|
fvWidget :: FieldView site -> WidgetFor site ()
|
||||||
|
fvWidget FieldView{..} = $(widgetFile "widgets/field-view/field-view")
|
||||||
|
|
||||||
-------------------
|
-------------------
|
||||||
-- Special Forms --
|
-- Special Forms --
|
||||||
-------------------
|
-------------------
|
||||||
@ -945,7 +948,7 @@ aformSection' = formToAForm . fmap (second pure) . formSection'
|
|||||||
-- allows tooltips and arbitrary attributs. Section header must be given through `fsLabel`
|
-- allows tooltips and arbitrary attributs. Section header must be given through `fsLabel`
|
||||||
formSection' :: (MonadHandler m, site ~ HandlerSite m, RenderMessage site FormMessage) =>
|
formSection' :: (MonadHandler m, site ~ HandlerSite m, RenderMessage site FormMessage) =>
|
||||||
FieldSettings site -> MForm m (FormResult (), FieldView site) -- TODO: WIP, delete
|
FieldSettings site -> MForm m (FormResult (), FieldView site) -- TODO: WIP, delete
|
||||||
formSection' formSectionTitleSettings = mreq noinputField sectionSettings Nothing
|
formSection' formSectionTitleSettings = Yesod.mreq noinputField sectionSettings Nothing
|
||||||
where
|
where
|
||||||
sectionSettings = formSectionTitleSettings { fsId = Just idFormSectionNoinput }
|
sectionSettings = formSectionTitleSettings { fsId = Just idFormSectionNoinput }
|
||||||
|
|
||||||
@ -1157,6 +1160,31 @@ wFormFields = mapRWST (fmap (\((a, s, w'), w) -> ((a, w), s, w')) . censor (cons
|
|||||||
-- Special variants of @mopt@, @mreq@, ... --
|
-- Special variants of @mopt@, @mreq@, ... --
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
data ValueRequired site = forall msg. RenderMessage site msg => ValueRequired msg
|
||||||
|
|
||||||
|
mreq :: forall m a.
|
||||||
|
( MonadHandler m
|
||||||
|
, RenderMessage (HandlerSite m) (ValueRequired (HandlerSite m))
|
||||||
|
)
|
||||||
|
=> Field m a -> FieldSettings (HandlerSite m) -> Maybe a -> MForm m (FormResult a, FieldView (HandlerSite m))
|
||||||
|
mreq f fs@FieldSettings{..} mdef = mreqMsg f fs (ValueRequired fsLabel) mdef
|
||||||
|
|
||||||
|
wreq :: forall m a.
|
||||||
|
( MonadHandler m
|
||||||
|
, RenderMessage (HandlerSite m) (ValueRequired (HandlerSite m))
|
||||||
|
)
|
||||||
|
=> Field m a -> FieldSettings (HandlerSite m) -> Maybe a -> WForm m (FormResult a)
|
||||||
|
wreq f fs@FieldSettings{..} mdef = wreqMsg f fs (ValueRequired fsLabel) mdef
|
||||||
|
|
||||||
|
areq :: forall m a.
|
||||||
|
( MonadHandler m
|
||||||
|
, RenderMessage (HandlerSite m) (ValueRequired (HandlerSite m))
|
||||||
|
)
|
||||||
|
=> Field m a -> FieldSettings (HandlerSite m) -> Maybe a -> AForm m a
|
||||||
|
areq f fs@FieldSettings{..} mdef = areqMsg f fs (ValueRequired fsLabel) mdef
|
||||||
|
|
||||||
|
|
||||||
mforced :: (site ~ HandlerSite m, MonadHandler m)
|
mforced :: (site ~ HandlerSite m, MonadHandler m)
|
||||||
=> Field m a -> FieldSettings site -> a -> MForm m (FormResult a, FieldView site)
|
=> Field m a -> FieldSettings site -> a -> MForm m (FormResult a, FieldView site)
|
||||||
mforced Field{..} FieldSettings{..} val = do
|
mforced Field{..} FieldSettings{..} val = do
|
||||||
@ -1223,13 +1251,13 @@ wforcedJust f fs (Just fDef) = wforced f fs fDef
|
|||||||
wforcedJust _ _ Nothing = error "wforcedJust called with Nothing"
|
wforcedJust _ _ Nothing = error "wforcedJust called with Nothing"
|
||||||
|
|
||||||
|
|
||||||
mpreq :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m)
|
mpreq :: (RenderMessage site (ValueRequired site), HandlerSite m ~ site, MonadHandler m)
|
||||||
=> Field m a -> FieldSettings site -> Maybe a -> MForm m (FormResult a, FieldView site)
|
=> Field m a -> FieldSettings site -> Maybe a -> MForm m (FormResult a, FieldView site)
|
||||||
-- ^ Pseudo required
|
-- ^ Pseudo required
|
||||||
--
|
--
|
||||||
-- `FieldView` has `fvRequired` set to `True` and @FormSuccess Nothing@ is cast to `FormFailure`.
|
-- `FieldView` has `fvRequired` set to `True` and @FormSuccess Nothing@ is cast to `FormFailure`.
|
||||||
-- Otherwise acts exactly like `mopt`.
|
-- Otherwise acts exactly like `mopt`.
|
||||||
mpreq f fs mx = do
|
mpreq f fs@FieldSettings{..} mx = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
(res, fv) <- mopt f fs (Just <$> mx)
|
(res, fv) <- mopt f fs (Just <$> mx)
|
||||||
let fv' = fv { fvRequired = True }
|
let fv' = fv { fvRequired = True }
|
||||||
@ -1237,22 +1265,33 @@ mpreq f fs mx = do
|
|||||||
FormSuccess (Just res')
|
FormSuccess (Just res')
|
||||||
-> (FormSuccess res', fv')
|
-> (FormSuccess res', fv')
|
||||||
FormSuccess Nothing
|
FormSuccess Nothing
|
||||||
-> (FormFailure [mr MsgValueRequired], fv' { fvErrors = Just . toHtml $ mr MsgValueRequired })
|
-> let errMsg = mr $ ValueRequired fsLabel
|
||||||
|
in ( FormFailure [errMsg]
|
||||||
|
, fv' { fvErrors = Just
|
||||||
|
[shamlet|
|
||||||
|
$newline never
|
||||||
|
$maybe pErr <- fvErrors fv'
|
||||||
|
#{pErr}
|
||||||
|
<br />
|
||||||
|
#{errMsg}
|
||||||
|
|]
|
||||||
|
}
|
||||||
|
)
|
||||||
FormFailure errs
|
FormFailure errs
|
||||||
-> (FormFailure errs, fv')
|
-> (FormFailure errs, fv')
|
||||||
FormMissing
|
FormMissing
|
||||||
-> (FormMissing, fv')
|
-> (FormMissing, fv')
|
||||||
|
|
||||||
apreq :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m)
|
apreq :: (RenderMessage site (ValueRequired site), HandlerSite m ~ site, MonadHandler m)
|
||||||
=> Field m a -> FieldSettings site -> Maybe a -> AForm m a
|
=> Field m a -> FieldSettings site -> Maybe a -> AForm m a
|
||||||
apreq f fs mx = formToAForm $ over _2 pure <$> mpreq f fs mx
|
apreq f fs mx = formToAForm $ over _2 pure <$> mpreq f fs mx
|
||||||
|
|
||||||
wpreq :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m)
|
wpreq :: (RenderMessage site (ValueRequired site), HandlerSite m ~ site, MonadHandler m)
|
||||||
=> Field m a -> FieldSettings site -> Maybe a -> WForm m (FormResult a)
|
=> Field m a -> FieldSettings site -> Maybe a -> WForm m (FormResult a)
|
||||||
wpreq f fs mx = mFormToWForm $ mpreq f fs mx
|
wpreq f fs mx = mFormToWForm $ mpreq f fs mx
|
||||||
|
|
||||||
|
|
||||||
mpopt :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m)
|
mpopt :: (RenderMessage site (ValueRequired site), HandlerSite m ~ site, MonadHandler m)
|
||||||
=> Field m a -> FieldSettings site -> Maybe a -> MForm m (FormResult a, FieldView site)
|
=> Field m a -> FieldSettings site -> Maybe a -> MForm m (FormResult a, FieldView site)
|
||||||
-- ^ Pseudo optional
|
-- ^ Pseudo optional
|
||||||
--
|
--
|
||||||
@ -1260,10 +1299,10 @@ mpopt :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m)
|
|||||||
-- Otherwise acts exactly like `mreq`.
|
-- Otherwise acts exactly like `mreq`.
|
||||||
mpopt f fs mx = set (_2 . _fvRequired) False <$> mreq f fs mx
|
mpopt f fs mx = set (_2 . _fvRequired) False <$> mreq f fs mx
|
||||||
|
|
||||||
apopt :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m)
|
apopt :: (RenderMessage site (ValueRequired site), HandlerSite m ~ site, MonadHandler m)
|
||||||
=> Field m a -> FieldSettings site -> Maybe a -> AForm m a
|
=> Field m a -> FieldSettings site -> Maybe a -> AForm m a
|
||||||
apopt f fs mx = formToAForm $ over _2 pure <$> mpopt f fs mx
|
apopt f fs mx = formToAForm $ over _2 pure <$> mpopt f fs mx
|
||||||
|
|
||||||
wpopt :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m)
|
wpopt :: (RenderMessage site (ValueRequired site), HandlerSite m ~ site, MonadHandler m)
|
||||||
=> Field m a -> FieldSettings site -> Maybe a -> WForm m (FormResult a)
|
=> Field m a -> FieldSettings site -> Maybe a -> WForm m (FormResult a)
|
||||||
wpopt f fs mx = mFormToWForm $ mpopt f fs mx
|
wpopt f fs mx = mFormToWForm $ mpopt f fs mx
|
||||||
|
|||||||
@ -84,6 +84,7 @@ data Icon
|
|||||||
| IconBreadcrumbSeparator
|
| IconBreadcrumbSeparator
|
||||||
| IconMissingAllocationPriority
|
| IconMissingAllocationPriority
|
||||||
| IconFileUploadSession
|
| IconFileUploadSession
|
||||||
|
| IconStandaloneFieldError
|
||||||
deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic, Typeable)
|
deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic, Typeable)
|
||||||
|
|
||||||
iconText :: Icon -> Text
|
iconText :: Icon -> Text
|
||||||
@ -146,6 +147,7 @@ iconText = \case
|
|||||||
IconBreadcrumbSeparator -> "angle-right"
|
IconBreadcrumbSeparator -> "angle-right"
|
||||||
IconMissingAllocationPriority -> "empty-set"
|
IconMissingAllocationPriority -> "empty-set"
|
||||||
IconFileUploadSession -> "file-upload"
|
IconFileUploadSession -> "file-upload"
|
||||||
|
IconStandaloneFieldError -> "exclamation"
|
||||||
|
|
||||||
instance Universe Icon
|
instance Universe Icon
|
||||||
instance Finite Icon
|
instance Finite Icon
|
||||||
|
|||||||
@ -7,7 +7,7 @@ $if is _Just muid
|
|||||||
_{MsgAllocationPriority}
|
_{MsgAllocationPriority}
|
||||||
<div .allocation-course__priority>
|
<div .allocation-course__priority>
|
||||||
$maybe prioView <- mApplyFormView' >>= afvPriority
|
$maybe prioView <- mApplyFormView' >>= afvPriority
|
||||||
^{fvInput prioView}
|
^{fvWidget prioView}
|
||||||
$nothing
|
$nothing
|
||||||
_{MsgAllocationNoApplication}
|
_{MsgAllocationNoApplication}
|
||||||
<a .allocation-course__name href=@{CourseR courseTerm courseSchool courseShorthand CShowR} target="_blank">
|
<a .allocation-course__name href=@{CourseR courseTerm courseSchool courseShorthand CShowR} target="_blank">
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td colspan=3>
|
<td colspan=3>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput addView}
|
^{fvWidget addView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput btn}
|
^{fvWidget btn}
|
||||||
|
|||||||
@ -6,4 +6,4 @@
|
|||||||
<td>
|
<td>
|
||||||
^{messageTooltip invWarnMsg}
|
^{messageTooltip invWarnMsg}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput lrwView}
|
^{fvWidget lrwView}
|
||||||
|
|||||||
@ -3,4 +3,4 @@ $newline never
|
|||||||
#{csrf}
|
#{csrf}
|
||||||
^{nameEmailWidget userEmail userDisplayName userSurname} #
|
^{nameEmailWidget userEmail userDisplayName userSurname} #
|
||||||
<td>
|
<td>
|
||||||
^{fvInput lrwView}
|
^{fvWidget lrwView}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ $newline never
|
|||||||
<tr .massinput__cell>
|
<tr .massinput__cell>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
^{addWdgts ! (0, 0)}
|
^{addWdgts ! (0, 0)}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td>
|
<td>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput addView}
|
^{fvWidget addView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ $newline never
|
|||||||
<tr .massinput__cell>
|
<tr .massinput__cell>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
^{addWdgts ! (0, 0)}
|
^{addWdgts ! (0, 0)}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td colspan=2>
|
<td colspan=2>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput addView}
|
^{fvWidget addView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ $newline never
|
|||||||
<tr .massinput__cell>
|
<tr .massinput__cell>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
^{addWdgts ! (0, 0)}
|
^{addWdgts ! (0, 0)}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td colspan=5>
|
<td colspan=5>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput addView}
|
^{fvWidget addView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ $case userIdent
|
|||||||
^{identWidget}
|
^{identWidget}
|
||||||
<td>
|
<td>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput stateView}
|
^{fvWidget stateView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput byTutView}
|
^{fvWidget byTutView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput propView}
|
^{fvWidget propView}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ $newline never
|
|||||||
<tr .massinput__cell .table__row>
|
<tr .massinput__cell .table__row>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
^{addWdgts ! (0, 0)}
|
^{addWdgts ! (0, 0)}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td colspan=2>
|
<td colspan=2>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput addView}
|
^{fvWidget addView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ $newline never
|
|||||||
<tr .massinput__cell>
|
<tr .massinput__cell>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
^{addWdgts ! (0, 0)}
|
^{addWdgts ! (0, 0)}
|
||||||
|
|||||||
@ -28,7 +28,8 @@ $case formLayout
|
|||||||
<div .form-group__input>
|
<div .form-group__input>
|
||||||
^{fvInput view}
|
^{fvInput view}
|
||||||
$maybe err <- fvErrors view
|
$maybe err <- fvErrors view
|
||||||
<div .form-error>#{err}
|
<div .form-error>
|
||||||
|
#{err}
|
||||||
$if formHasRequiredFields
|
$if formHasRequiredFields
|
||||||
<div .form-section-legend>
|
<div .form-section-legend>
|
||||||
<span .form-group__required-marker>
|
<span .form-group__required-marker>
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>_{MsgCampusIdent}
|
<th>_{MsgCampusIdent}
|
||||||
<td>^{fvInput identView}
|
<td>^{fvWidget identView}
|
||||||
<tr>
|
<tr>
|
||||||
<th>_{MsgCampusPassword}
|
<th>_{MsgCampusPassword}
|
||||||
<td>^{fvInput passwordView}
|
<td>^{fvWidget passwordView}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" style="text-align: right">
|
<td colspan="2" style="text-align: right">
|
||||||
<button type="submit">_{MsgCampusSubmit}
|
<button type="submit">_{MsgCampusSubmit}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<div .recipient-category__option-add.massinput__cell.massinput__cell--add>
|
<div .recipient-category__option-add.massinput__cell.massinput__cell--add>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput addView}
|
^{fvWidget addView}
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<div .recipient-category__option.massinput__cell>
|
<div .recipient-category__option.massinput__cell>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput tickView}
|
^{fvWidget tickView}
|
||||||
<label .recipient-category__option-label for=#{fvId tickView}>
|
<label .recipient-category__option-label for=#{fvId tickView}>
|
||||||
#{email}
|
#{email}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<div .recipient-category__option.massinput__cell>
|
<div .recipient-category__option.massinput__cell>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput tickView}
|
^{fvWidget tickView}
|
||||||
<label .recipient-category__option-label for=#{fvId tickView}>
|
<label .recipient-category__option-label for=#{fvId tickView}>
|
||||||
#{nameHtml userDisplayName userSurname}
|
#{nameHtml userDisplayName userSurname}
|
||||||
|
|||||||
7
templates/widgets/field-view/field-view.hamlet
Normal file
7
templates/widgets/field-view/field-view.hamlet
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
$newline never
|
||||||
|
<div .standalone-field .interactive-fieldset__target :fvRequired:.standalone-field--required :not fvRequired:.standalone-field--optional :is _Just fvErrors:.standalone-field--has-error>
|
||||||
|
<div .standalone-field__input>
|
||||||
|
^{fvInput}
|
||||||
|
$maybe err <- fvErrors
|
||||||
|
<div .standalone-field__error>
|
||||||
|
^{messageTooltip (Message Error err $ Just IconStandaloneFieldError)}
|
||||||
@ -1,3 +1,3 @@
|
|||||||
^{cellWdgt}
|
^{cellWdgt}
|
||||||
$maybe delWdgt <- fmap fvInput deleteButton
|
$maybe delWdgt <- fmap fvWidget deleteButton
|
||||||
^{delWdgt}
|
^{delWdgt}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td colspan=3>
|
<td colspan=3>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput addView}
|
^{fvWidget addView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput btn}
|
^{fvWidget btn}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ $newline never
|
|||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
$maybe delButton <- delButtons !? coord
|
$maybe delButton <- delButtons !? coord
|
||||||
^{fvInput delButton}
|
^{fvWidget delButton}
|
||||||
$maybe addWdgt <- addWdgts !? (0, 0)
|
$maybe addWdgt <- addWdgts !? (0, 0)
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td colspan=2>
|
<td colspan=2>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput addView}
|
^{fvWidget addView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ $newline never
|
|||||||
<tr .massinput__cell>
|
<tr .massinput__cell>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
^{addWdgts ! (0, 0)}
|
^{addWdgts ! (0, 0)}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td colspan=2>
|
<td colspan=2>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput addView}
|
^{fvWidget addView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput btn}
|
^{fvWidget btn}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ $newline never
|
|||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
$maybe delButton <- delButtons !? coord
|
$maybe delButton <- delButtons !? coord
|
||||||
^{fvInput delButton}
|
^{fvWidget delButton}
|
||||||
$maybe addWdgt <- addWdgts !? (0, 0)
|
$maybe addWdgt <- addWdgts !? (0, 0)
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
$newline never
|
$newline never
|
||||||
^{formWidget}
|
^{formWidget}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td>#{csrf}^{fvInput epfIdView}^{fvInput epfNumberView}
|
<td>
|
||||||
<td>^{fvInput epfNameView}
|
#{csrf}
|
||||||
<td>^{fvInput epfMaxPointsView}
|
^{fvInput epfIdView}
|
||||||
<td>^{fvInput epfWeightView}
|
^{fvWidget epfNumberView}
|
||||||
|
<td>^{fvWidget epfNameView}
|
||||||
|
<td>^{fvWidget epfMaxPointsView}
|
||||||
|
<td>^{fvWidget epfWeightView}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ $newline never
|
|||||||
<tr .massinput__cell>
|
<tr .massinput__cell>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
^{addWdgts ! (0, 0)}
|
^{addWdgts ! (0, 0)}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
$newline never
|
$newline never
|
||||||
^{formWidget}
|
^{formWidget}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td>#{csrf}^{fvInput eofIdView}^{fvInput eofNameView}
|
<td>#{csrf}^{fvInput eofIdView}^{fvWidget eofNameView}
|
||||||
<td>^{fvInput eofRoomView}
|
<td>^{fvWidget eofRoomView}
|
||||||
<td>^{fvInput eofCapacityView}
|
<td>^{fvWidget eofCapacityView}
|
||||||
<td>^{fvInput eofStartView}
|
<td>^{fvWidget eofStartView}
|
||||||
<td>^{fvInput eofEndView}
|
<td>^{fvWidget eofEndView}
|
||||||
<td>^{fvInput eofDescView}
|
<td>^{fvWidget eofDescView}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ $newline never
|
|||||||
<tr .massinput__cell>
|
<tr .massinput__cell>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
^{addWdgts ! (0, 0)}
|
^{addWdgts ! (0, 0)}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
$newline never
|
$newline never
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput}
|
^{fvWidget fv}
|
||||||
|
|||||||
@ -5,6 +5,6 @@ $newline never
|
|||||||
<div .massinput-list__field>
|
<div .massinput-list__field>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<div .massinput-list__delete>
|
<div .massinput-list__delete>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
<div .massinput-list__add .massinput__cell .massinput__cell--add>
|
<div .massinput-list__add .massinput__cell .massinput__cell--add>
|
||||||
^{addWdgts ! (0, 0)}
|
^{addWdgts ! (0, 0)}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td colspan=2>
|
<td colspan=2>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput addView}
|
^{fvWidget addView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput btn}
|
^{fvWidget btn}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ $newline never
|
|||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
$maybe delButton <- delButtons !? coord
|
$maybe delButton <- delButtons !? coord
|
||||||
^{fvInput delButton}
|
^{fvWidget delButton}
|
||||||
$maybe addWdgt <- addWdgts !? (0, 0)
|
$maybe addWdgt <- addWdgts !? (0, 0)
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td>
|
<td>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput routeView}<br />
|
^{fvWidget routeView}<br />
|
||||||
^{fvInput restrView}
|
^{fvWidget restrView}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput btn}
|
^{fvWidget btn}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td>
|
<td>
|
||||||
#{csrf}
|
#{csrf}
|
||||||
^{fvInput routeView}<br />
|
^{fvWidget routeView}<br />
|
||||||
^{fvInput restrView}
|
^{fvWidget restrView}
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@ -6,7 +6,7 @@ $newline never
|
|||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
$maybe delButton <- delButtons !? coord
|
$maybe delButton <- delButtons !? coord
|
||||||
^{fvInput delButton}
|
^{fvWidget delButton}
|
||||||
$maybe addWdgt <- addWdgts !? (0, 0)
|
$maybe addWdgt <- addWdgts !? (0, 0)
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
$newline never
|
$newline never
|
||||||
^{formWidget}
|
^{formWidget}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<td>#{csrf}^{fvInput labelView}
|
<td>#{csrf}^{fvWidget labelView}
|
||||||
<td>^{fvInput nameView}
|
<td>^{fvWidget nameView}
|
||||||
<td>^{fvInput reqView}
|
<td>^{fvWidget reqView}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ $newline never
|
|||||||
<tr .massinput__cell>
|
<tr .massinput__cell>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr .massinput__cell.massinput__cell--add>
|
<tr .massinput__cell.massinput__cell--add>
|
||||||
^{addWdgts ! (0, 0)}
|
^{addWdgts ! (0, 0)}
|
||||||
|
|||||||
@ -2,4 +2,4 @@ $newline never
|
|||||||
<td colspan=2>
|
<td colspan=2>
|
||||||
^{addWidget}
|
^{addWidget}
|
||||||
<td style="vertical-align: bottom">
|
<td style="vertical-align: bottom">
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ $newline never
|
|||||||
<tr .massinput__cell>
|
<tr .massinput__cell>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
$if null (review liveCoords lLength)
|
$if null (review liveCoords lLength)
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan=3 style="font-weight: 600; font-size: 0.9rem; color: var(--color-fontsec);">
|
<td colspan=3 style="font-weight: 600; font-size: 0.9rem; color: var(--color-fontsec);">
|
||||||
|
|||||||
@ -2,4 +2,4 @@ $newline never
|
|||||||
<td colspan=2>
|
<td colspan=2>
|
||||||
^{addWidget}
|
^{addWidget}
|
||||||
<td style="vertical-align: bottom">
|
<td style="vertical-align: bottom">
|
||||||
^{fvInput submitView}
|
^{fvWidget submitView}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ $newline never
|
|||||||
<tr .massinput__cell>
|
<tr .massinput__cell>
|
||||||
^{cellWdgts ! coord}
|
^{cellWdgts ! coord}
|
||||||
<td>
|
<td>
|
||||||
^{fvInput (delButtons ! coord)}
|
^{fvWidget (delButtons ! coord)}
|
||||||
$if null (review liveCoords lLength)
|
$if null (review liveCoords lLength)
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan=3 style="font-weight: 600; font-size: 0.9rem; color: var(--color-fontsec);">
|
<td colspan=3 style="font-weight: 600; font-size: 0.9rem; color: var(--color-fontsec);">
|
||||||
|
|||||||
@ -4,11 +4,11 @@ $# extra protects us against CSRF
|
|||||||
$# Maybe display textField for passcode
|
$# Maybe display textField for passcode
|
||||||
$maybe secretView <- msecretView
|
$maybe secretView <- msecretView
|
||||||
^{fvLabel secretView}
|
^{fvLabel secretView}
|
||||||
^{fvInput secretView}
|
^{fvWidget secretView}
|
||||||
$# Ask for associated primary field uf study, unless registered
|
$# Ask for associated primary field uf study, unless registered
|
||||||
$maybe sfView <- msfView
|
$maybe sfView <- msfView
|
||||||
^{fvLabel sfView}
|
^{fvLabel sfView}
|
||||||
^{fvInput sfView}
|
^{fvWidget sfView}
|
||||||
|
|
||||||
$# Always display register/deregister button
|
$# Always display register/deregister button
|
||||||
^{fvInput btnView}
|
^{fvWidget btnView}
|
||||||
|
|||||||
@ -16,4 +16,4 @@ $newline never
|
|||||||
$forall function <- allFunctions
|
$forall function <- allFunctions
|
||||||
<td .table__td>
|
<td .table__td>
|
||||||
$maybe (_, boxView) <- Map.lookup (function, sid) boxRights
|
$maybe (_, boxView) <- Map.lookup (function, sid) boxRights
|
||||||
^{fvInput boxView}
|
^{fvWidget boxView}
|
||||||
|
|||||||
Reference in New Issue
Block a user