diff --git a/package.json b/package.json index 30f89923e..9c67067a3 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,6 @@ "eslint-webpack-plugin": "^5.0.2", "file-loader": "^6.2.0", "html2canvas": "^1.4.1", - "jquery": "^3.7.1", "jspdf": "^4.2.1", "less": "^4.4.2", "less-loader": "^12.3.0", diff --git a/src/js/listener/handlers/configuration_handlers.js b/src/js/listener/handlers/configuration_handlers.js new file mode 100644 index 000000000..6cbb7cc1d --- /dev/null +++ b/src/js/listener/handlers/configuration_handlers.js @@ -0,0 +1,48 @@ +import { getFilePickerBuilder } from "@nextcloud/dialogs"; +import { configuration, updateCurrentCompany, updateDBConfiguration } from "../../modules/ajaxRequest.js"; +import { path } from "../../modules/mainFunction.js"; + +const chooseFolderLabel = t('gestion', 'Choose work folder'); + +export function openAboutModal() { + const modal = document.getElementById("modalConfig"); + if (modal) { + modal.style.display = "block"; + } +} + +export function closeModal(target) { + const modal = target.parentElement.parentElement; + modal.style.display = "none"; +} + +export function openFolderPicker() { + getFilePickerBuilder(chooseFolderLabel) + .allowDirectories(true) + .setMultiSelect(false) + .addButton({ + label: t('gestion', 'Choose'), + callback: updateSelectedFolder, + }) + .build() + .pick() + .catch(error => { + console.error("Erreur lors de l'ouverture du sélecteur :", error); + }); +} + +export function updateCurrentCompanySelection(target) { + updateCurrentCompany(target.value); +} + +function updateSelectedFolder(nodes) { + const values = nodes.map(node => node.path); + const theFolder = document.getElementById('theFolder'); + const table = theFolder.getAttribute('data-table'); + const column = theFolder.getAttribute('data-column'); + const id = theFolder.getAttribute('data-id'); + + updateDBConfiguration(table, column, values[0], id); + configuration(path); + document.getElementById('theFolder').value = values[0]; +} diff --git a/src/js/listener/handlers/editable_handlers.js b/src/js/listener/handlers/editable_handlers.js new file mode 100644 index 000000000..a7923bd33 --- /dev/null +++ b/src/js/listener/handlers/editable_handlers.js @@ -0,0 +1,65 @@ +import { updateEditable } from "../../modules/ajaxRequest.js"; +import { updateNumerical } from "../../modules/mainFunction.js"; + +const EDITABLE_CLASSES = [ + "editableNumber", + "editableNumeric", + "editableComment", + "editable", +]; + +const NON_INLINE_EDITABLE_CLASSES = [ + "editableSelect", + "editableConfiguration", + "editableConfigurationSelect", +]; + +const IGNORED_SAVE_CLASSES = [ + ...NON_INLINE_EDITABLE_CLASSES, + "editableComment", +]; + +export function isInlineEditable(element) { + return EDITABLE_CLASSES.some(className => element.classList.contains(className)); +} + +export function shouldSkipInlineEdit(element) { + return NON_INLINE_EDITABLE_CLASSES.some(className => element.classList.contains(className)); +} + +export function enableInlineEdit(element) { + element.setAttribute('contenteditable', 'true'); + element.focus(); +} + +export function saveEditableElement(element, ignoreComment = false) { + const targetClass = element.className; + + if (targetClass.includes("editableNumber") || targetClass.includes("editableNumeric")) { + const formatAsCurrency = element.dataset.column !== "quantite"; + updateNumerical(element, formatAsCurrency); + return; + } + + const ignoredClasses = ignoreComment ? IGNORED_SAVE_CLASSES : NON_INLINE_EDITABLE_CLASSES; + + if (ignoredClasses.some(className => targetClass.includes(className))) { + return; + } + + if (targetClass.includes("editable")) { + updateEditable(element); + } +} + +export function applyMouseOverStyles(element) { + element.style.fontWeight = "bold"; + element.addEventListener('mouseout', resetMouseOverStyles); +} + +function resetMouseOverStyles(event) { + event.target.style.border = null; + event.target.style.padding = null; + event.target.style.fontWeight = null; + event.target.style.borderRadius = null; +} diff --git a/src/js/listener/handlers/product_handlers.js b/src/js/listener/handlers/product_handlers.js new file mode 100644 index 000000000..620e13987 --- /dev/null +++ b/src/js/listener/handlers/product_handlers.js @@ -0,0 +1,57 @@ +import { showError } from "@nextcloud/dialogs"; +import { baseUrl } from "../../modules/mainFunction.js"; +import { getProduitsById, listProduit, updateDB } from "../../modules/ajaxRequest.js"; + +export function addProductToDevis() { + const devisId = document.getElementById('devisid').dataset.id; + const produitDevis = { id: devisId }; + + fetch(baseUrl + '/insertProduitDevis', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(produitDevis) + }) + .then(function(response) { + if (response.ok) { + return response.json(); + } + throw new Error('Network response was not ok.'); + }) + .then(function() { + getProduitsById(); + }) + .catch(function() { + showError(t('gestion', "Please create a new product")); + }); +} + +export function showProductSelect(target) { + const id = target.dataset.id; + const produitid = target.dataset.val; + target.textContent = ""; + target.innerHTML = ''; - listProduit(document.getElementById('listProduit'), id, produitid); - } - }); - - document.body.addEventListener('change', function(event) { - if (event.target.classList.contains('listClient') || event.target.classList.contains('listDevis')) { - var myDiv = event.target.closest("div"); - var id = myDiv.dataset.id; - var val = event.target.value; - var column = myDiv.dataset.column; - var table = myDiv.dataset.table; - event.target.setAttribute('data-current', event.target.value); - updateDB(table, column, val, id); - } - - if (event.target.classList.contains('inputDate')) { - var id = event.target.dataset.id; - var val = event.target.value; - var column = event.target.dataset.column; - var table = event.target.dataset.table; - updateDB(table, column, val, id); - } - - if (event.target.id === 'listProduit' || event.target.id === 'listDevis') { - waitforUpdateProduits(event, table, column, val, id) - } - - if (event.target.classList.contains('editableSelect')) { - var table = event.target.getAttribute('data-table'); - var column = event.target.getAttribute('data-column'); - var value = event.target.value; - var id = event.target.getAttribute('data-id'); - - updateDB(table, column, value, id); - } - - if(event.target.id === "CurrentCompany-select"){ - var value = event.target.value; - updateCurrentCompany(value); - } - }); - - var lastKeyEventTime = 0; - - document.body.addEventListener('keydown', function(e) { - if (e.key === "Enter") { - - lastKeyEventTime = Date.now(); - - var targetClass = e.target.className; - - if (targetClass.includes("editableNumber") || targetClass.includes("editableNumeric")) { - - const formatAsCurrency = - e.target.dataset.column !== "quantite"; - - updateNumerical(e.target, formatAsCurrency); - - } else if ( - targetClass.includes("editableSelect") || - targetClass.includes("editableConfiguration") || - targetClass.includes("editableConfigurationSelect") || - targetClass.includes("editableComment") - ) { - - // Empêcher le comportement par défaut - - } else if (targetClass.includes("editable")) { - - updateEditable(e.target); - } - } - }); - - document.body.addEventListener('focusout', function(e) { - if (Date.now() - lastKeyEventTime < 100) { - e.preventDefault(); +import { + applyMouseOverStyles, + enableInlineEdit, + isInlineEditable, + saveEditableElement, + shouldSkipInlineEdit, +} from './handlers/editable_handlers.js'; +import { + closeModal, + openAboutModal, + openFolderPicker, + updateCurrentCompanySelection, +} from './handlers/configuration_handlers.js'; +import { + deleteItem, + dropItem, + duplicateItem, + handleNewItemClick, +} from './handlers/table_handlers.js'; +import { + addProductToDevis, + showProductSelect, + updateSelectedProduct, +} from './handlers/product_handlers.js'; +import { + updateDateInput, + updateEditableSelect, + updateLinkedListSelection, +} from './handlers/select_handlers.js'; + +let lastKeyEventTime = 0; + +const HOVERABLE_CLASSES = ["editable", "loadSelect", "selectable"]; + +function registerMainListeners() { + document.body.addEventListener('click', handleBodyClick); + document.body.addEventListener('dblclick', handleBodyDoubleClick); + document.body.addEventListener('change', handleBodyChange); + document.body.addEventListener('keydown', handleBodyKeydown); + document.body.addEventListener('focusout', handleBodyFocusout); + document.body.addEventListener('mouseover', handleBodyMouseover); +} + +function handleBodyClick(event) { + const target = event.target; + + if (target && target.id === 'about') { + openAboutModal(); + } + + if (target && target.id === 'theFolder') { + openFolderPicker(); + } + + handleEditableOrCreationClick(event); + + if (target.classList.contains('menu')) { + const menu = document.getElementById('menu-' + target.dataset.menu); + menu.classList.toggle('open'); + } + + if (target.classList.contains('modalClose')) { + closeModal(target); + } + + if (target.classList.contains('duplicateItem')) { + duplicateItem(target); + } + + if (target.classList.contains('drop_down')) { + dropItem(target, 'down'); + } + + if (target.classList.contains('drop_up')) { + dropItem(target, 'up'); + } + + if (target.classList.contains('deleteItem')) { + deleteItem(target); + } + + if (target.id === 'devisAdd') { + addProductToDevis(); + } +} + +function handleEditableOrCreationClick(event) { + const target = event.target; + + if (shouldSkipInlineEdit(target)) { return; } - var targetClass = e.target.className; + if (isInlineEditable(target)) { + enableInlineEdit(target); + return; + } + + if (target.classList.contains("loadSelect_listclient")) { + Client.loadClientList_cid(event); + return; + } - if (targetClass.includes("editableNumber") || targetClass.includes("editableNumeric")) { + if (target.classList.contains("loadSelect_listdevis")) { + Devis.loadDevisList_dnum(event); + return; + } - const formatAsCurrency = - e.target.dataset.column !== "quantite"; + handleNewItemClick(target); +} - updateNumerical(e.target, formatAsCurrency); +function handleBodyDoubleClick(event) { + if (event.target.classList.contains('selectable')) { + showProductSelect(event.target); + } +} - } else if ( - targetClass.includes("editableSelect") || - targetClass.includes("editableConfiguration") || - targetClass.includes("editableConfigurationSelect") - ) { - } else if (targetClass.includes("editable")) { +function handleBodyChange(event) { + const target = event.target; - updateEditable(e.target); + if (target.classList.contains('listClient') || target.classList.contains('listDevis')) { + updateLinkedListSelection(target); } -}); - - - document.body.addEventListener('mouseover', function(event) { - if(event.target.classList.contains("editable") || event.target.classList.contains("loadSelect") || event.target.classList.contains("selectable")){ - applyMouseOverStyles(event.target); - } - }); - - function applyMouseOverStyles(element) { - element.style.fontWeight = "bold"; - element.addEventListener('mouseout', function(e) { - e.target.style.border = null; - e.target.style.padding = null; - e.target.style.fontWeight = null; - e.target.style.borderRadius = null; - }); + + if (target.classList.contains('inputDate')) { + updateDateInput(target); } - function reloadDataTable(modifier) { - var dt = new DataTable('.tabledt'); - if (modifier === "getProduitsById") { getProduitsById(); } - if (modifier === "client") { Client.loadClientDT(dt); } - if (modifier === "devis") { Devis.loadDevisDT(dt); } - if (modifier === "facture") { Facture.loadFactureDT(dt); } - if (modifier === "produit") { Produit.loadProduitDT(dt); } + if (target.id === 'listProduit' || target.id === 'listDevis') { + updateSelectedProduct(event); } - async function waitforUpdateProduits(event, table, column, val, id){ + if (target.classList.contains('editableSelect')) { + updateEditableSelect(target); + } - var id = event.target.options[event.target.selectedIndex].dataset.id; - var val = event.target.options[event.target.selectedIndex].dataset.val; - var column = event.target.options[event.target.selectedIndex].dataset.column; - var table = event.target.options[event.target.selectedIndex].dataset.table; + if (target.id === "CurrentCompany-select") { + updateCurrentCompanySelection(target); + } +} - await updateDB(table, column, val, id); +function handleBodyKeydown(event) { + if (event.key !== "Enter") { + return; + } - if (event.target.parentNode.className === 'selectableClient_devis') { - getClientByIdDevis(id); - } + lastKeyEventTime = Date.now(); + saveEditableElement(event.target, true); +} - if (event.target.id === 'listProduit') { - getProduitsById(); - } +function handleBodyFocusout(event) { + if (Date.now() - lastKeyEventTime < 100) { + event.preventDefault(); + return; + } - event.target.parentNode.textContent = event.target.value; - event.target.parentNode.dataset.val = id; + saveEditableElement(event.target); +} + +function handleBodyMouseover(event) { + if (HOVERABLE_CLASSES.some(className => event.target.classList.contains(className))) { + applyMouseOverStyles(event.target); } -}); \ No newline at end of file +} + +document.addEventListener('DOMContentLoaded', registerMainListeners); diff --git a/webpack.js b/webpack.js index c0c90900c..dcd3b644c 100755 --- a/webpack.js +++ b/webpack.js @@ -31,12 +31,6 @@ module.exports = new webpack.DefinePlugin({ 'process.platform': JSON.stringify('browser') // or 'win32' if you need to simulate Windows }), - new webpack.ProvidePlugin({ - $: 'jquery', - jQuery: 'jquery', - "window.jQuery": "jquery", - jquery: 'jquery' - }), ], resolve: { fallback: {