forked from ScoDoc/ScoDoc
multiselect.py + fix bug event + changement icône + unfixed height
This commit is contained in:
parent
00eb37e8ac
commit
5b68adaf87
118
app/forms/multiselect.py
Normal file
118
app/forms/multiselect.py
Normal file
@ -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
|
@ -750,7 +750,7 @@ def groups_table(
|
|||||||
name="options",
|
name="options",
|
||||||
html_id="group_list_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(
|
H.extend(
|
||||||
# ;
|
# ;
|
||||||
[
|
[
|
||||||
|
@ -63,6 +63,8 @@ from werkzeug.http import HTTP_STATUS_CODES
|
|||||||
from config import Config
|
from config import Config
|
||||||
from app import log, ScoDocJSONEncoder
|
from app import log, ScoDocJSONEncoder
|
||||||
|
|
||||||
|
from app.forms.multiselect import MultiSelect
|
||||||
|
|
||||||
from app.scodoc.codes_cursus import NOTES_TOLERANCE, CODES_EXPL
|
from app.scodoc.codes_cursus import NOTES_TOLERANCE, CODES_EXPL
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
from app.scodoc import sco_xml
|
from app.scodoc import sco_xml
|
||||||
@ -445,121 +447,6 @@ def translate_assiduites_metric(metric, inverse=True, short=True) -> str:
|
|||||||
return None
|
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
|
# Types de modules
|
||||||
class ModuleType(IntEnum):
|
class ModuleType(IntEnum):
|
||||||
"""Code des types de module."""
|
"""Code des types de module."""
|
||||||
|
@ -76,18 +76,28 @@ class MultiSelect extends HTMLElement {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
max-height: 200px;
|
|
||||||
overflow-y: auto;
|
|
||||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
.dropdown-content .optgroup {
|
.dropdown-content .optgroup {
|
||||||
padding: 10px;
|
padding: 4px 8px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.dropdown-content .optgroup div {
|
.dropdown-content .optgroup div {
|
||||||
font-weight: bold;
|
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 {
|
.dropdown-content .option {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -252,11 +262,6 @@ class MultiSelect extends HTMLElement {
|
|||||||
} else {
|
} else {
|
||||||
btn.textContent = `${checkedBoxes.length} sélections`;
|
btn.textContent = `${checkedBoxes.length} sélections`;
|
||||||
}
|
}
|
||||||
|
|
||||||
btn.textContent += " ⮛";
|
|
||||||
|
|
||||||
this._values(values);
|
|
||||||
|
|
||||||
this.dispatchEvent(new Event("change"));
|
this.dispatchEvent(new Event("change"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,6 +285,7 @@ class MultiSelect extends HTMLElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this._internals.setFormValue(this._values());
|
this._internals.setFormValue(this._values());
|
||||||
|
this._updateSelect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user