Add button feature

This commit is contained in:
2025-08-14 13:01:01 +02:00
commit bd567d0788
7 changed files with 196 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

12
.idea/add-to-basket.iml generated Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Max Scheme" />
</state>
</component>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/add-to-basket.iml" filepath="$PROJECT_DIR$/.idea/add-to-basket.iml" />
</modules>
</component>
</project>

18
README.md Normal file
View File

@@ -0,0 +1,18 @@
# Add To Basket Button #
Use the function to generate the markup. Then just insert the button somewhere in your item element.
### How to use ###
1. Copy the code, and use **idmAddToBasket** function to generate the markup
2. Don't forget to put it somewhere after
```
const afterWhatPaste = document.getElementById('item-container');
const idmAddToBasketElement = idmAddToBasket(product, size);
afterWhatPaste.insertAdjacentHTML('afterend', idmAddToBasketElement);
```
---
Created by • **[IdoMods](https://idomods.pl/)** • 2025

92
main.js Normal file
View File

@@ -0,0 +1,92 @@
/**
* @product {object} product information
* @size product size, get form product.sizes.[0]
* @return html markup
**/
function idmAddToBasket(product, size) {
const can = product?.type === 'product' && product?.sizes?.length === 1 && size;
if (!can) return '';
const sellBy = size?.unitSellby || 1;
const precision = size?.unitPrecision || 0;
const max = (typeof size?.amount === 'number' && size.amount > 0) ? size.amount : '';
return `
<div class='idm-products-banner__add-to-basket'>
<form class='idm-products-banner__add-to-basket-form' action='/basketchange.php' method='post'>
<input type='hidden' name='mode' value='1'>
<input type='hidden' name='product' value='${escapeHtml(product.id)}'>
<input type='hidden' name='size' value='${escapeHtml(size.id)}'>
<div class='idm-products-banner__qty'
data-sell-by='${escapeHtml(String(sellBy))}'
data-precision='${escapeHtml(String(precision))}'
data-max='${escapeHtml(String(max))}'>
<button type='button' class='idm-products-banner__qty-decrease'></button>
<input type='number'
name='number'
class='idm-products-banner__qty-input'
value='${escapeHtml(String(sellBy))}'
step='${escapeHtml(String(sellBy))}'
min='${escapeHtml(String(sellBy))}'
max='${escapeHtml(String(max))}'>
<button type='button' class='idm-products-banner__qty-increase'>+</button>
</div>
<button type='submit' class='btn --solid --medium idm-products-banner__add-to-basket-button'>
<span>${<iai:variable vid='Do koszyka' />}</span>
</button>
</form>
</div>`;
}
// +/- i walidacja inputów ilości
document.addEventListener('click', (e) => {
const wrapper = e.target.closest('.idm-products-banner__qty');
if (!wrapper) return;
const input = wrapper.querySelector('.idm-products-banner__qty-input');
const step = parseFloat(wrapper.dataset.sellBy || '1');
const precision = parseInt(wrapper.dataset.precision || '0');
const max = parseFloat(wrapper.dataset.max || '999999');
let current = parseFloat(input.value) || 0;
if (e.target.classList.contains('idm-products-banner__qty-increase')) {
current += step;
if (current > max) current = max;
} else if (e.target.classList.contains('idm-products-banner__qty-decrease')) {
current -= step;
if (current < step) current = step;
}
input.value = current.toFixed(precision);
});
document.addEventListener('blur', (e) => {
if (!e.target.classList.contains('idm-products-banner__qty-input')) return;
const input = e.target;
const wrapper = input.closest('.idm-products-banner__qty');
const step = parseFloat(wrapper.dataset.sellBy || '1');
const precision = parseInt(wrapper.dataset.precision || '0');
const max = parseFloat(wrapper.dataset.max || '999999');
let val = parseFloat(input.value);
if (isNaN(val) || val < step) {
val = step;
} else if (val > max) {
val = max;
} else {
val = Math.round(val / step) * step;
}
input.value = val.toFixed(precision);
}, true);
// helper
const escapeHtml = (v = '') => String(v)
.replace(/&/g, '&amp;').replace(/</g, '&lt;')
.replace(/>/g, '&gt;').replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');

53
style.less Normal file
View File

@@ -0,0 +1,53 @@
.idm-products-banner__qty {
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
gap: 1rem;
}
.idm-products-banner__qty-input {
height: 4rem;
text-align: center;
border: 1px solid #ccc;
width: 60%;
max-width: unset;
min-width: unset;
}
.idm-products-banner__qty button {
background: #000;
height: 4rem;
width: 4rem;
color: #fff;
border-radius: 0.5rem;
min-width: 4rem;
}
.idm-products-banner__add-to-basket {
display: flex;
align-items: end;
flex-direction: column;
width: 80%;
margin: 0 auto;
}
.btn.--solid.--medium.idm-products-banner__add-to-basket-button {
height: 4rem;
background: #000;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #000;
}
.btn.--solid.--medium.idm-products-banner__add-to-basket-link {
width: 100%;
height: 4rem;
display: flex;
align-items: center;
justify-content: center;
background: #000;
border: 1px solid #000;
margin-top: auto;
}