Files
newwalls.pl/themes/ayon/templates/catalog/product.tpl
Jacek Pyziak 7ac795ba3f feat(new-layout): add-to-cart handler + piece configurator (Phase 02 plans 01-02)
Plan 02-01 (piece/crop configurator, complete):
- #piece reuse z shared partial product-cover-thumbnails.tpl
- 8 hidden inputs (is_crop, crop_pos_x/y, crop_width/height, piece_bg_top/left, is_reflection) w formie #add-to-cart-or-refresh
- Defensive setup w custom.js: setTimeout(600) init, no-op override totalpriceinfospecific/prod, DOM stubs
- CSS scope pod body#product .product-size-data .product-size-data--new

Plan 02-02 (add-to-cart submission, PARTIAL):
- Capture-phase native addEventListener (useCapture=true) blokuje PS core crash
  (button poza formą w nowym layoucie — closest('form') zwracało 0)
- Manualny AJAX POST: form.serialize() + qty + add=1&action=update do /pl/koszyk
- Fancybox-blocker port z custom.js:327 (nie odpalał się bo selector 0 matches)
- Manual sync is_crop/crop_width/height przed POST (obejście crash checkedHandler)
- prestashop.emit('updatedCart') + defensive blockcart refresh fetch
- Loading spinner + success flash CSS
- Inline handler mirror w product.tpl z idempotency guard (window.__p02p02Bound)
  — cache-buster dla browser cachowanego custom.js

Deferred do Plan 02-03 (customization + modal blocker dla production):
- Customization nie zapisuje się (squaremeter hook gate'owany discretion=on + brak dimension fields)
- Success modal (wymaga POST do /module/ps_shoppingcart/ajax)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 23:33:45 +02:00

861 lines
37 KiB
Smarty

{**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*}
{extends file=$layout}
{assign var="pl_manufacturer" value=Manufacturer::getNameById($product.id_manufacturer)}
{block name='head_seo' prepend}
<link rel="canonical" href="{$product.canonical_url}">
{/block}
{block name='head' append}
<meta property="og:type" content="product">
<meta property="og:url" content="{$urls.current_url}">
<meta property="og:title" content="{$page.meta.title}">
<meta property="og:site_name" content="{$shop.name}">
<meta property="og:description" content="{$page.meta.description}">
<meta property="og:image" content="{$product.cover.large.url}">
{if $product.show_price}
<meta property="product:pretax_price:amount" content="{$product.price_tax_exc}">
<meta property="product:pretax_price:currency" content="{$currency.iso_code}">
<meta property="product:price:amount" content="{$product.price_amount}">
<meta property="product:price:currency" content="{$currency.iso_code}">
{/if}
{if isset($product.weight) && ($product.weight != 0)}
<meta property="product:weight:value" content="{$product.weight}">
<meta property="product:weight:units" content="{$product.weight_unit}">
{/if}
{/block}
{if $smarty.server.REMOTE_ADDR != '89.69.31.86'}
{block name='content'}
<section id="main" itemscope itemtype="https://schema.org/Product">
<meta itemprop="url" content="{$product.url}">
<meta itemprop="gtin13" content="{$product.ean13}" />
<meta itemprop="brand" content="{if isset($pl_manufacturer)}{$pl_manufacturer}{else}{$shop.name}{/if}" />
{if isset($product.isbn)}<meta itemprop="productID" content="{$product.isbn}">{/if}
<div class="container">
{if isset($roythemes.b_pos_pro) && $roythemes.b_pos_pro == "2"}
{block name='breadcrumb'}
{include file='_partials/breadcrumb.tpl'}
{/block}
{/if}
{block name='page_header_container'}
{block name='page_header'}
<h1 class="h1 product-title" itemprop="name">{block name='page_title'}{$product.name}{/block}</h1>
{hook h='displayProductNav' product=$product}
{/block}
{/block}
<div class="product-block-prices">
{block name='product_discounts'}
{include file='catalog/_partials/product-discounts.tpl'}
{/block}
{if isset($roythemes.nc_pp_con) && $roythemes.nc_pp_con == "1"}
{block name='product_prices'}
{include file='catalog/_partials/product-prices.tpl'}
{/block}
{/if}
</div>
{$last_img = Product::getProductImages($product.link_rewrite,$product.id, $this->context)}
<!--
{$attrs = $product.attributes}
{foreach from=$attrs item=elem key=key}
{$elem.id_attribute}
{/foreach}
-->
<div class="product-top-banner">
<img src="{$last_img}" width="100" itemprop="image" draggable="false">
</div>
<div class="row {if isset($roythemes.pp_sticky) && $roythemes.pp_sticky == "1"}pp_stick_parent{/if}">
<div class="col-lg-6 col-image">
{block name='page_content_container'}
<section class="col-image-inside">
{block name='page_content'}
{block name='product_flags'}
<ul class="product-flags">
{foreach from=$product.flags item=flag}
<li class="product-flag {$flag.type}">{$flag.label}</li>
{/foreach}
</ul>
{/block}
<div class="product_image_wrapper">
{block name='product_cover_thumbnails'}
{include file='catalog/_partials/product-cover-thumbnails.tpl'}
{/block}
</div>
{/block}
</section>
{/block}
</div>
<div class="col-lg-6 col-content">
<div class="col-content-inside {if isset($roythemes.pp_sticky) && $roythemes.pp_sticky == "1"}pp_stick_it{/if}">
{if isset($nb_comments) && $nb_comments > 0}
<div class="comments-note">
{include file='module:productcomments/views/templates/hook/average-grade-stars.tpl' grade=$average_grade}
<a class="nb-comments noeffect goreviews" href="#tabsection"><span itemprop="reviewCount">{l s='%s'|sprintf:$nbComments mod='productcomments'}</span> {if isset($nbComments) && $nbComments == 1}{l s='Review'}{else}{l s='Reviews'}{/if}</a>
<div itemprop="aggregateRating" itemtype="http://schema.org/AggregateRating" itemscope>
<meta itemprop="reviewCount" content="{$nb_comments}" />
<meta itemprop="ratingValue" content="{$average_grade}" />
</div>
</div>
{/if}
{widget name='productcomments' hook='displayProductExtraContent'}
<div class="product-information">
{if $product.is_customizable && count($product.customizations.fields)}
{block name='product_customization'}
{include file="catalog/_partials/product-customization.tpl" customizations=$product.customizations}
{/block}
{/if}
{if isset($roythemes.nc_pp_con) && $roythemes.nc_pp_con == "2"}
{block name='product_additional_info'}
{include file='catalog/_partials/product-additional-info.tpl'}
{/block}
{/if}
{if isset($roythemes.nc_pp_con) && ($roythemes.nc_pp_con == "2" || $roythemes.nc_pp_con == "3")}
{block name='product_prices'}
{include file='catalog/_partials/product-prices.tpl'}
{/block}
{/if}
</div>
</div>
</div>
</div>
<div class="product-actions">{block name='product_buy'}{*<div id="zapisz">ZAPISZ</div> *}
<form action="{$urls.pages.cart}" method="post" id="add-to-cart-or-refresh">
<input type="hidden" name="token" value="{$static_token}">
<input type="hidden" name="id_product" value="{$product.id}" id="product_page_product_id">
<input type="hidden" name="id_customization" value="{$product.id_customization}" id="product_customization_id" class="js-product-customization-id">
<input type="hidden" name="fixed_price" value="{$product.price_amount}" id="product_fixed_price">
<input type="hidden" name="base_price" value="{$product.price_amount}" id="product_base_price">
<input type="hidden" name="is_crop" value="0" id="product_is_crop">
<input type="hidden" name="is_reflection" value="0" id="product_is_reflection">
<input type="hidden" name="crop_pos_x" value="0" id="product_crop_pos_x">
<input type="hidden" name="crop_pos_y" value="0" id="product_crop_pos_y">
<input type="hidden" name="crop_width" value="0" id="product_crop_width">
<input type="hidden" name="crop_height" value="0" id="product_crop_height">
<input type="hidden" name="product_total_price_calc" id="product_total_price_calc" value='' />
<input type="hidden" name="piece_bg_top" id="piece_bg_top" value='' />
<input type="hidden" name="piece_bg_left" id="piece_bg_left" value='' />
<div class="product-bar-container 1">
<div class="product-bar product-bar-title container">
<h3>Konfigurator</h3>
<h2>Dopasuj tapetę do swoich potrzeb</h2>
</div>
<div class="product-bar product-bar-data container">
{$product_variant_mode = 1}
<a rel="nofollow" href="javascript:void(0);" class="fancybox-size-controls">
<div id="fancybox-size-controls" class="">
<div class="product-block-piece">
<div class="product-bar-label">
<p>1.</p>
</div>
<div class="product-bar-icon crop-icon">
<img src="/themes/ayon/assets/images/dopasuj-wymiar.png" alt="">
{* <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M17 15h2V7c0-1.1-.9-2-2-2H9v2h8v8zM7 17V1H5v4H1v2h4v10c0 1.1.9 2 2 2h10v4h2v-4h4v-2H7z"/></svg> *}
</div>
<div class="product-bar-box">
<div class="piece-size-controls product-bar-box">
Dopasuj wymiar
{* {l s='Rozmiar:' d='Shop.Theme.Catalog'} <br/>
<span id="piece-size-view" class="strong">
{l s='Wybierz' d='Shop.Theme.Catalog'}
</span> *}
</div>
<div class="piece-size-controls hidden">
<input type="checkbox" id="checkbox-piece"><label for="checkbox-piece">Wymiary tapety</label>
</div>
<div class="piece-size-values hidden">
<input type="number" min="50" max="500" value="100" id="piece-width" readonly>
<input type="number" min="50" max="300" value="100" id="piece-height" readonly>
</div>
</div>
</div></a>
</div>
{block name='product_variants'}
{include file='catalog/_partials/product-variants.tpl'}
{/block}
<div id="button-mirror-reflection">
<div class="product-bar-label">
<p>3.</p>
</div>
<div class="product-bar-icon rotate-icon" style="margin-top: 0px !important;">
<img src="/themes/ayon/assets/images/odbicie-iustrzane.png" alt="">
{* <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M15 21h2v-2h-2v2zm4-12h2V7h-2v2zM3 5v14c0 1.1.9 2 2 2h4v-2H5V5h4V3H5c-1.1 0-2 .9-2 2zm16-2v2h2c0-1.1-.9-2-2-2zm-8 20h2V1h-2v22zm8-6h2v-2h-2v2zM15 5h2V3h-2v2zm4 8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2z"/></svg> *}
</div>
<div class="product-bar-box">
{* <p class="button-mirror-reflection-label">Odbicie<br/>lustrzane</p> *}
<p class="button-mirror-reflection-label">Odbicie lustrzane</p>
</div>
</div>
<div id="button-color-variants">
<div class="product-bar-label">
<p>4.</p>
</div>
<div class="product-bar-icon rotate-icon" style="margin-top: 0px !important;">
<img src="/themes/ayon/assets/images/wariant-kolorystyczny.png" alt="">
</div>
<div class="product-bar-box">
<p class="button-color-variants-label">Wariant kolorystyczny</p>
</div>
</div>
{* <div class="product-block-custom-price">
<div class="product-bar-icon"></div>
<div class="product-bar-box">
<div class="clearfix product-variants-item">
<p id="custom-wallpaper-price-label">Cena</p>
<p id="custom-wallpaper-price"></p>
</div>
</div>
</div> *}
{* {block name='product_add_to_cart'}
{include file='catalog/_partials/product-add-to-cart.tpl'}
{/block}
{block name='product_discounts'}
{include file='catalog/_partials/product-discounts.tpl'}
{/block} *}
</div>
</div>
<div id="box-color-variants">
{$product_variant_mode = 2}
{block name='product_variants'}
{include file='catalog/_partials/product-variants.tpl'}
{/block}
</div>
<div class="product-actions-custom">
<div class="product-bar container">
<div class="product-actions-custom--wrapper">
{block name='product_add_to_cart'}
{include file='catalog/_partials/product-add-to-cart.tpl'}
{/block}
{block name='product_discounts'}
{include file='catalog/_partials/product-discounts.tpl'}
{/block}
</div>
</div>
</div>
{* {$product_variant_mode = 2}
{block name='product_variants'}
{include file='catalog/_partials/product-variants.tpl'}
{/block} *}
</form>
{/block}
</div>
{if in_array(6,Product::getProductCategories($product->id|intval))}
<a href="https://designer.hpwallart.com/mcdn?external_link=true"><div class="wallcover-button">Stwórz wzór tapety</div></a>
{/if}
{block name='product_tabs'}
<div class="tabs" id="tabsection">
<div class="container">
<ul class="nav nav-tabs" role="tablist">
{if $product.description}
<li class="nav-item">
<a
class="nav-link{if $product.description} active{/if}"
data-toggle="tab"
href="#description"
role="tab"
aria-controls="description"
{if $product.description} aria-selected="true"{/if}>{l s='Description' d='Shop.Theme.Catalog'}</a>
</li>
{/if}
{if $product.features}
<li class="nav-item">
<a
class="nav-link{if !$product.description} active{/if}"
data-toggle="tab"
href="#product-details"
role="tab"
aria-controls="product-details"
{if !$product.description} aria-selected="true"{/if}>{l s='Product Details' d='Shop.Theme.Catalog'}</a>
</li>
{/if}
{if $product.attachments}
<li class="nav-item">
<a
class="nav-link"
data-toggle="tab"
href="#attachments"
role="tab"
aria-controls="attachments">{l s='Attachments' d='Shop.Theme.Catalog'}</a>
</li>
{/if}
{foreach from=$product.extraContent item=extra key=extraKey}
<li class="nav-item">
<a
class="nav-link"
data-toggle="tab"
href="#extra-{$extraKey}"
role="tab"
aria-controls="extra-{$extraKey}">{$extra.title}</a>
</li>
{/foreach}
</ul>
<div class="tab-content" id="tab-content">
<div class="tab-pane fade in{if $product.description} active{/if}" id="description" role="tabpanel">
{block name='product_description'}
<div class="product-description">{$product.description nofilter}</div>
{/block}
</div>
{block name='product_details'}
{include file='catalog/_partials/product-details.tpl'}
{/block}
{block name='product_attachments'}
{if $product.attachments}
<div class="tab-pane fade in" id="attachments" role="tabpanel">
<section class="product-attachments">
<h3 class="h5 text-uppercase">{l s='Download' d='Shop.Theme.Actions'}</h3>
{foreach from=$product.attachments item=attachment}
<div class="attachment">
<h4><a href="{url entity='attachment' params=['id_attachment' => $attachment.id_attachment]}">{$attachment.name}</a></h4>
<p>{$attachment.description}</p
<a href="{url entity='attachment' params=['id_attachment' => $attachment.id_attachment]}">
{l s='Download' d='Shop.Theme.Actions'} ({$attachment.file_size_formatted})
</a>
</div>
{/foreach}
</section>
</div>
{/if}
{/block}
{foreach from=$product.extraContent item=extra key=extraKey}
<div class="tab-pane fade in {$extra.attr.class}" id="extra-{$extraKey}" role="tabpanel" {foreach $extra.attr as $key => $val} {$key}="{$val}"{/foreach}>
{$extra.content nofilter}
</div>
{/foreach}
</div>
</div>
</div>
{/block}
{hook h='displayProductBeforeBuy' mod='roy_content'}
{block name='product_accessories'}
{if $accessories}
<section class="product-accessories featured-products slideme clearfix mt-3">
<div class="pp_products_wrapper">
<h2 class="products-section-title">
{l s='You might also like' d='Shop.Theme.Catalog'}
</h2>
<div class="products">
{foreach from=$accessories item="product_accessory"}
{block name='product_miniature'}
{include file='catalog/_partials/miniatures/product.tpl' product=$product_accessory}
{/block}
{/foreach}
</div>
</div>
</section>
{/if}
{/block}
<a href="/Instrukcja.pdf" class="product-manual-button">Pobierz instrukcję PDF</a>
{block name='special_order_modal'}
{include file='catalog/_partials/custom/special-order.tpl'}
{/block}
{block name='email_pattern_modal'}
{include file='catalog/_partials/custom/email-pattern.tpl'}
{/block}
{block name='product_footer'}
{hook h='displayFooterProduct' product=$product category=$category}
{/block}
{block name='product_images_modal'}
{include file='catalog/_partials/product-images-modal.tpl'}
{/block}
</div>
{block name='page_footer_container'}
<footer class="page-footer">
{block name='page_footer'}
<!-- Footer content -->
{/block}
</footer>
{/block}
<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
<!-- Background of PhotoSwipe.
It's a separate element as animating opacity is faster than rgba(). -->
<div class="pswp__bg"></div>
<!-- Slides wrapper with overflow:hidden. -->
<div class="pswp__scroll-wrap">
<!-- Container that holds slides.
PhotoSwipe keeps only 3 of them in the DOM to save memory.
Don't modify these 3 pswp__item elements, data is added later on. -->
<div class="pswp__container">
<div class="pswp__item"></div>
<div class="pswp__item"></div>
<div class="pswp__item"></div>
</div>
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
<div class="pswp__ui pswp__ui--hidden">
<div class="pswp__top-bar">
<!-- Controls are self-explanatory. Order can be changed. -->
<div class="pswp__counter"></div>
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
<button class="pswp__button pswp__button--share" title="Share"></button>
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
<!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->
<!-- element will get class pswp__preloader--active when preloader is running -->
<div class="pswp__preloader">
<div class="pswp__preloader__icn">
<div class="pswp__preloader__cut">
<div class="pswp__preloader__donut"></div>
</div>
</div>
</div>
</div>
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div class="pswp__share-tooltip"></div>
</div>
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
</button>
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
</button>
<div class="pswp__caption">
<div class="pswp__caption__center"></div>
</div>
</div>
</div>
</div>
</section>
<div class="piece-left-positon hidden">10</div>
<div class="piece-top-positon hidden">10</div>
{/block}
{/if}
{if $smarty.server.REMOTE_ADDR == '89.69.31.86'}
{block name='content'}
<section id="main" itemscope itemtype="https://schema.org/Product">
<meta itemprop="url" content="{$product.url}">
<meta itemprop="gtin13" content="{$product.ean13}" />
<meta itemprop="brand" content="{if isset($pl_manufacturer)}{$pl_manufacturer}{else}{$shop.name}{/if}" />
{if isset($product.isbn)}<meta itemprop="productID" content="{$product.isbn}">{/if}
<div class="container">
{if isset($roythemes.b_pos_pro) && $roythemes.b_pos_pro == "2"}
{block name='breadcrumb'}
{include file='_partials/breadcrumb.tpl'}
{/block}
{/if}
<div class="row">
<div class="col-md-6">
<div class="product_image">
{block name='product_flags'}
<ul class="product-flags">
{foreach from=$product.flags item=flag}
<li class="product-flag {$flag.type}">{$flag.label}</li>
{/foreach}
</ul>
{/block}
<div class="product_image_wrapper">
{block name='product_cover_thumbnails'}
{include file='catalog/_partials/product-cover-thumbnails.tpl'}
{/block}
{* #piece jest wewnatrz product-cover-thumbnails.tpl (rendered inside .product-images li) — NIE duplikowac tutaj *}
</div>
</div>
</div>
<div class="col-md-6">
{block name='page_header_container'}
{block name='page_header'}
<h1 class="h1 product-title" itemprop="name">{block name='page_title'}{$product.name}{/block}</h1>
{hook h='displayProductNav' product=$product}
{/block}
{/block}
{block name='product_description'}
{if $product.description}
<div class="product-box block-description-data">
<h4 class="block-title" data-type="description">{l s='Wallpaper description' d='Shop.Theme.Catalog'}</h4>
<div class="product-description">{$product.description nofilter}</div>
</div>
{/if}
{/block}
{block name='product_config_info'}
<div class="product-box block-config-info-data">
<h4 class="block-title">Skonfiguruj tapetę do wymiarów swojej ściany</h4>
<p>Przed dodaniem do koszyka dopasuj tapetę do wymiarów swojej ściany. Nasz konfigurator pozwala na dostosowanie wymiarów i kolorystyki tapety.</p>
</div>
{/block}
{block name='product_price'}
<div class="product-box product-price-data">
<div class="product-price-data--wrapper">
<h4 class="block-title">Cena</h4>
<div class="product-prices-data">
{block name='product_prices'}
{include file='catalog/_partials/product-prices.tpl'}
{/block}
{block name='product_discounts'}
{include file='catalog/_partials/product-discounts.tpl'}
{/block}
</div>
</div>
<div class="product-config-btn">
<a href="#" class="_btn-1"><span>Skonfiguruj tapetę</span></a>
</div>
</div>
{/block}
{block name='product_variants'}
{$product_variant_mode = 2}
<div class="product-box product-variants-data product-variants-data--new">
<h4 class="block-title">Wybierz wersję kolorystyczną</h4>
<form action="{$urls.pages.cart}" method="post" id="add-to-cart-or-refresh">
<input type="hidden" name="token" value="{$static_token}">
<input type="hidden" name="id_product" value="{$product.id}" id="product_page_product_id">
<input type="hidden" name="id_customization" value="{$product.id_customization}" id="product_customization_id" class="js-product-customization-id">
<input type="hidden" name="is_crop" value="0" id="product_is_crop">
<input type="hidden" name="is_reflection" value="0" id="product_is_reflection">
<input type="hidden" name="crop_pos_x" value="0" id="product_crop_pos_x">
<input type="hidden" name="crop_pos_y" value="0" id="product_crop_pos_y">
<input type="hidden" name="crop_width" value="0" id="product_crop_width">
<input type="hidden" name="crop_height" value="0" id="product_crop_height">
<input type="hidden" name="piece_bg_top" id="piece_bg_top" value="">
<input type="hidden" name="piece_bg_left" id="piece_bg_left" value="">
<div class="product-variants-grid">
{include file='catalog/_partials/product-variants.tpl'}
</div>
</form>
</div>
{/block}
{block name='product_size'}
<div class="product-box product-size-data" >
<div class="product-box--head">
<a rel="nofollow" href="javascript:void(0);" class="fancybox-size-controls">
<h4 class="block-title">Rozmiar i dostosowanie</h4>
</a>
</div>
<div class="product-box--data">
<div class="product-size-data--new">
<a rel="nofollow" href="javascript:void(0);" class="fancybox-size-controls piece-summary">
<span id="piece-size-view" class="strong">Wybierz rozmiar</span>
<span class="piece-hint">&mdash; kliknij aby zmienić</span>
</a>
<div id="button-mirror-reflection">
<div class="product-bar-icon rotate-icon">
<img src="/themes/ayon/assets/images/odbicie-iustrzane.png" alt="">
</div>
<div class="product-bar-box">
<p class="button-mirror-reflection-label">Odbicie lustrzane</p>
</div>
</div>
{* Hidden state trzymane w DOM — istniejące handlery w custom.js bindują się po ID. *}
<input type="checkbox" id="checkbox-piece" checked style="display:none;">
<input type="number" min="50" max="500" value="100" id="piece-width" style="display:none;">
<input type="number" min="50" max="300" value="100" id="piece-height" style="display:none;">
<div class="piece-left-positon" style="display:none;">10</div>
<div class="piece-top-positon" style="display:none;">10</div>
</div>
</div>
</div>
{/block}
{block name='product_texture'}
<div class="product-box product-texture-data">
<div class="product-box--head">
<a rel="nofollow" href="javascript:void(0);" class="fancybox-size-controls">
<h4 class="block-title">Tekstura materiału</h4>
</a>
</div>
<div class="product-box--data">
{$product_variant_mode = 1}
{block name='product_variants'}
{include file='catalog/_partials/product-variants.tpl'}
{/block}
</div>
</div>
{/block}
{block name='product_realization_time'}
<div class="product-box product-realization-time">
<div class="product-box--head">
<h4 class="block-title">Czas realizacji zamówienia</h4>
</div>
<div class="product-box--data">
</div>
</div>
{/block}
{block name='product_protect'}
<div class="product-box product-protect">
<div class="product-box--head">
<h4 class="block-title">Zabezpiecz tapetę</h4>
</div>
<div class="product-box--data">
</div>
</div>
{/block}
{block name='product_installation'}
<div class="product-box product-installation">
<div class="product-box--head">
<h4 class="block-title">Montaż</h4>
</div>
<div class="product-box--data">
</div>
</div>
{/block}
{block name='product_order_sample'}
<div class="product-box product-order-sample">
<div class="product-order-sample--wrapper">
<h4 class="block-title">Zamów próbkę</h4>
<p>Masz trudność w wyborze odpowiedniej tapety?<br/>Zamów próbkę o wymiarach 30x60 cm korzystając z konfiguratora.</p>
</div>
<div class="product-config-btn">
<a href="#" class="_btn-1"><span>Zamów próbkę</span></a>
</div>
</div>
{/block}
<div class="product-add-to-cart">
<div class="product-bar container">
<div class="product-actions-custom--wrapper">
{block name='product_add_to_cart'}
{include file='catalog/_partials/product-add-to-cart.tpl'}
{/block}
{block name='product_discounts'}
{include file='catalog/_partials/product-discounts.tpl'}
{/block}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="product-box-free-example">
<div class="container">
<div class="_c-row _c-row-1">
<div class="_c-col">
<p>Tekstura</p>
</div>
</div>
<div class="_c-row _c-row-2">
<div class="_c-col _c-col-1"><img src="/img/cms/home/image 5.png" alt="" /></div>
<div class="_c-col _c-col-2">
<h3>Zamów darmowy wzornik struktur</h3>
<div class="_box-text">
<p>Zamawiając nasz wzorki struktur masz możliwość sprawdzenia rzeczywistych barw wzoru oraz zapoznania się z wybraną teskturą.</p>
<p>W próbce uchwyciliśmy fragment grafiki, starannie pomniejszony, by maksymalnie zaprezentować wybrany wzór.</p>
</div>
<a href="#" class="_btn-1"><span>Dodaj do koszyka</span></a></div>
</div>
</div>
</div>
</section>
{/block}
{* =========================================================================
Phase 02 Plan 02-02: inline add-to-cart handler (cache-buster).
Powod: <script src="custom.js"> w tym temacie jest serwowany bez wersji
i browser cache'uje stara wersje przy kolejnych iteracjach. Ten inline
<script> jest czescia HTML response wiec ZAWSZE jest swiezy. Idempotentny
guard `window.__p02p02Bound` zapobiega double-register jesli custom.js
tez jest aktualny (happy path z hard-reload).
Kod IDENTYCZNY z custom.js:994-1113 — zmiany wprowadzaj w OBU miejscach
do czasu dodania systemowego cache-bustera (Plan 02-03+).
========================================================================= *}
<script type="text/javascript">
(function() {
if (window.__p02p02Bound) return;
window.__p02p02Bound = true;
document.addEventListener('click', function(e) {
var btn = e.target.closest ? e.target.closest('[data-button-action=add-to-cart]') : null;
if (!btn) return;
if (!document.querySelector('.product-variants-data--new')) return;
var $form = jQuery('#add-to-cart-or-refresh');
if (!$form.length) return;
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
if (!jQuery('#checkbox-piece').is(':checked')) {
jQuery.fancybox({
minWidth: 800, maxWidth: 1000, padding: 30, height: 100,
content: 'Proszę wybrać rozmiar i wycinek tapety przed dodaniem jej do koszyka.'
});
return;
}
if (jQuery('#product_is_crop').val() === '0' || !jQuery('#product_crop_width').val() || jQuery('#product_crop_width').val() === '0') {
jQuery('#product_is_crop').val('1');
var pw = parseInt(jQuery('#piece-width').val(), 10) || 100;
var ph = parseInt(jQuery('#piece-height').val(), 10) || 100;
jQuery('#product_crop_width').val(pw);
jQuery('#product_crop_height').val(ph);
}
var $btn = jQuery(btn);
$btn.prop('disabled', true).addClass('loading');
var qty = parseInt(jQuery('#quantity_wanted').val(), 10) || 1;
var payload = $form.serialize() + '&qty=' + encodeURIComponent(qty) + '&add=1&action=update';
var actionUrl = $form.attr('action') || window.location.href;
jQuery.ajax({
url: actionUrl,
type: 'POST',
data: payload,
dataType: 'json',
headers: { 'Accept': 'application/json' },
success: function(resp) {
var hasError = !resp || resp.hasError === true || resp.success === false ||
(resp.errors && (Array.isArray(resp.errors) ? resp.errors.length : Object.keys(resp.errors).length));
if (hasError) {
var errs = resp && resp.errors;
var msg = '';
if (Array.isArray(errs)) msg = errs.join('<br>');
else if (errs && typeof errs === 'object') msg = Object.values(errs).join('<br>');
else msg = 'Nie udało się dodać produktu do koszyka. Spróbuj ponownie.';
jQuery.fancybox({
minWidth: 400, maxWidth: 800, padding: 30, height: 100,
content: msg
});
return;
}
if (window.prestashop && typeof prestashop.emit === 'function') {
prestashop.emit('updatedCart', { resp: resp, reason: { linkAction: 'add-to-cart' } });
}
jQuery(document).trigger('updatedCart', [resp]);
if (window.prestashop && prestashop.urls && prestashop.urls.pages && prestashop.urls.pages.cart) {
jQuery.get(prestashop.urls.pages.cart, { action: 'refresh', ajax: 1 }, null, 'json')
.done(function(cartResp) {
if (cartResp && cartResp.preview) {
jQuery('.blockcart').replaceWith(cartResp.preview);
}
});
}
$btn.addClass('added-flash');
setTimeout(function() { $btn.removeClass('added-flash'); }, 1200);
},
error: function() {
jQuery.fancybox({
minWidth: 400, maxWidth: 800, padding: 30, height: 100,
content: 'Błąd połączenia z serwerem. Spróbuj ponownie za chwilę.'
});
},
complete: function() {
$btn.prop('disabled', false).removeClass('loading');
}
});
}, true);
})();
</script>
{/if}