Zmiana funkcji na klasy
This commit is contained in:
185
README.md
185
README.md
@@ -2,55 +2,108 @@
|
||||
Funkcje js składające się na customowe ramki rekomendacji
|
||||
|
||||
## UWAGI PRZEDWDROŻENIOWE ##
|
||||
- kod zawiera app_shop.fn.idmSetHeight używany do wyrównywania wysokości
|
||||
- kod zawiera app_shop.fn.idmGetOmnibusDetails który jest przerobionym kodem idosella app_shop.fn.getOmnibusDetails używanym w zwykłych ramkach rekomendacji
|
||||
- kod zawiera **app_shop.fn.idmGetOmnibusDetails** który jest przerobionym kodem idosella app_shop.fn.getOmnibusDetails używanym w zwykłych ramkach rekomendacji
|
||||
|
||||
### Pliki ###
|
||||
- bundle.js - całość
|
||||
- 1graphQL.js - graphQL + literały
|
||||
- 2funkcje.js - ogólne funkcje jak dodawanie do koszyka, czy lazy loading
|
||||
- 3markup.js - funkcje związane z markupem np zdjęć, cen
|
||||
- 4init.js - obiekt z ogólnymi ustawieniami Hotspota + init swipera
|
||||
- 5ainsertHotspotHTML.js - wstawienie ramki po kodzie html
|
||||
- 5binsertHotspotObject.js - wstawienie ramki po obiekcie js
|
||||
- 6style.css -
|
||||
- **style.css** - style wstawiane do css
|
||||
- **klasa.js** - kod js
|
||||
|
||||
### Użycie ###
|
||||
1. Wstawienie całego kodu do komponentu/dodatku
|
||||
2. Ustawienie defaultowych ustawień w obiekcie idmGeneralHotspotObjData
|
||||
1. Wstawienie całego kodu do komponentu (najlepiej chyba Hotspoty javascript RAYPATH - #IdoMods
|
||||
w zwykły Javascript)/dodatku(uwaga tutaj na literały)
|
||||
2. Ustawienie defaultowych ustawień na początku klasy w **idmDefaultSwiperConfig** i w **idmDefaultHotspotOptions**
|
||||
3. Wstawienie HTML lub Obiektu js z odpowienimi danymi i wywołanie funkcji od tworzenia ramek
|
||||
|
||||
#### Dodatkowe informacje ####
|
||||
Można użyć extends w innym miejscu (np tym razem w wydzielonym JS) żeby nadpisać jakąś metodę, bez zmian w kodzie ramki. Będzie to przydatne w przypadku gdzie trzeba będzie zaktualizować kod ramki.
|
||||
|
||||
**Przykład**
|
||||
```
|
||||
class IdmRaypathHotspot extends IdmHotspot {
|
||||
markupLabel(prod) {
|
||||
// Standardowe labelki
|
||||
let labelMarkup = super.markupLabel(prod);
|
||||
|
||||
// Customowe labelki
|
||||
const awards = prod?.awardedParameters;
|
||||
if (awards?.length) {
|
||||
const awardParam = awards.find(award => award.name === "Idm_custom_label");
|
||||
const values = awardParam?.values?.map(v => v.name) || [];
|
||||
|
||||
const html = values
|
||||
.map(label => {
|
||||
const [text, bgColor, color] = label.split("||");
|
||||
return `<span class="label --custom" style="background-color:${bgColor}; color:${color}">${text}</span>`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
labelMarkup += html;
|
||||
}
|
||||
|
||||
return labelMarkup;
|
||||
}
|
||||
}
|
||||
```
|
||||
Warto gdzieś później zapisać nową nazwę klasy np w opisie komponentu, albo w opisie szablonu.
|
||||
|
||||
### Literały do uzupełnienia w szablonie ###
|
||||
- Coś poszło nie tak podczas dodawania do koszyka. Spróbuj ponownie lub odśwież stronę
|
||||
- Błąd przy pobieraniu danych
|
||||
- Maksymalna liczba sztuk tego towaru które możesz dodać do koszyka to:
|
||||
- Minimalna liczba sztuk tego towaru które możesz dodać do koszyka to:
|
||||
- Wystąpił błąd z inicjalizacją. Proszę odśwież stronę
|
||||
- Nie znaleziono kontenera
|
||||
- Nie znaleziono metody graphql
|
||||
|
||||
#### Przykład ####
|
||||
##### Jedna ramka - obiekt ######
|
||||
```
|
||||
idmInsertHotspotObject({
|
||||
{
|
||||
id: "idmMainHotspot1",
|
||||
title: "Nowoczesna ramka rekomendacji",
|
||||
classes: "abcdefg",
|
||||
placement: {
|
||||
selector: "#content",
|
||||
insert: "afterbegin"
|
||||
},
|
||||
query: {
|
||||
string: `searchInput: {productsId : [589, 180, 181590,160740, 155978, 153632, 123350, 82542, 37321, 17040, 25065, 25114, 85452]}`,
|
||||
graphFn: IDM_PRODUCTS_GQL
|
||||
},
|
||||
options: {
|
||||
lazy: false,
|
||||
addToBasket: "range",
|
||||
swiper: true,
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
##### Wszystkie ramki - tablica obiektów ######
|
||||
```
|
||||
idmInsertAllObjectHotspots(hotspotArr);
|
||||
new IdmHotspot({
|
||||
id: "idmTestHotspot1",
|
||||
title: "tescik",
|
||||
placement: {
|
||||
selector: "#content",
|
||||
insert: "beforeend",
|
||||
},
|
||||
source: {
|
||||
productsMenu: 1649
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### Wszystkie możliwe dane JS ####
|
||||
```
|
||||
/**
|
||||
* @typedef {object} Hotspot
|
||||
* @property {string} id - Identyfikator ramki (required).
|
||||
* @property {string} title - Tytuł ramki.
|
||||
* @property {string} classes - Dodatkowe klasy CSS.
|
||||
* @property {object} placement - Określa, gdzie wstawić ramkę (required).
|
||||
* @property {string} placement.selector - Selektor miejsca osadzenia.
|
||||
* @property {string} placement.insert - Pozycja wstawienia względem selektora (np. "afterbegin", "beforeend").
|
||||
* @property {object} source - Dane źródłowe dla hotspotu (required).
|
||||
* @property {string} [source.hotspotType] - Typ hotspotu (np. "promotion").
|
||||
* @property {number[]} [source.productsId] - Tablica ID produktów.
|
||||
* @property {number} [source.productsMenu] - Identyfikator menu produktów.
|
||||
* @property {object} query - Dane zapytania, nadpisują source (DEV).
|
||||
* @property {string} query.string - Zapytanie w formacie GraphQL.
|
||||
* @property {Function} query.graphFn - Funkcja do pobierania danych.
|
||||
* @property {object} options - Ustawienia dla hotspotu (required).
|
||||
* @property {boolean} options.lazy - Czy wczytywać w trybie lazy.
|
||||
* @property {boolean|string} options.addToBasket - Obsługa koszyka:
|
||||
* - true = włącz
|
||||
* - false = wyłącz
|
||||
* - "range" = dodaj z zakresem
|
||||
* @property {boolean|object} options.swiper - Slider:
|
||||
* - true = aktywny
|
||||
* - false = nieaktywny
|
||||
* - object = konfiguracja Swiper
|
||||
* @property {Function} options.callbackFn - Funkcja callback która dzieje się po wywołaniu wszystkiego włącznie ze swiperem
|
||||
*
|
||||
* @type {Hotspot[]}
|
||||
*/
|
||||
```
|
||||
|
||||
|
||||
###### Jedna ramka - HTML ######
|
||||
@@ -72,52 +125,24 @@ idmInsertAllObjectHotspots(hotspotArr);
|
||||
idmInsertHotspotElement(document.getElementByid("idmBlogHotspot1"));
|
||||
</script>
|
||||
```
|
||||
|
||||
###### Wszystkie ramki - HTML ######
|
||||
#### Wszystkie możliwe dane HTML####
|
||||
```
|
||||
idmInsertAllHTMLHotspots();
|
||||
/**
|
||||
* Struktura sekcji hotspotu w HTML.
|
||||
*
|
||||
* @typedef {HTMLElement} HotspotSection
|
||||
* @property {string} id - Identyfikator elementu (np. "idmBlogHotspot1").
|
||||
* @property {string} class - Klasy CSS używane do stylowania.
|
||||
*
|
||||
* @attribute {string} data-products-id - Lista ID produktów (rozdzielona przecinkami).
|
||||
* @attribute {number} data-products-menu - Identyfikator menu produktów.
|
||||
* @attribute {string} data-hotspots-type - Typ hotspotu (np. "promotion").
|
||||
* @attribute {boolean} data-lazy - Czy sekcja ma być ładowana w trybie lazy.
|
||||
*
|
||||
* @example
|
||||
*/
|
||||
|
||||
```
|
||||
|
||||
|
||||
### LISTA GLOBALNYCH FUNKCJI, ZMIENNYCH ###
|
||||
##### INIT #####
|
||||
- priceQuery
|
||||
- productQuery
|
||||
- IDM_PRODUCTS_GQL
|
||||
- IDM_HOTSPOTS_GQL
|
||||
- IDM_PRODUCT_GQL
|
||||
- IDM_HOTSPOT_ADD_TO_BASKET
|
||||
- idmHotspotTextObject
|
||||
|
||||
#### FUNKCJE ####
|
||||
- app_shop.fn.idmGetOmnibusDetails
|
||||
- idmHandleAddToBasket
|
||||
- idmRangeMaxAlert
|
||||
- idmRangeMinAlert
|
||||
- idmQuantityButtonClick
|
||||
- idmQuantityInputChange
|
||||
- idmGetHotspotData
|
||||
- idmGetQueryData
|
||||
- idmObserveOnce
|
||||
- app_shop.fn.idmSetHeight
|
||||
|
||||
|
||||
#### MARKUP ####
|
||||
- idmPrepareProductsMarkup
|
||||
- idmPrepareSingleProductMarkup
|
||||
- idmPrepareHotspotImgMarkup
|
||||
- idmPrepareHotspotPriceMarkup
|
||||
- idmPrepareHotspotAddToBasketMarkup
|
||||
|
||||
#### INIT ####
|
||||
- idmPriceType
|
||||
- idmGeneralHotspotObjData
|
||||
- idmHotspotInit
|
||||
|
||||
#### INSERT ####
|
||||
- idmInsertHotspotElement
|
||||
- idmInsertAllHTMLHotspots
|
||||
- idmInsertHotspotObject
|
||||
- idmInsertAllObjectHotspots
|
||||
|
||||
Created by • **[IdoMods](https://idomods.pl/)** • 2025
|
||||
@@ -1,207 +0,0 @@
|
||||
///////////////////////////////////////////////
|
||||
// GraphQL
|
||||
// ogolne
|
||||
const priceQuery = `price {
|
||||
rebateCodeActive
|
||||
price {
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
omnibusPrice {
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
omnibusPriceDetails {
|
||||
unit {
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
youSavePercent
|
||||
omnibusPriceIsHigherThanSellingPrice
|
||||
newPriceEffectiveUntil {
|
||||
formatted
|
||||
}
|
||||
}
|
||||
max {
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
unit {
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
unitConvertedPrice {
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
youSavePercent
|
||||
beforeRebate {
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
beforeRebateDetails {
|
||||
youSavePercent
|
||||
unit {
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
}
|
||||
advancePrice {
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
suggested {
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
rebateNumber {
|
||||
number
|
||||
gross {
|
||||
value
|
||||
formatted
|
||||
}
|
||||
}
|
||||
}`;
|
||||
|
||||
const productQuery = `id
|
||||
type
|
||||
name
|
||||
zones
|
||||
icon
|
||||
iconSecond
|
||||
iconSmall
|
||||
iconSmallSecond
|
||||
link
|
||||
zones
|
||||
producer{
|
||||
name
|
||||
}
|
||||
category{
|
||||
name
|
||||
}
|
||||
sizes{
|
||||
id
|
||||
amount
|
||||
name
|
||||
${priceQuery}
|
||||
}
|
||||
group{
|
||||
id
|
||||
name
|
||||
link
|
||||
versions{
|
||||
id
|
||||
name
|
||||
icon
|
||||
iconSecond
|
||||
iconSmall
|
||||
iconSmallSecond
|
||||
}
|
||||
}
|
||||
awardedParameters {
|
||||
name
|
||||
id
|
||||
description
|
||||
values {
|
||||
name
|
||||
id
|
||||
}
|
||||
}
|
||||
enclosuresImages {
|
||||
position
|
||||
url
|
||||
}
|
||||
points
|
||||
unit{
|
||||
id, name, singular, plural, fraction, sellBy, precision, unitConvertedFormat
|
||||
}
|
||||
${priceQuery}`;
|
||||
// 1. products
|
||||
const IDM_PRODUCTS_GQL = (args) => JSON.stringify({
|
||||
query: `{
|
||||
products(${args}){
|
||||
took
|
||||
products{
|
||||
${productQuery}
|
||||
}
|
||||
}
|
||||
}`
|
||||
});
|
||||
|
||||
// 2. hotspots
|
||||
const IDM_HOTSPOTS_GQL = (args) => JSON.stringify({
|
||||
query: `{
|
||||
hotspots(${args}){
|
||||
took
|
||||
products{
|
||||
${productQuery}
|
||||
}
|
||||
}
|
||||
}`
|
||||
});
|
||||
|
||||
// 3. single product
|
||||
const IDM_PRODUCT_GQL = (args) => JSON.stringify({
|
||||
query: `{
|
||||
product(${args}){
|
||||
product{
|
||||
${productQuery}
|
||||
}
|
||||
}
|
||||
}`
|
||||
});
|
||||
// ADD TO BASKET
|
||||
const IDM_HOTSPOT_ADD_TO_BASKET = (t, e, a) => JSON.stringify({
|
||||
query: `mutation {\n addProductsToBasket(ProductInput: {id: ${t}, size: "${e}", quantity: ${a}}) {\n status\n results {\n status\n error {\n code\n message\n }\n productCode\n productId\n sizeId\n quantity\n quantityAvailable\n }\n clientDetailsInBasket {\n id\n login\n firstname\n lastname\n participationPartnerProgram\n usesVat\n email\n isWholesaler\n isWholesalerOrder\n clientIdUpc\n }\n }\n }`
|
||||
});
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// TEXT
|
||||
const idmHotspotTextObject = {
|
||||
["Kod rabatowy"]: "Kod rabatowy",
|
||||
["Okazja"]: "Okazja",
|
||||
["Promocja"]: "Promocja",
|
||||
["Bestseller"]: "Bestseller",
|
||||
["Nowość"]: "Nowość",
|
||||
["Ilość"]: "Ilość",
|
||||
["Zwiększ ilość"]: "Zwiększ ilość",
|
||||
["Zmniejsz ilość"]: "Zmniejsz ilość",
|
||||
["Najniższa cena produktu w okresie 30 dni przed wprowadzeniem obniżki"]: "Najniższa cena produktu w okresie 30 dni przed wprowadzeniem obniżki",
|
||||
["Cena regularna"]: "Cena regularna",
|
||||
["Cena bez kodu"]: "Cena bez kodu",
|
||||
["Cena nadchodząca od"]: "Cena nadchodząca od",
|
||||
["Coś poszło nie tak podczas dodawania do koszyka. Spróbuj ponownie lub odśwież stronę"]: "Coś poszło nie tak podczas dodawania do koszyka. Spróbuj ponownie lub odśwież stronę",
|
||||
["Nie znaleziono produktów"]: "Nie znaleziono produktów",
|
||||
["Błąd przy pobieraniu danych"]: "Błąd przy pobieraniu danych",
|
||||
["Kliknij, by przejść do formularza kontaktu"]: "Kliknij, by przejść do formularza kontaktu",
|
||||
["Cena na telefon"]: "Cena na telefon",
|
||||
["Dodany"]: "Dodany",
|
||||
["Wystąpił błąd"]: "Wystąpił błąd",
|
||||
["Do koszyka"]: "Do koszyka",
|
||||
["Maksymalna liczba sztuk tego towaru które możesz dodać do koszyka to:"]: "Maksymalna liczba sztuk tego towaru które możesz dodać do koszyka to:",
|
||||
["Minimalna liczba sztuk tego towaru które możesz dodać do koszyka to:"]: "Minimalna liczba sztuk tego towaru które możesz dodać do koszyka to:",
|
||||
["Wystąpił błąd z inicjalizacją. Proszę odśwież stronę"]: "Wystąpił błąd z inicjalizacją. Proszę odśwież stronę",
|
||||
["Nie znaleziono kontenera"]: "Nie znaleziono kontenera",
|
||||
["Nie znaleziono metody graphql"]: "Nie znaleziono metody graphql",
|
||||
}
|
||||
@@ -1,321 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////\\\\\\\\\\\\
|
||||
// IDOSELL omnibus details
|
||||
|
||||
// omnibusDetailsTxt - nadpisać na własny obiekt
|
||||
|
||||
app_shop.fn.idmGetOmnibusDetails = (options) => {
|
||||
const {
|
||||
productData, sizeId, priceType = app_shop.vars.priceType,
|
||||
} = options || {};
|
||||
if (!productData) return false;
|
||||
const sizeData = productData.sizes.find((size) => size.id === sizeId) || productData;
|
||||
if (!sizeData?.price) return false;
|
||||
const classes = {
|
||||
add: [],
|
||||
remove: ['--omnibus', '--omnibus-short', '--omnibus-code', '--omnibus-code-short', '--omnibus-new-price', '--omnibus-higher'],
|
||||
};
|
||||
const activeLabel = {};
|
||||
|
||||
const omnibusPrice = sizeData.price?.omnibusPriceDetails?.unit?.[priceType]?.formatted || sizeData.price.omnibusPrice[priceType]?.formatted;
|
||||
if (!omnibusPrice) {
|
||||
return {
|
||||
classes,
|
||||
};
|
||||
}
|
||||
// Omnibus
|
||||
classes.add.push('--omnibus');
|
||||
classes.remove = classes.remove.filter((item) => item !== '--omnibus');
|
||||
|
||||
const sellBy = productData?.unit?.sellBy;
|
||||
|
||||
const unitMaxPrice = sizeData?.price?.unit?.[priceType]?.formatted && sizeData.price.max?.[priceType]?.value ? format_price(parseFloat(sizeData.price.max?.[priceType]?.value) * parseFloat(sellBy), {
|
||||
mask: app_shop.vars.currency_format,
|
||||
currency: app_shop.vars?.currency?.symbol,
|
||||
currency_space: app_shop.vars.currency_space,
|
||||
currency_before_price: app_shop.vars.currency_before_value,
|
||||
}) : false;
|
||||
|
||||
const maxPrice = unitMaxPrice || sizeData.price.max?.[priceType]?.formatted;
|
||||
// Skrócona wersja omnibusa
|
||||
if (!maxPrice || maxPrice === omnibusPrice) {
|
||||
classes.add.push('--omnibus-short');
|
||||
classes.remove = classes.remove.filter((item) => item !== '--omnibus-short');
|
||||
}
|
||||
// Aktywny kod rabatowy
|
||||
if (app_shop.vars.omnibus?.rebateCodeActivate && sizeData.price?.rebateCodeActive) {
|
||||
classes.add.push('--omnibus-code');
|
||||
activeLabel.rebateCodeActive = `<span class="label --code --omnibus">${idmHotspotTextObject["Kod rabatowy"]}</span>`;
|
||||
classes.remove = classes.remove.filter((item) => item !== '--omnibus-code');
|
||||
}
|
||||
// Skrócona wersja omnibusa, gdy aktywny kod rabatowy
|
||||
const beforeRebatePrice = sizeData.price.beforeRebateDetails?.unit?.[priceType]?.formatted || sizeData.price.beforeRebate[priceType]?.formatted;
|
||||
if (app_shop.vars.omnibus?.rebateCodeActivate && beforeRebatePrice === omnibusPrice && sizeData.price?.rebateCodeActive) {
|
||||
classes.add.push('--omnibus-code-short');
|
||||
classes.remove = classes.remove.filter((item) => item !== '--omnibus-code-short');
|
||||
}
|
||||
// Nadchodząca cena
|
||||
const newDate = sizeData.price.omnibusPriceDetails?.newPriceEffectiveUntil?.formatted;
|
||||
if (newDate && maxPrice) {
|
||||
classes.add.push('--omnibus-new-price');
|
||||
classes.remove = classes.remove.filter((item) => item !== '--omnibus-new-price');
|
||||
}
|
||||
// Cena omnibusa wyższa niż cena sprzedaży
|
||||
const higher = sizeData.price.omnibusPriceDetails?.omnibusPriceIsHigherThanSellingPrice;
|
||||
if (higher) {
|
||||
classes.add.push('--omnibus-higher');
|
||||
classes.remove = classes.remove.filter((item) => item !== '--omnibus-higher');
|
||||
}
|
||||
// label okazja
|
||||
if ((!higher || newDate) && !activeLabel?.rebateCodeActive) {
|
||||
activeLabel.bargain = `<span class="label --bargain --omnibus">${idmHotspotTextObject["Okazja"]}</span>`;
|
||||
}
|
||||
// label promocja
|
||||
if (Object.keys(activeLabel)?.length === 0) {
|
||||
activeLabel.bargain = `<span class="label --promo --omnibus">${idmHotspotTextObject["Promocja"]}</span>`;
|
||||
}
|
||||
|
||||
// labele zones
|
||||
if(productData.zones.find(zone => zone ==="bestseller")) activeLabel.bestseller = `<span class="label --bestseller --omnibus">${idmHotspotTextObject["Bestseller"]}</span>`;
|
||||
if(productData.zones.find(zone => zone ==="news")) activeLabel.news = `<span class="label --news --omnibus">${idmHotspotTextObject["Nowość"]}</span>`;
|
||||
|
||||
|
||||
|
||||
let omnibusPercentSign = '';
|
||||
if (higher) {
|
||||
omnibusPercentSign = '-';
|
||||
} else if (sizeData.price.omnibusPriceDetails?.youSavePercent !== 0) {
|
||||
omnibusPercentSign = '+';
|
||||
}
|
||||
const omnibusPercent = `${omnibusPercentSign}${sizeData.price.omnibusPriceDetails?.youSavePercent}%`;
|
||||
const omnibus = {
|
||||
price: omnibusPrice,
|
||||
visible: true,
|
||||
percent: omnibusPercent,
|
||||
html: `<span class="omnibus_price__text">${idmHotspotTextObject['Najniższa cena produktu w okresie 30 dni przed wprowadzeniem obniżki']}: </span><del class="omnibus_price__value">${omnibusPrice}</del><span class="price_percent">${omnibusPercent}</span>`,
|
||||
};
|
||||
|
||||
const max = (maxPrice) ? {
|
||||
max: {
|
||||
price: maxPrice,
|
||||
visible: true,
|
||||
percent: `-${sizeData.price.youSavePercent}%`,
|
||||
html: `<span class="omnibus_label">${idmHotspotTextObject['Cena regularna']}: </span>
|
||||
<del>${maxPrice}</del><span class="price_percent">-${sizeData.price.youSavePercent}%</span>`,
|
||||
},
|
||||
} : {};
|
||||
|
||||
const beforeRebate = (beforeRebatePrice) ? {
|
||||
beforeRebate: {
|
||||
price: beforeRebatePrice,
|
||||
visible: !!classes.add.includes('--omnibus-code'),
|
||||
percent: `-${sizeData.price.beforeRebateDetails?.youSavePercent}%`,
|
||||
html: `<span class="omnibus_label">${idmHotspotTextObject['Cena bez kodu']}: </span>
|
||||
<del>${beforeRebatePrice}</del>
|
||||
<span class="price_percent">-${sizeData.price.beforeRebateDetails?.youSavePercent}%</span>`,
|
||||
},
|
||||
} : {};
|
||||
|
||||
const newPriceEffectiveUntil = (newDate) ? {
|
||||
newPriceEffectiveUntil: {
|
||||
date: newDate,
|
||||
price: maxPrice,
|
||||
visible: !!classes.add.includes('--omnibus-new-price'),
|
||||
html: `<span class="omnibus_label">${idmHotspotTextObject['Cena nadchodząca od']} </span>
|
||||
<span class="new_price__date">${newDate}: </span>
|
||||
<span class="new_price__value">${maxPrice}</span>`,
|
||||
},
|
||||
} : {};
|
||||
|
||||
|
||||
return {
|
||||
classes,
|
||||
omnibus,
|
||||
...max,
|
||||
...beforeRebate,
|
||||
...newPriceEffectiveUntil,
|
||||
activeLabel,
|
||||
};
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EVENTY
|
||||
// dodawanie do koszyka
|
||||
async function idmHandleAddToBasket(e){
|
||||
const formEl = e.target.closest("form.add_to_basket");
|
||||
if(!formEl) return;
|
||||
try{
|
||||
// pobieranie danych i elementów
|
||||
formEl.classList.add("--loading")
|
||||
const buttonEl = formEl.querySelector(".add_to_basket__button");
|
||||
e.preventDefault();
|
||||
|
||||
const id = formEl.querySelector("input[name='product']")?.value;
|
||||
const size = formEl.querySelector("input[type='hidden'][name='size']")?.value;
|
||||
const number = formEl.querySelector("input[name='number']")?.value;
|
||||
|
||||
// dodanie do koszyka
|
||||
const res = await fetch(`/graphql/v1/`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: IDM_HOTSPOT_ADD_TO_BASKET(id, size, number)
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
// Błąd
|
||||
if(data?.data?.addProductsToBasket?.status !== "success") throw new Error(data);
|
||||
else{
|
||||
// Obsługiwanie sukcesu
|
||||
app_shop.graphql.trackingEvents(res);
|
||||
buttonEl.classList.add("--success");
|
||||
|
||||
// Dodawanie do koszyka na stronie basketedit.php będzie wymagał innego indywidualnego kodu!!!!!
|
||||
buttonEl.innerHTML = `<span>${buttonEl.dataset.success}</span>`;
|
||||
setTimeout(()=>{
|
||||
buttonEl.innerHTML = `<span>${buttonEl.dataset.text}</span>`;
|
||||
app_shop.fn?.menu_basket_cache?.();
|
||||
buttonEl.classList.remove("--success");
|
||||
}, 3000);
|
||||
}
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
Alertek.Error(idmHotspotTextObject["Coś poszło nie tak podczas dodawania do koszyka. Spróbuj ponownie lub odśwież stronę"]);
|
||||
buttonEl.innerHTML = `<span>${buttonEl.dataset.error}</span>`;
|
||||
buttonEl.classList.add("--error")
|
||||
setTimeout(()=>{
|
||||
buttonEl.classList.remove("--error")
|
||||
buttonEl.innerHTML = `<span>${buttonEl.dataset.text}</span>`;
|
||||
}, 3000);
|
||||
}finally{
|
||||
formEl.classList.remove("--loading")
|
||||
}
|
||||
}
|
||||
|
||||
///qty
|
||||
const idmRangeMaxAlert = (max)=> Alertek.Error(`${idmHotspotTextObject["Maksymalna liczba sztuk tego towaru które możesz dodać do koszyka to:"]} ${max}`)
|
||||
const idmRangeMinAlert = (min)=> Alertek.Error(`${idmHotspotTextObject["Minimalna liczba sztuk tego towaru które możesz dodać do koszyka to:"]} ${min}`)
|
||||
|
||||
function idmQuantityButtonClick(e){
|
||||
if(e.target.classList.contains("idm-products-banner__qty-input")) return e.target.select();
|
||||
const wrapper = e.target.closest(".idm-products-banner__qty");
|
||||
|
||||
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;
|
||||
idmRangeMaxAlert(max)
|
||||
}
|
||||
} else if (e.target.classList.contains("idm-products-banner__qty-decrease")) {
|
||||
current -= step;
|
||||
if (current < step){
|
||||
current = step;
|
||||
idmRangeMinAlert(step)
|
||||
}
|
||||
}
|
||||
input.value = current.toFixed(precision);
|
||||
}
|
||||
function idmQuantityInputChange(e){
|
||||
if(e.target.value > +e.target.max){
|
||||
idmRangeMaxAlert(e.target.max)
|
||||
e.target.value = +e.target.max
|
||||
}
|
||||
if(e.target.value < +e.target.min){
|
||||
idmRangeMinAlert(e.target.min)
|
||||
e.target.value = +e.target.min;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// DANE
|
||||
// dwie funkcje zamiast jednej
|
||||
async function idmGetHotspotData(query, graphFn){
|
||||
try{
|
||||
const res = await fetch(`/graphql/v1/`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: graphFn ? graphFn(query) : IDM_PRODUCTS_GQL(query)
|
||||
});
|
||||
const data = await res.json();
|
||||
const products = graphFn === IDM_HOTSPOTS_GQL ? data?.data?.hotspots?.products : data?.data?.products?.products;
|
||||
if(!products || !products.length) throw new Error(idmHotspotTextObject["Nie znaleziono produktów"]);
|
||||
|
||||
console.log(data);
|
||||
return products;
|
||||
}catch(err){
|
||||
console.error(idmHotspotTextObject["Błąd przy pobieraniu danych"], err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function idmGetQueryData({
|
||||
productsID,
|
||||
productsMenu,
|
||||
hotspotsType
|
||||
}){
|
||||
let graphFn, query;
|
||||
|
||||
if(productsID){
|
||||
graphFn = IDM_PRODUCTS_GQL;
|
||||
query = `searchInput: {productsId: [${productsID}]}`;
|
||||
}else if(productsMenu){
|
||||
graphFn = IDM_PRODUCTS_GQL;
|
||||
query = `searchInput: {navigation: ${productsMenu}}`;
|
||||
}else if(hotspotsType){
|
||||
graphFn = IDM_HOTSPOTS_GQL;
|
||||
query = `searchInput: {hotspot: ${hotspotsType}, limit: 16}`;
|
||||
}
|
||||
|
||||
return {graphFn, query}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// LAZY LOADING
|
||||
function idmObserveOnce(element, callback, options = { root: null, rootMargin: "0px", threshold: 0.1 }) {
|
||||
if (!element) return;
|
||||
|
||||
const observer = new IntersectionObserver((entries, obs) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
callback(entry); // run your callback
|
||||
obs.disconnect(); // stop observing after first trigger
|
||||
}
|
||||
});
|
||||
}, options);
|
||||
|
||||
observer.observe(element);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// IDM SET HEIGHT
|
||||
app_shop.fn.idmSetHeight = options => {
|
||||
const { selector, selectors, container } = options || {}
|
||||
if ((!selector && !selectors) || !container) return
|
||||
|
||||
const containerElement = document.querySelector(container)
|
||||
if (!containerElement) return
|
||||
|
||||
const adjustAllHeights = itemSelector => {
|
||||
const targets = containerElement.querySelectorAll(itemSelector)
|
||||
if (!targets.length) return
|
||||
|
||||
targets.forEach(el => (el.style.minHeight = ''))
|
||||
|
||||
const max = Math.max(...[...targets].map(el => el.offsetHeight || 0))
|
||||
|
||||
targets.forEach(el => (el.style.minHeight = `${max}px`))
|
||||
}
|
||||
|
||||
if (selector) adjustAllHeights(selector)
|
||||
if (selectors?.length) selectors.forEach(adjustAllHeights)
|
||||
}
|
||||
147
sklad/3markup.js
147
sklad/3markup.js
@@ -1,147 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Markup
|
||||
|
||||
// Funkcja przygotująca markup dla wszystkich produktów
|
||||
function idmPrepareProductsMarkup(products, addToBasket){
|
||||
let markup = "";
|
||||
products.forEach((prod)=>{
|
||||
markup += idmPrepareSingleProductMarkup(prod, addToBasket);
|
||||
})
|
||||
return markup;
|
||||
}
|
||||
|
||||
// funkcja przygotowująca markup dla wybranego produktu
|
||||
function idmPrepareSingleProductMarkup(prod, addToBasket){
|
||||
const prodExchangedData = app_shop.fn?.idmGetOmnibusDetails({productData: prod});
|
||||
|
||||
// pobranie labelek
|
||||
let labelHTMLMarkup = "";
|
||||
if(typeof prodExchangedData.activeLabel === "object") Object.entries(prodExchangedData.activeLabel).forEach(([key,value])=>{
|
||||
labelHTMLMarkup += value;
|
||||
})
|
||||
|
||||
// markup pojedynczego produktu
|
||||
let singleMarkup = "";
|
||||
singleMarkup += `
|
||||
<div class="product hotspot__product swiper-slide d-flex flex-column ${prod.price.price[idmPriceType].value === 0 ? "--phone" : ""}" data-id="${prod.id}">
|
||||
<div class="product__yousave --hidden">
|
||||
<span class="product__yousave --label"></span>
|
||||
<span class="product__yousave --value"></span>
|
||||
</div>
|
||||
<a class="product__icon d-flex justify-content-center align-items-center" tabindex="-1" href="${prod.link}">
|
||||
${idmPrepareHotspotImgMarkup(prod)}
|
||||
<strong class="label_icons">
|
||||
${labelHTMLMarkup}
|
||||
</strong>
|
||||
</a>
|
||||
<div class="product__content_wrapper">
|
||||
<a class="product__name" tabindex="0" href="${prod.link}" title="${prod.name}">${prod.name}</a>
|
||||
<div class="product__prices mb-auto ${prodExchangedData?.classes?.add?.reduce((acc,val) => acc + " " + val,"")}">
|
||||
${idmPrepareHotspotPriceMarkup(prod, prodExchangedData)}
|
||||
</div>
|
||||
</div>
|
||||
${idmPrepareHotspotAddToBasketMarkup(prod, addToBasket)}
|
||||
</div>`;
|
||||
|
||||
return singleMarkup;
|
||||
}
|
||||
|
||||
// markup zdjęcia
|
||||
function idmPrepareHotspotImgMarkup(prod){
|
||||
let markup = "";
|
||||
if(prod.iconSmallSecond !== undefined && prod.iconSecond !== undefined) markup +=`<picture>
|
||||
<source media="(min-width: 421px)" type="image/webp" srcset="${prod.icon}"/>
|
||||
<source media="(min-width: 421px)" type="image/jpeg" srcset="${prod.iconSecond}"/>
|
||||
<source media="(max-width: 420px)" type="image/webp" srcset="${prod.iconSmall}"/>
|
||||
<source media="(max-width: 420px)" type="image/jpeg" srcset="${prod.iconSmallSecond}"/>
|
||||
<img src="${prod.iconSecond}" loading="lazy" alt="${prod.name}">
|
||||
</picture>`;
|
||||
else if(prod?.iconSmall !== undefined) markup += `<picture>
|
||||
<source media="(min-width: 421px)" srcset="${prod.icon}"/>
|
||||
<source media="(max-width: 420px)" srcset="${prod.iconSmall}"/>
|
||||
<img src="${prod.iconSecond}" loading="lazy" alt="${prod.name}">
|
||||
</picture>`;
|
||||
else markup += `<img src="${prod.icon}" loading="lazy" alt="${prod.name}">`
|
||||
return markup;
|
||||
}
|
||||
|
||||
// markup cen
|
||||
function idmPrepareHotspotPriceMarkup(prod, prodExchangedData){
|
||||
const price = prod.price.price[idmPriceType];
|
||||
const unit = prod.unit;
|
||||
const pointsPrice = prod?.points;
|
||||
const convertedPrice = prod.price?.unitConvertedPrice?.[idmPriceType]?.formatted;
|
||||
|
||||
return `
|
||||
<strong class="price --normal --main ${price.value === 0 ? "--hidden" : ""}">
|
||||
<span class="price__sub">${price.formatted}</span>
|
||||
<span class="price_sellby">
|
||||
<span class="price_sellby__sep">/</span>
|
||||
<span class="price_sellby__sellby" data-sellby="${unit?.sellBy}">${unit?.sellBy}</span>
|
||||
<span class="price_sellby__unit">${unit?.sellBy > 1 ? unit?.plural : unit?.singular}</span>
|
||||
</span>
|
||||
${convertedPrice ? `<span class="price --convert">${convertedPrice}</span>` : ""}
|
||||
</strong>
|
||||
${pointsPrice ? `<span class="price --points">${pointsPrice} pkt.</span>` : ""}
|
||||
${price.value === 0 ? `<a class="price --phone" href="/contact.php" tabindex="-1" title="${idmHotspotTextObject["Kliknij, by przejść do formularza kontaktu"]}">${idmHotspotTextObject["Cena na telefon"]}</a>` : ""}
|
||||
${prodExchangedData?.beforeRebate?.visible ? `<span class="price --before-rebate">${prodExchangedData?.beforeRebate?.html}</span>` : ""}
|
||||
${prodExchangedData?.newPriceEffectiveUntil?.visible ? `<span class="price --new-price new_price">${prodExchangedData?.newPriceEffectiveUntil?.html}</span>` : ""}
|
||||
${prodExchangedData?.omnibus?.visible ? `<span class="price --omnibus omnibus_price">${prodExchangedData?.omnibus?.html}</span>` : ""}
|
||||
${prodExchangedData?.max?.visible ? `<span class="price --max">${prodExchangedData?.max?.html}</span>` : ""}
|
||||
`;
|
||||
}
|
||||
|
||||
// markup dodawania do koszyka
|
||||
function idmPrepareHotspotAddToBasketMarkup(prod, addToBasket){
|
||||
let markup = "";
|
||||
if(!addToBasket && typeof addToBasket !== "undefined" ||
|
||||
(typeof addToBasket === "undefined" && typeof idmGeneralHotspotObjData === "object" && !idmGeneralHotspotObjData?.options?.addToBasket) ||
|
||||
!addToBasket && typeof idmGeneralHotspotObjData === "undefined") return markup;
|
||||
|
||||
// link do produktu jak nie jest to zwykły produkt
|
||||
if(prod.type !== "product") markup = `<a class="btn --solid --medium add_to_basket__link" href="${prod.href}">Zobacz produkt</a>`;
|
||||
else if(addToBasket === "range"
|
||||
|| typeof addToBasket === "undefined" && typeof idmGeneralHotspotObjData === "object" && idmGeneralHotspotObjData?.options?.addToBasket === "range") // +-
|
||||
markup = `<form class="add_to_basket --range" action="/basketchange.php" type="post" onsubmit="idmHandleAddToBasket(event)">
|
||||
<input name="mode" type="hidden" value="1">
|
||||
<input name="product" type="hidden" value="${prod.id}">
|
||||
<input name="size" type="hidden" value="${prod.sizes[0].id}">
|
||||
<div class="idm-products-banner__qty"
|
||||
data-sell-by="${prod.unit?.sellBy}"
|
||||
data-precision="${prod.unit?.precision}"
|
||||
data-max="${prod.sizes[0].amount === -1 ? 999999 : prod.sizes[0].amount}"
|
||||
onclick="idmQuantityButtonClick(event)"
|
||||
>
|
||||
<button type="button" class="idm-products-banner__qty-decrease" aria-label="${idmHotspotTextObject["Zmniejsz ilość"]}">−</button>
|
||||
|
||||
<input type="number"
|
||||
name="number"
|
||||
class="idm-products-banner__qty-input"
|
||||
value="${prod.unit?.sellBy}"
|
||||
step="${prod.unit?.sellBy}"
|
||||
min="${prod.unit?.sellBy}"
|
||||
max="${prod.sizes[0].amount === -1 ? 999999 : prod.sizes[0].amount}"
|
||||
aria-label="${idmHotspotTextObject["Ilość"]}"
|
||||
oninput="idmQuantityInputChange(event)"
|
||||
>
|
||||
|
||||
<button type="button" class="idm-products-banner__qty-increase" aria-label="${idmHotspotTextObject["Zwiększ ilość"]}">+</button>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn --solid --medium add_to_basket__button" tabindex="0" data-success="${idmHotspotTextObject["Dodany"]}" data-error="${idmHotspotTextObject["Wystąpił błąd"]}" data-text="${idmHotspotTextObject["Do koszyka"]}">
|
||||
<span>${idmHotspotTextObject["Do koszyka"]}</span>
|
||||
</button>
|
||||
</form>`;
|
||||
else // Zwykłe dodanie do koszyka
|
||||
markup = `
|
||||
<form class="add_to_basket" action="/basketchange.php" type="post" onsubmit="idmHandleAddToBasket(event)">
|
||||
<input name="mode" type="hidden" value="1">
|
||||
<input name="product" type="hidden" value="${prod.id}">
|
||||
<input name="size" type="hidden" value="${prod.sizes[0].id}">
|
||||
<input name="number" type="hidden" value="${prod.unit?.sellBy}">
|
||||
<button type="submit" class="btn --solid --medium add_to_basket__button" tabindex="0" data-success="${idmHotspotTextObject["Dodany"]}" data-error="${idmHotspotTextObject["Wystąpił błąd"]}" data-text="${idmHotspotTextObject["Do koszyka"]}">
|
||||
<span>${idmHotspotTextObject["Do koszyka"]}</span>
|
||||
</button>
|
||||
</form>`;
|
||||
return markup;
|
||||
}
|
||||
167
sklad/4init.js
167
sklad/4init.js
@@ -1,167 +0,0 @@
|
||||
////////////////////////////////////////////////////
|
||||
// INIT
|
||||
|
||||
// brutto/netto
|
||||
const idmPriceType = app_shop?.vars?.priceType || "gross";
|
||||
|
||||
|
||||
// Zmienna trzymająca dane o ustawieniach customowych ramek rekomendacji na całym sklepie
|
||||
/**
|
||||
* Obiekt konfiguracyjny ogólnych ustawień hotspotów rekomendacji.
|
||||
*
|
||||
* @typedef {object} idmGeneralHotspotObjData
|
||||
* @property {object} options - Główne ustawienia hotspotów
|
||||
* @property {boolean} options.lazy - Czy wczytywać zawartość w trybie lazy (required).
|
||||
* @property {boolean|string} options.addToBasket - Zachowanie przy dodawaniu do koszyka:
|
||||
* - true = przycisk dodaj do koszyka
|
||||
* - false = brak przycisku
|
||||
* - "range" = dodaj z wyborem zakresu (required).
|
||||
* @property {boolean|object} options.swiper - Ustawienia slidera:
|
||||
* - true/false = włącz/wyłącz
|
||||
* - object = konfiguracja instancji Swiper (required jeśli obiekt).
|
||||
*/
|
||||
const idmGeneralHotspotObjData = {
|
||||
options: {
|
||||
lazy: true,
|
||||
addToBasket: true, // true, false, "range"
|
||||
swiper: { // true, false, obiekt z opcjami swipera
|
||||
loop: false,
|
||||
autoHeight: false,
|
||||
spaceBetween: 16,
|
||||
slidesPerView: 1.4,
|
||||
centeredSlides: true,
|
||||
centeredSlidesBounds: true,
|
||||
breakpoints: {
|
||||
550: {
|
||||
slidesPerView: 3,
|
||||
centeredSlides: true,
|
||||
centeredSlidesBounds: true,
|
||||
},
|
||||
979: {
|
||||
slidesPerView: 4,
|
||||
centeredSlides: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Funkcja inicjalizująca wybranego hotspota(addtobasket range - swiper)
|
||||
async function idmHotspotInit(id, options={}){
|
||||
try{
|
||||
const hotspotEl = document.getElementById(id);
|
||||
if(!hotspotEl) throw new Error("Nie znaleziono elementu");
|
||||
|
||||
// add to basket + -
|
||||
if(options?.addToBasket === "range" ||
|
||||
typeof options?.addToBasket === "undefined" && typeof idmGeneralHotspotObjData === "object" && idmGeneralHotspotObjData?.options?.addToBasket === "range"){
|
||||
|
||||
// obsługa i sprawdzanie clicków
|
||||
// hotspotEl.addEventListener("click", e=>{
|
||||
// const wrapper = e.target.closest(".idm-products-banner__qty");
|
||||
// if (!wrapper) return;
|
||||
|
||||
// if(e.target.classList.contains("idm-products-banner__qty-input")) return e.target.select();
|
||||
|
||||
// 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;
|
||||
// rangeMaxAlert(max)
|
||||
// }
|
||||
// } else if (e.target.classList.contains("idm-products-banner__qty-decrease")) {
|
||||
// current -= step;
|
||||
// if (current < step){
|
||||
// current = step;
|
||||
// rangeMinAlert(step)
|
||||
// }
|
||||
// }
|
||||
// input.value = current.toFixed(precision);
|
||||
// });
|
||||
// sprawdzanie na input
|
||||
// hotspotEl.querySelectorAll(".idm-products-banner__qty-input").forEach(inp=>{
|
||||
// inp.addEventListener("input", e=>{
|
||||
// if(e.target.value > +e.target.max){
|
||||
// rangeMaxAlert(e.target.max)
|
||||
// e.target.value = +e.target.max
|
||||
// }
|
||||
// if(e.target.value < +e.target.min){
|
||||
// rangeMinAlert(e.target.min)
|
||||
// e.target.value = +e.target.min;
|
||||
// }
|
||||
// });
|
||||
// })
|
||||
|
||||
}
|
||||
|
||||
// swiper || slick
|
||||
if(options?.swiper ||
|
||||
typeof options?.swiper === "undefined" && typeof idmGeneralHotspotObjData === "object" && idmGeneralHotspotObjData?.options?.swiper){
|
||||
|
||||
|
||||
// Opcje swipera
|
||||
let swiperOptions = typeof options.swiper === "object" ? options.swiper : "";
|
||||
if(typeof options.swiper === "object") swiperOptions = options.swiper;
|
||||
else if(typeof idmGeneralHotspotObjData === "object" && typeof idmGeneralHotspotObjData?.options?.swiper === "object"){
|
||||
swiperOptions = idmGeneralHotspotObjData?.options?.swiper;
|
||||
swiperOptions.navigation = {
|
||||
nextEl: `#${id} .idm-button-next`,
|
||||
prevEl: `#${id} .idm-button-prev`,
|
||||
}
|
||||
}else{
|
||||
swiperOptions = {
|
||||
loop: false,
|
||||
autoHeight: false,
|
||||
spaceBetween: 16,
|
||||
slidesPerView: 1.4,
|
||||
centeredSlides: true,
|
||||
centeredSlidesBounds: true,
|
||||
breakpoints: {
|
||||
550: {
|
||||
slidesPerView: 3,
|
||||
centeredSlides: true,
|
||||
centeredSlidesBounds: true,
|
||||
},
|
||||
979: {
|
||||
slidesPerView: 4,
|
||||
centeredSlides: false,
|
||||
},
|
||||
},
|
||||
navigation: {
|
||||
nextEl: `#${id} .idm-button-next`,
|
||||
prevEl: `#${id} .idm-button-prev`,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Wywołanie swipera
|
||||
const selectedSwiper = new HotspotSlider({
|
||||
selector: `#${id} .swiper`,
|
||||
hotspotName: `${id}`,
|
||||
options: swiperOptions,
|
||||
});
|
||||
await selectedSwiper.init();
|
||||
}
|
||||
|
||||
|
||||
if(typeof options?.callbackFn === "function") options?.callbackFn();
|
||||
|
||||
// IDM setHeight
|
||||
app_shop.fn.idmSetHeight({
|
||||
selectors: [
|
||||
`#${id} .product__prices`,
|
||||
`#${id} .product__name`,
|
||||
],
|
||||
container: `#${id} .products__wrapper`,
|
||||
});
|
||||
console.log(`Initialized hotspot #${id}`);
|
||||
}catch(err){
|
||||
console.error(idmHotspotTextObject["Wystąpił błąd z inicjalizacją. Proszę odśwież stronę"], err);
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Funkcja init ELEMENT HTML
|
||||
async function idmInsertHotspotElement(selectedContainerEl){
|
||||
|
||||
selectedContainerEl.classList.add("--init");
|
||||
const {graphFn, query} = idmGetQueryData({
|
||||
productsID: selectedContainerEl?.dataset?.productsId,
|
||||
productsMenu: selectedContainerEl?.dataset?.productsMenu,
|
||||
hotspotsType: selectedContainerEl.dataset.hotspotsType
|
||||
});
|
||||
|
||||
if(!graphFn || !query){
|
||||
console.log(idmHotspotTextObject["Nie znaleziono metody graphql"], selectedContainerEl)
|
||||
return selectedContainerEl.remove();
|
||||
}
|
||||
|
||||
// Funkcja od uzupełniania danych
|
||||
const idmFill = async ()=>{
|
||||
try{
|
||||
// pobranie danych o produktach
|
||||
const products = await idmGetHotspotData(query, graphFn);
|
||||
if(!products) throw new Error(idmHotspotTextObject["Nie znaleziono produktów"]);
|
||||
|
||||
|
||||
// wstawienie produktów zależnie czy w section jest .hotspot czy nie
|
||||
const hotspotInsideEl = selectedContainerEl.querySelector(".hotspot");
|
||||
if(hotspotInsideEl) hotspotInsideEl.innerHTML += `<div class="products__wrapper swiper">
|
||||
<div class="products hotspot__products swiper-wrapper">
|
||||
${idmPrepareProductsMarkup(products, true)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-button-prev --rounded --edge idm-button-prev"><i class="icon-angle-left"></i></div>
|
||||
<div class="swiper-button-next --rounded --edge idm-button-next"><i class="icon-angle-right"></i></div>
|
||||
<div class="swiper-pagination"></div>`;
|
||||
else selectedContainerEl.innerHTML = `<div class="hotspot --initialized"><div class="products__wrapper swiper">
|
||||
<div class="products hotspot__products swiper-wrapper">
|
||||
${idmPrepareProductsMarkup(products, true)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-button-prev --rounded --edge idm-button-prev"><i class="icon-angle-left"></i></div>
|
||||
<div class="swiper-button-next --rounded --edge idm-button-next"><i class="icon-angle-right"></i></div>
|
||||
<div class="swiper-pagination"></div></div>`;
|
||||
|
||||
selectedContainerEl.classList.remove("idm-loading")
|
||||
// init swipera
|
||||
idmHotspotInit(selectedContainerEl.id)
|
||||
}catch(err){
|
||||
console.error(idmHotspotTextObject["Wystąpił błąd"], err);
|
||||
selectedContainerEl.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(selectedContainerEl.dataset?.lazy ||
|
||||
!selectedContainerEl.dataset?.lazy && typeof idmGeneralHotspotObjData === "object" && idmGeneralHotspotObjData?.options?.lazy) idmObserveOnce(selectedContainerEl, idmFill);
|
||||
else idmFill();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Zebranie wszystkich ramek HTML i wstawienie ich.
|
||||
async function idmInsertAllHTMLHotspots(){
|
||||
try{
|
||||
const reqArr = []
|
||||
document.querySelectorAll(".idm__hotspot:not(.--init):not(.--lazy-hotspot)").forEach(hotspot=>{
|
||||
reqArr.push(idmInsertHotspotElement(hotspot));
|
||||
});
|
||||
await Promise.all(reqArr);
|
||||
}catch(err){
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
idmInsertAllHTMLHotspots();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// wdrożenie dla elementu HTML
|
||||
/**
|
||||
* Struktura sekcji hotspotu w HTML.
|
||||
*
|
||||
* @typedef {HTMLElement} HotspotSection
|
||||
* @property {string} id - Identyfikator elementu (np. "idmBlogHotspot1").
|
||||
* @property {string} class - Klasy CSS używane do stylowania.
|
||||
*
|
||||
* @attribute {string} data-products-id - Lista ID produktów (rozdzielona przecinkami).
|
||||
* @attribute {number} data-products-menu - Identyfikator menu produktów.
|
||||
* @attribute {string} data-hotspots-type - Typ hotspotu (np. "promotion").
|
||||
* @attribute {boolean} data-lazy - Czy sekcja ma być ładowana w trybie lazy.
|
||||
*
|
||||
* @example
|
||||
<section id="idmBlogHotspot1"
|
||||
class="hotspot__wrapper idm__hotspot idm-loading"
|
||||
data-products-id="589,180,181590"
|
||||
data-products-menu="122"
|
||||
data-hotspots-type="promotion"
|
||||
data-lazy="true"
|
||||
>
|
||||
<div class="hotspot --initialized">
|
||||
<h3 class="hotspot__name headline__wrapper">
|
||||
<span class="headline">
|
||||
<span class="headline__name" aria-label="aaa">aaa</span>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
</section>
|
||||
*/
|
||||
@@ -1,167 +0,0 @@
|
||||
////////////////////////////////////////////////////
|
||||
// Funkcja init OBIEKT JS
|
||||
async function idmInsertHotspotObject(idmHotspotObj){
|
||||
// Wstaw kontener
|
||||
const selectedEl = document.querySelector(idmHotspotObj?.placement.selector);
|
||||
if(!selectedEl) throw new Error(idmHotspotTextObject["Nie znaleziono kontenera"]);
|
||||
|
||||
selectedEl.insertAdjacentHTML(idmHotspotObj.placement.insert || "afterend", `<section id="${idmHotspotObj.id}" class="hotspot__wrapper idm__hotspot --init idm-loading ${idmHotspotObj?.classes}">
|
||||
<div class="hotspot --initialized">
|
||||
${idmHotspotObj?.title ? `
|
||||
<h3 class="hotspot__name headline__wrapper">
|
||||
<span class="headline"><span class="headline__name" aria-label="${idmHotspotObj.title}">${idmHotspotObj.title}</span></span>
|
||||
</h3>
|
||||
` : ""}
|
||||
<div class="products__wrapper swiper">
|
||||
<div class="products hotspot__products swiper-wrapper">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-button-prev --rounded --edge idm-button-prev"><i class="icon-angle-left"></i></div>
|
||||
<div class="swiper-button-next --rounded --edge idm-button-next"><i class="icon-angle-right"></i></div>
|
||||
<div class="swiper-pagination"></div>
|
||||
</div>
|
||||
</section>`);
|
||||
|
||||
|
||||
// Utworzenie markupa HTML
|
||||
const selectedContainerEl = document.getElementById(idmHotspotObj.id);
|
||||
if(!selectedContainerEl) throw new Error(idmHotspotTextObject["Nie znaleziono kontenera"]);
|
||||
|
||||
const idmFill = async ()=>{
|
||||
try{
|
||||
let {graphFn, query} = idmGetQueryData({
|
||||
productsID: idmHotspotObj?.source?.productsId,
|
||||
productsMenu: idmHotspotObj?.source?.productsMenu,
|
||||
hotspotsType: idmHotspotObj?.source?.hotspotsType
|
||||
});
|
||||
|
||||
if(idmHotspotObj?.query?.graphFn && idmHotspotObj?.query?.string){
|
||||
graphFn = idmHotspotObj.query.graphFn;
|
||||
query = idmHotspotObj.query.string;
|
||||
}
|
||||
|
||||
// pobranie danych o produktach
|
||||
const products = await idmGetHotspotData(query, graphFn);
|
||||
if(!products) throw new Error(idmHotspotTextObject["Nie znaleziono produktów"]);
|
||||
|
||||
|
||||
// Wstawienie markupa na strone
|
||||
const hotspotMarkup = `${idmPrepareProductsMarkup(products, idmHotspotObj?.options?.addToBasket)}`;
|
||||
selectedContainerEl.querySelector(".products.hotspot__products")?.insertAdjacentHTML("beforeend", hotspotMarkup);
|
||||
selectedContainerEl.classList.remove("idm-loading");
|
||||
|
||||
// init swiper + add to basket
|
||||
idmHotspotInit(idmHotspotObj.id, idmHotspotObj?.options)
|
||||
}catch(err){
|
||||
console.error(idmHotspotTextObject["Wystąpił błąd"], err);
|
||||
selectedContainerEl.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(idmHotspotObj?.options?.lazy ||
|
||||
typeof idmHotspotObj?.options?.lazy === "undefined" && typeof idmGeneralHotspotObjData === "object" && idmGeneralHotspotObjData?.options?.lazy) idmObserveOnce(selectedContainerEl, idmFill);
|
||||
else idmFill();
|
||||
}
|
||||
|
||||
|
||||
// obiekt js z przykładowymi danymi
|
||||
/**
|
||||
* Tablica konfiguracji hotspotów rekomendacji.
|
||||
*
|
||||
* @typedef {object} Hotspot
|
||||
* @property {string} id - Identyfikator ramki (required).
|
||||
* @property {string} title - Tytuł ramki.
|
||||
* @property {string} classes - Dodatkowe klasy CSS.
|
||||
* @property {object} placement - Określa, gdzie wstawić ramkę (required).
|
||||
* @property {string} placement.selector - Selektor miejsca osadzenia.
|
||||
* @property {string} placement.insert - Pozycja wstawienia względem selektora (np. "afterbegin", "beforeend").
|
||||
* @property {object} source - Dane źródłowe dla hotspotu (required).
|
||||
* @property {string} [source.hotspotType] - Typ hotspotu (np. "promotion").
|
||||
* @property {number[]} [source.productsId] - Tablica ID produktów.
|
||||
* @property {number} [source.productsMenu] - Identyfikator menu produktów.
|
||||
* @property {object} query - Dane zapytania, nadpisują source (DEV).
|
||||
* @property {string} query.string - Zapytanie w formacie GraphQL.
|
||||
* @property {Function} query.graphFn - Funkcja do pobierania danych.
|
||||
* @property {object} options - Ustawienia dla hotspotu (required).
|
||||
* @property {boolean} options.lazy - Czy wczytywać w trybie lazy.
|
||||
* @property {boolean|string} options.addToBasket - Obsługa koszyka:
|
||||
* - true = włącz
|
||||
* - false = wyłącz
|
||||
* - "range" = dodaj z zakresem
|
||||
* @property {boolean|object} options.swiper - Slider:
|
||||
* - true = aktywny
|
||||
* - false = nieaktywny
|
||||
* - object = konfiguracja Swiper
|
||||
* @property {Function} options.callbackFn - Funkcja callback która dzieje się po wywołaniu wszystkiego włącznie ze swiperem
|
||||
*
|
||||
* @type {Hotspot[]}
|
||||
*/
|
||||
// const idmHotspotArr = [
|
||||
// {
|
||||
// id: "idmMainHotspot1",//!id ramki
|
||||
// title: "Nowoczesna ramka rekomendacji",//
|
||||
// classes: "abcdefg",
|
||||
// placement: {
|
||||
// selector: "#content",
|
||||
// insert: "afterbegin"
|
||||
// },
|
||||
// source: {
|
||||
// hotspotType: "protomtion",
|
||||
// productsId: [11,12],
|
||||
// productsMenu: 122,
|
||||
// },
|
||||
// query: {
|
||||
// string: `searchInput: {productsId : [589, 180, 181590,160740, 155978, 153632, 123350, 82542, 37321, 17040, 25065, 25114, 85452]}`,
|
||||
// graphFn: IDM_PRODUCTS_GQL
|
||||
// },
|
||||
// // addToBasket: true,
|
||||
// options: {
|
||||
// lazy: false,
|
||||
// addToBasket: "range",
|
||||
// swiper: true,
|
||||
// callbackFn: ()=>{console.log("test")}
|
||||
// // swiper: albo true false - albo obiekt z opcjami swipera
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// id: "idmMainHotspot2",
|
||||
// title: "Super ramka rekomendacji",
|
||||
// placement: {
|
||||
// selector: "#content",
|
||||
// insert: "beforeend"
|
||||
// },
|
||||
// source: {
|
||||
// productsMenu: 488,
|
||||
// },
|
||||
// query: {
|
||||
// string: `searchInput: {hotspot: promotion,limit: 16}`,
|
||||
// graphFn: IDM_HOTSPOTS_GQL
|
||||
// },
|
||||
// // addToBasket: true,
|
||||
// options: {
|
||||
// lazy: true,
|
||||
// addToBasket: "range",
|
||||
// swiper: true,
|
||||
// // swiper: albo true false - albo obiekt z opcjami swipera
|
||||
// }
|
||||
// }
|
||||
// ];
|
||||
|
||||
|
||||
// Wrzucenie na strone wszystkich ramek z obiektu js
|
||||
async function idmInsertAllObjectHotspots(hotspotArr){
|
||||
try{
|
||||
const reqArr = []
|
||||
hotspotArr.forEach(hotspotObj=>{
|
||||
reqArr.push(idmInsertHotspotObject(hotspotObj));
|
||||
});
|
||||
await Promise.all(reqArr);
|
||||
}catch(err){
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// idmInsertAllObjectHotspots(idmHotspotArr);
|
||||
Reference in New Issue
Block a user