Edition préférences: sections dépliables. + Code cleaning.

This commit is contained in:
Emmanuel Viennet 2022-10-02 23:43:29 +02:00
parent ad46a190ab
commit 37a8b3bb0b
41 changed files with 178 additions and 127 deletions

View File

@ -47,7 +47,7 @@ def pvjury_table_but(formsemestre_id: int, format="html"):
title = "Procès-verbal de jury BUT annuel"
if format == "html":
line_sep = "<br/>"
line_sep = "<br>"
else:
line_sep = "\n"
# remplace pour le BUT la fonction sco_pvjury.pvjury_table

View File

@ -253,7 +253,7 @@ def get_annotation_PE(etudid, tag_annotation_pe):
) # Suppression du tag d'annotation PE
annotationPE = annotationPE.replace("\r", "") # Suppression des \r
annotationPE = annotationPE.replace(
"<br/>", "\n\n"
"<br>", "\n\n"
) # Interprète les retours chariots html
return annotationPE
return "" # pas d'annotations

View File

@ -55,7 +55,7 @@ def _pe_view_sem_recap_form(formsemestre_id):
<p class="help">
Cette fonction génère un ensemble de fichiers permettant d'éditer des avis de
poursuites d'études.
<br/>
<br>
De nombreux aspects sont paramétrables:
<a href="https://scodoc.org/AvisPoursuiteEtudes" target="_blank" rel="noopener">
voir la documentation</a>.
@ -65,7 +65,7 @@ def _pe_view_sem_recap_form(formsemestre_id):
<div class="pe_template_up">
Les templates sont généralement installés sur le serveur ou dans le
paramétrage de ScoDoc.
<br/>
<br>
Au besoin, vous pouvez spécifier ici votre propre fichier de template
(<tt>un_avis.tex</tt>):
<div class="pe_template_upb">Template:

View File

@ -38,6 +38,9 @@ def TrivialFormulator(
html_foot_markup="",
readonly=False,
is_submitted=False,
title="",
after_table="",
before_table="{title}",
):
"""
form_url : URL for this form
@ -74,7 +77,8 @@ def TrivialFormulator(
HTML elements:
input_type : 'text', 'textarea', 'password',
'radio', 'menu', 'checkbox',
'hidden', 'separator', 'file', 'date', 'datedmy' (avec validation),
'hidden', 'separator', 'table_separator',
'file', 'date', 'datedmy' (avec validation),
'boolcheckbox', 'text_suggest',
'color'
(default text)
@ -111,6 +115,9 @@ def TrivialFormulator(
html_foot_markup=html_foot_markup,
readonly=readonly,
is_submitted=is_submitted,
title=title,
after_table=after_table,
before_table=before_table,
)
form = t.getform()
if t.canceled():
@ -144,6 +151,9 @@ class TF(object):
html_foot_markup="", # html snippet put at the end, just after the table
readonly=False,
is_submitted=False,
title="",
after_table="",
before_table="{title}",
):
self.form_url = form_url
self.values = values.copy()
@ -165,6 +175,9 @@ class TF(object):
self.top_buttons = top_buttons
self.bottom_buttons = bottom_buttons
self.html_foot_markup = html_foot_markup
self.title = title
self.after_table = after_table
self.before_table = before_table
self.readonly = readonly
self.result = None
self.is_submitted = is_submitted
@ -426,6 +439,7 @@ class TF(object):
R.append('<input type="hidden" name="%s_submitted" value="1">' % self.formid)
if self.top_buttons:
R.append(buttons_markup + "<p></p>")
R.append(self.before_table.format(title=self.title))
R.append('<table class="tf">')
for field, descr in self.formdescription:
if descr.get("readonly", False):
@ -453,6 +467,16 @@ class TF(object):
etempl = separatortemplate
R.append(etempl % {"label": title, "item_dom_attr": item_dom_attr})
continue
elif input_type == "table_separator":
etempl = ""
# Table ouverte ?
if len([p for p in R if "<table" in p]) > len(
[p for p in R if "</table" in p]
):
R.append(f"""</table>{self.after_table}""")
R.append(
f"""{self.before_table.format(title=descr.get("title", ""))}<table class="tf">"""
)
else:
etempl = itemtemplate
lab = []
@ -610,7 +634,7 @@ class TF(object):
'<input type="hidden" name="%s" id="%s" value="%s" %s >'
% (field, wid, values[field], attribs)
)
elif input_type == "separator":
elif (input_type == "separator") or (input_type == "table_separator"):
pass
elif input_type == "file":
lem.append(
@ -641,13 +665,15 @@ var {field}_as = new bsn.AutoSuggest('{field}', {field}_opts);
)
lem.append(('value="%(' + field + ')s" >') % values)
else:
raise ValueError("unkown input_type for form (%s)!" % input_type)
raise ValueError(f"unkown input_type for form ({input_type})!")
explanation = descr.get("explanation", "")
if explanation:
lem.append('<span class="tf-explanation">%s</span>' % explanation)
lem.append(f"""<span class="tf-explanation">{explanation}</span>""")
comment = descr.get("comment", "")
if comment:
lem.append('<br/><span class="tf-comment">%s</span>' % comment)
if (input_type != "checkbox") and (input_type != "boolcheckbox"):
lem.append("<br>")
lem.append(f"""<span class="tf-comment">{comment}</span>""")
R.append(
etempl
% {
@ -657,11 +683,11 @@ var {field}_as = new bsn.AutoSuggest('{field}', {field}_opts);
}
)
R.append("</table>")
R.append(self.after_table)
R.append(self.html_foot_markup)
if self.bottom_buttons:
R.append("<br/>" + buttons_markup)
R.append("<br>" + buttons_markup)
if add_no_enter_js:
R.append(
@ -753,7 +779,7 @@ var {field}_as = new bsn.AutoSuggest('{field}', {field}_opts);
if input_type == "separator": # separator
R.append('<td colspan="2">%s' % title)
else:
elif input_type != "table_separator":
R.append('<td class="tf-ro-fieldlabel%s">' % klass)
R.append("%s</td>" % title)
R.append('<td class="tf-ro-field%s">' % klass)
@ -786,7 +812,11 @@ var {field}_as = new bsn.AutoSuggest('{field}', {field}_opts);
R.append(
'<div class="tf-ro-textarea">%s</div>' % html.escape(self.values[field])
)
elif input_type == "separator" or input_type == "hidden":
elif (
input_type == "separator"
or input_type == "hidden"
or input_type == "table_separator"
):
pass
elif input_type == "file":
R.append("'%s'" % self.values[field])

View File

@ -284,8 +284,8 @@ def sco_header(
if current_user.passwd_temp:
H.append(
f"""<div class="passwd_warn">
Attention !<br/>
Vous avez reçu un mot de passe temporaire.<br/>
Attention !<br>
Vous avez reçu un mot de passe temporaire.<br>
Vous devez le changer: <a href="{scu.UsersURL}/form_change_password?user_name={current_user.user_name}">cliquez ici</a>
</div>"""
)

View File

@ -48,26 +48,26 @@ def sidebar_common():
url_for("users.user_info_page",
scodoc_dept=g.scodoc_dept, user_name=current_user.user_name)
}">{current_user.user_name}</a>
<br/><a id="deconnectlink" href="{url_for("auth.logout")}">déconnexion</a>
<br><a id="deconnectlink" href="{url_for("auth.logout")}">déconnexion</a>
</div>
{sidebar_dept()}
<h2 class="insidebar">Scolarité</h2>
<a href="{scu.ScoURL()}" class="sidebar">Semestres</a> <br/>
<a href="{scu.NotesURL()}" class="sidebar">Programmes</a> <br/>
<a href="{scu.AbsencesURL()}" class="sidebar">Absences</a> <br/>
<a href="{scu.ScoURL()}" class="sidebar">Semestres</a> <br>
<a href="{scu.NotesURL()}" class="sidebar">Programmes</a> <br>
<a href="{scu.AbsencesURL()}" class="sidebar">Absences</a> <br>
"""
]
if current_user.has_permission(
Permission.ScoUsersAdmin
) or current_user.has_permission(Permission.ScoUsersView):
H.append(
f"""<a href="{scu.UsersURL()}" class="sidebar">Utilisateurs</a> <br/>"""
f"""<a href="{scu.UsersURL()}" class="sidebar">Utilisateurs</a> <br>"""
)
if current_user.has_permission(Permission.ScoChangePreferences):
H.append(
f"""<a href="{url_for("scolar.edit_preferences", scodoc_dept=g.scodoc_dept)}"
class="sidebar">Paramétrage</a> <br/>"""
class="sidebar">Paramétrage</a> <br>"""
)
return "".join(H)
@ -84,7 +84,7 @@ def sidebar(etudid: int = None):
H = [
f"""<div class="sidebar">
{ sidebar_common() }
<div class="box-chercheetud">Chercher étudiant:<br/>
<div class="box-chercheetud">Chercher étudiant:<br>
<form method="get" id="form-chercheetud"
action="{url_for('scolar.search_etud_in_dept', scodoc_dept=g.scodoc_dept) }">
<div><input type="text" size="12" class="in-expnom" name="expnom" spellcheck="false"></input></div>
@ -121,7 +121,7 @@ def sidebar(etudid: int = None):
nbabsnj = nbabs - nbabsjust
H.append(
f"""<span title="absences du { cur_sem["date_debut"] } au { cur_sem["date_fin"] }">(1/2 j.)
<br/>{ nbabsjust } J., { nbabsnj } N.J.</span>"""
<br>{ nbabsjust } J., { nbabsnj } N.J.</span>"""
)
H.append("<ul>")
if current_user.has_permission(Permission.ScoAbsChange):
@ -150,7 +150,7 @@ def sidebar(etudid: int = None):
# Logo
H.append(
f"""<div class="logo-insidebar">
<div class="sidebar-bottom"><a href="{ url_for( 'scodoc.about', scodoc_dept=g.scodoc_dept ) }" class="sidebar">À propos</a><br/>
<div class="sidebar-bottom"><a href="{ url_for( 'scodoc.about', scodoc_dept=g.scodoc_dept ) }" class="sidebar">À propos</a><br>
<a href="{ scu.SCO_USER_MANUAL }" target="_blank" class="sidebar">Aide</a>
</div></div>
<div class="logo-logo">

View File

@ -51,7 +51,7 @@ def convert_html_to_text(s):
def newline_to_br(text):
return text.replace("\n", "<br/>")
return text.replace("\n", "<br>")
class HTMLSanitizer(HTMLParser):

View File

@ -251,7 +251,7 @@ def SignaleAbsenceEtud(): # etudid implied
<td><input type="text" name="datefin" size="10" class="datepicker"/> <em>j/m/a</em></td>
</tr>
</table>
<br/>
<br>
<input type="radio" name="demijournee" value="2" checked>Journée(s)
&nbsp;<input type="radio" name="demijournee" value="1">Matin(s)
&nbsp;<input type="radio" name="demijournee" value="0">Après-midi
@ -260,7 +260,7 @@ def SignaleAbsenceEtud(): # etudid implied
<p>
<input type="checkbox" name="estjust"/>Absence justifiée.
<br/>
<br>
Raison: <input type="text" name="description" size="42"/> (optionnel)
</p>
@ -398,13 +398,13 @@ def JustifAbsenceEtud(): # etudid implied
<td><input type="text" name="datefin" size="10" class="datepicker"/></td>
</tr>
</table>
<br/>
<br>
<input type="radio" name="demijournee" value="2" checked>Journée(s)
&nbsp;<input type="radio" name="demijournee" value="1">Matin(s)
&nbsp;<input type="radio" name="demijournee" value="0">Apr&egrave;s midi
<br/><br/>
<br><br>
Raison: <input type="text" name="description" size="42"/> (optionnel)
<p>
@ -752,9 +752,9 @@ def CalAbs(etudid, sco_year=None):
),
"""<table><tr><td><h2>Absences de %(nomprenom)s (%(inscription)s)</h2><p>"""
% etud,
"""<b><font color="#EE0000">A : absence NON justifiée</font><br/>
<font color="#F8B7B0">a : absence justifiée</font><br/>
<font color="#8EA2C6">X : justification sans absence</font><br/>
"""<b><font color="#EE0000">A : absence NON justifiée</font><br>
<font color="#F8B7B0">a : absence justifiée</font><br>
<font color="#8EA2C6">X : justification sans absence</font><br>
%d absences sur l'année, dont %d justifiées (soit %d non justifiées)</b> <em>(%d justificatifs inutilisés)</em>
</p>
"""

View File

@ -980,8 +980,8 @@ class ApoData(object):
log("Colonnes declarees: %s" % declared)
log("Colonnes presentes: %s" % present)
raise ScoFormatError(
"""Fichier Apogee invalide<br/>Colonnes declarees: <tt>%s</tt>
<br/>Colonnes presentes: <tt>%s</tt>"""
"""Fichier Apogee invalide<br>Colonnes declarees: <tt>%s</tt>
<br>Colonnes presentes: <tt>%s</tt>"""
% (declared, present)
)
# l'ensemble de tous les codes des elements apo des semestres:

View File

@ -295,7 +295,7 @@ def etudarchive_import_files_form(group_id):
supprimer, via la fiche de chaque étudiant.</b>
</p>
<p class="help">Cette page permet de charger en une seule fois les fichiers
de plusieurs étudiants.<br/>
de plusieurs étudiants.<br>
Il faut d'abord remplir une feuille excel donnant les noms
des fichiers (un fichier par étudiant).
</p>

View File

@ -237,7 +237,7 @@ class BulletinGenerator:
# compris: reportlab is not thread safe !
# see http://two.pairlist.net/pipermail/reportlab-users/2006-June/005037.html
# (donc maintenant protégé dans ScoDoc par un Lock global)
self.diagnostic = "erreur lors de la génération du PDF<br/>"
self.diagnostic = "erreur lors de la génération du PDF<br>"
self.diagnostic += "<pre>" + traceback.format_exc() + "</pre>"
return []
return Table(Pt, colWidths=colWidths, style=pdfTableStyle)

View File

@ -132,9 +132,9 @@ def formsemestre_table_estim_cost(
],
html_caption="""<div class="help">
Estimation du coût de formation basé sur le programme pédagogique
et les nombres de groupes.<br/>
Coût théorique en heures équivalent TD.<br/>
Attention: ne prend en compte que les modules utilisés dans ce semestre.<br/>
et les nombres de groupes.<br>
Coût théorique en heures équivalent TD.<br>
Attention: ne prend en compte que les modules utilisés dans ce semestre.<br>
Attention: prend en compte <em>tous les modules</em> utilisés dans ce semestre, ce qui
peut conduire à une sur-estimation du coût s'il y a des modules optionnels
(dans ce cas, retoucher le tableau excel exporté).
@ -173,10 +173,10 @@ def formsemestre_estim_cost(
h = """
<form name="f" method="get" action="%s">
<input type="hidden" name="formsemestre_id" value="%s"></input>
Nombre de groupes de TD: <input type="text" name="n_group_td" value="%s" onchange="document.f.submit()"/><br/>
Nombre de groupes de TD: <input type="text" name="n_group_td" value="%s" onchange="document.f.submit()"/><br>
Nombre de groupes de TP: <input type="text" name="n_group_tp" value="%s" onchange="document.f.submit()"/>
&nbsp;Coefficient heures TP: <input type="text" name="coef_tp" value="%s" onchange="document.f.submit()"/>
<br/>
<br>
</form>
""" % (
request.base_url,

View File

@ -98,7 +98,7 @@ def index_html(showcodes=0, showsemtable=0):
H.append(
"""<h2>Aucun utilisateur défini !</h2><p>Pour définir des utilisateurs
<a href="Users">passez par la page Utilisateurs</a>.
<br/>
<br>
Définissez au moins un utilisateur avec le rôle AdminXXX (le responsable du département XXX).
</p>
"""

View File

@ -542,7 +542,7 @@ class EtapeBilan(object):
ind_col,
comptage,
"",
json.dumps(self.titres[ind_col].replace("<br/>", " / "))[1:-1],
json.dumps(self.titres[ind_col].replace("<br>", " / "))[1:-1],
)
elif ind_col == COL_CUMUL:
javascript = "doFiltrage(%s, %s, '.%s', '*', '%s', '%s', '%s');" % (
@ -561,7 +561,7 @@ class EtapeBilan(object):
ind_col,
comptage,
json.dumps(self.titres[ind_row])[1:-1],
json.dumps(self.titres[ind_col].replace("<br/>", " / "))[1:-1],
json.dumps(self.titres[ind_col].replace("<br>", " / "))[1:-1],
)
return '<a href="#synthese" onclick="%s">%d</a>' % (javascript, count)
@ -590,9 +590,9 @@ class EtapeBilan(object):
for key_etape in liste_etapes:
col_id = self.indicatifs[key_etape]
col_ids.append(col_id)
self.titres[col_id] = "%s<br/>%s" % key_to_values(key_etape)
self.titres[col_id] = "%s<br>%s" % key_to_values(key_etape)
col_ids.append(COL_CUMUL)
self.titres[COL_CUMUL] = "Total<br/>semestre"
self.titres[COL_CUMUL] = "Total<br>semestre"
rows = []
for semestre in liste_semestres:
@ -675,7 +675,7 @@ class EtapeBilan(object):
NIP_NON_UNIQUE,
)
H.append(
'Code(s) nip) partagé(s) par <a href="#synthèse" onclick="%s">%d</a> étudiants<br/>'
'Code(s) nip) partagé(s) par <a href="#synthèse" onclick="%s">%d</a> étudiants<br>'
% (javascript, self.tag_count[NIP_NON_UNIQUE])
)
return "\n".join(H)
@ -728,11 +728,11 @@ class EtapeBilan(object):
prenom = data_etu.data_scodoc["prenom"]
link = self.link_etu(etudid, nom)
tag = ", ".join([tag for tag in sorted(data_etu.tags)])
semestre = "<br/>".join(
semestre = "<br>".join(
[self.link_semestre(sem, True) for sem in data_etu.semestres]
)
annees = "<br/>".join([etape[0] for etape in data_etu.etapes])
etapes = "<br/>".join([etape[1] for etape in data_etu.etapes])
annees = "<br>".join([etape[0] for etape in data_etu.etapes])
etapes = "<br>".join([etape[1] for etape in data_etu.etapes])
classe = data_etu.ind_row + data_etu.ind_col
if NIP_NON_UNIQUE in data_etu.tags:
classe += " " + NIP_NON_UNIQUE

View File

@ -907,7 +907,7 @@ def fill_etuds_info(etuds: list[dict], add_admission=True):
etud["ilycee"] = "Lycée " + format_lycee(etud["nomlycee"])
if etud["villelycee"]:
etud["ilycee"] += " (%s)" % etud.get("villelycee", "")
etud["ilycee"] += "<br/>"
etud["ilycee"] += "<br>"
else:
if etud.get("codelycee"):
etud["ilycee"] = format_lycee_from_code(etud["codelycee"])

View File

@ -224,7 +224,7 @@ def formsemestre_check_absences_html(formsemestre_id):
"Vérification absences aux évaluations de ce semestre",
),
"""<p class="help">Vérification de la cohérence entre les notes saisies et les absences signalées.
Sont listés tous les modules avec des évaluations.<br/>Aucune action n'est effectuée:
Sont listés tous les modules avec des évaluations.<br>Aucune action n'est effectuée:
il vous appartient de corriger les erreurs détectées si vous le jugez nécessaire.
</p>""",
]

View File

@ -58,7 +58,7 @@ def form_search_etud(
<b>{title}</b>
<input type="text" name="expnom" class="in-expnom" width="12" spellcheck="false" value="">
<input type="submit" value="Chercher">
<br/>(entrer une partie du nom)
<br>(entrer une partie du nom)
"""
)
if dest_url:

View File

@ -1659,7 +1659,7 @@ def formsemestre_change_publication_bul(
"<h2>Confirmer la %s publication des bulletins ?</h2>" % msg,
helpmsg="""Il est parfois utile de désactiver la diffusion des bulletins,
par exemple pendant la tenue d'un jury ou avant harmonisation des notes.
<br/>
<br>
Ce réglage n'a d'effet que si votre établissement a interfacé ScoDoc et un portail étudiant.
""",
dest_url="",

View File

@ -893,7 +893,7 @@ def formsemestre_inscrits_ailleurs(formsemestre_id):
H.append("</ul>")
H.append("<p>Total: %d étudiants concernés.</p>" % len(etudlist))
H.append(
"""<p class="help">Ces étudiants sont inscrits dans le semestre sélectionné et aussi dans d'autres semestres qui se déroulent en même temps ! <br/>Sauf exception, cette situation est anormale:</p>
"""<p class="help">Ces étudiants sont inscrits dans le semestre sélectionné et aussi dans d'autres semestres qui se déroulent en même temps ! <br>Sauf exception, cette situation est anormale:</p>
<ul>
<li>vérifier que les dates des semestres se suivent sans se chevaucher</li>
<li>ou si besoin désinscrire le(s) étudiant(s) de l'un des semestres (via leurs fiches individuelles).</li>

View File

@ -349,7 +349,7 @@ def formsemestre_validation_etud_form(
H.append("</table>")
H.append(
'<p><br/></p><input type="submit" value="Valider ce choix" disabled="1" id="subut"/>'
'<p><br></p><input type="submit" value="Valider ce choix" disabled="1" id="subut"/>'
)
H.append("</form>")
@ -1299,7 +1299,7 @@ def check_formation_ues(formation_id):
H = [
"""<div class="ue_warning"><span>Attention:</span> les UE suivantes de cette formation
sont utilisées dans des
semestres de rangs différents (eg S1 et S3). <br/>Cela peut engendrer des problèmes pour
semestres de rangs différents (eg S1 et S3). <br>Cela peut engendrer des problèmes pour
la capitalisation des UE. Il serait préférable d'essayer de rectifier cette situation:
soit modifier le programme de la formation (définir des UE dans chaque semestre),
soit veiller à saisir le bon indice de semestre dans le menu lors de la validation d'une

View File

@ -302,7 +302,7 @@ def scolars_import_excel_file(
else:
unknown.append(f)
raise ScoValueError(
"""Nombre de colonnes incorrect (devrait être %d, et non %d)<br/>
"""Nombre de colonnes incorrect (devrait être %d, et non %d)<br>
(colonnes manquantes: %s, colonnes invalides: %s)"""
% (len(titles), len(fs), list(missing.keys()), unknown)
)

View File

@ -122,7 +122,7 @@ def import_excel_file(datafile, force=""):
del cols[tit]
if cols or unknown:
raise ScoValueError(
"""colonnes incorrectes (on attend %d, et non %d) <br/>
"""colonnes incorrectes (on attend %d, et non %d) <br>
(colonnes manquantes: %s, colonnes invalides: %s)"""
% (len(TITLES), len(fs), list(cols.keys()), unknown)
)

View File

@ -517,18 +517,18 @@ def _make_table_notes(
hh += "s"
hh += ", %d en attente." % (nb_att)
pdf_title = "<br/> BORDEREAU DE SIGNATURES"
pdf_title += "<br/><br/>%(titre)s" % sem
pdf_title += "<br/>(%(mois_debut)s - %(mois_fin)s)" % sem
pdf_title = "<br> BORDEREAU DE SIGNATURES"
pdf_title += "<br><br>%(titre)s" % sem
pdf_title += "<br>(%(mois_debut)s - %(mois_fin)s)" % sem
pdf_title += " semestre %s %s" % (
sem["semestre_id"],
sem.get("modalite", ""),
)
pdf_title += f"<br/>Notes du module {module.code} - {module.titre}"
pdf_title += "<br/>Evaluation : %(description)s " % e
pdf_title += f"<br>Notes du module {module.code} - {module.titre}"
pdf_title += "<br>Evaluation : %(description)s " % e
if len(e["jour"]) > 0:
pdf_title += " (%(jour)s)" % e
pdf_title += "(noté sur %(note_max)s )<br/><br/>" % e
pdf_title += "(noté sur %(note_max)s )<br><br>" % e
else:
hh = " %s, %s (%d étudiants)" % (
E["description"],
@ -623,11 +623,11 @@ def _make_table_notes(
commentkeys.sort(key=lambda x: int(x[1]))
for (comment, key) in commentkeys:
C.append(
'<span class="colcomment">(%s)</span> <em>%s</em><br/>' % (key, comment)
'<span class="colcomment">(%s)</span> <em>%s</em><br>' % (key, comment)
)
if commentkeys:
C.append(
'<span><a class=stdlink" href="evaluation_list_operations?evaluation_id=%s">Gérer les opérations</a></span><br/>'
'<span><a class=stdlink" href="evaluation_list_operations?evaluation_id=%s">Gérer les opérations</a></span><br>'
% E["evaluation_id"]
)
eval_info = "xxx"

View File

@ -229,7 +229,7 @@ def js_coords_lycees(etuds_by_lycee):
lyc = etuds_by_lycee[codelycee][0]
if not lyc.get("positionlycee", False):
continue
listeetuds = "<br/>%d étudiants: " % len(
listeetuds = "<br>%d étudiants: " % len(
etuds_by_lycee[codelycee]
) + ", ".join(
[

View File

@ -152,7 +152,7 @@ def moduleimpl_inscriptions_edit(moduleimpl_id, etuds=[], submitted=False):
{ _make_menu(partitions, "Ajouter", "true") }
{ _make_menu(partitions, "Enlever", "false")}
</tr></table>
<p><br/></p>
<p><br></p>
<table class="sortable" id="mi_table">
<tr>
<th>Nom</th>

View File

@ -189,7 +189,7 @@ def ficheEtud(etudid=None):
else:
info["paysdomicile"] = ""
if info["telephone"] or info["telephonemobile"]:
info["telephones"] = "<br/>%s &nbsp;&nbsp; %s" % (
info["telephones"] = "<br>%s &nbsp;&nbsp; %s" % (
info["telephonestr"],
info["telephonemobilestr"],
)
@ -506,9 +506,9 @@ def ficheEtud(etudid=None):
<b>Ajouter une annotation sur %(nomprenom)s: </b>
<table><tr>
<tr><td><textarea name="comment" rows="4" cols="50" value=""></textarea>
<br/><font size=-1>
<br><font size=-1>
<i>Ces annotations sont lisibles par tous les enseignants et le secrétariat.</i>
<br/>
<br>
<i>L'annotation commençant par "PE:" est un avis de poursuite d'études.</i>
</font>
</td></tr>

View File

@ -338,7 +338,7 @@ class PlacementRunner:
return scu.send_file(xls, filename, scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE)
def _production_pdf(self):
pdf_title = "<br/>".join(self.desceval)
pdf_title = "<br>".join(self.desceval)
pdf_title += (
"\nDate : %(jour)s - Horaire : %(heure_debut)s à %(heure_fin)s"
% self.eval_data

View File

@ -43,7 +43,7 @@ Au niveau du code interface, on défini pour chaque préférence:
- initvalue : valeur initiale
- explanation: explication en français
- size: longueur du chap texte
- input_type: textarea,separator,... type de widget TrivialFormulator a utiliser
- input_type: textarea, separator, ... type de widget TrivialFormulator a utiliser
- rows, rols: geometrie des textareas
- category: misc ou bul ou page_bulletins ou abs ou general ou portal
ou pdf ou pvpdf ou ...
@ -202,7 +202,7 @@ _INSTALLED_FONTS = ", ".join(sco_pdf.get_available_font_names())
PREF_CATEGORIES = (
# sur page "Paramètres"
("general", {}),
("general", {"title": ""}), # voir paramètre titlr de TrivialFormulator
("misc", {"title": "Divers"}),
("apc", {"title": "BUT et Approches par Compétences"}),
("abs", {"title": "Suivi des absences", "related": ("bul",)}),
@ -1008,7 +1008,7 @@ class BasePreferences(object):
(
"PV_LETTER_DIPLOMA_SIGNATURE",
{
"initvalue": """Le %(DirectorTitle)s, <br/>%(DirectorName)s""",
"initvalue": """Le %(DirectorTitle)s, <br>%(DirectorName)s""",
"title": """Signature des lettres individuelles de diplôme""",
"explanation": """%(DirectorName)s et %(DirectorTitle)s remplacés""",
"input_type": "textarea",
@ -1020,8 +1020,8 @@ class BasePreferences(object):
(
"PV_LETTER_PASSAGE_SIGNATURE",
{
"initvalue": """Pour le Directeur de l'IUT<br/>
et par délégation<br/>
"initvalue": """Pour le Directeur de l'IUT<br>
et par délégation<br>
Le Chef du département""",
"title": """Signature des lettres individuelles de passage d'un semestre à l'autre""",
"explanation": """%(DirectorName)s et %(DirectorTitle)s remplacés""",
@ -1056,7 +1056,7 @@ class BasePreferences(object):
<para leftindent="%(pv_htab1)s">%(codepostaldomicile)s %(villedomicile)s</para>
<para spaceBefore="25mm" fontSize="14" alignment="center">
<b>Jury de %(type_jury)s <br/> %(titre_formation)s</b>
<b>Jury de %(type_jury)s <br> %(titre_formation)s</b>
</para>
<para spaceBefore="10mm" fontSize="14" leftindent="0">
@ -1499,7 +1499,7 @@ class BasePreferences(object):
"bul_pdf_sig_left",
{
"initvalue": """<para>La direction des études
<br/>
<br>
%(responsable)s
</para>
""",
@ -1515,7 +1515,7 @@ class BasePreferences(object):
"bul_pdf_sig_right",
{
"initvalue": """<para>Le chef de département
<br/>
<br>
%(ChiefDeptName)s
</para>
""",
@ -1891,7 +1891,7 @@ class BasePreferences(object):
"explanation": """si cette adresse est indiquée, TOUS les mails
envoyés par ScoDoc de ce département vont aller vers elle
AU LIEU DE LEUR DESTINATION NORMALE !""",
"size": 30,
"size": 60,
"category": "debug",
"only_global": True,
},
@ -1935,7 +1935,7 @@ class BasePreferences(object):
value = _get_pref_default_value_from_config(name, pref[1])
self.default[name] = value
self.prefs[None][name] = value
log("creating missing preference for %s=%s" % (name, value))
log(f"creating missing preference for {name}={value}")
# add to db table
self._editor.create(
cnx, {"dept_id": self.dept_id, "name": name, "value": value}
@ -1999,7 +1999,7 @@ class BasePreferences(object):
if not pdb:
# crée préférence
log("create pref sem=%s %s=%s" % (formsemestre_id, name, value))
log(f"create pref sem={formsemestre_id} {name}={value}")
self._editor.create(
cnx,
{
@ -2036,7 +2036,7 @@ class BasePreferences(object):
def set(self, formsemestre_id, name, value):
if not name or name[0] == "_" or name not in self.prefs_name:
raise ValueError("invalid preference name: %s" % name)
raise ValueError(f"invalid preference name: {name}")
if formsemestre_id and name in self.prefs_only_global:
raise ValueError("pref %s is always defined globaly")
if not formsemestre_id in self.prefs:
@ -2055,7 +2055,7 @@ class BasePreferences(object):
cnx, args={"formsemestre_id": formsemestre_id, "name": name}
)
if pdb:
log("deleting pref sem=%s %s" % (formsemestre_id, name))
log(f"deleting pref sem={formsemestre_id} {name}")
assert pdb[0]["dept_id"] == self.dept_id
self._editor.delete(cnx, pdb[0]["pref_id"])
sco_cache.invalidate_formsemestre() # > modif preferences
@ -2067,13 +2067,17 @@ class BasePreferences(object):
self.load()
H = [
html_sco_header.sco_header(page_title="Préférences"),
"<h2>Préférences globales pour %s</h2>" % scu.ScoURL(),
f"<h2>Préférences globales pour {scu.ScoURL()}</h2>",
# f"""<p><a href="{url_for("scodoc.configure_logos", scodoc_dept=g.scodoc_dept)
# }">modification des logos du département (pour documents pdf)</a></p>"""
# if current_user.is_administrator()
# else "",
"""<p class="help">Ces paramètres s'appliquent par défaut à tous les semestres, sauf si ceux-ci définissent des valeurs spécifiques.</p>
<p class="msg">Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !</p>
"""<p class="help">Ces paramètres s'appliquent par défaut à tous les semestres,
sauf si ceux-ci définissent des valeurs spécifiques.
</p>
<p class="msg">Attention: cliquez sur "Enregistrer les modifications"
en bas de page pour appliquer vos changements !
</p>
""",
]
form = self.build_tf_form()
@ -2083,6 +2087,9 @@ class BasePreferences(object):
form,
initvalues=self.prefs[None],
submitlabel="Enregistrer les modifications",
title="Département et institution",
before_table="<details><summary>{title}</summary>",
after_table="</details>",
)
if tf[0] == 0:
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
@ -2094,7 +2101,7 @@ class BasePreferences(object):
self.save()
return flask.redirect(scu.ScoURL() + "?head_message=Préférences modifiées")
def build_tf_form(self, categories=[], formsemestre_id=None):
def build_tf_form(self, categories: list[str] = None, formsemestre_id: int = None):
"""Build list of elements for TrivialFormulator.
If formsemestre_id is not specified, edit global prefs.
"""
@ -2119,7 +2126,7 @@ class BasePreferences(object):
onclick="set_global_pref(this, '{pref_name}');"
>utiliser paramètre global</span>"""
if formsemestre_id and self.is_global(formsemestre_id, pref_name):
# valeur actuelle globale (ou vient d'etre supprimee localement):
# valeur actuelle globale (ou vient d'etre supprimée localement):
# montre la valeur et menus pour la rendre locale
descr["readonly"] = True
menu_global = f"""<select class="tf-selglobal"
@ -2138,8 +2145,11 @@ class BasePreferences(object):
if title:
form.append(
(
f"sep_{cat}",
{"input_type": "separator", "title": f"<h3>{title}</h3>"},
f"table_{cat}",
{
"input_type": "table_separator",
"title": f"{title}",
},
)
)
subtitle = cat_descr.get("subtitle", None)
@ -2246,6 +2256,9 @@ function set_global_pref(el, pref_name) {
initvalues=self,
cssclass="sco_pref",
submitlabel="Enregistrer les modifications",
title="Département et institution",
before_table="<details><summary>{title}</summary>",
after_table="</details>",
)
dest_url = (
scu.NotesURL()

View File

@ -340,11 +340,11 @@ class PVTemplate(CourrierIndividuelTemplate):
def _simulate_br(paragraph_txt: str, para="<para>") -> str:
"""Reportlab bug turnaround (could be removed in a future version).
p is a string with Reportlab intra-paragraph XML tags.
Replaces <br/> (currently ignored by Reportlab) by </para><para>
Also replaces <br> by <br/>
Replaces <br> (currently ignored by Reportlab) by </para><para>
Also replaces <br> by <br>
"""
return ("</para>" + para).join(
re.split(r"<.*?br.*?/>", paragraph_txt.replace("<br>", "<br/>"))
re.split(r"<.*?br.*?/>", paragraph_txt.replace("<br>", "<br>"))
)
@ -515,7 +515,7 @@ def pdf_lettre_individuelle(sem, decision, etud: Identite, params, signature=Non
params.update(decision["identite"])
# fix domicile
if params["domicile"]:
params["domicile"] = params["domicile"].replace("\\n", "<br/>")
params["domicile"] = params["domicile"].replace("\\n", "<br>")
# UE capitalisées:
if decision["decisions_ue"] and decision["decisions_ue_descr"]:
@ -649,8 +649,8 @@ def add_apc_infos(formsemestre: FormSemestre, params: dict, decision: dict):
params["decision_sem_descr"] = decision_annee.get("code") or ""
params[
"decision_ue_txt"
] = f"""{params["decision_ue_txt"]}<br/>
<b>Niveaux de compétences:</b><br/> {decision.get("descr_decisions_rcue") or ""}
] = f"""{params["decision_ue_txt"]}<br>
<b>Niveaux de compétences:</b><br> {decision.get("descr_decisions_rcue") or ""}
"""

View File

@ -384,7 +384,7 @@ def formsemestre_report_counts(
else:
checked = ""
F.append(
'<br/><input type="checkbox" name="only_primo" onchange="document.f.submit()" %s>Restreindre aux primo-entrants</input>'
'<br><input type="checkbox" name="only_primo" onchange="document.f.submit()" %s>Restreindre aux primo-entrants</input>'
% checked
)
F.append(
@ -928,7 +928,7 @@ def _gen_form_selectetuds(
else:
checked = ""
F.append(
'<br/><input type="checkbox" name="only_primo" onchange="javascript: submit(this);" %s/>Restreindre aux primo-entrants'
'<br><input type="checkbox" name="only_primo" onchange="javascript: submit(this);" %s/>Restreindre aux primo-entrants'
% checked
)
F.append(

View File

@ -237,7 +237,7 @@ def do_evaluation_upload_xls():
ni += 1
except:
diag.append(
'Erreur: Ligne invalide ! (erreur ligne %d)<br/>"%s"'
'Erreur: Ligne invalide ! (erreur ligne %d)<br>"%s"'
% (ni, str(lines[ni]))
)
raise InvalidNoteValue()

View File

@ -139,7 +139,7 @@ class SemSet(dict):
# Construction du ou des lien(s) vers le semestre
pattern = '<a class="stdlink" href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titreannee)s</a>'
self["semlinks"] = [(pattern % sem) for sem in self.sems]
self["semtitles_str"] = "<br/>".join(self["semlinks"])
self["semtitles_str"] = "<br>".join(self["semlinks"])
def fill_formsemestres(self):
for sem in self.sems:
@ -290,16 +290,15 @@ class SemSet(dict):
% (self["semset_id"], sem["formsemestre_id"])
)
H.append(
"<br/>Etapes: <tt>%(etapes_apo_str)s</tt>, %(nbinscrits)s inscrits"
% sem
"<br>Etapes: <tt>%(etapes_apo_str)s</tt>, %(nbinscrits)s inscrits" % sem
)
H.append("<br/>Elément Apogée année: ")
H.append("<br>Elément Apogée année: ")
if sem["elt_annee_apo"]:
H.append("<tt>%(elt_annee_apo)s</tt>" % sem)
else:
H.append('<span style="color: red;">manquant</span>')
H.append("<br/>Elément Apogée semestre: ")
H.append("<br>Elément Apogée semestre: ")
if sem["elt_sem_apo"]:
H.append("<tt>%(elt_sem_apo)s</tt>" % sem)
else:

View File

@ -463,7 +463,7 @@ def list_synch(sem, anneeapogee=None):
"id": "etuds_noninscrits",
"title": "Étudiants non inscrits dans ce semestre",
"help": """Ces étudiants sont déjà connus par ScoDoc, sont inscrits dans cette étape Apogée mais ne sont pas inscrits à ce semestre ScoDoc. Cochez les étudiants à inscrire.""",
"comment": """ dans ScoDoc et Apogée, <br/>mais pas inscrits
"comment": """ dans ScoDoc et Apogée, <br>mais pas inscrits
dans ce semestre""",
"title_target": "",
"with_checkbox": True,

View File

@ -506,7 +506,7 @@ def photos_import_files_form(group_ids=()):
de chaque étudiant (menu "Étudiant" / "Changer la photo").</b>
</p>
<p class="help">Cette page permet de charger en une seule fois les photos
de plusieurs étudiants.<br/>
de plusieurs étudiants.<br>
Il faut d'abord remplir une feuille excel donnant les noms
des fichiers images (une image par étudiant).
</p>

View File

@ -238,7 +238,7 @@ def external_ue_create_form(formsemestre_id: int, etudid: int):
javascripts=["js/sco_ue_external.js"],
),
"""<p class="help">Cette page permet d'indiquer que l'étudiant a suivi une UE
dans un autre établissement et qu'elle doit être intégrée dans le semestre courant.<br/>
dans un autre établissement et qu'elle doit être intégrée dans le semestre courant.<br>
La note (/20) obtenue par l'étudiant doit toujours être spécifiée.</br>
On peut choisir une UE externe existante (dans le menu), ou bien en créer une, qui sera
alors ajoutée à la formation.

View File

@ -290,7 +290,7 @@ def check_modif_user(
(si ok est faux, l'utilisateur peut quand même forcer la creation)
- msg: message warning à presenter à l'utilisateur
"""
MSG_OPT = """<br/>Attention: (vous pouvez forcer l'opération en cochant "<em>Ignorer les avertissements</em>" en bas de page)"""
MSG_OPT = """<br>Attention: (vous pouvez forcer l'opération en cochant "<em>Ignorer les avertissements</em>" en bas de page)"""
# ce login existe ?
user = _user_list(user_name)
if edit and not user: # safety net, le user_name ne devrait pas changer

View File

@ -2863,10 +2863,13 @@ select.tf-selglobal {
}
td.tf-fieldlabel {
/* font-weight: bold; */
vertical-align: top;
}
td.tf-field {
max-width: 800px;
}
.tf-comment {
font-size: 80%;
font-style: italic;
@ -2876,6 +2879,12 @@ td.tf-fieldlabel {
font-style: italic;
}
#tf details summary {
font-size: 130%;
margin-top: 6px;
margin-bottom: 6px;
}
.radio_green {
background-color: green;
}

View File

@ -699,7 +699,7 @@ def _gen_form_saisie_groupe(
}
</script>
<div id="AjaxDiv"></div>
<br/>
<br>
<table rules="cols" frame="box" class="abs_form_table">
<tr><th class="formabs_contetud">%d étudiants</th>
"""
@ -990,7 +990,7 @@ def EtatAbsencesGr(
),
html_title=html_sco_header.html_sem_header(title, with_page_header=False)
+ form_date,
# "<p>Période du %s au %s (nombre de <b>demi-journées</b>)<br/>" % (debut, fin),
# "<p>Période du %s au %s (nombre de <b>demi-journées</b>)<br>" % (debut, fin),
base_url="%s&formsemestre_id=%s&debut=%s&fin=%s"
% (groups_infos.base_url, formsemestre_id, debut, fin),
filename="etat_abs_"
@ -1003,7 +1003,7 @@ def EtatAbsencesGr(
Justifs non utilisés: nombre de demi-journées avec justificatif mais sans absences relevées.
</p>
<p class="help">
Cliquez sur un nom pour afficher le calendrier des absences<br/>
Cliquez sur un nom pour afficher le calendrier des absences<br>
ou entrez une date pour visualiser les absents un jour donné&nbsp;:
</p>
<div style="margin-bottom: 10px;">
@ -1422,7 +1422,7 @@ def process_billet_absence_form(billet_id):
H.append(tab.html())
if billet.justified:
H.append(
"""<p>L'étudiant pense pouvoir justifier cette absence.<br/>
"""<p>L'étudiant pense pouvoir justifier cette absence.<br>
<em>Vérifiez le justificatif avant d'enregistrer.</em></p>"""
)
F = f"""<p><a class="stdlink" href="{
@ -1437,7 +1437,7 @@ def process_billet_absence_form(billet_id):
</p>
"""
return "\n".join(H) + "<br/>" + tf[1] + F + html_sco_header.sco_footer()
return "\n".join(H) + "<br>" + tf[1] + F + html_sco_header.sco_footer()
elif tf[0] == -1:
return flask.redirect(scu.ScoURL())
else:

View File

@ -852,7 +852,7 @@ def formsemestre_change_lock(formsemestre_id, dialog_confirmed=False):
helpmsg="""Les notes d'un semestre verrouillé ne peuvent plus être modifiées.
Un semestre verrouillé peut cependant être déverrouillé facilement à tout moment
(par son responsable ou un administrateur).
<br/>
<br>
Le programme d'une formation qui a un semestre verrouillé ne peut plus être modifié.
""",
dest_url="",
@ -3045,12 +3045,12 @@ def check_sem_integrity(formsemestre_id, fix=False):
if bad_ue:
H += [
"<h2>Modules d'une autre formation que leur UE:</h2>",
"<br/>".join([str(x) for x in bad_ue]),
"<br>".join([str(x) for x in bad_ue]),
]
if bad_sem:
H += [
"<h2>Module du semestre dans une autre formation:</h2>",
"<br/>".join([str(x) for x in bad_sem]),
"<br>".join([str(x) for x in bad_sem]),
]
if not bad_ue and not bad_sem:
H.append("<p>Aucun problème à signaler !</p>")
@ -3106,7 +3106,7 @@ def check_form_integrity(formation_id, fix=False):
if mod["formation_id"] != formation_id:
bad.append(mod)
if bad:
txth = "<br/>".join([str(x) for x in bad])
txth = "<br>".join([str(x) for x in bad])
txt = "\n".join([str(x) for x in bad])
log("check_form_integrity: formation_id=%s\ninconsistencies:" % formation_id)
log(txt)
@ -3162,7 +3162,7 @@ def check_formsemestre_integrity(formsemestre_id):
diag = ["OK"]
log("ok")
return (
html_sco_header.sco_header() + "<br/>".join(diag) + html_sco_header.sco_footer()
html_sco_header.sco_header() + "<br>".join(diag) + html_sco_header.sco_footer()
)

View File

@ -2141,9 +2141,9 @@ def form_students_import_infos_admissions(formsemestre_id=None):
Seuls les étudiants actuellement inscrits dans ce semestre ScoDoc seront affectés,
les autres lignes de la feuille seront ignorées. Et seules les colonnes intéressant ScoDoc
seront importées: il est inutile d'éliminer les autres.
<br/>
<br>
<em>Seules les données "admission" seront modifiées (et pas l'identité de l'étudiant).</em>
<br/>
<br>
<em>Les colonnes "nom" et "prenom" sont requises, ou bien une colonne "etudid".</em>
</p>
<p>
@ -2240,7 +2240,7 @@ def formsemestre_import_etud_admission(formsemestre_id, import_email=True):
H.append("<h3>Adresses mails modifiées:</h3>")
for (info, new_mail) in changed_mails:
H.append(
"%s: <tt>%s</tt> devient <tt>%s</tt><br/>"
"%s: <tt>%s</tt> devient <tt>%s</tt><br>"
% (info["nom"], info["email"], new_mail)
)
return "\n".join(H) + html_sco_header.sco_footer()

View File

@ -936,7 +936,7 @@ def change_password(user_name, password, password2):
if not is_valid_password(password):
H.append(
f"""<p><b>ce mot de passe n'est pas assez compliqué !</b>
<br/>(oui, il faut un mot de passe vraiment compliqué !)
<br>(oui, il faut un mot de passe vraiment compliqué !)
</p>
<p><a href="{dest_url}" class="stdlink">Recommencer</a></p>
"""