diff --git a/CHANGELOG.md b/CHANGELOG.md index 6329d35..0e599b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,16 +2,32 @@ Toutes les modifications notables de ce projet seront documentées dans ce fichier. +## [1.1] - 2023-12-16 +### Ajouté : +- ajout d'un délai optionnel avant le lancement des entrées claviers pour plus de granularité +- ajout d'une option pour le port de Weda-Helper-Companion +- déplacement de keyCommands dans un fichier à part +- ajout de la possibilité d'une cotation par défaut dans la réalisation d'une FSE (attention ne se déclenche que si les questions OUI/NON sont cochées via les appuis clavier "o" et "n") + +### Correction : +- correcteur de date plus performant + +## [1.0.3] - 2023-12-08 + +### Ajouté + +- Ajout du formatage automatique des dates dans la page d'importations (à nouveau car la fonctionnalité semble fonctionner de façon aléatoire) +- mode cors ## [1.0.2] - 2023-12-09 ### Retiré -- Ajout ddu formatage automatique des dates dans la page d'importations (implémenté par Weda le 8 décembre environ...) +- Ajout du formatage automatique des dates dans la page d'importations (implémenté par Weda le 8 décembre environ...) ## [1.0.1] - 2023-12-08 ### Ajouté -- Ajout ddu formatage automatique des dates dans la page d'importations +- Ajout du formatage automatique des dates dans la page d'importations ## [1.0] - 2023-12-01 diff --git a/README.md b/README.md index 8001d59..9ab15d4 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,8 @@ Lors de l'usage de la calculette il devient possible d'utiliser les chiffres du - touche "retour arrière" pour effacer les valeurs numériques ## Écoute des entrées claviers dans la réalisation des FSE -les touches "n" et "o" permettent de sélectionner "non"/"oui" pour accidents de droit commun, puis ALD +- les touches "n" et "o" permettent de sélectionner "non"/"oui" pour accidents de droit commun, puis ALD +- si elles sont utilisées, entre automatiquement la cotation par défaut (à définir dans les options) ## Weda-Helper-Companion Est un script python, à récupérer sur https://github.com/Refhi/Weda-Helper-Companion qui reçoit des instructions de l'extension Weda-Helper. diff --git a/content.js b/content.js index 06ed025..82e9020 100644 --- a/content.js +++ b/content.js @@ -9,8 +9,6 @@ function ListTabOrderer(validTarget) { } - - // place a listener on the search box and focus on the first element of the list after a search function SearchBoxEntryListener(idsSearchBox, validTarget, listTabOrderer = false) { var searchBox = document.getElementById(idsSearchBox); @@ -284,13 +282,14 @@ function sendtpeinstruction(amount) { chrome.storage.sync.set({ 'lastTPEamount': amount }, function () { console.log('lastTPEamount', amount, 'sauvegardé avec succès'); }); - chrome.storage.sync.get(['ipTPE', 'portTPE', 'RemoveLocalCompanionTPE'], function (result) { + chrome.storage.sync.get(['portCompanion','ipTPE', 'portTPE', 'RemoveLocalCompanionTPE'], function (result) { + const portCompanion = result.portCompanion; const ipTPE = result.ipTPE; const portTPE = result.portTPE; const removeLocalCompanionTPE = result.RemoveLocalCompanionTPE; - if (!ipTPE || !portTPE || removeLocalCompanionTPE !== false) { - console.log('ipTPE, portTPE ou RemoveLocalCompanionTPE ne sont pas définis ou RemoveLocalCompanionTPE est !false (valeur actuelle :', removeLocalCompanionTPE, ')'); + if (!portCompanion || !ipTPE || !portTPE || removeLocalCompanionTPE !== false) { + console.warn('ipTPE, portTPE ou RemoveLocalCompanionTPE ne sont pas définis ou RemoveLocalCompanionTPE est !false (valeur actuelle :', removeLocalCompanionTPE, ')'); return; } else if (!(/^\d+$/.test(amount))) { console.log('amount', amount, 'n\'est pas un nombre entier'); @@ -298,10 +297,10 @@ function sendtpeinstruction(amount) { } else { console.log('sendinstruction', amount + 'c€' + ' to ' + ipTPE + ':' + portTPE); - fetch(`http://localhost:3000/tpe/${ipTPE}/${portTPE}/${amount}`, { mode: 'no-cors' }) + fetch(`http://localhost:${portCompanion}/tpe/${ipTPE}/${portTPE}/${amount}`) // les deux ci-dessous sont désactivés car ils ne fonctionnent pas avec no-cors - // .then(response => response.json()) - // .then(data => console.log(data)) + .then(response => response.json()) + .then(data => console.log(data)) .catch(error => console.error('Error:', error)); } }); @@ -328,15 +327,20 @@ function sendPrint() { return; } else { console.log('send Print'); - // recover values of 'delay_btw_tabs', 'delay_btw_tab_and_enter', 'delay_btw_enters', - chrome.storage.sync.get(['delay_btw_tabs', 'delay_btw_tab_and_enter', 'delay_btw_enters'], function (result) { + chrome.storage.sync.get(['portCompanion', 'delay_primary', 'delay_btw_tabs', 'delay_btw_tab_and_enter', 'delay_btw_enters'], function (result) { + const portCompanion = result.portCompanion; + const delay_primary = result.delay_primary; const delay_btw_tabs = result.delay_btw_tabs; const delay_btw_tab_and_enter = result.delay_btw_tab_and_enter; const delay_btw_enters = result.delay_btw_enters; + if (!portCompanion || !delay_primary || !delay_btw_tabs || !delay_btw_tab_and_enter || !delay_btw_enters) { + console.warn('ipTPE, portTPE ou RemoveLocalCompanionTPE ne sont pas définis. Aller à chrome-extension://fnfdbangkcmjacbeaaiongkbacaamnfd/options.html pour les définir'); + return; + } console.log('delay_btw_tabs', delay_btw_tabs); console.log('delay_btw_tab_and_enter', delay_btw_tab_and_enter); console.log('delay_btw_enters', delay_btw_enters); - fetch(`http://localhost:3000/print/${delay_btw_tabs}/${delay_btw_tab_and_enter}/${delay_btw_enters}`, { mode: 'no-cors' }) + fetch(`http://localhost:${portCompanion}/print/${delay_primary}/${delay_btw_tabs}/${delay_btw_tab_and_enter}/${delay_btw_enters}`) .catch(error => console.error('Error:', error)); }); } @@ -345,134 +349,6 @@ function sendPrint() { -const keyCommands = { - 'push_valider': { - description: 'Appuie le bouton Valider ou équivalent', - key: 'alt+v', - action: function () { - push_valider(); - } - }, - 'push_annuler': { - description: 'Appuie le bouton Annuler ou équivalent', - key: 'alt+a', - action: function () { - console.log('push_annuler activé'); - if (!clickElementByClass('button cancel')) { - GenericClicker("title", "Annuler") - GenericClicker("title", "Quitter") - clickElementByChildtextContent("ANNULER") - }; - } - }, - 'print_meds': { - description: 'Imprime les médicaments', - key: 'ctrl+p', - action: function () { - console.log('print_meds activé'); - clickFirstPrinter(); - waitForElementToExist('ContentPlaceHolder1_ViewPdfDocumentUCForm1_ButtonCloseStay', function (element) { - console.log('Element détecté:', element); - setTimeout(function () { - focusElementByName('ctl00$ContentPlaceHolder1$ViewPdfDocumentUCForm1$ButtonCloseStay'); - sendPrint(); - }, 400); - }); - } - }, - 'push_enregistrer': { - description: 'Appuie le bouton Enregistrer ou équivalent', - key: 'ctrl+s', - action: function () { - console.log('push_enregistrer activé'); - clickElementById('ButtonSave'); - } - }, - 'push_delete': { - description: 'Appuie le bouton Supprimer ou équivalent', - key: 'alt+s', - action: function () { - console.log('push_delete activé'); - clickElementByClass('button delete'); - } - }, - 'shortcut_w': { - description: 'Raccourci W', - key: 'alt+w', - action: function () { - console.log('shortcut_w activé'); - clickElementByOnclick("ctl00$ContentPlaceHolder1$EvenementUcForm1$MenuNavigate") - } - }, - 'shortcut_consult': { - description: 'Raccourci Consultation (crée une nouvelle consultation ou ouvre celle existante)', - key: 'alt+&', - action: function () { - console.log('shortcut_consult activé'); - submenuW(' Consultation'); - } - }, - 'shortcut_certif': { - description: 'Raccourci Certificat (crée un nouveau certificat ou ouvre celui existant)', - key: 'alt+é', - action: function () { - console.log('shortcut_certif activé'); - submenuW(' Certificat'); - } - }, - 'shortcut_demande': { - description: 'Raccourci Demande (crée une nouvelle demande ou ouvre celle existante)', - key: 'alt+\"', - action: function () { - console.log('shortcut_demande activé'); - submenuW(' Demande'); - } - }, - 'shortcut_prescription': { - description: 'Raccourci Prescription (crée une nouvelle prescription ou ouvre celle existante)', - key: 'alt+\'', - action: function () { - console.log('shortcut_prescription activé'); - submenuW(' Prescription'); - } - }, - 'shortcut_formulaire': { - description: 'Raccourci Formulaire (crée un nouveau formulaire ou ouvre celui existant)', - key: 'alt+f', - action: function () { - console.log('shortcut_formulaire activé'); - submenuW(' Formulaire'); - } - }, - 'shortcut_courrier': { - description: 'Raccourci Courrier (crée un nouveau courrier ou ouvre celui existant)', - key: 'alt+(', - action: function () { - console.log('shortcut_courrier activé'); - submenuW(' Courrier'); - } - }, - 'shortcut_fse': { - description: 'Raccourci FSE', - key: 'alt+-', - action: function () { - console.log('shortcut_fse activé'); - submenuW(' FSE'); - } - }, - 'shortcut_carte_vitale': { - description: 'Raccourci Carte Vitale', - key: 'alt+c', - action: function () { - console.log('shortcut_carte_vitale activé'); - clickElementByClass("cv"); - if (!GenericClicker("title", "Relance une lecture de la carte vitale")) { //TODO à tester : pour l'instant sous linux j'ai un message d'erreur - GenericClicker("mattooltip", "Lire la Carte Vitale"); - } - } - }, -}; - // // Listeners // Listen for messages from the background script about options const actions = { @@ -576,13 +452,81 @@ chrome.storage.sync.get('TweakImports', function (result) { } } + // Convert a truncated date to a full date + function convertDate(truncatedDate) { + let parts = truncatedDate.split('/'); + let day = parts[0]; + let month = parts[1] || new Date().getMonth() + 1; + let year = new Date().getFullYear(); + let length = day.length; + let validDayLengths = [1, 2, 4, 6, 8]; + + if (length === 4) { + // If truncatedDate is 4 digits, assume the first 2 digits are the day and the last 2 digits are the month + day = truncatedDate.substring(0, 2); + month = truncatedDate.substring(2, 4); + } else if (length === 6) { + // If truncatedDate is 6 digits, assume the first 2 digits are the day, the next 2 digits are the month, and the last 2 digits are the year + day = truncatedDate.substring(0, 2); + month = truncatedDate.substring(2, 4); + year = '20' + truncatedDate.substring(4, 6); // Add '20' to the beginning of the year to make it 4 digits + } else if (length === 8) { + // If truncatedDate is 8 digits, assume the first 2 digits are the day, the next 2 digits are the month, and the last 4 digits are the year + day = truncatedDate.substring(0, 2); + month = truncatedDate.substring(2, 4); + year = truncatedDate.substring(4, 8); + } else if (!validDayLengths.includes(length)){ + // If truncatedDate is not 4, 6, or 8 digits, return it without modification + console.log('Invalid date format:', truncatedDate); + return truncatedDate; + } + + // Add leading zeros to day and month if needed + if (day < 10 && day.length < 2) { + day = '0' + day; + } + + if (month < 10 && month.length < 2) { + month = '0' + month; + } + + return day + '/' + month + '/' + year; + } + + // Function to handle the 'keydown' event + function handleKeyDown(event) { + if (event.key === 'Tab') { + // The 'Tab' key was pressed, check and modify the text content as needed + let textField = event.target; + let datePattern = /^\d{2}\/\d{2}\/\d{4}$/; // Regular expression for dd/mm/yyyy + if (!datePattern.test(textField.value)) { + // The text is not in the correct date format. Check if it contains only / and numbers + let validPattern = /^[\d\/]+$/; + if (validPattern.test(textField.value)) { + // The text is valid, convert it to a full date + textField.value = convertDate(textField.value); + } + // ... + } + } + } + + // Add the event listener to each date document field + function addEventListeners() { + for (let i = 0; i <= 7; i++) { + let textField = document.getElementById(`ContentPlaceHolder1_FileStreamClassementsGrid_EditBoxGridFileStreamClassementDate_${i}`); + if (textField) { + textField.addEventListener('keydown', handleKeyDown); + } + } + } // modifie la page d'upload : modifie la taille de prévisu, modifie l'ordre de tabulation et place un listener sur la searchbox. function uploaderformSetup() { uploaderformResizeElements(); uploaderformSetTabOrder(); SearchBoxEntryListener(idsSearchBox, validTarget, listTabOrderer = true); - // addEventListeners(); // retiré car implémenté par Weda quasiment le jour-même... + addEventListeners(); }; if (result.TweakImports !== false) { @@ -727,7 +671,6 @@ if (window.location.href.startsWith('https://secure.weda.fr/FolderMedical/Prescr // Tweak the FSE page (Add a button in the FSE page to send the amount to the TPE, implement shortcuts) if (window.location.href.startsWith('https://secure.weda.fr/vitalzen/fse.aspx')) { console.log('fse started'); - // Make a dictionnary with keystrokes and their corresponding actions var index = { 'n': ['mat-radio-9-input', 'mat-radio-3-input'], @@ -752,19 +695,22 @@ if (window.location.href.startsWith('https://secure.weda.fr/vitalzen/fse.aspx')) } // add a visual clue to the element with id element_id function addVisualClue(element_id) { - var radioButton = document.getElementById(element_id); - if (radioButton) { - var labelContents = radioButton.getElementsByClassName('mat-radio-label-content'); - console.log('labelContents', labelContents); - if (labelContents.length > 0) { - var labelContent = labelContents[0]; - var text = labelContent.innerHTML; - console.log('Texte à souligner', text); - text = text.replace('N', 'N'); - text = text.replace('O', 'O'); - labelContent.innerHTML = text; + var checkExist = setInterval(function() { + var radioButton = document.getElementById(element_id); + if (radioButton) { + clearInterval(checkExist); // Arrête de vérifier une fois que l'élément est trouvé + var labelContents = radioButton.getElementsByClassName('mat-radio-label-content'); + console.log('labelContents', labelContents); + if (labelContents.length > 0) { + var labelContent = labelContents[0]; + var text = labelContent.innerHTML; + console.log('Texte à souligner', text); + text = text.replace('N', 'N'); + text = text.replace('O', 'O'); + labelContent.innerHTML = text; + } } - } + }, 100); // Vérifie l'existence de l'élément toutes les 100ms } function removeVisualClue(element_id) { console.log('removeVisualClue', element_id); @@ -782,11 +728,63 @@ if (window.location.href.startsWith('https://secure.weda.fr/vitalzen/fse.aspx')) } } } - // Small delay to add visual clues - setTimeout(function () { - addVisualClue(clue_index['n'][0]); - addVisualClue(clue_index['o'][0]); - }, 100); + + // function setDefaultValue() { + // // set defaut value + // chrome.storage.sync.get('defaultCotation', function (result) { + // var defaultCotation = result.defaultCotation; + // // si defaultCotation n'est pas défini, le définir à '' + // if (!defaultCotation) { + // defaultCotation = ''; + // } + // console.log('Je met la cotation par défaut : ', defaultCotation); + + // var checkExist = setInterval(function() { + // var inputField = document.querySelector('.acteCell .mat-input-element'); + // if (inputField) { + // clearInterval(checkExist); // Arrête de vérifier une fois que l'élément est trouvé + // inputField.value = defaultCotation; + // } + // }, 100); // Vérifie l'existence de l'élément toutes les 100ms + // }); + // } + + function setDefaultValue() { + // set defaut value + chrome.storage.sync.get('defaultCotation', function (result) { + var defaultCotation = result.defaultCotation; + // si defaultCotation n'est pas défini, le définir à '' + if (!defaultCotation) { + defaultCotation = ''; + } + console.log('Je met la cotation par défaut : ', defaultCotation); + + var checkExist = setInterval(function() { + var inputField = document.querySelector('.acteCell .mat-input-element'); + if (inputField) { + clearInterval(checkExist); // Arrête de vérifier une fois que l'élément est trouvé + for (let i = 0; i < defaultCotation.length; i++) { + var event = new KeyboardEvent('keydown', { + key: defaultCotation[i], + bubbles: true, + cancelable: true, + }); + inputField.dispatchEvent(event); + inputField.value += defaultCotation[i]; + var event = new Event('input', { + bubbles: true, + cancelable: true, + }); + inputField.dispatchEvent(event); + } + } + }, 100); // Vérifie l'existence de l'élément toutes les 100ms + }); + } + // Add visual clues + addVisualClue(clue_index['n'][0]); + addVisualClue(clue_index['o'][0]); + // detect the press of keys in index, and check the corresponding element with clickElementById document.addEventListener('keydown', function (event) { @@ -828,6 +826,7 @@ if (window.location.href.startsWith('https://secure.weda.fr/vitalzen/fse.aspx')) if (inputField) { setTimeout(function () { inputField.focus(); + setDefaultValue(); }, 100); } } @@ -837,5 +836,4 @@ if (window.location.href.startsWith('https://secure.weda.fr/vitalzen/fse.aspx')) // TODO : ajouter d'autres fenêtres d'information -// TODO : basculer l'écoute du clavier sur keydown et keyup -// TODO : basculer keyCommands dans un fichier à part \ No newline at end of file +// TODO : basculer l'écoute du clavier sur keydown et keyup \ No newline at end of file diff --git a/keyCommands.js b/keyCommands.js new file mode 100644 index 0000000..269d530 --- /dev/null +++ b/keyCommands.js @@ -0,0 +1,136 @@ +/** + * Fichier contenant les commandes clés pour l'application. + * Les commandes clés sont définies comme des objets avec une description, une combinaison de touches et une action associée. + * @typedef {Object} KeyCommand + * @property {string} description - La description de la commande clé. + * @property {string} key - La combinaison de touches associée à la commande clé. + * @property {Function} action - La fonction exécutée lorsque la commande clé est activée. + */ + +const keyCommands = { + 'push_valider': { + description: 'Appuie le bouton Valider ou équivalent', + key: 'alt+v', + action: function () { + push_valider(); + } + }, + 'push_annuler': { + description: 'Appuie le bouton Annuler ou équivalent', + key: 'alt+a', + action: function () { + console.log('push_annuler activé'); + if (!clickElementByClass('button cancel')) { + GenericClicker("title", "Annuler") + GenericClicker("title", "Quitter") + clickElementByChildtextContent("ANNULER") + }; + } + }, + 'print_meds': { + description: 'Imprime les médicaments', + key: 'ctrl+p', + action: function () { + console.log('print_meds activé'); + clickFirstPrinter(); + waitForElementToExist('ContentPlaceHolder1_ViewPdfDocumentUCForm1_ButtonCloseStay', function (element) { + console.log('Element détecté:', element); + setTimeout(function () { + focusElementByName('ctl00$ContentPlaceHolder1$ViewPdfDocumentUCForm1$ButtonCloseStay'); + sendPrint(); + }, 400); + }); + } + }, + 'push_enregistrer': { + description: 'Appuie le bouton Enregistrer ou équivalent', + key: 'ctrl+s', + action: function () { + console.log('push_enregistrer activé'); + clickElementById('ButtonSave'); + } + }, + 'push_delete': { + description: 'Appuie le bouton Supprimer ou équivalent', + key: 'alt+s', + action: function () { + console.log('push_delete activé'); + clickElementByClass('button delete'); + } + }, + 'shortcut_w': { + description: 'Raccourci W', + key: 'alt+w', + action: function () { + console.log('shortcut_w activé'); + clickElementByOnclick("ctl00$ContentPlaceHolder1$EvenementUcForm1$MenuNavigate") + } + }, + 'shortcut_consult': { + description: 'Raccourci Consultation (crée une nouvelle consultation ou ouvre celle existante)', + key: 'alt+&', + action: function () { + console.log('shortcut_consult activé'); + submenuW(' Consultation'); + } + }, + 'shortcut_certif': { + description: 'Raccourci Certificat (crée un nouveau certificat ou ouvre celui existant)', + key: 'alt+é', + action: function () { + console.log('shortcut_certif activé'); + submenuW(' Certificat'); + } + }, + 'shortcut_demande': { + description: 'Raccourci Demande (crée une nouvelle demande ou ouvre celle existante)', + key: 'alt+\"', + action: function () { + console.log('shortcut_demande activé'); + submenuW(' Demande'); + } + }, + 'shortcut_prescription': { + description: 'Raccourci Prescription (crée une nouvelle prescription ou ouvre celle existante)', + key: 'alt+\'', + action: function () { + console.log('shortcut_prescription activé'); + submenuW(' Prescription'); + } + }, + 'shortcut_formulaire': { + description: 'Raccourci Formulaire (crée un nouveau formulaire ou ouvre celui existant)', + key: 'alt+f', + action: function () { + console.log('shortcut_formulaire activé'); + submenuW(' Formulaire'); + } + }, + 'shortcut_courrier': { + description: 'Raccourci Courrier (crée un nouveau courrier ou ouvre celui existant)', + key: 'alt+(', + action: function () { + console.log('shortcut_courrier activé'); + submenuW(' Courrier'); + } + }, + 'shortcut_fse': { + description: 'Raccourci FSE', + key: 'alt+-', + action: function () { + console.log('shortcut_fse activé'); + submenuW(' FSE'); + } + }, + 'shortcut_carte_vitale': { + description: 'Raccourci Carte Vitale', + key: 'alt+c', + action: function () { + console.log('shortcut_carte_vitale activé'); + clickElementByClass("cv"); + if (!GenericClicker("title", "Relance une lecture de la carte vitale")) { //TODO à tester : pour l'instant sous linux j'ai un message d'erreur + GenericClicker("mattooltip", "Lire la Carte Vitale"); + } + } + }, +}; \ No newline at end of file diff --git a/manifest.json b/manifest.json index 627f155..fc8fe9e 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Weda Helper", - "version": "1.0.2", + "version": "1.1", "options_page": "options.html", "permissions": ["storage"], "host_permissions": ["http://localhost:3000/"], @@ -15,7 +15,7 @@ "content_scripts": [ { "matches": ["*://secure.weda.fr/*"], - "js": ["content.js", "clickHelpers.js"] + "js": ["content.js", "clickHelpers.js", "keyCommands.js"] } ], "commands": { diff --git a/options.html b/options.html index 063910f..3edc6e7 100644 --- a/options.html +++ b/options.html @@ -10,6 +10,14 @@ Activer les modifications de la fenêtre recherche patient (permet d'utiliser tab plus facilement)
Activer les modifications de la fenêtre recherche médicaments (permet d'utiliser tab plus facilement)
Désactiver l'impression automatique complète via le companion
+
+ + +
+
+ + +
@@ -28,6 +36,8 @@ + +
diff --git a/options.js b/options.js index 64317e5..027ddd4 100644 --- a/options.js +++ b/options.js @@ -7,20 +7,25 @@ document.addEventListener('DOMContentLoaded', function () { 'TweakTabSearchPatient', 'TweakTabPrescription', 'RemoveLocalCompanionPrint', + 'delay_primary', 'delay_btw_tabs', 'delay_btw_tab_and_enter', 'delay_btw_enters', 'RemoveLocalCompanionTPE', 'ipTPE', - 'portTPE' + 'portTPE', + 'portCompanion', + 'defaultCotation' ]; var defautsTextValues = { + 'delay_primary': '0.02', 'delay_btw_tabs': '0.01', 'delay_btw_tab_and_enter': '0.01', 'delay_btw_enters': '0.5', 'ipTPE': 'localhost', - 'portTPE': '5000' + 'portTPE': '5000', + 'portCompanion': '3000' }; options.forEach(function (option) { @@ -68,12 +73,19 @@ document.addEventListener('DOMContentLoaded', function () { return; } - if (option === 'portTPE' && (!portRegex.test(value) || value < 1 || value > 65535)) { + if ((option === 'portTPE' || option === 'portCompanion') && (!portRegex.test(value) || value < 1 || value > 65535)) { alert('Veuillez entrer un numéro de port valide'); isValid = false; return; } + var letterRegex = /^([A-Z0-9]{1,7})?$/; + if (option === 'defaultCotation' && !letterRegex.test(value)) { + alert('defaultCotation doit être composé uniquement de lettres majuscules et ne doit pas contenir plus de 7 lettres, ou être une chaîne vide'); + isValid = false; + return; + } + // check that values in defautsTextValues entered are valid : they must be not be more than 10 times the default value nor less than 0.1 times the default value for (var key in defautsTextValues) { if (key === option && option.includes('delay')) {