From 5b68adaf872ee672c4f6f956147ae611d5ab6b29 Mon Sep 17 00:00:00 2001
From: Iziram <matthias.hartmann@iziram.fr>
Date: Wed, 31 Jul 2024 16:08:21 +0200
Subject: [PATCH] =?UTF-8?q?multiselect.py=20+=20fix=20bug=20event=20+=20ch?=
=?UTF-8?q?angement=20ic=C3=B4ne=20+=20unfixed=20height?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/forms/multiselect.py | 118 ++++++++++++++++++++++++++++++++++
app/scodoc/sco_groups_view.py | 2 +-
app/scodoc/sco_utils.py | 117 +--------------------------------
app/static/js/multi-select.js | 22 ++++---
4 files changed, 135 insertions(+), 124 deletions(-)
create mode 100644 app/forms/multiselect.py
diff --git a/app/forms/multiselect.py b/app/forms/multiselect.py
new file mode 100644
index 00000000..77b13626
--- /dev/null
+++ b/app/forms/multiselect.py
@@ -0,0 +1,118 @@
+"""
+Simplification des multiselect HTML/JS
+"""
+
+
+class MultiSelect:
+ """
+ Classe pour faciliter l'utilisation du multi-select HTML/JS
+
+ Les values sont représentées en dict {
+ value: "...",
+ label:"...",
+ selected: True/False (default to False),
+ single: True/False (default to False)
+ }
+
+ Args:
+ values (dict[str, list[dict]]): Dictionnaire des valeurs
+ génère des <optgroup> pour chaque clef du dictionnaire
+ génère des <option> pour chaque valeur du dictionnaire
+ name (str, optional): Nom du multi-select. Defaults to "multi-select".
+ html_id (str, optional): Id HTML du multi-select. Defaults to "multi-select".
+ classname (str, optional): Classe CSS du multi-select. Defaults to "".
+ label (str, optional): Label du multi-select. Defaults to "".
+ export (str, optional): Format du multi-select (HTML/JS). Defaults to "js".
+ HTML : group_ids="val1"&group_ids="val2"...
+ JS : ["val1","val2", ...]
+
+ **kwargs: Arguments supplémentaires (appliqué au multiselect en HTML <multi-select key="value" ...>)
+ """
+
+ def __init__(
+ self,
+ values: dict[str, list[dict]],
+ name="multi-select",
+ html_id="multi-select",
+ label="",
+ classname="",
+ **kwargs,
+ ) -> None:
+ self.values: dict[str, list[dict]] = values
+ self._on = ""
+
+ self.name: str = name
+ self.html_id: str = html_id
+ self.classname: str = classname
+ self.label: str = label or name
+
+ self.args: dict = kwargs
+ self.js: str = ""
+ self.export: str = "return values"
+
+ def html(self) -> str:
+ """
+ Génère l'HTML correspondant au multi-select
+ """
+ opts: list[str] = []
+
+ for key, values in self.values.items():
+ optgroup = f"<optgroup label='{key}'>"
+ for value in values:
+ selected = "selected" if value.get("selected", False) else ""
+ single = "single" if value.get("single", False) else ""
+ opt = f"<option value='{value.get('value')}' {selected} {single} >{value.get('label')}</option>"
+ optgroup += opt
+ optgroup += "</optgroup>"
+ opts.append(optgroup)
+
+ args: list[str] = [f'{key}="{value}"' for key, value in self.args.items()]
+ js: str = "{" + self.js + "}"
+ export: str = "{" + self.export + "}"
+ return f"""
+ <multi-select
+ label="{self.label}"
+ id="{self.html_id}"
+ name="{self.name}"
+ class="{self.classname}"
+ {" ".join(args)}
+ >
+ {"".join(opts)}
+ </multi-select>
+ <script>
+ window.addEventListener('load', () => {{document.getElementById("{self.html_id}").on((values)=>{js});
+ document.getElementById("{self.html_id}").format((values)=>{export});}} );
+ </script>
+ """
+
+ def change_event(self, js: str) -> None:
+ """
+ Ajoute un évènement de changement au multi-select
+
+ CallBack JS : (event) => {/*actions à effectuer*/}
+
+ Sera retranscrit dans l'HTML comme :
+
+ document.getElementById(%self.id%).on((event)=>{%self.js%})
+
+ Exemple d'utilisation :
+
+ js : "console.log(event.target.value)"
+ """
+ self.js: str = js
+
+ def export_format(self, js: str) -> None:
+ """
+ Met à jour le format de retour de valeur du multi-select
+
+ CallBack JS : (values) => {/*actions à effectuer*/}
+
+ Sera retranscrit dans l'HTML comme :
+
+ document.getElementById(%self.id%).format((values)=>{%self.js%})
+
+ Exemple d'utilisation :
+
+ js : "return values.map(v=> 'val:'+v)"
+ """
+ self.export: str = js
diff --git a/app/scodoc/sco_groups_view.py b/app/scodoc/sco_groups_view.py
index ba15e0fc..2988dc3e 100644
--- a/app/scodoc/sco_groups_view.py
+++ b/app/scodoc/sco_groups_view.py
@@ -750,7 +750,7 @@ def groups_table(
name="options",
html_id="group_list_options",
)
- multi_select.change_event("change_list_options(values)")
+ multi_select.change_event("change_list_options(event.target.value);")
H.extend(
# ;
[
diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py
index a97834cb..a51790c7 100644
--- a/app/scodoc/sco_utils.py
+++ b/app/scodoc/sco_utils.py
@@ -63,6 +63,8 @@ from werkzeug.http import HTTP_STATUS_CODES
from config import Config
from app import log, ScoDocJSONEncoder
+from app.forms.multiselect import MultiSelect
+
from app.scodoc.codes_cursus import NOTES_TOLERANCE, CODES_EXPL
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc import sco_xml
@@ -445,121 +447,6 @@ def translate_assiduites_metric(metric, inverse=True, short=True) -> str:
return None
-class MultiSelect:
- """
- Classe pour faciliter l'utilisation du multi-select HTML/JS
-
- Les values sont représentées en dict {
- value: "...",
- label:"...",
- selected: True/False (default to False),
- single: True/False (default to False)
- }
-
- Args:
- values (dict[str, list[dict]]): Dictionnaire des valeurs
- génère des <optgroup> pour chaque clef du dictionnaire
- génère des <option> pour chaque valeur du dictionnaire
- name (str, optional): Nom du multi-select. Defaults to "multi-select".
- html_id (str, optional): Id HTML du multi-select. Defaults to "multi-select".
- classname (str, optional): Classe CSS du multi-select. Defaults to "".
- label (str, optional): Label du multi-select. Defaults to "".
- export (str, optional): Format du multi-select (HTML/JS). Defaults to "js".
- HTML : group_ids="val1"&group_ids="val2"...
- JS : ["val1","val2", ...]
-
- **kwargs: Arguments supplémentaires (appliqué au multiselect en HTML <multi-select key="value" ...>)
- """
-
- def __init__(
- self,
- values: dict[str, list[dict]],
- name="multi-select",
- html_id="multi-select",
- label="",
- classname="",
- **kwargs,
- ) -> None:
- self.values: dict[str, list[dict]] = values
- self._on = ""
-
- self.name: str = name
- self.html_id: str = html_id
- self.classname: str = classname
- self.label: str = label or name
-
- self.args: dict = kwargs
- self.js: str = ""
- self.export: str = "return values"
-
- def html(self) -> str:
- """
- Génère l'HTML correspondant au multi-select
- """
- opts: list[str] = []
-
- for key, values in self.values.items():
- optgroup = f"<optgroup label='{key}'>"
- for value in values:
- selected = "selected" if value.get("selected", False) else ""
- single = "single" if value.get("single", False) else ""
- opt = f"<option value='{value.get('value')}' {selected} {single} >{value.get('label')}</option>"
- optgroup += opt
- optgroup += "</optgroup>"
- opts.append(optgroup)
-
- args: list[str] = [f'{key}="{value}"' for key, value in self.args.items()]
- js: str = "{" + self.js + "}"
- export: str = "{" + self.export + "}"
- return f"""
- <multi-select
- label="{self.label}"
- id="{self.html_id}"
- name="{self.name}"
- class="{self.classname}"
- {" ".join(args)}
- >
- {"".join(opts)}
- </multi-select>
- <script>
- window.addEventListener('load', () => {{document.getElementById("{self.html_id}").on((values)=>{js});
- document.getElementById("{self.html_id}").format((values)=>{export});}} );
- </script>
- """
-
- def change_event(self, js: str) -> None:
- """
- Met à jour l'évènement de changement de valeur du multi-select
-
- CallBack JS : (values) => {/*actions à effectuer*/}
-
- Sera retranscrit dans l'HTML comme :
-
- document.getElementById(%self.id%).on((values)=>{%self.js%})
-
- Exemple d'utilisation :
-
- js : "console.log(values)"
- """
- self.js: str = js
-
- def export_format(self, js: str) -> None:
- """
- Met à jour le format de retour de valeur du multi-select
-
- CallBack JS : (values) => {/*actions à effectuer*/}
-
- Sera retranscrit dans l'HTML comme :
-
- document.getElementById(%self.id%).format((values)=>{%self.js%})
-
- Exemple d'utilisation :
-
- js : "return values.map(v=> 'val:'+v)"
- """
- self.export: str = js
-
-
# Types de modules
class ModuleType(IntEnum):
"""Code des types de module."""
diff --git a/app/static/js/multi-select.js b/app/static/js/multi-select.js
index e10194ad..178586f8 100644
--- a/app/static/js/multi-select.js
+++ b/app/static/js/multi-select.js
@@ -76,18 +76,28 @@ class MultiSelect extends HTMLElement {
position: absolute;
background-color: #fff;
min-width: 200px;
- max-height: 200px;
- overflow-y: auto;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.dropdown-content .optgroup {
- padding: 10px;
+ padding: 4px 8px;
width: 100%;
}
.dropdown-content .optgroup div {
font-weight: bold;
}
+ .dropdown-button::after{
+ content: "";
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 4px;
+ vertical-align: middle;
+ border-top: 4px dashed;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+ }
+
.dropdown-content .option {
display: flex;
align-items: center;
@@ -252,11 +262,6 @@ class MultiSelect extends HTMLElement {
} else {
btn.textContent = `${checkedBoxes.length} sélections`;
}
-
- btn.textContent += " ⮛";
-
- this._values(values);
-
this.dispatchEvent(new Event("change"));
}
@@ -280,6 +285,7 @@ class MultiSelect extends HTMLElement {
});
this._internals.setFormValue(this._values());
+ this._updateSelect();
}
}
--
GitLab