/* eslint-disable camelcase */
/* globals jQuery $ */
/*
Alacarte
@name alacarte.js
@author Rémi Angot
@license MIT License
@homepage https://copmaths.fr
@example http://coopmaths.fr/alacarte
*/
import { telechargeFichier, introLatex, introLatexCoop, exerciceSimpleToContenu } from './modules/outils.js'
import dictionnaireDesExercicesAleatoires from './modules/dictionnaireDesExercicesAleatoires.js'
import { dictionnaireC3 } from './modules/dictionnaireC3.js'
import { dictionnaireDNB } from './modules/dictionnaireDNB.js'
import { dictionnaireLycee } from './modules/dictionnaireLycee.js'
import { loadPrism } from './modules/loaders.js'
import { setOutputLatex } from './modules/context.js'
import '../css/style_mathalea.css'
const dictionnaireDesExercices = { ...dictionnaireDesExercicesAleatoires, ...dictionnaireDNB, ...dictionnaireC3, ...dictionnaireLycee }
// Les variables globales nécessaires aux exercices (pas terrible...)
window.mathalea = { sortieNB: false, anglePerspective: 30, coeffPerspective: 0.5, pixelsParCm: 20, scale: 1, unitesLutinParCm: 50, mainlevee: false, amplitude: 1, fenetreMathalea2d: [-1, -10, 29, 10], objets2D: [] }
setOutputLatex()
// Pour le menu du haut
document.addEventListener('DOMContentLoaded', (event) => {
$('.ui.dropdown').dropdown()
})
let codeLatex; let codeLatex_corr; let tableau_de_demandes; const objet_contenu = []; const objet_contenuCorrection = []
const listeDesExercicesDemandes = []; let contenu_fichier = ''; const listeObjetsExercice = {}; let message_d_erreur = ''
const tableau_url_tex = [['items/MATHS.6.G14_ProgrammeConstruction', 'MATHS.6.G14_.tex', 'MATHS.6.G14_-cor.tex'], ['items/MATHS.6.M20_Aire_triangles', 'MATHS.6.M20v2.tex', 'MATHS.6.M20v2-cor.tex'], ['items/MATHS.6.M20_Aire_triangles', 'MATHS.6.M20_.tex', 'MATHS.6.M20_-cor.tex'], ['items/MATHS.6.G11_Perpendiculaire', 'MATHS.6.G11_.tex', 'MATHS.6.G11_-cor.tex'], ['items/MATHS.6.G23_Rapporteur', 'MATHS.6.G23.tex', 'MATHS.6.G23-cor.tex'], ['items/MATHS.6.M23_PerimetreAiresDisques', 'MATHS.6.M23.tex', 'MATHS.6.M23-cor.tex'], ['items/MATHS.6.N22_CalculsFractions', 'MATHS.6.N22_.tex', 'MATHS.6.N22_-cor.tex'], ['items/MATHS.6.G10_VocabulaireNotations', 'MATHS.6.G10_.tex', 'MATHS.6.G10_-cor.tex'], ['items/MATHS.6.R10_ProprietesParallelesPerpendiculaires', 'MATHS.6.R10_.tex', 'MATHS.6.R10_-cor.tex'], ['items/MATHS.6.N23_NombresDecimaux', 'MATHS.6.N23_.tex', 'MATHS.6.N23_-cor.tex'], ['items/MATHS.6.C11_DivisionsEuclidiennes', 'MATHS.6.C11_v1.tex', 'MATHS.6.C11_v1-cor.tex'], ['items/MATHS.6.N21_AbscissesFractionnaires', 'MATHS.6.N21_.tex', 'MATHS.6.N21_-cor.tex'], ['items/MATHS.6.R12_ProprietesDefinitionsMediatrice', 'MATHS.6.R12.tex', 'MATHS.6.R12-cor.tex'], ['items/MATHS.6.G13_CarresRectangles', 'MATHS.6.G13_.tex', 'MATHS.6.G13_-cor.tex'], ['items/MATHS.6.C12_ProblemesNiveau1', 'MATHS.6.C12_v1.tex', 'MATHS.6.C12_v1-cor.tex'], ['items/MATHS.6.G12_Paralleles', 'MATHS.6.G12_.tex', 'MATHS.6.G12_-cor.tex'], ['items/MATHS.6.R11_SchemaProprietesParallelesPerpendiculaires', 'MATHS.6.R11_v1.tex', 'MATHS.6.R11_v1-cor.tex'], ['items/MATHS.6.M21_Aire_assemblage', 'MATHS.6.M21.tex', 'MATHS.6.M21-cor.tex'], ['items/MATHS.6.M24_Portions_disque', 'MATHS.6.M24.tex', 'MATHS.6.M24-cor.tex'], ['items/MATHS.6.N20_FractionsEtEntiers', 'MATHS.6.N20_v1.tex', 'MATHS.6.N20_v1-cor.tex'], ['items/MATHS.6.C10_AddSousMulEntiers', 'MATHS.6.C10_v1.tex', 'MATHS.6.C10_v1-cor.tex'], ['items/MATHS.6.C22_Problemes2', 'MATHS.6.C22.tex', 'MATHS.6.C22-cor.tex']]
const listePackages = new Set()
/**
* tableau_url_tex est un tableau de tableaux
*
* Chaque tableau est de la forme [nom du répertoire,nom du fichier, nom du fichier de la correction]
*
* On ajoute un dernnier element qui est une simplification du nom du répertoire (pas de points, pas /items)
*
* @author Rémi Angot
*/
function creeIdPourComparaison (item, index, arr) {
item[3] = item[0].replace(/\./g, '').replace('items/', '')
// une fois tous les points supprimés, on chercher le dernier 'tex' du string pour remettre '.tex'
// plus utilisé : .replace(/tex(?!.*tex)/g,'.tex') pour trouver le dernier 'tex' et le remplacer par '.tex'
item[3] = item[3].split('_')[0]
// ne garde que ce qui est avant le caractère _
}
tableau_url_tex.forEach(creeIdPourComparaison)
/**
* Récupère le texte saisi pour le transformer en tableau de tableaux.
*
* Premier séparateur le saut de ligne ; deuxième séparateur le point-virgule.
*
* @author Rémi Angot
*/
function textarea_to_array (textarea_id_textarea) {
const text = textarea_id_textarea.value// .replace(/[ ]/g,'');
// récupère le texte en effaçant tous les espaces
const tableau = text.split('\n')
tableau.forEach(function (ligne, i) {
tableau[i] = ligne.split(';')
// Regarde s'il y a besoin de modifier le préambule
// if (tableau[i].includes('6N21')) {besoin_des_axes_gradues=true} inutile avec liste_package
})
return tableau
}
/**
* Transforme un id d'exercice en url d'exercice statique
*
* Affiche un message d'erreur s'il n'y a pas d'exercice disponible.
*
* @author Rémi Angot
*/
// function id_to_url (id) {
// // Retourne les éléments du tableau qui inclue l'id demandé
// const tableau_items = tableau_url_tex.filter(element => element[3].includes(id))
// if (tableau_items.length === 0) {
// return 'pas_d_url'
// } else {
// // Choisit un fichier tex au hasard dans les répertoires
// const item = tableau_items[Math.floor(Math.random() * tableau_items.length)]
// return [item[0] + '/' + item[1], item[0] + '/' + item[2]]
// }
// }
/**
* Transforme le texte saisi par l'utilisateur en un dictionnaire avec l'id des exercices et les éventuels paramètres (sup, sup2, nbQuestions)
*
*
* txt_to_objet_parametres_exercice('6C10,sup=false,nbQuestions=5')
* {id: "6C10", sup: false, nbQuestions: 5}
* @author Rémi Angot
*/
function txt_to_objet_parametres_exercice (txt) {
const CleValeur = txt.split(',')
const ObjetParametres = {}
ObjetParametres.id = CleValeur[0] // Récupère le premier élément qui est forcément l'id
CleValeur.shift() // Retire ce premier élément
if (CleValeur.length > 0) {
for (const i in CleValeur) {
CleValeur[i] = CleValeur[i].split('=')
// change le type de ce qui ne doit pas être un string
if (CleValeur[i][1] === 'true' || CleValeur[i][1] === 'false') { // "true"=>true
ObjetParametres[CleValeur[i][0]] = (CleValeur[i][1] === 'true')
} else if (!isNaN(CleValeur[i][1])) { // "17"=>17
ObjetParametres[CleValeur[i][0]] = parseInt(CleValeur[i][1])
} else {
ObjetParametres[CleValeur[i][0]] = CleValeur[i][1]
}
}
}
return ObjetParametres
}
/**
* Met à jour le code LaTeX à partir de l'identifiant d'un exercice.
*
* On regarde d'abord si un exercice aléatoire a le même identifiant.
*
* //// ANNULÉ //// Si ce n'est pas le cas, on cherche dans le répertoire /items s'il y a un répertoire qui correspond
*
* @author Rémi Angot
*/
function item_to_contenu (txt) {
// De préférence un exercice aléatoire
const dictionnaire = txt_to_objet_parametres_exercice(txt)
const e = dictionnaire.id
const idExerciceMathALEA = e.replace('MATHS', '').replace(/\./g, '').replace(/ /g, '')
// Pour faire la correspondance entre SACoche et MathALEA, on supprime 'MATHS' et tous les points dans les noms des id
if (idExerciceMathALEA in listeObjetsExercice) {
const exercice_aleatoire = listeObjetsExercice[idExerciceMathALEA]
// Les paramètres peuvent être saisies de manière longue (nb_questions, sup, sup2, sup3) ou de manière courte (n, s, s2, s3)
if (dictionnaire.sup) {
exercice_aleatoire.sup = dictionnaire.sup
}
if (dictionnaire.s) {
exercice_aleatoire.sup = dictionnaire.s
}
if (dictionnaire.sup2) {
exercice_aleatoire.sup2 = dictionnaire.sup2
}
if (dictionnaire.s2) {
exercice_aleatoire.sup2 = dictionnaire.s2
}
if (dictionnaire.sup3) {
exercice_aleatoire.sup3 = dictionnaire.sup3
}
if (dictionnaire.s3) {
exercice_aleatoire.sup3 = dictionnaire.s3
}
if (dictionnaire.s4) {
exercice_aleatoire.sup4 = dictionnaire.s4
}
if (dictionnaire.nb_questions) {
exercice_aleatoire.nbQuestions = dictionnaire.nb_questions
}
if (dictionnaire.n) {
exercice_aleatoire.nbQuestions = dictionnaire.n
}
exercice_aleatoire.id = idExerciceMathALEA
if (exercice_aleatoire.typeExercice !== 'dnb') {
exercice_aleatoire.nouvelleVersion()
}
if (exercice_aleatoire.typeExercice === 'simple') {
exerciceSimpleToContenu(exercice_aleatoire)
}
codeLatex += `\n\n%%% ${e} : Exercice aléatoire - ${exercice_aleatoire.titre}%%%\n\n`
codeLatex += exercice_aleatoire.contenu + '\n\n'
codeLatex_corr += exercice_aleatoire.contenuCorrection + '\n\n'
if (typeof exercice_aleatoire.listePackages === 'string') {
listePackages.add(exercice_aleatoire.listePackages)
} else { // si c'est un tableau
exercice_aleatoire.listePackages.forEach(listePackages.add, listePackages)
}
// Sinon un exercice statique si le nom de l'item est inclus dans le nom du répertoire
} else {
// Si l'identifiant de l'exercice n'est disponible ni sur MathALEA ni dans la liste statique des url tableau_url_tex
codeLatex += `\n\n%%% Pas d'exercice disponible pour ${e}.\n\n`
updateMessageErreur(`Pas d'exercice disponible pour ${e}.\n`)
}
}
/**
* Met à jour le message d'erreur en évitant les doublons.
*
* @author Rémi Angot
*/
function updateMessageErreur (text) {
if (message_d_erreur.indexOf(text) === -1) {
message_d_erreur += text
}
}
window.addEventListener('load', function () {
jQuery.ajaxSetup({ async: false }) // Tout le traitement se fait de manière synchrone.
// On attend le résultat des requetes url vers les fichiers statiques pour bien avoir les exercices dans l'ordre
$('.ui.radio.checkbox').checkbox() // active les boutons radio (pour le style)
$('.ui.checkbox').checkbox()
// Gestion du menu déroulant par une fonction auto-exécutante
let attendre = 0;
(function menu_deroulant () {
const el = document.getElementsByClassName('menu_exercices_construit')
// Vérifie que ce div inutile a bien été créé
if (el.length && attendre > 1) {
// S'il est présent on règle le menu
$('.ui.dropdown').dropdown({ // gestion du clic sur le menu déroulant pour ajouter un item dans le textarea
action: function (text, value, element) { $('#textarea_id_items').val($('#textarea_id_items').val() + ';' + text.split(' ')[0]) }
}) // active les menus déroulants
} else {
setTimeout(menu_deroulant, 300) // retente dans 300 milliseconds
attendre += 1
}
})()
$('.ui.radio.checkbox').checkbox() // active les boutons radio (pour le style)
// Gestion de la suppression des identifiants
// const form_supprimer_reference = document.getElementById('supprimer_reference')
// form_supprimer_reference.addEventListener('change', function (e) { // Dès que le statut change, on met à jour
// document.getElementById('valider').click()
// })
$('#reglages_sortie_LaTeX').hide()
$('#valider').click(function () {
$('#div_codeLatex').html(' ')
codeLatex = ''
codeLatex_corr = ''
message_d_erreur = ''
tableau_de_demandes = textarea_to_array(textarea_id_items)
tableau_de_demandes.forEach(function (ligne, numero_de_ligne) {
// On créé un tableau pour chaque élève
objet_contenu[numero_de_ligne] = []
objet_contenuCorrection[numero_de_ligne] = []
ligne.forEach(function (e, i) {
let rang_premier_item = 0
if ($('#style1:checked').val()) {
rang_premier_item = 2
if (i === 0) {
objet_contenu[numero_de_ligne][i] = entete_eleve(ligne[0], ligne[1])
objet_contenuCorrection[numero_de_ligne][i] = entete_eleve(ligne[0], ligne[1])
}
}
if ($('#style2:checked').val()) {
rang_premier_item = 1
if (i === 0) {
objet_contenu[numero_de_ligne][i] = entete_eleve(ligne[0])
objet_contenuCorrection[numero_de_ligne][i] = entete_eleve(ligne[0])
}
}
if ($('#style3:checked').val()) {
rang_premier_item = 0
if (i === 0) {
objet_contenu[numero_de_ligne][i] = entete_eleve()
objet_contenuCorrection[numero_de_ligne][i] = entete_eleve()
}
}
if (i >= rang_premier_item) {
if (e.replace(/ /g, '').length > 2) {
e = e.replace(/ /g, '')
e = e.split(',')[0]
e = e.replace('MATHS', '').replace(/\./g, '').replace(/ /g, '')
// Pour faire la correspondance entre SACoche et MathALEA, on supprime 'MATHS' et tous les points dans les noms des id
objet_contenu[numero_de_ligne][i] = e
objet_contenuCorrection[numero_de_ligne][i] = e
if (dictionnaireDesExercices[e]) {
if (listeDesExercicesDemandes.indexOf(e) < 0) {
listeDesExercicesDemandes.push(e)
}
} else {
// console.log(`Pas d'exercice disponible pour ${e}.`)
}
}
}
})
})
const promises = []
for (let i = 0, id; i < listeDesExercicesDemandes.length; i++) {
id = listeDesExercicesDemandes[i]
let url
try {
url = dictionnaireDesExercices[id].url
} catch (error) {
console.log(error)
// console.log(`Exercice ${id} non disponible`);
}
if (dictionnaireDesExercices[id].typeExercice === 'dnb') {
listeObjetsExercice[id] = dictionnaireDesExercices[id]
promises.push(
fetch(url)
.then((response) => response.text())
.then((data) => {
listeObjetsExercice[id].nbQuestionsModifiable = false
listeObjetsExercice[id].video = ''
listeObjetsExercice[id].titre = id
listeObjetsExercice[id].contenu = data
listeObjetsExercice[id].listePackages = 'dnb'
})
)
promises.push(
fetch(dictionnaireDesExercices[id].urlcor)
.then((response) => response.text())
.then((data) => {
listeObjetsExercice[id].contenuCorrection = data
})
)
} else {
// promises.push(
// import(url)
// avec webpack on ne peut pas faire de import(url), car il faut lui indiquer quels fichiers sont susceptibles d'être chargés
// ici il ne peut s'agir que de js contenus dans exercices (dnb déjà traité dans le if au dessus)
const chunks = /^\/exercices\/(.*)/.exec(url)
if (!chunks) throw Error(`url non prévue : ${url}`)
const path = chunks[1]
promises.push(
// cf https://webpack.js.org/api/module-methods/#magic-comments
import(/* webpackMode: "lazy" */ './exercices/' + path)
.catch((error) => {
console.log(error)
// FIXME si c'est effectivement un [i] et pas [id], mettre un commentaire ici pour dire pourquoi, car en survolant le code ça semble un bug
listeObjetsExercice[i] = { titre: "Cet exercice n'existe pas", contenu: '', contenuCorrection: '' } // Un exercice vide pour l'exercice qui n'existe pas
})
.then(({ default: Exo }) => {
listeObjetsExercice[id] = new Exo() // Ajoute l'objet dans la liste des
})
)
}
}
// FIXME ce promise.all est lancé avant que le chargement de l'exo ne soit fini (listeObjetsExercice n'est pas encore complété), et on sait pas qui va terminer en premier
Promise.all(promises)
.then(() => {
tableau_de_demandes.forEach(function (ligne) {
ligne.forEach(function (e, i) {
let rang_premier_item = 0
if ($('#style1:checked').val()) {
rang_premier_item = 2
if (i === 0) {
codeLatex += entete_eleve(ligne[0], ligne[1])
codeLatex_corr += entete_eleve(ligne[0], ligne[1])
}
}
if ($('#style2:checked').val()) {
rang_premier_item = 1
if (i === 0) {
codeLatex += entete_eleve(ligne[0])
codeLatex_corr += entete_eleve(ligne[0])
}
}
if ($('#style3:checked').val()) {
rang_premier_item = 0
if (i === 0) {
codeLatex += entete_eleve()
codeLatex_corr += entete_eleve()
}
}
if (i >= rang_premier_item) {
if (e.replace(/ /g, '').length > 2) {
item_to_contenu(e)
}
}
})
})
if (message_d_erreur.length > 1) {
window.alert(message_d_erreur)
}
// Affiche les boutons de compilation
if (codeLatex.length > 2) {
$('#reglages_sortie_LaTeX').show()
}
// Affiche le code LaTeX
$('#div_codeLatex').html('<pre><code class="language-latex">' + codeLatex + intro_correction +
codeLatex_corr + '</code></pre>')
})
.then(loadPrism)
.then(() => {
/* global Prism */
const div = document.getElementById('div_codeLatex')
Prism.highlightAllUnder(div) // Met à jour la coloration syntaxique
})
})
// Gestion du téléchargement
$('#btn_telechargement').click(function () {
creer_fichier()
if ($('#nom_du_fichier').val()) {
telechargeFichier(contenu_fichier, $('#nom_du_fichier').val() + '.tex')
} else {
telechargeFichier(contenu_fichier, 'mathalea.tex')
}
})
$('#btn_overleaf').click(function () {
creer_fichier()
// Envoi à Overleaf.com en modifiant la valeur dans le formulaire
$('input[name=encoded_snip]').val(encodeURIComponent(contenu_fichier))
if (listePackages.has('dnb')) {
// Force le passage à xelatex sur Overleaf pour les exercices de DNB
$('input[name=engine]').val('xelatex')
}
if ($('#nom_du_fichier').val()) {
$('input[name=snip_name]').val($('#nom_du_fichier').val()) // nomme le projet sur Overleaf
}
})
// Gestion des paramètres du fichier LaTeX
$('#options_style_CoopMaths').hide() // par défaut le style est classique donc on
$('a.lien_images').hide() // cache les options du style Coop
$(function () {
$("input:radio[name='style']").change(function () {
if ($('#style_classique:checked').val()) {
$('#options_style_CoopMaths').hide()
$('a.lien_preambule').attr('href', 'fichiers/preambule.tex')
$('a.lien_images').hide()
} else {
$('a.lien_images').show()
$('#options_style_CoopMaths').show()
$('a.lien_preambule').attr('href', 'fichiers/preambule_coop.tex')
}
})
})
})
function creer_fichier () {
// Gestion du style pour l'entête du fichier
if ($('#style_classique:checked').val()) {
contenu_fichier = introLatex($('#entete_du_fichier').val(), listePackages) + macro_nom_copie()
} else {
contenu_fichier = introLatexCoop(listePackages) + macro_nom_copie('coop')
// contenu_fichier +='\n\n\\theme{' + $('input[name=theme]:checked').val() + '}{' + $("#entete_droit_du_fichier").val() + '}'
// contenu_fichier += '{' + $("#items").val() + '}{' + $("#domaine").val() + '}\n'
contenu_fichier += '\\begin{document}\n\n'
}
contenu_fichier += codeLatex
let supprimerCorrection = false
const supprimerCorrectionCheckbox = document.getElementById('supprimer_correction')
if (supprimerCorrectionCheckbox !== null) supprimerCorrection = supprimerCorrectionCheckbox.checked
if (!supprimerCorrection) contenu_fichier += intro_correction + codeLatex_corr
contenu_fichier += '\n\n\\end{document}'
}
// Gestion des en-têtes
let counter = 'section'
let entete_correction = ''
if ($('#style_classique:checked').val()) {
counter = 'exo'
entete_correction = '\\fancyhead[C]{Correction}\n'
}
function entete_eleve (prenom = '', nom = '') {
return `\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n
\\cleardoublepage
\\NomCopie{${prenom.toUpperCase()} ${nom.toUpperCase()}}
\\bigskip
`
}
const intro_correction = '\n%%%%%%%%%%%%%%%%\n%%%CORRECTION%%%\n%%%%%%%%%%%%%%%%' +
`\n\n\\newpage\n${entete_correction}\\setcounter{${counter}}{0}\n\n`
function macro_nom_copie (style = 'classique') {
if (style === 'classique') {
return `\\newcommand\\NomCopie[1]{\\fancyhead[L]{#1}
\\fancyhead[R]{${$('#entete_droit_du_fichier').val()}}
\\setcounter{exo}{0}
}\n\n`
} else {
return `\\newcommand\\NomCopie[1]{\\theme{${$('input[name=theme]:checked').val()}}{${$('#entete_du_fichier').val()}}{${$('#entete_droit_du_fichier').val()}}{#1}
\\setcounter{section}{0}
}\n\n`
}
}