From 44847558f780eb767fdb909c29eb7b02b2fbf667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ste=CC=A8pien=CC=81?= Date: Mon, 23 Oct 2023 01:04:36 +0200 Subject: [PATCH 1/8] checkout jsdocs --- .../theme/core/checkout/checkoutController.js | 29 ++++++---------- .../handler/address/editAddressHandler.js | 6 ++-- .../address/showAddressErrorMessageHandler.js | 4 ++- .../delivery/changeDeliveryMethodHandler.js | 6 ++-- .../delivery/editDeliveryStepHandler.js | 6 ++-- .../handler/payment/confirmOrderHandler.js | 8 +++++ .../payment/orderConfirmationErrorsHandler.js | 8 +++-- .../payment/toggleOrderButtonStateHandler.js | 6 ++++ .../payment/togglePaymentOptionsHandler.js | 6 ++++ .../process/checkoutFormSubmitHandler.js | 7 ++-- .../process/checkoutStepChangeHandler.js | 7 ++-- _dev/js/theme/core/checkout/index.js | 15 ++++++++- .../request/checkCartStillOrderableRequest.js | 17 ++++++---- .../request/selectDeliveryMethodRequest.js | 25 ++++++++------ .../checkout/utils/areConditionsAccepted.js | 33 +++++++++++++++++-- .../core/checkout/utils/canProceedOrder.js | 21 ++++++++++-- .../utils/collapseAllPaymentOptions.js | 22 ++++++++++++- .../core/checkout/utils/getEditAddress.js | 6 ++-- .../utils/getSelectedPaymentOption.js | 6 ++-- .../checkout/utils/refreshCheckoutPage.js | 6 ++-- .../switchConfirmAddressesButtonState.js | 9 ++--- .../utils/switchEditAddressButtonColor.js | 13 ++++---- .../toggleOrderConfirmationButtonState.js | 9 ++--- 23 files changed, 200 insertions(+), 75 deletions(-) diff --git a/_dev/js/theme/core/checkout/checkoutController.js b/_dev/js/theme/core/checkout/checkoutController.js index 5be4ff1d..0722249c 100644 --- a/_dev/js/theme/core/checkout/checkoutController.js +++ b/_dev/js/theme/core/checkout/checkoutController.js @@ -1,23 +1,8 @@ -import prestashop from 'prestashop'; -import useEvent from '../../components/event/useEvent'; -import editAddressHandler from './handler/address/editAddressHandler'; -import changeAddressHandler from './handler/address/changeAddressHandler'; -import changeDeliveryMethodHandler from './handler/delivery/changeDeliveryMethodHandler'; -import editDeliveryStepHandler from './handler/delivery/editDeliveryStepHandler'; -import showAddressErrorMessageHandler from './handler/address/showAddressErrorMessageHandler'; -import orderConfirmationErrorsHandler from './handler/payment/orderConfirmationErrorsHandler'; -import toggleOrderButtonStateHandler from './handler/payment/toggleOrderButtonStateHandler'; -import togglePaymentOptionsHandler from './handler/payment/togglePaymentOptionsHandler'; -import confirmOrderHandler from './handler/payment/confirmOrderHandler'; -import checkoutFormSubmitHandler from './handler/process/checkoutFormSubmitHandler'; -import checkoutStepChangeHandler from './handler/process/checkoutStepChangeHandler'; - -const { on } = useEvent(); - /** - * Checkout controller - * @returns {object} return - * @returns {function} return.init initialize checkout controller + * Checkout controller. + * + * @returns {object} The checkout controller object. + * @property {function} init - Initializes the checkout controller. */ const checkoutController = () => { const { @@ -29,6 +14,12 @@ const checkoutController = () => { confirmationSelector, } = prestashop.selectors.checkout; + /** + * Initializes the checkout controller by attaching event handlers. + * + * @function + * @returns {void} + */ const init = () => { on(document, 'click', editAddresses, editAddressHandler); on(document, 'click', deliveryAddressRadios, changeAddressHandler); diff --git a/_dev/js/theme/core/checkout/handler/address/editAddressHandler.js b/_dev/js/theme/core/checkout/handler/address/editAddressHandler.js index 8e219f5c..59fd777d 100644 --- a/_dev/js/theme/core/checkout/handler/address/editAddressHandler.js +++ b/_dev/js/theme/core/checkout/handler/address/editAddressHandler.js @@ -1,8 +1,10 @@ import prestashop from 'prestashop'; /** - * Edit address handler - * @param event {object} - click event + * Handles the click event for editing an address in the Prestashop checkout process. + * + * @function + * @param {object} event - The click event object. */ const editAddressHandler = (event) => { const { diff --git a/_dev/js/theme/core/checkout/handler/address/showAddressErrorMessageHandler.js b/_dev/js/theme/core/checkout/handler/address/showAddressErrorMessageHandler.js index ab34a2ac..12d65f4c 100644 --- a/_dev/js/theme/core/checkout/handler/address/showAddressErrorMessageHandler.js +++ b/_dev/js/theme/core/checkout/handler/address/showAddressErrorMessageHandler.js @@ -6,7 +6,9 @@ import { isElementVisible } from '../../../../utils/DOMHelpers'; import getEditAddress from '../../utils/getEditAddress'; /** - * Show address error message handler + * Handles the display of address error messages in the Prestashop checkout process. + * + * @function * @returns {void} */ const showAddressErrorMessageHandler = () => { diff --git a/_dev/js/theme/core/checkout/handler/delivery/changeDeliveryMethodHandler.js b/_dev/js/theme/core/checkout/handler/delivery/changeDeliveryMethodHandler.js index be17acc4..0e6d2cea 100644 --- a/_dev/js/theme/core/checkout/handler/delivery/changeDeliveryMethodHandler.js +++ b/_dev/js/theme/core/checkout/handler/delivery/changeDeliveryMethodHandler.js @@ -6,8 +6,10 @@ import refreshCheckoutPage from '../../utils/refreshCheckoutPage'; import { each } from '../../../../utils/DOMHelpers'; /** - * Change delivery method handler - * @param event {object} - change event + * Handles the change of delivery method in the Prestashop checkout process. + * + * @function + * @param {object} event - The change event. * @returns {Promise} */ const changeDeliveryMethodHandler = async (event) => { diff --git a/_dev/js/theme/core/checkout/handler/delivery/editDeliveryStepHandler.js b/_dev/js/theme/core/checkout/handler/delivery/editDeliveryStepHandler.js index f1ffe1f3..0998f85b 100644 --- a/_dev/js/theme/core/checkout/handler/delivery/editDeliveryStepHandler.js +++ b/_dev/js/theme/core/checkout/handler/delivery/editDeliveryStepHandler.js @@ -2,8 +2,10 @@ import prestashop from 'prestashop'; import useCheckoutStepsController from '../../components/useCheckoutStepsController'; /** - * Edit delivery step handler - * @param event {object} - click event + * Handles the click event to edit the delivery step in the Prestashop checkout process. + * + * @function + * @param {object} event - The click event. */ const editDeliveryStepHandler = (event) => { event.preventDefault(); diff --git a/_dev/js/theme/core/checkout/handler/payment/confirmOrderHandler.js b/_dev/js/theme/core/checkout/handler/payment/confirmOrderHandler.js index 7b133b40..6a3c77f0 100644 --- a/_dev/js/theme/core/checkout/handler/payment/confirmOrderHandler.js +++ b/_dev/js/theme/core/checkout/handler/payment/confirmOrderHandler.js @@ -13,6 +13,14 @@ const showNativeFormErrors = () => { }); }; +/** + * Handles the click event to confirm the order in the Prestashop checkout process. + * + * @async + * @function + * @param {object} e - The click event. + * @returns {Promise} + */ const confirmOrderHandler = async (e) => { e.preventDefault(); diff --git a/_dev/js/theme/core/checkout/handler/payment/orderConfirmationErrorsHandler.js b/_dev/js/theme/core/checkout/handler/payment/orderConfirmationErrorsHandler.js index 516029f5..9a88324b 100644 --- a/_dev/js/theme/core/checkout/handler/payment/orderConfirmationErrorsHandler.js +++ b/_dev/js/theme/core/checkout/handler/payment/orderConfirmationErrorsHandler.js @@ -1,6 +1,10 @@ /** - * Redirect to cart page if there are errors on order confirmation - * @param event {object} - event object + * Handles errors on order confirmation by redirecting to the cart page if needed. + * + * @function + * @param {object} event - The event object containing the response information. + * @param {object} event.resp - The response object. + * @returns {void} */ const orderConfirmationErrorsHandler = ({ resp }) => { if (resp?.cartUrl !== '') { diff --git a/_dev/js/theme/core/checkout/handler/payment/toggleOrderButtonStateHandler.js b/_dev/js/theme/core/checkout/handler/payment/toggleOrderButtonStateHandler.js index e015bed1..5cd6c560 100644 --- a/_dev/js/theme/core/checkout/handler/payment/toggleOrderButtonStateHandler.js +++ b/_dev/js/theme/core/checkout/handler/payment/toggleOrderButtonStateHandler.js @@ -6,6 +6,12 @@ import { each } from '../../../../utils/DOMHelpers'; const { toggle } = useToggleDisplay(); +/** + * Handles toggling the order button state based on the conditions and emits an event with the updated terms status. + * + * @function + * @returns {void} + */ const toggleOrderButtonStateHandler = () => { const { conditionAlertSelector } = prestashop.selectors.checkout; diff --git a/_dev/js/theme/core/checkout/handler/payment/togglePaymentOptionsHandler.js b/_dev/js/theme/core/checkout/handler/payment/togglePaymentOptionsHandler.js index b9592dd3..17200098 100644 --- a/_dev/js/theme/core/checkout/handler/payment/togglePaymentOptionsHandler.js +++ b/_dev/js/theme/core/checkout/handler/payment/togglePaymentOptionsHandler.js @@ -7,6 +7,12 @@ import { each } from '../../../../utils/DOMHelpers'; const { show } = useToggleDisplay(); +/** + * Handles toggling the visibility of payment options based on the selected payment method, and updates the order button state accordingly. + * + * @function + * @returns {void} + */ const togglePaymentOptionsHandler = () => { const paymentBtnEnabled = canProceedOrder(); diff --git a/_dev/js/theme/core/checkout/handler/process/checkoutFormSubmitHandler.js b/_dev/js/theme/core/checkout/handler/process/checkoutFormSubmitHandler.js index a6db247b..9df23b9e 100644 --- a/_dev/js/theme/core/checkout/handler/process/checkoutFormSubmitHandler.js +++ b/_dev/js/theme/core/checkout/handler/process/checkoutFormSubmitHandler.js @@ -2,8 +2,11 @@ import prestashop from 'prestashop'; import { each } from '../../../../utils/DOMHelpers'; /** - * Checkout form submit handler - * @param event {object} - submit event + * Handles the submission of the checkout form, disables submit buttons, and emits a 'submitCheckoutForm' event. + * + * @function + * @param {object} event - The submit event object. + * @returns {void} */ const checkoutFormSubmitHandler = (event) => { const submitButtons = event.target.querySelectorAll('button[type="submit"]'); diff --git a/_dev/js/theme/core/checkout/handler/process/checkoutStepChangeHandler.js b/_dev/js/theme/core/checkout/handler/process/checkoutStepChangeHandler.js index df3430c7..0240e4ad 100644 --- a/_dev/js/theme/core/checkout/handler/process/checkoutStepChangeHandler.js +++ b/_dev/js/theme/core/checkout/handler/process/checkoutStepChangeHandler.js @@ -2,8 +2,11 @@ import prestashop from 'prestashop'; import useCheckoutStepsController from '../../components/useCheckoutStepsController'; /** - * Checkout step change handler - * @param event {object} - click event + * Handles the change of a checkout step, preventing the default click event, updating the step, and emitting a 'changedCheckoutStep' event. + * + * @function + * @param {object} event - The click event object. + * @returns {void} */ const checkoutStepChangeHandler = (event) => { event.preventDefault(); diff --git a/_dev/js/theme/core/checkout/index.js b/_dev/js/theme/core/checkout/index.js index b8342142..ffa7b897 100644 --- a/_dev/js/theme/core/checkout/index.js +++ b/_dev/js/theme/core/checkout/index.js @@ -5,7 +5,13 @@ import checkoutController from './checkoutController'; prestashop.checkout = prestashop.checkout || {}; -// GLOBAL +/** + * Event handler for checking orderable cart response. + * + * @param {object} resp - Response object. + * @param {object} paymentObject - Payment object. + * @returns {boolean} Returns true if there are errors; otherwise, returns false. + */ prestashop.checkout.onCheckOrderableCartResponse = (resp, paymentObject) => { if (resp.errors === true) { prestashop.emit('orderConfirmationErrors', { @@ -19,6 +25,11 @@ prestashop.checkout.onCheckOrderableCartResponse = (resp, paymentObject) => { return false; }; +/** + * Initializes the checkout process if the page is the checkout page. + * + * @returns {void} + */ const initCheckout = () => { if (prestashop.page.page_name !== 'checkout') { return; @@ -29,6 +40,8 @@ const initCheckout = () => { init(); }; +// Event listener for DOM ready event. DOMReady(() => { + // Initialize the checkout process when the DOM is ready. initCheckout(); }); diff --git a/_dev/js/theme/core/checkout/request/checkCartStillOrderableRequest.js b/_dev/js/theme/core/checkout/request/checkCartStillOrderableRequest.js index 1793f3c2..660644eb 100644 --- a/_dev/js/theme/core/checkout/request/checkCartStillOrderableRequest.js +++ b/_dev/js/theme/core/checkout/request/checkCartStillOrderableRequest.js @@ -2,18 +2,23 @@ import prestashop from 'prestashop'; import useDefaultHttpRequest from '../../../components/http/useDefaultHttpRequest'; /** - * @typedef ServerResponse - * @type {object} - * @property {string} cartUrl - cart page url - * @property {boolean} errors - errors flag (true if errors) + * Represents the server response from a check cart still orderable request. + * @typedef {object} ServerResponse + * @property {string} cartUrl - The URL of the cart page. + * @property {boolean} errors - A flag indicating whether there are errors (true if there are errors). */ /** - * Check cart still orderable request + * Provides a check cart still orderable request with a method to get the request promise. + * + * @function * @returns {{getRequest: (function(): Promise)}} */ const checkCartStillOrderableRequest = () => { - // payload not typed because it isn't needed + /** + * Payload not typed because it isn't needed. + * @type {object} + */ const payloadToSend = { ajax: 1, action: 'checkCartStillOrderable', diff --git a/_dev/js/theme/core/checkout/request/selectDeliveryMethodRequest.js b/_dev/js/theme/core/checkout/request/selectDeliveryMethodRequest.js index 1927f09e..8198eed5 100644 --- a/_dev/js/theme/core/checkout/request/selectDeliveryMethodRequest.js +++ b/_dev/js/theme/core/checkout/request/selectDeliveryMethodRequest.js @@ -1,18 +1,20 @@ import useDefaultHttpRequest from '../../../components/http/useDefaultHttpRequest'; /** - * @typedef ServerResponse - * @type {object} - * @property {string} preview - checkout summary html content + * Represents the server response from a select delivery method request. + * @typedef {object} ServerResponse + * @property {string} preview - The HTML content of the checkout summary. */ /** - * Select delivery method request - * @param url {string} - checkout url to send request - * @param payload {object} - request payload - * @param payload.delivery_option[id] {string} - delivery option id with id_address_delivery - * @param payload.ajax {number} - optional - * @param payload.action {string} - optional + * Provides a select delivery method request with a method to get the request promise. + * + * @function + * @param {string} url - The checkout URL to send the request. + * @param {object} payload - The request payload. + * @param {object} payload.delivery_option[id] - The delivery option ID with id_address_delivery. + * @param {number} payload.ajax - An optional parameter. + * @param {string} payload.action - An optional parameter. * @example * const payload = { * 'delivery_option[1]': '2,', @@ -29,7 +31,10 @@ import useDefaultHttpRequest from '../../../components/http/useDefaultHttpReques * @returns {{getRequest: (function(): Promise)}} */ const selectDeliveryMethodRequest = (url, payload) => { - // payload not typed because delivery option parameter is dynamic + /** + * Payload not typed because the delivery option parameter is dynamic. + * @type {object} + */ const payloadToSend = { ajax: 1, action: 'selectDeliveryOption', diff --git a/_dev/js/theme/core/checkout/utils/areConditionsAccepted.js b/_dev/js/theme/core/checkout/utils/areConditionsAccepted.js index a50d9cff..df6d2961 100644 --- a/_dev/js/theme/core/checkout/utils/areConditionsAccepted.js +++ b/_dev/js/theme/core/checkout/utils/areConditionsAccepted.js @@ -2,14 +2,42 @@ import prestashop from 'prestashop'; import { each } from '../../../utils/DOMHelpers'; /** - * Check if all conditions are accepted - * @returns {boolean} true if all conditions are accepted or false otherwise + * Checks if all conditions are accepted. + * + * @function + * @returns {boolean} True if all conditions are accepted, or false otherwise. */ const areConditionsAccepted = () => { + /** + * The flag indicating whether all conditions are accepted. + * @type {boolean} + */ let accepted = true; + + /** + * The selector for conditions. + * @type {string} + */ const { conditionsSelector } = prestashop.selectors.checkout; + + /** + * The list of conditions. + * @type {NodeList} + */ const conditions = document.querySelectorAll(`${conditionsSelector} input[type="checkbox"]`); + /** + * Iterates through each condition and checks if it is accepted. + * + * @callback eachCallback + * @param {HTMLInputElement} condition - The current condition. + * @returns {void} + */ + + /** + * The helper function for iterating through each condition. + * @type {eachCallback} + */ each(conditions, (condition) => { if (!condition.checked) { accepted = false; @@ -20,3 +48,4 @@ const areConditionsAccepted = () => { }; export default areConditionsAccepted; + diff --git a/_dev/js/theme/core/checkout/utils/canProceedOrder.js b/_dev/js/theme/core/checkout/utils/canProceedOrder.js index b213a90d..5e38b06b 100644 --- a/_dev/js/theme/core/checkout/utils/canProceedOrder.js +++ b/_dev/js/theme/core/checkout/utils/canProceedOrder.js @@ -2,13 +2,28 @@ import areConditionsAccepted from './areConditionsAccepted'; import getSelectedPaymentOption from './getSelectedPaymentOption'; /** - * Check if order can be proceeded - * @returns {boolean} true if order can be proceeded or false otherwise + * Checks if the order can be proceeded. + * + * @function + * @returns {boolean} True if the order can be proceeded, or false otherwise. */ const canProceedOrder = () => { + /** + * The flag indicating whether the conditions are accepted. + * @type {boolean} + */ let proceed = areConditionsAccepted(); - if (!getSelectedPaymentOption()) { + /** + * The selected payment option. + * @type {HTMLElement | null} + */ + const selectedPaymentOption = getSelectedPaymentOption(); + + /** + * Checks if a payment option is selected. + */ + if (!selectedPaymentOption) { proceed = false; } diff --git a/_dev/js/theme/core/checkout/utils/collapseAllPaymentOptions.js b/_dev/js/theme/core/checkout/utils/collapseAllPaymentOptions.js index b11e71ba..76a5ea78 100644 --- a/_dev/js/theme/core/checkout/utils/collapseAllPaymentOptions.js +++ b/_dev/js/theme/core/checkout/utils/collapseAllPaymentOptions.js @@ -3,11 +3,31 @@ import { each } from '../../../utils/DOMHelpers'; import useToggleDisplay from '../../../components/display/useToggleDisplay'; /** - * Collapse all payment options additional information blocks and options form + * Collapses all payment options' additional information blocks and options forms. + * + * @function + * @returns {void} */ const collapseAllPaymentOptions = () => { + /** + * The selectors related to payment options. + * @type {object} + * @property {string} additionalInformatonSelector - Selector for additional information blocks. + * @property {string} optionsForm - Selector for options forms. + */ const { additionalInformatonSelector, optionsForm } = prestashop.selectors.checkout; + + /** + * All payment-related blocks to be collapsed. + * @type {NodeListOf} + */ const paymentRelatedBlocks = document.querySelectorAll(`${additionalInformatonSelector}, ${optionsForm}`); + + /** + * The toggle display utility. + * @type {object} + * @property {function} hide - Function to hide an element. + */ const { hide } = useToggleDisplay(); each(paymentRelatedBlocks, hide); diff --git a/_dev/js/theme/core/checkout/utils/getEditAddress.js b/_dev/js/theme/core/checkout/utils/getEditAddress.js index 2fce3e2e..853ab008 100644 --- a/_dev/js/theme/core/checkout/utils/getEditAddress.js +++ b/_dev/js/theme/core/checkout/utils/getEditAddress.js @@ -1,6 +1,8 @@ /** - * Check if browser url contains editAddress parameter - * @returns {string | null} editAddress parameter value or null if not found + * Checks if the browser URL contains the 'editAddress' parameter. + * + * @function + * @returns {string | null} The value of the 'editAddress' parameter, or null if not found. */ const getEditAddress = () => { const urlParams = new URLSearchParams(window.location.search); diff --git a/_dev/js/theme/core/checkout/utils/getSelectedPaymentOption.js b/_dev/js/theme/core/checkout/utils/getSelectedPaymentOption.js index 7ab0144f..715f21e0 100644 --- a/_dev/js/theme/core/checkout/utils/getSelectedPaymentOption.js +++ b/_dev/js/theme/core/checkout/utils/getSelectedPaymentOption.js @@ -1,6 +1,8 @@ /** - * Get selected payment option - * @returns {HTMLElement|null} Selected payment option HTMLElement or null if not found + * Gets the selected payment option. + * + * @function + * @returns {HTMLElement | null} The selected payment option HTMLElement, or null if not found. */ const getSelectedPaymentOption = () => document.querySelector('input[name="payment-option"]:checked'); diff --git a/_dev/js/theme/core/checkout/utils/refreshCheckoutPage.js b/_dev/js/theme/core/checkout/utils/refreshCheckoutPage.js index 94eec1a1..cedfc3d7 100644 --- a/_dev/js/theme/core/checkout/utils/refreshCheckoutPage.js +++ b/_dev/js/theme/core/checkout/utils/refreshCheckoutPage.js @@ -1,12 +1,14 @@ /** - * Refresh checkout page with updated transaction parameter + * Refreshes the checkout page with an updated transaction parameter. + * + * @function + * @returns {void} */ const refreshCheckoutPage = () => { const urlParams = new URLSearchParams(window.location.search); if (urlParams.has('updatedTransaction')) { window.location.reload(); - return; } diff --git a/_dev/js/theme/core/checkout/utils/switchConfirmAddressesButtonState.js b/_dev/js/theme/core/checkout/utils/switchConfirmAddressesButtonState.js index 2f115664..63667e5d 100644 --- a/_dev/js/theme/core/checkout/utils/switchConfirmAddressesButtonState.js +++ b/_dev/js/theme/core/checkout/utils/switchConfirmAddressesButtonState.js @@ -1,8 +1,9 @@ -import { each } from '../../../utils/DOMHelpers'; - /** - * Switch confirm addresses button state - * @param enable {boolean} - false if button should be disabled + * Switches the state of the confirm addresses button. + * + * @function + * @param {boolean} enable - `false` if the button should be disabled. + * @returns {void} */ const switchConfirmAddressesButtonState = (enable) => { each('button[name=confirm-addresses]', (button) => { diff --git a/_dev/js/theme/core/checkout/utils/switchEditAddressButtonColor.js b/_dev/js/theme/core/checkout/utils/switchEditAddressButtonColor.js index c41eb6a6..5e8eb3c6 100644 --- a/_dev/js/theme/core/checkout/utils/switchEditAddressButtonColor.js +++ b/_dev/js/theme/core/checkout/utils/switchEditAddressButtonColor.js @@ -1,10 +1,11 @@ -import { each } from '../../../utils/DOMHelpers'; - /** - * Change the color of the edit button for the wrong address - * @param {boolean} enabled - true if button should be dangered or false otherwise - * @param {number} id - address id - * @param {string} type - address type (delivery or invoice) + * Changes the color of the edit button for the wrong address. + * + * @function + * @param {boolean} enabled - `true` if the button should be dangered, `false` otherwise. + * @param {number} id - Address ID. + * @param {string} type - Address type (`delivery` or `invoice`). + * @returns {void} */ const switchEditAddressButtonColor = ( enabled, diff --git a/_dev/js/theme/core/checkout/utils/toggleOrderConfirmationButtonState.js b/_dev/js/theme/core/checkout/utils/toggleOrderConfirmationButtonState.js index 8c55914c..d97740f4 100644 --- a/_dev/js/theme/core/checkout/utils/toggleOrderConfirmationButtonState.js +++ b/_dev/js/theme/core/checkout/utils/toggleOrderConfirmationButtonState.js @@ -1,8 +1,9 @@ -import prestashop from 'prestashop'; - /** - * Toggle order confirmation button state - * @param active {boolean} - false if button should be disabled + * Toggles the order confirmation button state. + * + * @function + * @param {boolean} active - `false` if the button should be disabled, `true` otherwise. + * @returns {void} */ const toggleOrderConfirmationButtonState = (active = false) => { const { confirmationSelector } = prestashop.selectors.checkout; From 1eb4464254c8db572c6f6add9c2fe63de18c7f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ste=CC=A8pien=CC=81?= Date: Mon, 23 Oct 2023 01:07:22 +0200 Subject: [PATCH 2/8] utils code jsdocs --- _dev/js/theme/core/display/psShowHide.js | 3 +++ _dev/js/theme/core/email/emailIdn.js | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/_dev/js/theme/core/display/psShowHide.js b/_dev/js/theme/core/display/psShowHide.js index 56ad30cd..6ea0834b 100644 --- a/_dev/js/theme/core/display/psShowHide.js +++ b/_dev/js/theme/core/display/psShowHide.js @@ -1,5 +1,8 @@ import useToggleDisplay from '@js/theme/components/display/useToggleDisplay'; +/** + * Toggle the display of elements with the 'ps-shown-by-js' and 'ps-hidden-by-js' classes. + */ const psShowHide = () => { const { show, hide } = useToggleDisplay(); diff --git a/_dev/js/theme/core/email/emailIdn.js b/_dev/js/theme/core/email/emailIdn.js index e364835a..5e2341da 100644 --- a/_dev/js/theme/core/email/emailIdn.js +++ b/_dev/js/theme/core/email/emailIdn.js @@ -1,20 +1,32 @@ import punycode from 'punycode'; +/** + * Initializes the conversion of Internationalized Domain Names (IDN) in email fields. + * @param {string} selector - The CSS selector for the email fields. + */ const initEmailIdn = (selector) => { - const emailFields = document.querySelectorAll(selector); + /** + * Handles the conversion of IDN in the provided email field. + * @param {HTMLInputElement} field - The email input field. + */ const handleField = (field) => { + // Check if the email field is not valid if (!field.checkValidity()) { const parts = field.value.split('@'); + // Convert the local part of the email address to ASCII if needed if (punycode.toASCII(parts[0]) === parts[0]) { field.value = punycode.toASCII(field.value); } } }; - emailFields.forEach((field) => { + // Iterate through each email field + document.querySelectorAll(selector).forEach((field) => { + // Initial handling of the email field handleField(field); + // Attach blur event listener to re-handle the email field on blur field.addEventListener('blur', () => { handleField(field); }); @@ -22,3 +34,4 @@ const initEmailIdn = (selector) => { }; export default initEmailIdn; + From 75fb76a6ff339756de8a4656d8940558fcf7df2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ste=CC=A8pien=CC=81?= Date: Mon, 23 Oct 2023 01:07:29 +0200 Subject: [PATCH 3/8] listing jsdocs --- .../listing/handler/updateFacetsHandler.js | 19 +++++- .../theme/core/listing/listingController.js | 8 +++ .../request/updateListingFacetsRequest.js | 65 ++++++++++--------- 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/_dev/js/theme/core/listing/handler/updateFacetsHandler.js b/_dev/js/theme/core/listing/handler/updateFacetsHandler.js index bc665b3f..7fb9a4db 100644 --- a/_dev/js/theme/core/listing/handler/updateFacetsHandler.js +++ b/_dev/js/theme/core/listing/handler/updateFacetsHandler.js @@ -2,9 +2,9 @@ import prestashop from 'prestashop'; import updateListingFacetsRequest from '../request/updateListingFacetsRequest'; /** - * Build new facets url - add from-xhr param - * @param {string} url - current url - * @returns {string} - new url with from-xhr param + * Builds a new facets URL by adding the 'from-xhr' parameter. + * @param {string} url - The current URL. + * @returns {string} - The new URL with the 'from-xhr' parameter. */ const buildNewFacetsUrl = (url) => { const urlObject = new URL(url); @@ -14,16 +14,29 @@ const buildNewFacetsUrl = (url) => { return `${urlObject.origin}${urlObject.pathname}?${params.toString()}`; }; +/** + * Handles the update of facets by making a request to the updated URL. + * @param {string} url - The current URL. + * @returns {Promise} - A promise resolving to void. + */ const updateFacetsHandler = async (url) => { + // Build a new URL with the 'from-xhr' parameter const newUrl = buildNewFacetsUrl(url); + + // Get the request function for updating facets const { getRequest } = updateListingFacetsRequest(newUrl); try { + // Make the request and get the data const data = await getRequest(); + // Emit an event to update the product list prestashop.emit('updateProductList', data); + + // Update the browser history with the new URL window.history.pushState(data, document.title, data.current_url); } catch (error) { + // Handle errors by emitting an error event prestashop.emit('handleError', { eventType: 'updateFacets', resp: {}, diff --git a/_dev/js/theme/core/listing/listingController.js b/_dev/js/theme/core/listing/listingController.js index 15f2fe53..137cfc41 100644 --- a/_dev/js/theme/core/listing/listingController.js +++ b/_dev/js/theme/core/listing/listingController.js @@ -1,7 +1,15 @@ import prestashop from 'prestashop'; import updateFacetsHandler from './handler/updateFacetsHandler'; +/** + * Listing controller for handling facet updates. + * @returns {Object} An object with an initialization function. + * @returns {Function} init - Initializes the listing controller. + */ const listingController = () => { + /** + * Initializes the listing controller by subscribing to the 'updateFacets' event. + */ const init = () => { prestashop.on('updateFacets', updateFacetsHandler); }; diff --git a/_dev/js/theme/core/listing/request/updateListingFacetsRequest.js b/_dev/js/theme/core/listing/request/updateListingFacetsRequest.js index a08227ea..7968df47 100644 --- a/_dev/js/theme/core/listing/request/updateListingFacetsRequest.js +++ b/_dev/js/theme/core/listing/request/updateListingFacetsRequest.js @@ -5,62 +5,69 @@ import GenericHttpRequestError from '../../../components/http/error/GenericHttpR const { dispatch, abortAll } = useHttpController(); /** - * @typedef ServerResponse - * @type {object} - * @property {string} current_url - new url - * @property {boolean} js_enabled - is js enabled - * @property {string} label - listing label - * @property {object} pagination - pagination object - * @property {number} pagination.current_page - pagination current page - * @property {number} pagination.items_shown_from - pagination items shown from - * @property {number} pagination.items_shown_to - pagination items shown to - * @property {array} pagination.pages - pagination pages array - * @property {object[]} products - array of front representations of products - * @property {string} rendered_active_filters - active filters html content - * @property {string} rendered_facets - facets html content - * @property {string} rendered_products - listing products html content - * @property {string} rendered_products_bottom - listing products bottom html content - * @property {string} rendered_products_header - listing products header html content - * @property {string} rendered_products_top - listing products top html content - * @property {object} result - result empty object - * @property {object[]} sort_orders - available sort orders - * @property {string} sort_selected - selected sort order + * @typedef {Object} ServerResponse + * @property {string} current_url - The new URL. + * @property {boolean} js_enabled - Indicates whether JavaScript is enabled. + * @property {string} label - The listing label. + * @property {Object} pagination - Pagination information. + * @property {number} pagination.current_page - The current page in pagination. + * @property {number} pagination.items_shown_from - The number of items shown from. + * @property {number} pagination.items_shown_to - The number of items shown to. + * @property {number[]} pagination.pages - Array of pagination pages. + * @property {Object[]} products - Array of front representations of products. + * @property {string} rendered_active_filters - HTML content for active filters. + * @property {string} rendered_facets - HTML content for facets. + * @property {string} rendered_products - HTML content for listing products. + * @property {string} rendered_products_bottom - HTML content for listing products bottom. + * @property {string} rendered_products_header - HTML content for listing products header. + * @property {string} rendered_products_top - HTML content for listing products top. + * @property {Object} result - Empty result object. + * @property {Object[]} sort_orders - Available sort orders. + * @property {string} sort_selected - The selected sort order. */ /** - * Update listing facets request - * @param url {string} - new url with from-xhr param + * Generates an update listing facets request. + * @param {string} url - The new URL with the 'from-xhr' parameter. * @example - * const { getRequest } = updateListingFacetsRequest(url); + * const { getRequest } = updateListingFacetsRequest(url); * - * try { - * const resp = await getRequest(); - * } catch (error) { - * console.error(error); - * } + * try { + * const resp = await getRequest(); + * } catch (error) { + * console.error(error); + * } * @returns {{getRequest: (function(): Promise)}} */ const updateListingFacetsRequest = (url) => { + // Create an HTTP request with the specified URL and headers const { request, controller } = useHttpRequest(url, { headers: { accept: 'application/json', }, }); + /** + * Sends an asynchronous GET request to update listing facets. + * @returns {Promise} - A promise resolving to the server response. + */ const getRequest = () => new Promise((resolve, reject) => { + // Abort all previous requests abortAll(); + // Dispatch the request and use the controller dispatch(request, controller)(() => request .get() .json((resp) => { resolve(resp); }) .catch((e) => { - // IF ABORTED + // Handle abort (DOMException) if (e instanceof DOMException) { return; } + // Reject with a generic HTTP request error reject(new GenericHttpRequestError('Error while sending request')); })); }); From fd4169a43f614cbbfb88586fecf366a79ad53172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ste=CC=A8pien=CC=81?= Date: Mon, 23 Oct 2023 01:25:16 +0200 Subject: [PATCH 4/8] checkout fixes --- .../js/theme/core/checkout/checkoutController.js | 16 ++++++++++++++++ .../core/checkout/utils/areConditionsAccepted.js | 1 - .../utils/switchConfirmAddressesButtonState.js | 2 ++ .../utils/switchEditAddressButtonColor.js | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/_dev/js/theme/core/checkout/checkoutController.js b/_dev/js/theme/core/checkout/checkoutController.js index 0722249c..050ed0b1 100644 --- a/_dev/js/theme/core/checkout/checkoutController.js +++ b/_dev/js/theme/core/checkout/checkoutController.js @@ -1,3 +1,19 @@ +import prestashop from 'prestashop'; +import useEvent from '../../components/event/useEvent'; +import editAddressHandler from './handler/address/editAddressHandler'; +import changeAddressHandler from './handler/address/changeAddressHandler'; +import changeDeliveryMethodHandler from './handler/delivery/changeDeliveryMethodHandler'; +import editDeliveryStepHandler from './handler/delivery/editDeliveryStepHandler'; +import showAddressErrorMessageHandler from './handler/address/showAddressErrorMessageHandler'; +import orderConfirmationErrorsHandler from './handler/payment/orderConfirmationErrorsHandler'; +import toggleOrderButtonStateHandler from './handler/payment/toggleOrderButtonStateHandler'; +import togglePaymentOptionsHandler from './handler/payment/togglePaymentOptionsHandler'; +import confirmOrderHandler from './handler/payment/confirmOrderHandler'; +import checkoutFormSubmitHandler from './handler/process/checkoutFormSubmitHandler'; +import checkoutStepChangeHandler from './handler/process/checkoutStepChangeHandler'; + +const { on } = useEvent(); + /** * Checkout controller. * diff --git a/_dev/js/theme/core/checkout/utils/areConditionsAccepted.js b/_dev/js/theme/core/checkout/utils/areConditionsAccepted.js index df6d2961..93d037cb 100644 --- a/_dev/js/theme/core/checkout/utils/areConditionsAccepted.js +++ b/_dev/js/theme/core/checkout/utils/areConditionsAccepted.js @@ -48,4 +48,3 @@ const areConditionsAccepted = () => { }; export default areConditionsAccepted; - diff --git a/_dev/js/theme/core/checkout/utils/switchConfirmAddressesButtonState.js b/_dev/js/theme/core/checkout/utils/switchConfirmAddressesButtonState.js index 63667e5d..3869f540 100644 --- a/_dev/js/theme/core/checkout/utils/switchConfirmAddressesButtonState.js +++ b/_dev/js/theme/core/checkout/utils/switchConfirmAddressesButtonState.js @@ -1,3 +1,5 @@ +import { each } from '../../../utils/DOMHelpers'; + /** * Switches the state of the confirm addresses button. * diff --git a/_dev/js/theme/core/checkout/utils/switchEditAddressButtonColor.js b/_dev/js/theme/core/checkout/utils/switchEditAddressButtonColor.js index 5e8eb3c6..9e2a9cd2 100644 --- a/_dev/js/theme/core/checkout/utils/switchEditAddressButtonColor.js +++ b/_dev/js/theme/core/checkout/utils/switchEditAddressButtonColor.js @@ -1,3 +1,5 @@ +import { each } from '../../../utils/DOMHelpers'; + /** * Changes the color of the edit button for the wrong address. * From b8761b38e7ef651113361461bd8a759bc95f4a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ste=CC=A8pien=CC=81?= Date: Mon, 23 Oct 2023 01:25:26 +0200 Subject: [PATCH 5/8] product jsdocs --- .../product/productFormChangeHandler.js | 14 ++- .../handler/product/productPopStateHandler.js | 41 ++++++++- .../product/productUpdateErrorHandler.js | 7 +- .../updateProductCustomizationHandler.js | 15 ++-- .../updateProductDOMElementsHandler.js | 55 ++++++------ .../handler/product/updateProductHandler.js | 9 +- .../product/updateQuantityInputHandler.js | 14 ++- .../handler/product/updatedProductHandler.js | 19 ++-- .../quickView/quickViewClickHandler.js | 7 +- .../handler/quickView/quickViewHandler.js | 9 +- .../persister/productFormDataPersister.js | 15 ++-- .../theme/core/product/productController.js | 22 +++-- .../request/product/updateProductRequest.js | 90 ++++++++++--------- .../request/quickView/quickViewRequest.js | 49 +++++----- .../core/product/store/productStateStore.js | 63 +++++++++---- .../core/product/utils/isProductPreview.js | 7 +- .../core/product/utils/isQuickViewOpen.js | 6 +- .../utils/productEventContextSelector.js | 6 ++ 18 files changed, 280 insertions(+), 168 deletions(-) diff --git a/_dev/js/theme/core/product/handler/product/productFormChangeHandler.js b/_dev/js/theme/core/product/handler/product/productFormChangeHandler.js index d68041fe..57e2fa4b 100644 --- a/_dev/js/theme/core/product/handler/product/productFormChangeHandler.js +++ b/_dev/js/theme/core/product/handler/product/productFormChangeHandler.js @@ -4,13 +4,21 @@ import productStateStore from '../../store/productStateStore'; const { setFormChanged } = productStateStore(); /** - * Sets the form changed state - * Side effect: emits 'updateProduct' event - * @param event {Event} + * Handles changes in the product form. + * Sets the form changed state and emits the 'updateProduct' event. + * @param {Event} event - The change event. + * @returns {void} + * @sideeffect Modifies the form changed state and emits an event. */ const productFormChangeHandler = (event) => { + /** + * Sets the form changed state to true. + */ setFormChanged(true); + /** + * Emits the 'updateProduct' event with specific event details. + */ prestashop.emit('updateProduct', { eventType: 'updatedProductCombination', event, diff --git a/_dev/js/theme/core/product/handler/product/productPopStateHandler.js b/_dev/js/theme/core/product/handler/product/productPopStateHandler.js index 77182d60..6601db93 100644 --- a/_dev/js/theme/core/product/handler/product/productPopStateHandler.js +++ b/_dev/js/theme/core/product/handler/product/productPopStateHandler.js @@ -8,32 +8,67 @@ const { setOnPopState, isFormChanged } = productStateStore(); const { get } = productFormDataPersister(); /** - * Handle popstate event for product page - * Side effect: emits 'updateProduct' event, sets popState in productStateStore - * @param {Event} event + * Handles the popstate event for the product page. + * Side effect: Emits the 'updateProduct' event and sets popState in productStateStore. + * @param {Event} event - The popstate event. + * @returns {void} + * @sideeffect Modifies the popState in productStateStore and emits an event. */ const productPopStateHandler = (event) => { + /** + * Retrieves the context element for the product event. + */ const contextElement = document.querySelector(productEventContextSelector()); + + /** + * Sets the popState in productStateStore to true. + */ setOnPopState(true); + /** + * Retrieves the form data from the popstate event or from the productFormDataPersister. + */ const formData = event?.state?.form || get(); + /** + * Checks if the form data is empty and the form is not changed. If so, returns early. + */ if ((!formData || formData?.length === 0) && !isFormChanged()) { return; } + /** + * Retrieves the product form element from the context element. + */ const form = contextElement.querySelector(`${prestashop.selectors.product.actions} .js-product-form`); + /** + * Handles the state of form elements based on the retrieved form data. + * @param {object} data - Form data object. + * @returns {void} + */ const handleFormElementState = (data) => { + /** + * Retrieves the form element by name. + */ const element = form.querySelector(`[name="${data.name}"]`); + /** + * If the element exists, sets its value to the corresponding value from the form data. + */ if (element) { element.value = data.value; } }; + /** + * Iterates over the form data and handles the state of each form element. + */ formData.forEach(handleFormElementState); + /** + * Emits the 'updateProduct' event with specific event details. + */ prestashop.emit('updateProduct', { eventType: 'updatedProductCombination', event, diff --git a/_dev/js/theme/core/product/handler/product/productUpdateErrorHandler.js b/_dev/js/theme/core/product/handler/product/productUpdateErrorHandler.js index e09b1b46..e8eec9e3 100644 --- a/_dev/js/theme/core/product/handler/product/productUpdateErrorHandler.js +++ b/_dev/js/theme/core/product/handler/product/productUpdateErrorHandler.js @@ -3,8 +3,11 @@ import useAlertToast from '../../../../components/useAlertToast'; const { danger } = useAlertToast(); /** - * Handle product update error - * @param event + * Handles product update errors by displaying a danger toast with the error message. + * + * @param {object} event - The event object containing the error message. + * @returns {void} + * @sidEffect Displays a danger toast with the error message. */ const productUpdateErrorHandler = (event) => { if (event?.errorMessage) { diff --git a/_dev/js/theme/core/product/handler/product/updateProductCustomizationHandler.js b/_dev/js/theme/core/product/handler/product/updateProductCustomizationHandler.js index ddd6c71c..8c19d465 100644 --- a/_dev/js/theme/core/product/handler/product/updateProductCustomizationHandler.js +++ b/_dev/js/theme/core/product/handler/product/updateProductCustomizationHandler.js @@ -2,18 +2,19 @@ import prestashop from 'prestashop'; import productEventContextSelector from '../../utils/productEventContextSelector'; /** - * Update product customization input value - * Side effect: update product customization input value - * @param eventType {string} - event type - * @param eventData {object} - event data - * @param eventData.id_customization {number} - customization id - * @return {void} + * Handles the update of the product customization input value based on the provided event type and data. + * + * @param {string} eventType - Type of the event. + * @param {object} eventData - Data associated with the event. + * @param {number} eventData.id_customization - Customization ID. + * @returns {void} + * @sideEffect Updates the product customization input value. */ const updateProductCustomizationHandler = (eventType, { id_customization: idCustomization }) => { const contextElement = document.querySelector(productEventContextSelector()); const customizationIdInput = contextElement.querySelector(prestashop.selectors.cart.productCustomizationId); - // refill customizationId input value when updating quantity or combination + // Refill customizationId input value when updating quantity or combination if ( (eventType === 'updatedProductQuantity' || eventType === 'updatedProductCombination') && idCustomization diff --git a/_dev/js/theme/core/product/handler/product/updateProductDOMElementsHandler.js b/_dev/js/theme/core/product/handler/product/updateProductDOMElementsHandler.js index b8221c1d..46bd8c80 100644 --- a/_dev/js/theme/core/product/handler/product/updateProductDOMElementsHandler.js +++ b/_dev/js/theme/core/product/handler/product/updateProductDOMElementsHandler.js @@ -4,43 +4,44 @@ import { each } from '../../../../utils/DOMHelpers'; import productEventContextSelector from '../../utils/productEventContextSelector'; /** - * Replace element with new html string - * @param element {HTMLElement} - element to replace - * @param htmlString {string} - html string to replace with + * Replaces an HTML element with a new HTML string. + * + * @param {HTMLElement} element - The element to replace. + * @param {string} htmlString - The HTML string to replace the element with. + * @returns {void} + * @sideeffect Replaces the specified element with the new HTML string. */ const replaceElement = (element, htmlString) => { const newElement = parseToHtml(htmlString); - element.replaceWith(newElement); }; /** - * Update DOM elements of the product page - * Side effect: update DOM elements of the product page - * @param eventData {object} - event data - * @param eventData.product_cover_thumbnails {string} - product cover thumbnails html string - * @param eventData.product_prices {string} - product prices html string - * @param eventData.product_customization {string} - product customization html string - * @param eventData.product_variants {string} - product variants html string - * @param eventData.product_discounts {string} - product discounts html string - * @param eventData.product_additional_info {string} - product additional info html string - * @param eventData.product_details {string} - product details html string - * @param eventData.product_flags {string} - product flags html string - * @param eventData.product_add_to_cart {string} - product add to cart html string - * @return {void} + * Updates DOM elements of the product page based on the provided event data. + * + * @param {object} eventData - Event data containing various HTML strings for different parts of the product page. + * @param {string} eventData.product_prices - HTML string for product prices. + * @param {string} eventData.product_customization - HTML string for product customization. + * @param {string} eventData.product_variants - HTML string for product variants. + * @param {string} eventData.product_discounts - HTML string for product discounts. + * @param {string} eventData.product_additional_info - HTML string for product additional info. + * @param {string} eventData.product_details - HTML string for product details. + * @param {string} eventData.product_flags - HTML string for product flags. + * @param {string} eventData.product_add_to_cart - HTML string for product add to cart. + * @returns {void} + * @sideeffect Updates DOM elements of the product page with the provided HTML strings. */ const updateProductDOMElementsHandler = ({ /* eslint-disable */ - product_cover_thumbnails, - product_prices, - product_customization, - product_variants, - product_discounts, - product_additional_info, - product_details, - product_flags, - product_add_to_cart, - /* eslint-enable */ + product_prices, + product_customization, + product_variants, + product_discounts, + product_additional_info, + product_details, + product_flags, + product_add_to_cart, + /* eslint-enable */ }) => { const contextSelector = productEventContextSelector(); diff --git a/_dev/js/theme/core/product/handler/product/updateProductHandler.js b/_dev/js/theme/core/product/handler/product/updateProductHandler.js index 20aa2695..7bb63903 100644 --- a/_dev/js/theme/core/product/handler/product/updateProductHandler.js +++ b/_dev/js/theme/core/product/handler/product/updateProductHandler.js @@ -13,10 +13,11 @@ import productEventContextSelector from '../../utils/productEventContextSelector const { getCurrentRequestDelayedId, setCurrentRequestDelayedId } = productStateStore(); /** - * Handle 'updateProduct' event - * @param params - event object - * @param params.eventType {string} - event type - * @return {Promise} + * Handles the 'updateProduct' event. + * + * @param {object} params - Event object. + * @param {string} params.eventType - Event type. + * @return {Promise} - A Promise that resolves when the update is completed. */ const updateProductHandler = async ({ eventType }) => { const isQuickView = isQuickViewOpen(); diff --git a/_dev/js/theme/core/product/handler/product/updateQuantityInputHandler.js b/_dev/js/theme/core/product/handler/product/updateQuantityInputHandler.js index 4ca8f82d..c35f4bbe 100644 --- a/_dev/js/theme/core/product/handler/product/updateQuantityInputHandler.js +++ b/_dev/js/theme/core/product/handler/product/updateQuantityInputHandler.js @@ -2,16 +2,14 @@ import prestashop from 'prestashop'; import productEventContextSelector from '../../utils/productEventContextSelector'; /** - * Update quantity input value - * @param eventType {string} - event type - * @param event {object} - event data - * @param event.product_minimal_quantity {number} - product minimal quantity + * Updates the quantity input value based on the event data. + * + * @param {string} eventType - The type of the event. + * @param {object} event - The event data. + * @param {number} event.product_minimal_quantity - The product minimal quantity. */ const updateQuantityInputHandler = (eventType, { product_minimal_quantity: productMinimalQuantity }) => { - const minimalProductQuantity = parseInt( - productMinimalQuantity, - 10, - ); + const minimalProductQuantity = parseInt(productMinimalQuantity, 10); const contextElement = document.querySelector(productEventContextSelector()); if (!Number.isNaN(minimalProductQuantity) && eventType !== 'updatedProductQuantity') { diff --git a/_dev/js/theme/core/product/handler/product/updatedProductHandler.js b/_dev/js/theme/core/product/handler/product/updatedProductHandler.js index 335709c3..296c7461 100644 --- a/_dev/js/theme/core/product/handler/product/updatedProductHandler.js +++ b/_dev/js/theme/core/product/handler/product/updatedProductHandler.js @@ -4,10 +4,15 @@ import productStateStore from '../../store/productStateStore'; const { isOnPopState, setOnPopState } = productStateStore(); /** - * Handle updated product on 'updatedProduct' event - * Side effect: changes the url and title, sets popState in productStateStore - * @param event - event object with response data - * @param formData - form data + * Handles the 'updatedProduct' event by updating the URL, title, and popState. + * + * @param {object} eventData - Event object with response data. + * @param {string|null} eventData.product_url - Updated product URL. + * @param {string|null} eventData.id_product_attribute - Updated product attribute ID. + * @param {string} eventData.product_title - Updated product title. + * @param {object} formData - Form data. + * @returns {void} + * @sideEffect Modifies the document title, updates the URL, and sets popState in productStateStore. */ const updatedProductHandler = ({ product_url: responseProductUrl = null, @@ -19,9 +24,9 @@ const updatedProductHandler = ({ } /* - * If quickview modal is present we are not on product page, so - * we don't change the url nor title - */ + * If the quickview modal is present, we are not on the product page, so + * we don't change the URL or title. + */ if (isQuickViewOpen()) { return; } diff --git a/_dev/js/theme/core/product/handler/quickView/quickViewClickHandler.js b/_dev/js/theme/core/product/handler/quickView/quickViewClickHandler.js index 1ed2dc34..caada7d2 100644 --- a/_dev/js/theme/core/product/handler/quickView/quickViewClickHandler.js +++ b/_dev/js/theme/core/product/handler/quickView/quickViewClickHandler.js @@ -1,9 +1,10 @@ import prestashop from 'prestashop'; /** - * Quick view btn click handler - * SideEffect: emit event on prestashop object clickViewOpen - * @param event {Event} - click event + * Click handler for the quick view button. + * Side effect: Emits 'clickQuickView' event on the prestashop object. + * + * @param {Event} event - The click event. */ const quickViewClickHandler = async (event) => { event.preventDefault(); diff --git a/_dev/js/theme/core/product/handler/quickView/quickViewHandler.js b/_dev/js/theme/core/product/handler/quickView/quickViewHandler.js index 18d1fc61..f9e30712 100644 --- a/_dev/js/theme/core/product/handler/quickView/quickViewHandler.js +++ b/_dev/js/theme/core/product/handler/quickView/quickViewHandler.js @@ -2,10 +2,11 @@ import prestashop from 'prestashop'; import quickViewRequest from '../../request/quickView/quickViewRequest'; /** - * Quick view handler - * SideEffect: emit event on prestashop object clickViewOpen - * @param idProduct - * @param idProductAttribute + * Quick view handler. + * Side effect: Emits 'clickViewOpen' event on the prestashop object. + * + * @param {string} idProduct - The product ID. + * @param {string} idProductAttribute - The product attribute ID. */ const quickViewHandler = async (idProduct, idProductAttribute) => { const payload = { diff --git a/_dev/js/theme/core/product/persister/productFormDataPersister.js b/_dev/js/theme/core/product/persister/productFormDataPersister.js index ad5b2c50..95253cc0 100644 --- a/_dev/js/theme/core/product/persister/productFormDataPersister.js +++ b/_dev/js/theme/core/product/persister/productFormDataPersister.js @@ -3,15 +3,17 @@ import { formSerializeArray } from '../../../utils/formSerialize'; let formData = []; /** - * Persists product form data + * Persists product form data. * @module + * @returns {object} - Object with methods for persisting and retrieving form data. */ const productFormDataPersister = () => { /** - * Persists form data from the form element + * Persists form data from the form element. + * * @method - * @param {HTMLFormElement} formElement - form element to persist - * @throws {Error} - if formElement is not a form element + * @param {HTMLFormElement} formElement - Form element to persist. + * @throws {Error} - If formElement is not a form element. * @return {void} */ const persist = (formElement) => { @@ -23,9 +25,10 @@ const productFormDataPersister = () => { }; /** - * Returns persisted data + * Returns persisted data. + * * @method - * @return {*[]} + * @return {Array} - Persisted form data. */ const get = () => formData; diff --git a/_dev/js/theme/core/product/productController.js b/_dev/js/theme/core/product/productController.js index 2b974c8b..f1587509 100644 --- a/_dev/js/theme/core/product/productController.js +++ b/_dev/js/theme/core/product/productController.js @@ -14,8 +14,11 @@ const { persist } = productFormDataPersister(); /** * Persists form data on init - * Side effect: set formData in productFormDataPersister - * @return {void} + * + * @function + * @name persistFormDataOnInit + * @memberof module:productController + * @returns {void} */ const persistFormDataOnInit = () => { const form = document.querySelector(`${prestashop.selectors.product.actions} .js-product-form`); @@ -26,16 +29,19 @@ const persistFormDataOnInit = () => { }; /** - * Product controller + * Product controller module. + * * @module productController - * @return {{init: init}} + * @returns {{init: Function}} */ const productController = () => { /** - * Init product controller - * @method init - * @public - * @return {void} + * Initializes the product controller. + * + * @function + * @name init + * @memberof module:productController + * @returns {void} */ const init = () => { persistFormDataOnInit(); diff --git a/_dev/js/theme/core/product/request/product/updateProductRequest.js b/_dev/js/theme/core/product/request/product/updateProductRequest.js index 729deeee..1686d355 100644 --- a/_dev/js/theme/core/product/request/product/updateProductRequest.js +++ b/_dev/js/theme/core/product/request/product/updateProductRequest.js @@ -7,54 +7,56 @@ import GenericHttpRequestError from '../../../../components/http/error/GenericHt const { dispatch, abortAll } = useHttpController(); /** - * @typedef ServerResponse - * @type {object} - * @property {number} id_customization - saved customization id - * @property {number} id_product_attribute - saved product attribute id - * @property {number} product_minimal_quantity - product minimal quantity - * @property {boolean} is_quick_view - is quick view - * @property {boolean} product_has_combinations - product has combinations - * @property {string} product_url - product url address - * @property {string} product_title - product meta title - * @property {string} product_add_to_cart - product add to cart html content - * @property {string} product_additional_info - product additional info html content - * @property {string} product_cover_thumbnails - product cover thumbnails html content - * @property {string} product_customization - product customization html content - * @property {string} product_details - product details html content - * @property {string} product_discounts - product discounts html content - * @property {string} product_flags - product flags html content - * @property {string} product_prices - product prices html content - * @property {string} product_images_modal - product images modal html content - * @property {string} product_variants - product variants html content + * Server response object for the update product request. + * + * @typedef {object} ServerResponse + * @property {number} id_customization - Saved customization id. + * @property {number} id_product_attribute - Saved product attribute id. + * @property {number} product_minimal_quantity - Product minimal quantity. + * @property {boolean} is_quick_view - Indicates if it's a quick view. + * @property {boolean} product_has_combinations - Indicates if the product has combinations. + * @property {string} product_url - Product URL address. + * @property {string} product_title - Product meta title. + * @property {string} product_add_to_cart - Product "Add to Cart" HTML content. + * @property {string} product_additional_info - Product additional info HTML content. + * @property {string} product_cover_thumbnails - Product cover thumbnails HTML content. + * @property {string} product_customization - Product customization HTML content. + * @property {string} product_details - Product details HTML content. + * @property {string} product_discounts - Product discounts HTML content. + * @property {string} product_flags - Product flags HTML content. + * @property {string} product_prices - Product prices HTML content. + * @property {string} product_images_modal - Product images modal HTML content. + * @property {string} product_variants - Product variants HTML content. */ /** - * Update listing facets request - * @param payload {object} - payload for request - * @param payload.preview {number} - is preview 1 or 0 - * @param payload.quickview {number} - is quick view 1 or 0 - * @param payload.quantity_wanted {number} - quantity wanted - * @param payload.id_product {number} - product id - * @param payload.id_product_attribute {number} - product attribute id - * @param payload.id_customization {number} - customization id - optional, default 0 - * @param payload.ajax {number} - optional, default 1 - * @param payload.action {string} - optional, default refresh - * @param payload.group[] {array} - array of attributes groups - optional + * Update listing facets request. + * + * @param {object} payload - Payload for the request. + * @param {number} payload.preview - Is preview (1 or 0). + * @param {number} payload.quickview - Is quick view (1 or 0). + * @param {number} payload.quantity_wanted - Quantity wanted. + * @param {number} payload.id_product - Product ID. + * @param {number} payload.id_product_attribute - Product attribute ID. + * @param {number} [payload.id_customization=0] - Customization ID (optional, default 0). + * @param {number} [payload.ajax=1] - AJAX flag (optional, default 1). + * @param {string} [payload.action='refresh'] - Action (optional, default 'refresh'). + * @param {Array} [payload.group] - Array of attributes groups (optional). * @example - * const payload = { - * id_product: 1, - * id_product_attribute: 1, - * quantity_wanted: 1, - * preview: 0, - * quickview: 0, - * } - * const { getRequest } = updateProductRequest(payload); + * const payload = { + * id_product: 1, + * id_product_attribute: 1, + * quantity_wanted: 1, + * preview: 0, + * quickview: 0, + * }; + * const { getRequest } = updateProductRequest(payload); * - * try { + * try { * const resp = await getRequest(); - * } catch (error) { + * } catch (error) { * console.error(error); - * } + * } * @returns {{getRequest: (function(): Promise)}} */ const updateProductRequest = (payload) => { @@ -108,6 +110,12 @@ const updateProductRequest = (payload) => { throw Error(validationErrors.join(',\n')); } + /** + * Get the request function for the update product request. + * + * @function + * @returns {Promise} - Promise that resolves to the server response. + */ const getRequest = () => { abortAll(); diff --git a/_dev/js/theme/core/product/request/quickView/quickViewRequest.js b/_dev/js/theme/core/product/request/quickView/quickViewRequest.js index 119d7d85..cba05f36 100644 --- a/_dev/js/theme/core/product/request/quickView/quickViewRequest.js +++ b/_dev/js/theme/core/product/request/quickView/quickViewRequest.js @@ -1,34 +1,35 @@ import prestashop from 'prestashop'; import useDefaultHttpRequest from '../../../../components/http/useDefaultHttpRequest'; import useHttpPayloadDefinition from '../../../../components/http/useHttpPayloadDefinition'; - /** - * @typedef ServerResponse - * @type {object} - * @property {string} quickview_html - html content of quick view - * @property {object} product - product front object + * Server response object for the quick view request. + * + * @typedef {object} ServerResponse + * @property {string} quickview_html - HTML content of quick view. + * @property {object} product - Product front object. */ /** - * Add voucher to cart request - * @param payload {Object} - payload object to send - * @param payload.id_product {number} - id_product to show - Required - * @param payload.id_product_attribute {number} - id_product to show - optional, default 0 - * @param payload.ajax {number} - optional, default 1 - * @param payload.action {string} - optional + * Add voucher to cart request. + * + * @param {Object} payload - Payload object to send. + * @param {number} payload.id_product - ID of the product to show (Required). + * @param {number} [payload.id_product_attribute=0] - ID of the product attribute (optional, default 0). + * @param {number} [payload.ajax=1] - AJAX flag (optional, default 1). + * @param {string} [payload.action] - Action (optional). * @example - * const payload = { - * id_product: 1, // Required - * id_product_attribute: 1, // Optional - default 0 - * }; + * const payload = { + * id_product: 1, // Required + * id_product_attribute: 1, // Optional - default 0 + * }; * - * const { getRequest } = quickViewRequest(payload); + * const { getRequest } = quickViewRequest(payload); * - * try { - * const resp = await getRequest(); - * } catch (error) { - * console.error(error); - * } + * try { + * const resp = await getRequest(); + * } catch (error) { + * console.error(error); + * } * @returns {{getRequest: (function(): Promise)}} */ const quickViewRequest = (payload) => { @@ -66,6 +67,12 @@ const quickViewRequest = (payload) => { throw Error(validationErrors.join(',\n')); } + /** + * Get the request function for the quick view request. + * + * @function + * @returns {Promise} - Promise that resolves to the server response. + */ const getRequest = () => useDefaultHttpRequest(prestashop.urls.pages.product, payloadToSend); return { diff --git a/_dev/js/theme/core/product/store/productStateStore.js b/_dev/js/theme/core/product/store/productStateStore.js index a6bb554c..c089aaa0 100644 --- a/_dev/js/theme/core/product/store/productStateStore.js +++ b/_dev/js/theme/core/product/store/productStateStore.js @@ -1,3 +1,17 @@ +/** + * Represents the state of the product. + * + * @typedef {object} ProductState + * @property {boolean} isOnPopStateEvent - Indicates if the current event is a popstate event. + * @property {boolean} formChanged - Indicates if the form has changed. + * @property {null|number} currentRequestDelayedId - The current request delayed id. + */ + +/** + * The state of the product. + * + * @type {ProductState} + */ const state = { isOnPopStateEvent: false, formChanged: false, @@ -5,53 +19,64 @@ const state = { }; /** - * Store for product state + * Store for managing the state of the product. + * * @module + * @returns {Object} - Object containing methods to interact with the product state. */ const productStateStore = () => { /** - * Returns true if the current event is a popstate event - * @method - * @return {boolean} + * Returns true if the current event is a popstate event. + * + * @function + * @returns {boolean} - True if the current event is a popstate event. */ const isOnPopState = () => state.isOnPopStateEvent; /** - * Sets the current event as a popstate event - * @method - * @param value {boolean} + * Sets the current event as a popstate event. + * + * @function + * @param {boolean} value - The value to set for the popstate event. + * @returns {void} */ const setOnPopState = (value) => { state.isOnPopStateEvent = value; }; /** - * Sets the form changed state - * @method - * @param value {boolean} + * Sets the form changed state. + * + * @function + * @param {boolean} value - The value to set for the form changed state. + * @returns {void} */ const setFormChanged = (value) => { state.formChanged = value; }; /** - * Returns true if the form has changed - * @method - * @return {boolean} + * Returns true if the form has changed. + * + * @function + * @returns {boolean} - True if the form has changed. */ const isFormChanged = () => state.formChanged; /** - * Returns the current request delayed id - * @method - * @return {null|number} + * Returns the current request delayed id. + * + * @function + * @returns {null|number} - The current request delayed id. */ const getCurrentRequestDelayedId = () => state.currentRequestDelayedId; /** - * Sets the current request delayed id - * @method - * @param value {null|number} + * Sets the current request delayed id. + * + * @function + * @param {null|number} value - The value to set for the current request delayed id. + * @returns {void} */ const setCurrentRequestDelayedId = (value) => { state.currentRequestDelayedId = value; diff --git a/_dev/js/theme/core/product/utils/isProductPreview.js b/_dev/js/theme/core/product/utils/isProductPreview.js index 8c431915..a595df8c 100644 --- a/_dev/js/theme/core/product/utils/isProductPreview.js +++ b/_dev/js/theme/core/product/utils/isProductPreview.js @@ -1,10 +1,11 @@ /** - * Check if the product is in preview mode - * @returns {boolean} + * Checks if the product is in preview mode. + * + * @function + * @returns {boolean} - True if the product is in preview mode, otherwise false. */ const isProductPreview = () => { const urlParams = new URLSearchParams(window.location.search); - return urlParams.has('preview'); }; diff --git a/_dev/js/theme/core/product/utils/isQuickViewOpen.js b/_dev/js/theme/core/product/utils/isQuickViewOpen.js index 5645a18f..7d133c93 100644 --- a/_dev/js/theme/core/product/utils/isQuickViewOpen.js +++ b/_dev/js/theme/core/product/utils/isQuickViewOpen.js @@ -1,6 +1,8 @@ /** - * Check if quick view is open - * @returns {boolean} + * Checks if the quick view is open. + * + * @function + * @returns {boolean} - True if the quick view is open, otherwise false. */ const isQuickViewOpen = () => !!document.querySelector('.modal.quickview.in'); diff --git a/_dev/js/theme/core/product/utils/productEventContextSelector.js b/_dev/js/theme/core/product/utils/productEventContextSelector.js index cebfd0c0..b58634e9 100644 --- a/_dev/js/theme/core/product/utils/productEventContextSelector.js +++ b/_dev/js/theme/core/product/utils/productEventContextSelector.js @@ -1,6 +1,12 @@ import prestashop from 'prestashop'; import isQuickViewOpen from './isQuickViewOpen'; +/** + * Returns the appropriate product event context selector based on whether the quick view is open or not. + * + * @function + * @returns {string} - The product event context selector. + */ const productEventContextSelector = () => { const { quickViewModal, From c8734a9d3c4bc3c5836ab959028d7a582e2fbcd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ste=CC=A8pien=CC=81?= Date: Mon, 23 Oct 2023 01:25:39 +0200 Subject: [PATCH 6/8] eslint fixes --- _dev/js/theme/components/useAlertToast.js | 4 ++-- _dev/js/theme/core/email/emailIdn.js | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/_dev/js/theme/components/useAlertToast.js b/_dev/js/theme/components/useAlertToast.js index e3ebac46..0896d0f5 100644 --- a/_dev/js/theme/components/useAlertToast.js +++ b/_dev/js/theme/components/useAlertToast.js @@ -18,10 +18,10 @@ const getId = (prefix = 'alert_toast_') => { * @param {number} [params.duration=4000] - Duration in milliseconds for which the toast is displayed. * @returns {Object} - An object containing methods for showing different types of toasts. */ -const useAlertToast = (params) => { +const useAlertToast = (params = {}) => { const { duration = 4000, - } = params || {}; + } = params; const stackTemplateId = 'alert-toast-stack'; const bodyElement = document.querySelector('body'); diff --git a/_dev/js/theme/core/email/emailIdn.js b/_dev/js/theme/core/email/emailIdn.js index 5e2341da..bcb2619a 100644 --- a/_dev/js/theme/core/email/emailIdn.js +++ b/_dev/js/theme/core/email/emailIdn.js @@ -34,4 +34,3 @@ const initEmailIdn = (selector) => { }; export default initEmailIdn; - From 384173b16f52b7f370188e4c6cf115b881bcb434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ste=CC=A8pien=CC=81?= Date: Mon, 23 Oct 2023 01:25:50 +0200 Subject: [PATCH 7/8] import changes to relative --- _dev/js/theme/core/index.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/_dev/js/theme/core/index.js b/_dev/js/theme/core/index.js index 81f7c41b..3efad871 100644 --- a/_dev/js/theme/core/index.js +++ b/_dev/js/theme/core/index.js @@ -1,14 +1,14 @@ -import '@js/theme/core/selectors'; +import './selectors'; -import '@js/theme/core/cart/index'; -import '@js/theme/core/product/index'; -import '@js/theme/core/listing/index'; -import '@js/theme/core/address/index'; -import '@js/theme/core/checkout/index'; +import './cart/index'; +import './product/index'; +import './listing/index'; +import './address/index'; +import './checkout/index'; -import psShowHide from '@js/theme/core/display/psShowHide'; -import emailIdn from '@js/theme/core/email/emailIdn'; -import DOMReady from '@js/theme/utils/DOMReady'; +import psShowHide from './display/psShowHide'; +import emailIdn from './email/emailIdn'; +import DOMReady from '../utils/DOMReady'; DOMReady(() => { psShowHide(); From 4f9bd6b9462c53c5946d164cf17c35f4a7228005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ste=CC=A8pien=CC=81?= Date: Mon, 23 Oct 2023 01:42:31 +0200 Subject: [PATCH 8/8] jsdocs for dynamicImports --- .../dynamicImports/componentProxyFactory.js | 24 +++--- .../useBootstrapComponentDynamicImport.js | 75 +++++++++++++++++++ .../useDynamicImportEventsHandler.js | 44 ++++------- .../dynamicImports/useFunctionCallstackMap.js | 63 ++++++++++------ .../utils/dynamicImports/useInstanceMap.js | 44 +++++++---- 5 files changed, 174 insertions(+), 76 deletions(-) diff --git a/_dev/js/theme/utils/dynamicImports/componentProxyFactory.js b/_dev/js/theme/utils/dynamicImports/componentProxyFactory.js index fe99a797..2eaf6bbe 100644 --- a/_dev/js/theme/utils/dynamicImports/componentProxyFactory.js +++ b/_dev/js/theme/utils/dynamicImports/componentProxyFactory.js @@ -1,8 +1,11 @@ /** - * @method handleProxyGet - * @param element - * @param proxyMethodHandler - * @return {(function(*, *, *): (*))|*} + * Handles the proxy get operation for a component. + * + * @function + * @name handleProxyGet + * @param {HTMLElement} element - The component element. + * @param {function} proxyMethodHandler - The proxy method handler. + * @returns {function(*, *, *): (*)|*} - The proxy handler function. */ const handleProxyGet = (element, proxyMethodHandler) => (target, prop, receiver) => { if (target[prop] !== undefined) { @@ -13,11 +16,14 @@ const handleProxyGet = (element, proxyMethodHandler) => (target, prop, receiver) }; /** - * @method componentProxyFactory - * @param element {HTMLElement} - component element - * @param options {object} - component options - * @param proxyMethodHandler {function} - proxy method handler - * @return {{_options, _element}} - component proxy + * Creates a proxy for a component. + * + * @function + * @name componentProxyFactory + * @param {HTMLElement} element - The component element. + * @param {object} options - The component options. + * @param {function} proxyMethodHandler - The proxy method handler. + * @returns {{_options, _element}} - The component proxy. */ const componentProxyFactory = ( element, diff --git a/_dev/js/theme/utils/dynamicImports/useBootstrapComponentDynamicImport.js b/_dev/js/theme/utils/dynamicImports/useBootstrapComponentDynamicImport.js index edddd6ac..7a01d469 100644 --- a/_dev/js/theme/utils/dynamicImports/useBootstrapComponentDynamicImport.js +++ b/_dev/js/theme/utils/dynamicImports/useBootstrapComponentDynamicImport.js @@ -3,6 +3,13 @@ import useDynamicImportEventsHandler from './useDynamicImportEventsHandler'; import useFunctionCallstackMap from './useFunctionCallstackMap'; import componentProxyFactory from './componentProxyFactory'; +/** + * Checks if jQuery is enabled. + * + * @function + * @name isJQueryEnabled + * @returns {boolean} - Whether jQuery is enabled or not. + */ const isJQueryEnabled = () => { try { return !!window.jQuery; @@ -11,6 +18,16 @@ const isJQueryEnabled = () => { } }; +/** + * Dynamically loads and initializes Bootstrap components with optional jQuery support. + * + * @param {Function[]} importFiles - Array of functions that import the necessary files for the component. + * @param {Object} options - Configuration options. + * @param {string} options.componentName - Name of the Bootstrap component. + * @param {string[]} [options.events=[]] - List of events to bind for dynamic loading. + * @returns {Object} - Object with an `init` function for initializing the dynamic loading. + * @throws {Error} - Throws an error if the component name is not provided. + */ const useBootstrapComponentDynamicImport = (importFiles, { componentName, events = [], @@ -42,6 +59,10 @@ const useBootstrapComponentDynamicImport = (importFiles, { const getJQueryComponentName = () => componentName.toLowerCase(); + /** + * Handles the loading of component files. + * @returns {Promise} - A Promise that resolves when files are loaded. + */ const loadFiles = () => Promise.all(importFiles()).then((files) => { for (let i = 0; i < files.length; i += 1) { const file = files[i]; @@ -56,6 +77,10 @@ const useBootstrapComponentDynamicImport = (importFiles, { filesLoading = false; }); + /** + * Executes component initialization and callback calls. + * @returns {void} + */ const executeComponentInitializationAndCallbackCalls = () => { const instances = getAllInstancesForComponent(); @@ -105,6 +130,10 @@ const useBootstrapComponentDynamicImport = (importFiles, { } }; + /** + * Handles the loading of the component. + * @returns {Promise} - A Promise that resolves when the component is loaded. + */ const handleComponentLoad = async () => { if (filesLoaded || filesLoading) { return; @@ -118,6 +147,11 @@ const useBootstrapComponentDynamicImport = (importFiles, { executeComponentInitializationAndCallbackCalls(); }; + /** + * Handles events triggered during dynamic loading. + * @param {Event} e - The event object. + * @returns {Promise} - A Promise that resolves when the event is handled. + */ const handleEvent = async (e) => { e.preventDefault(); @@ -128,10 +162,30 @@ const useBootstrapComponentDynamicImport = (importFiles, { delegateTarget.dispatchEvent(new Event(type)); }; + /** + * Binds events for dynamic loading. + * @type {Object} + * @property {Function} bindEvents - Binds events. + * @property {Function} unbindEvents - Unbinds events. + */ const { bindEvents, unbindEvents } = useDynamicImportEventsHandler(events, handleEvent); + /** + * Gets the component instance associated with an element. + * @param {HTMLElement} element - The HTML element. + * @returns {Object|null} - The component instance or null if not found. + */ const getComponentInstance = (element) => getInstanceFromMap(element); + /** + * Handles proxy method calls for the component. + * @param {Object} target - The target object. + * @param {string} prop - The property being accessed. + * @param {Object} receiver - The receiver object. + * @param {HTMLElement} element - The HTML element associated with the component. + * @param {Array} args - The arguments passed to the method. + * @returns {Object} - The receiver object. + */ const proxyMethodCallHandler = (target, prop, receiver, element, args) => { const instance = getInstanceFromMap(element); @@ -152,6 +206,12 @@ const useBootstrapComponentDynamicImport = (importFiles, { return receiver; }; + /** + * Constructor function for creating Bootstrap component instances. + * @param {string|HTMLElement} selectorOrElement - Selector or HTML element. + * @param {Object} [options={}] - Component options. + * @returns {Object} - The component instance proxy. + */ function ComponentObjectConstructorFunction(selectorOrElement, options = {}) { const element = selectorOrElement instanceof Element ? selectorOrElement : document.querySelector(selectorOrElement); const componentInstanceProxy = componentProxyFactory(element, options, proxyMethodCallHandler); @@ -161,6 +221,12 @@ const useBootstrapComponentDynamicImport = (importFiles, { return componentInstanceProxy; } + /** + * Gets or creates a component instance for a given element. + * @param {HTMLElement} element - The HTML element. + * @param {Object} options - Component options. + * @returns {Object} - The component instance. + */ ComponentObjectConstructorFunction.getOrCreateInstance = (element, options) => { const componentInstance = getComponentInstance(element); @@ -171,6 +237,11 @@ const useBootstrapComponentDynamicImport = (importFiles, { return new ComponentObjectConstructorFunction(element, options); }; + /** + * Gets an existing component instance for a given element. + * @param {HTMLElement} element - The HTML element. + * @returns {Object|null} - The existing component instance or null if not found. + */ ComponentObjectConstructorFunction.getInstance = getComponentInstance; window.bootstrap = window.bootstrap || {}; @@ -185,6 +256,10 @@ const useBootstrapComponentDynamicImport = (importFiles, { }; } + /** + * Initializes the dynamic loading of the Bootstrap component. + * @returns {void} + */ const init = () => { bindEvents(); }; diff --git a/_dev/js/theme/utils/dynamicImports/useDynamicImportEventsHandler.js b/_dev/js/theme/utils/dynamicImports/useDynamicImportEventsHandler.js index 85d757d7..161b070b 100644 --- a/_dev/js/theme/utils/dynamicImports/useDynamicImportEventsHandler.js +++ b/_dev/js/theme/utils/dynamicImports/useDynamicImportEventsHandler.js @@ -3,56 +3,40 @@ import useEvent from '../../components/event/useEvent'; const { on, off } = useEvent(); /** - * Use dynamic import events handler - * @param {array} events - Array of events - * @param {function} handler - Event handler - * @return {{ - * bindEvents: function(): (void), - * unbindEvents: (function(): (void)), + * Handles dynamic import events by binding and unbinding specified events on the document. + * @param {Array} events - An array of event configurations, each containing a name and selector. + * @param {Function} handler - The event handler function. + * @returns {{ + * bindEvents: Function, + * unbindEvents: Function, * }} */ const useDynamicImportEventsHandler = (events, handler) => { /** - * Bind events - * @return {void} + * Binds the specified events on the document. + * @returns {void} */ const bindEvents = () => { - events.forEach(({ - name = '', - selector = '', - }) => { + events.forEach(({ name = '', selector = '' }) => { if (!name || !selector) { throw new Error('Event name and selector are required'); } - on( - document, - name, - selector, - handler, - ); + on(document, name, selector, handler); }); }; /** - * Unbind events - * @return {void} + * Unbinds the specified events on the document. + * @returns {void} */ const unbindEvents = () => { - events.forEach(({ - name = '', - selector = '', - }) => { + events.forEach(({ name = '', selector = '' }) => { if (!name || !selector) { throw new Error('Event name and selector are required'); } - off( - document, - name, - selector, - handler, - ); + off(document, name, selector, handler); }); }; diff --git a/_dev/js/theme/utils/dynamicImports/useFunctionCallstackMap.js b/_dev/js/theme/utils/dynamicImports/useFunctionCallstackMap.js index df40b20b..0ddd371c 100644 --- a/_dev/js/theme/utils/dynamicImports/useFunctionCallstackMap.js +++ b/_dev/js/theme/utils/dynamicImports/useFunctionCallstackMap.js @@ -1,15 +1,17 @@ const callbackMap = new Map(); /** + * Manages a map for function callbacks associated with specific elements or keys. + * * @module useFunctionCallstackMap - * @description create instance map - * @param {string} key - map key + * @description Creates and manages a callback map for function callstacks. + * @param {string} key - The key for the function callbacks map. * @return {{ - * getCallbacksForElement: (function(any): (null|array)), - * setCallbackForElement: (function(any, object): (void)), - * removeCallbacksForElement: (function(any): (void)), - * getAllCallbacksForComponent: (function(): (any|null)), - * createCallbackObject: (function(string, ...args): (CallbackObject)) + * getCallbacksForElement: function(any): (array|null), + * setCallbackForElement: function(any, object): void, + * removeCallbacksForElement: function(any): void, + * getAllCallbacksForComponent: function(): (any|null), + * createCallbackObject: function(string, ...args): CallbackObject * }} */ const useFunctionCallstackMap = (key) => { @@ -18,9 +20,11 @@ const useFunctionCallstackMap = (key) => { } /** + * Represents a callback object containing a property and arguments. + * * @class CallbackObject - * @param prop - * @param args + * @param {string} prop - The callback function property. + * @param {...any} args - The callback function arguments. * @constructor */ function CallbackObject(prop, args) { @@ -29,11 +33,13 @@ const useFunctionCallstackMap = (key) => { } /** + * Retrieves the functions callback map for a specific element or key. + * * @method getCallbacksForElement - * @description get functions callback map for elementKey - * @param {any} elementKey - map elementKey + * @description Gets the functions callback map for a specified element key. + * @param {any} elementKey - The element or key to retrieve callbacks for. * @public - * @return {array|null} - functions callback map for key or null + * @return {array|null} - An array of callbacks or null if not found. */ const getCallbacksForElement = (elementKey) => { if (!callbackMap.has(key)) { @@ -50,12 +56,14 @@ const useFunctionCallstackMap = (key) => { }; /** + * Sets a callback for a specific element or key. + * * @method setCallbackForElement - * @description set callback for elementKey + * @description Sets a callback for a specified element key. * @public - * @param {any} elementKey - component elementKey - * @param {CallbackObject} callback - callback object - * @throws {Error} - if callback is not instance of CallbackObject + * @param {any} elementKey - The element or key to set the callback for. + * @param {CallbackObject} callback - The callback object to set. + * @throws {Error} - If the callback is not an instance of CallbackObject. * @return {void} */ const setCallbackForElement = (elementKey, callback) => { @@ -77,10 +85,13 @@ const useFunctionCallstackMap = (key) => { }; /** + * Removes callbacks associated with a specific element or key. + * * @method removeCallbacksForElement - * @description remove component instance from map + * @description Removes callbacks associated with a specified element key. * @public - * @param {any} elementKey - component elementKey + * @param {any} elementKey - The element or key to remove callbacks for. + * @return {void} */ const removeCallbacksForElement = (elementKey) => { if (!callbackMap.has(key)) { @@ -101,10 +112,12 @@ const useFunctionCallstackMap = (key) => { }; /** + * Retrieves all callbacks for the component. + * * @method getAllCallbacksForComponent - * @description get all callbacks for component + * @description Gets all callbacks associated with the component. * @public - * @return {any|null} + * @return {any|null} - All callbacks for the component or null if none. */ const getAllCallbacksForComponent = () => { if (!callbackMap.has(key)) { @@ -115,12 +128,14 @@ const useFunctionCallstackMap = (key) => { }; /** + * Creates a callback object with a property and arguments. + * * @method createCallbackObject - * @description create callback object + * @description Creates a callback object with a specified property and arguments. * @public - * @param prop {string} - callback function - * @param args {...args} - callback arguments - * @return {CallbackObject} - callback object + * @param {string} prop - The callback function property. + * @param {...any} args - The callback function arguments. + * @return {CallbackObject} - The created callback object. */ const createCallbackObject = (prop, args) => new CallbackObject(prop, args); diff --git a/_dev/js/theme/utils/dynamicImports/useInstanceMap.js b/_dev/js/theme/utils/dynamicImports/useInstanceMap.js index f295ccbf..aac00013 100644 --- a/_dev/js/theme/utils/dynamicImports/useInstanceMap.js +++ b/_dev/js/theme/utils/dynamicImports/useInstanceMap.js @@ -1,13 +1,16 @@ const componentsInstancesMap = new Map(); /** + * Manages a map for component instances associated with specific elements or keys. + * * @module useInstanceMap - * @description create instance map - * @param {string} key - map key + * @description Creates and manages an instance map for component instances. + * @param {string} key - The key for the component instances map. * @return {{ - * getInstanceFromMap: (function(HTMLElement): (null|object)), - * setInstanceInMap: (function(HTMLElement, object): (void)), - * removeInstanceFromMap: (function(HTMLElement): (void)) + * getInstanceFromMap: function(HTMLElement): (object|null), + * setInstanceInMap: function(HTMLElement, object): void, + * removeInstanceFromMap: function(HTMLElement): void, + * getAllInstancesForComponent: function(): (object|null) * }} */ const useInstanceMap = (key) => { @@ -16,11 +19,13 @@ const useInstanceMap = (key) => { } /** + * Retrieves the component instance from the map for a specific element. + * * @method getInstanceFromMap - * @description get component instance from map + * @description Gets the component instance from the map for a specified element. * @public - * @param {HTMLElement} element - component element - * @return {object|null} - component instance or null + * @param {HTMLElement} element - The component element. + * @return {object|null} - The component instance or null if not found. */ const getInstanceFromMap = (element) => { if (!componentsInstancesMap.has(key)) { @@ -37,11 +42,13 @@ const useInstanceMap = (key) => { }; /** + * Sets the component instance in the map for a specific element. + * * @method setInstanceInMap - * @description set component instance in map + * @description Sets the component instance in the map for a specified element. * @public - * @param {HTMLElement} element - component element - * @param {object} instance - component instance + * @param {HTMLElement} element - The component element. + * @param {object} instance - The component instance. * @return {void} */ const setInstanceInMap = (element, instance) => { @@ -55,10 +62,13 @@ const useInstanceMap = (key) => { }; /** + * Removes the component instance from the map for a specific element. + * * @method removeInstanceFromMap - * @description remove component instance from map + * @description Removes the component instance from the map for a specified element. * @public - * @param {HTMLElement} element - component element + * @param {HTMLElement} element - The component element. + * @return {void} */ const removeInstanceFromMap = (element) => { if (!componentsInstancesMap.has(key)) { @@ -78,6 +88,14 @@ const useInstanceMap = (key) => { } }; + /** + * Retrieves all component instances for the component. + * + * @method getAllInstancesForComponent + * @description Gets all component instances associated with the component. + * @public + * @return {object|null} - All component instances for the component or null if none. + */ const getAllInstancesForComponent = () => { if (!componentsInstancesMap.has(key)) { return null;