ScoDoc/app/static/js/scodoc.js

375 lines
9.7 KiB
JavaScript

// JS for all ScoDoc pages (using jQuery UI)
$(function () {
// Autocomplete recherche etudiants par nom
$(".in-expnom").autocomplete({
delay: 300, // wait 300ms before suggestions
minLength: 2, // min nb of chars before suggest
position: { collision: "flip" }, // automatic menu position up/down
source: SCO_URL + "/search_etud_by_name",
select: function (event, ui) {
$(".in-expnom").val(ui.item.value);
$("#form-chercheetud").submit();
},
});
// Date picker
$(".datepicker").datepicker({
showOn: "button",
buttonImage: "/ScoDoc/static/icons/calendar_img.png",
buttonImageOnly: true,
dateFormat: "dd/mm/yy",
duration: "fast",
firstDay: 1, // Start with Monday
dayNames: [
"Dimanche",
"Lundi",
"Mardi",
"Mercredi",
"Jeudi",
"Vendredi",
"Samedi",
],
dayNamesMin: ["Di", "Lu", "Ma", "Me", "Je", "Ve", "Sa"],
dayNamesShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"],
monthNames: [
"Janvier",
"Février",
"Mars",
"Avril",
"May",
"Juin",
"Juilet",
"Août",
"Septembre",
"Octobre",
"Novembre",
"Décembre",
],
monthNamesShort: [
"Jan",
"Fév",
"Mar",
"Avr",
"Mai",
"Juin",
"Juil",
"Aoû",
"Sep",
"Oct",
"Nov",
"Déc",
],
});
$(".datepicker").datepicker(
"option",
$.extend({ showMonthAfterYear: false }, $.datepicker.regional["fr"])
);
/* Barre menu */
var sco_menu_position = { my: "left top", at: "left bottom" };
$("#sco_menu")
.menu({
position: sco_menu_position,
blur: function () {
$(this).menu("option", "position", sco_menu_position);
},
focus: function (e, ui) {
if ($("#sco_menu").get(0) !== $(ui).get(0).item.parent().get(0)) {
$(this).menu("option", "position", {
my: "left top",
at: "right top",
});
}
},
})
.mouseleave(function (x, y) {
$("#sco_menu").menu("collapseAll");
});
$("#sco_menu > li > a > span").switchClass(
"ui-icon-carat-1-e",
"ui-icon-carat-1-s"
);
/* Les menus isoles dropdown */
$(".sco_dropdown_menu")
.menu({
position: sco_menu_position,
})
.mouseleave(function (x, y) {
$(".sco_dropdown_menu").menu("collapseAll");
});
$(".sco_dropdown_menu > li > a > span").switchClass(
"ui-icon-carat-1-e",
"ui-icon-carat-1-s"
);
/* up-to-date status */
var update_div = document.getElementById("update_warning");
if (update_div) {
fetch("install_info")
.then((response) => response.text())
.then((text) => {
update_div.innerHTML = text;
if (text) {
update_div.style.display = "block";
}
});
}
});
function sco_capitalize(string) {
return string[0].toUpperCase() + string.slice(1).toLowerCase();
}
// Affiche un message transitoire (duration milliseconds, 0 means infinity)
function sco_message(msg, className = "message_custom", duration = 0) {
var div = document.createElement("div");
div.className = className;
div.innerHTML = msg;
document.querySelector("body").appendChild(div);
if (duration) {
setTimeout(() => {
div.remove();
}, duration);
}
}
function sco_error_message(msg) {
sco_message(msg, (className = "message_error"), (duration = 0));
}
function get_query_args() {
var s = window.location.search; // eg "?x=1&y=2"
var vars = {};
s.replace(
/[?&]+([^=&]+)=?([^&]*)?/gi, // regexp
function (m, key, value) {
// callback
vars[key] = value !== undefined ? value : "";
}
);
return vars;
}
// Tables (gen_tables)
$(function () {
if ($("table.gt_table").length > 0) {
const url = new URL(document.URL);
const order_info_key = JSON.stringify(["table_order", url.pathname]);
let order_info;
const x = localStorage.getItem(order_info_key);
if (x) {
try {
order_info = JSON.parse(x);
} catch (error) {
console.error(error);
}
}
var table_options = {
paging: false,
searching: false,
info: false,
/* "autoWidth" : false, */
fixedHeader: {
header: true,
footer: true,
},
orderCellsTop: true, // cellules ligne 1 pour tri
aaSorting: [], // Prevent initial sorting
order: order_info,
drawCallback: function (settings) {
// permet de conserver l'ordre de tri des colonnes
let table = $("table.gt_table").DataTable();
let order_info = JSON.stringify(table.order());
localStorage.setItem(order_info_key, order_info);
},
};
$("table.gt_table").DataTable(table_options);
table_options["searching"] = true;
$("table.gt_table_searchable").DataTable(table_options);
}
});
// Show tags (readonly)
function readOnlyTags(nodes) {
// nodes are textareas, hide them and create a span showing tags
for (var i = 0; i < nodes.length; i++) {
var node = $(nodes[i]);
node.hide();
var tags = nodes[i].value.split(",");
node.after(
'<span class="ro_tags"><span class="ro_tag">' +
tags.join('</span><span class="ro_tag">') +
"</span></span>"
);
}
}
/* Editeur pour champs
* Usage: créer un élément avec data-oid (object id)
* La méthode d'URL save sera appelée en POST avec deux arguments: oid et value,
* value contenant la valeur du champs.
* Inspiré par les codes et conseils de Seb. L.
*/
class ScoFieldEditor {
constructor(selector, save_url, read_only) {
this.save_url = save_url;
this.read_only = read_only;
this.selector = selector;
this.installListeners();
}
// Enregistre l'élément obj
save(obj) {
var value = obj.innerText.trim();
if (value.length == 0) {
value = "";
}
if (value == obj.dataset.value) {
return true; // Aucune modification, pas d'enregistrement mais on continue normalement
}
obj.classList.add("sco_wait");
// DEBUG
// console.log(`
// data : ${value},
// id: ${obj.dataset.oid}
// `);
$.post(
this.save_url,
{
oid: obj.dataset.oid,
value: value,
},
function (result) {
obj.classList.remove("sco_wait");
obj.classList.add("sco_modified");
}
);
return true;
}
/*****************************/
/* Gestion des évènements */
/*****************************/
installListeners() {
if (this.read_only) {
return;
}
document.body.addEventListener("keydown", this.key);
let editor = this;
this.handleSelectCell = (event) => {
editor.selectCell(event);
};
this.handleModifCell = (event) => {
editor.modifCell(event);
};
this.handleBlur = (event) => {
editor.blurCell(event);
};
this.handleKeyCell = (event) => {
editor.keyCell(event);
};
document.querySelectorAll(this.selector).forEach((cellule) => {
cellule.addEventListener("click", this.handleSelectCell);
cellule.addEventListener("dblclick", this.handleModifCell);
cellule.addEventListener("blur", this.handleBlur);
});
}
/*********************************/
/* Interaction avec les cellules */
/*********************************/
blurCell(event) {
let currentModif = document.querySelector(".sco_modifying");
if (currentModif) {
if (!this.save(currentModif)) {
return;
}
}
}
selectCell(event) {
let obj = event.currentTarget;
if (obj) {
if (obj.classList.contains("sco_modifying")) {
return; // Cellule en cours de modification, ne pas sélectionner.
}
let currentModif = document.querySelector(".sco_modifying");
if (currentModif) {
if (!this.save(currentModif)) {
return;
}
}
this.unselectCell();
obj.classList.add("sco_selected");
}
}
unselectCell() {
document
.querySelectorAll(".sco_selected, .sco_modifying")
.forEach((cellule) => {
cellule.classList.remove("sco_selected", "sco_modifying");
cellule.removeAttribute("contentEditable");
cellule.removeEventListener("keydown", this.handleKeyCell);
});
}
modifCell(event) {
let obj = event.currentTarget;
if (obj) {
obj.classList.add("sco_modifying");
obj.contentEditable = true;
obj.addEventListener("keydown", this.handleKeyCell);
obj.focus();
}
}
key(event) {
switch (event.key) {
case "Enter":
this.modifCell(document.querySelector(".sco_selected"));
event.preventDefault();
break;
}
}
keyCell(event) {
let obj = event.currentTarget;
if (obj) {
if (event.key == "Enter") {
event.preventDefault();
event.stopPropagation();
if (!this.save(obj)) {
return;
}
obj.classList.remove("sco_modifying");
// ArrowMove(0, 1);
// modifCell(document.querySelector(".sco_selected"));
this.unselectCell();
}
}
}
}
function getCurrentScriptPath() {
// Get all the script elements on the page
var scripts = document.getElementsByTagName("script");
// Find the last script element (which is the currently executing script)
var currentScript = scripts[scripts.length - 1];
// Retrieve the src attribute of the script element
var scriptPath = currentScript.src;
return scriptPath;
}
function removeLastTwoComponents(path) {
// Split the path into individual components
var components = path.split("/");
// Remove the last two components (filename and enclosing directory)
components.splice(-2);
// Join the remaining components back into a path
var newPath = components.join("/");
return newPath;
}