PageSourceSearch

https://www.cajova-zahrada.cz/user/documents/new-codes/js/script-2.js?v1.170

js cajova-zahrada.cz collected 2026-10-08 08:37:44 UTC 13,556 bytes, 383 lines download raw bytes

1$(document).ready(function(){
2
3  if($('.category-perex .col.image img').length === 0){
4    $('<style>@media (max-width: 767px) { .category-top::before { height: 480px; } }</style>').appendTo('head');
5  }
6
7  function applyFlagLogic($scope){
8    /*
9    var $root = ($scope && $scope.length) ? $scope : $(document);
10
11    $root.find('.flag.flag-discount').addBack('.flag.flag-discount').each(function(){
12      var $flag = $(this);
13      if($flag.data('flag-processed')) return;
14      $flag.data('flag-processed', true);
15
16      var $priceStandard = $flag.find('.price-standard');
17      if(!$priceStandard.length) return;
18
19      var $clone = $priceStandard.clone();
20      $priceStandard.remove();
21
22      var $target = $flag.closest('.products-block, .product').find('.p-bottom .prices').first();
23      if($target.length) $target.prepend($clone);
24    });
25
26    $root.find('.flag.flag-freeshipping').addBack('.flag.flag-freeshipping').each(function(){
27      var $flag = $(this);
28      if($flag.data('flag-processed')) return;
29      $flag.data('flag-processed', true);
30
31      var $flagText = $flag.find('.flag-text');
32      if($flagText.length) $flagText.text('Doprava zdarma');
33
34      var $flagsDefault = $flag.closest('.products-block, .product').find('.flags-default').first();
35      if($flagsDefault.length) $flag.appendTo($flagsDefault);
36    });
37    */
38  }
39
40  function getDeliveryText(){
41    var now = new Date();
42    var day = now.getDay();
43    var delivery = new Date(now);
44
45    if(day === 5) delivery.setDate(now.getDate() + 3);
46    else if(day === 6) delivery.setDate(now.getDate() + 2);
47    else delivery.setDate(now.getDate() + 1);
48
49    var dateStr = delivery.getDate() + '. ' + (delivery.getMonth() + 1) + '.';
50    var prefix = (day === 5 || day === 6) ? '' : 'již zítra ';
51
52    return prefix + dateStr + ' u vás';
53  }
54
55  function applyDeliveryDate($scope){
56    var $root = ($scope && $scope.length) ? $scope : $(document);
57    var text = getDeliveryText();
58
59    $root.find('.availability-amount').addBack('.availability-amount').each(function(){
60      if(this.textContent !== text){
61        this.textContent = text;
62      }
63    });
64
65    // Na některých shopech Shoptet .availability-amount vůbec nevykreslí (jiná
66    // konfigurace dostupnosti/skladu na tom shopu) - pak tu není nic k přepsání.
67    // Proto ho do .availability doplníme sami, ať termín dodání jde vidět i tam.
68    // Zobrazení/schování podle stavu skladem pak dál řeší CSS
69    // (.availability:not(:has([data-original-title="Skladem."])) .availability-amount).
70    $root.find('.availability').addBack('.availability').each(function(){
71      var $availability = $(this);
72      if($availability.find('.availability-amount').length) return;
73
74      $('<span class="availability-amount"></span>').text(text).appendTo($availability);
75    });
76  }
77
78  function applyRatingBadges($scope){
79    var $root = ($scope && $scope.length) ? $scope : $(document);
80
81    $root.find('.stars-wrapper[data-micro-rating-count]').addBack('.stars-wrapper[data-micro-rating-count]').each(function(){
82      var el = this;
83      var count = el.getAttribute('data-micro-rating-count');
84
85      $(el).find('.rating-count-badge').remove();
86
87      if(!count || count === '0') return;
88
89      var badge = document.createElement('span');
90      badge.className = 'rating-count-badge';
91      badge.textContent = '(' + count + ')';
92      badge.style.cssText = 'font-size:12px;color:#888;margin-top:2px;white-space:nowrap;';
93      el.appendChild(badge);
94    });
95  }
96
97  applyFlagLogic();
98  applyDeliveryDate();
99  applyRatingBadges();
100
101  var progressUpdating = false;
102  var ajaxRefreshRunning = false;
103  var ajaxRefreshTimer = null;
104  var productsPerPage = 0;
105
106  function getCurrentPageFromUrl(){
107    var match = window.location.href.match(/strana-(\d+)/);
108    return match ? parseInt(match[1], 10) : 1;
109  }
110
111  /* Kategorie (produkty) používá #products .product, výpis článků
112     (body.type-posts-listing) používá #newsWrapper .news-item. */
113  function getListingItemsSelector(){
114    return $('body').hasClass('type-posts-listing') ? '#newsWrapper .news-item' : '#products .product';
115  }
116
117  /* Slovo za počtem v textu "Už jste viděli X z Y ___". U receptů/blogu
118     nedává "produktů" smysl, tak ho podle stránky přepneme. */
119  function getItemsNoun(){
120    var $body = $('body');
121    if($body.hasClass('type-posts-listing')){
122      return $body.hasClass('in-nase-recepty') ? 'receptů' : 'článků';
123    }
124    return 'produktů';
125  }
126
127  function fixLoadMoreButton(){
128    var $btn = $('[data-testid="buttonMoreItems"]');
129    if(!$btn.length) return;
130    if($btn.text() !== 'Zobrazit další') $btn.text('Zobrazit další');
131  }
132
133  function updateProgressBar(){
134    if(progressUpdating) return;
135
136    var $itemsTotal = $('.itemsTotal');
137    if(!$itemsTotal.length) return;
138
139    var totalItems = parseInt($itemsTotal.find('strong').first().text(), 10) || 0;
140    if(!totalItems) return;
141
142    var currentPage = getCurrentPageFromUrl();
143    var $products = $(getListingItemsSelector());
144
145    if(productsPerPage === 0 || currentPage === 1){
146      productsPerPage = $products.length;
147    }
148
149    if(!productsPerPage) return;
150
151    var isLastPage = !$('[data-testid="linkNextPage"]').length;
152    var seenProducts = isLastPage ? totalItems : Math.min(currentPage * productsPerPage, totalItems);
153    var percent = Math.round((seenProducts / totalItems) * 100);
154    var itemsNoun = getItemsNoun();
155
156    progressUpdating = true;
157
158    var $existing = $('.iuv-progress-wrapper');
159
160    if($existing.length){
161      $existing.find('.iuv-progress-bar-fill').css('width', percent + '%');
162      $existing.find('.iuv-progress-text').text('Už jste viděli ' + seenProducts + ' z ' + totalItems + ' ' + itemsNoun);
163      progressUpdating = false;
164      return;
165    }
166
167    var $wrapper = $('<div>', { class: 'iuv-progress-wrapper' });
168    var $text = $('<p>', { class: 'iuv-progress-text', text: 'Už jste viděli ' + seenProducts + ' z ' + totalItems + ' ' + itemsNoun });
169    var $barBg = $('<div>', { class: 'iuv-progress-bar-bg' });
170    var $barFill = $('<div>', { class: 'iuv-progress-bar-fill' });
171
172    $barFill.css('width', percent + '%');
173    $barBg.append($barFill);
174    $wrapper.append($text).append($barBg);
175    $('.listingControls').prepend($wrapper);
176
177    progressUpdating = false;
178  }
179
180  /* Výpis receptů/článků nemá nativní AJAX "Zobrazit další" (buttonMoreItems) -
181     Shoptet tam renderuje jen klasické číslované stránkování. Tahle funkce
182     postaví vlastní tlačítko, které natáhne další stranu přes AJAX, přidá
183     nové .news-item do #newsWrapper a nahradí stránkování tím z natažené
184     stránky (aby další klik šel na stranu+2, případně tlačítko zmizelo). */
185  function initNewsLoadMore(){
186    if(!$('body').hasClass('type-posts-listing')) return;
187    if($('.iuv-load-more').length) return; // už inicializováno
188
189    var $wrapper = $('#newsWrapper');
190    if(!$wrapper.length) return;
191
192    var $pagination = $('.listingControls .pagination');
193    if(!$pagination.find('[data-testid="linkNextPage"]').length) return; // poslední strana
194
195    var $progressWrapper = $('.iuv-progress-wrapper');
196    if(!$progressWrapper.length) return; // progress bar se vytváří dřív (updateProgressBar())
197
198    var loading = false;
199
200    // Shoptet má pro "Zobrazit další" vlastní nativní třídy (.loadMore / .btn.loadMore__button)
201    // se stylem i flex/order rozvržením uvnitř .listingControls - použitím stejných tříd
202    // jako u kategorie odpadá potřeba vlastního CSS, vzhled bude automaticky sjednocený.
203    var $btnWrapper = $('<div>', { class: 'loadMore iuv-load-more' });
204    var $btn = $('<button>', {
205      type: 'button',
206      class: 'btn loadMore__button',
207      text: 'Zobrazit další'
208    });
209    $btnWrapper.append($btn);
210    // Pod progress bar, nad zachované klasické stránkování (to zůstává vidět i funkční)
211    $progressWrapper.after($btnWrapper);
212
213    // Shoptet ukazuje při AJAXu (např. na kategorii) celostránkový loader přes
214    // dvojici tříd: ajax-pending (na body) + loader-wrapper (na kontejneru,
215    // jehož :before/:after Shoptet CSS vykreslí jako spinner + přeslech).
216    // position:relative na #content-wrapper dočasně doplníme přes JS, ať
217    // přeslech sedí přesně na jeho rozměr.
218    var $loaderTarget = $('#content-wrapper');
219
220    function showAjaxLoader(){
221      $('body').addClass('ajax-pending');
222      $loaderTarget.addClass('loader-wrapper').css('position', 'relative');
223    }
224
225    function hideAjaxLoader(){
226      $('body').removeClass('ajax-pending');
227      $loaderTarget.removeClass('loader-wrapper').css('position', '');
228    }
229
230    $btn.on('click', function(){
231      if(loading) return;
232
233      var $nextLink = $pagination.find('[data-testid="linkNextPage"]');
234      var nextUrl = $nextLink.attr('href');
235      if(!nextUrl) return;
236
237      loading = true;
238      $btn.prop('disabled', true).text('Načítám...');
239      showAjaxLoader();
240
241      $.get(nextUrl, function(html){
242        var $doc = $($.parseHTML(html, document, true));
243        var $newItems = $doc.find('#newsWrapper .news-item');
244        var $newPagination = $doc.find('.listingControls .pagination');
245
246        // Obrázky z natažené (ještě nezpracované) stránky mají lazyload jen
247        // přes data-src - Shoptet vlastní lazyload skript sleduje jen obrázky
248        // přítomné při načtení stránky, na nově vložené nedosáhne.
249        $newItems.find('img[data-src]').each(function(){
250          var $img = $(this);
251          var dataSrc = $img.attr('data-src');
252          if(dataSrc && $img.attr('src') !== dataSrc){
253            $img.attr('src', dataSrc);
254          }
255          $img.removeAttr('loading');
256        });
257
258        $wrapper.append($newItems);
259        $(document).trigger('newsItemsAppended', [$newItems]);
260
261        if(window.history && window.history.pushState){
262          window.history.pushState({}, '', nextUrl);
263        }
264
265        if($newPagination.length){
266          $pagination.replaceWith($newPagination);
267          $pagination = $newPagination;
268        }
269
270        if(!$pagination.find('[data-testid="linkNextPage"]').length){
271          $btnWrapper.remove();
272        } else {
273          loading = false;
274          $btn.prop('disabled', false).text('Zobrazit další');
275        }
276      }).fail(function(){
277        loading = false;
278        $btn.prop('disabled', false).text('Zobrazit další');
279      }).always(function(){
280        hideAjaxLoader();
281      });
282    });
283  }
284
285  function scheduleAjaxRefresh($nodes, shouldUpdateProgress){
286    clearTimeout(ajaxRefreshTimer);
287
288    ajaxRefreshTimer = setTimeout(function(){
289      if(ajaxRefreshRunning) return;
290
291      ajaxRefreshRunning = true;
292
293      if($nodes && $nodes.length){
294        applyFlagLogic($nodes);
295        applyDeliveryDate($nodes);
296        applyRatingBadges($nodes);
297      }
298
299      applyDeliveryDate();
300      applyRatingBadges();
301      fixLoadMoreButton();
302
303      if(shouldUpdateProgress){
304        $('.iuv-progress-wrapper').remove();
305        updateProgressBar();
306      }
307
308      ajaxRefreshRunning = false;
309    }, 80); //80
310  }
311
312  updateProgressBar();
313  fixLoadMoreButton();
314  initNewsLoadMore();
315
316  var observerProgress = new MutationObserver(function(mutations){
317    if(ajaxRefreshRunning || progressUpdating) return;
318
319    var shouldUpdateProgress = false;
320    var $newNodes = $();
321
322    mutations.forEach(function(mutation){
323      var target = mutation.target;
324      var $target = $(target);
325
326      if(
327        $target.is('#products') ||
328        $target.closest('#products').length ||
329        $target.is('#newsWrapper') ||
330        $target.closest('#newsWrapper').length ||
331        $target.is('.itemsTotal') ||
332        $target.is('.pageInfoSpan') ||
333        $target.closest('.pageInfoSpan').length
334      ){
335        shouldUpdateProgress = true;
336      }
337
338      if(mutation.addedNodes && mutation.addedNodes.length){
339        mutation.addedNodes.forEach(function(node){
340          if(node.nodeType === 1){
341            $newNodes = $newNodes.add(node);
342          }
343        });
344      }
345    });
346
347    if($newNodes.length || shouldUpdateProgress){
348      scheduleAjaxRefresh($newNodes, shouldUpdateProgress);
349    }
350  });
351
352  observerProgress.observe(document.body, {
353    childList: true,
354    subtree: true,
355    attributes: true,
356    attributeFilter: ['data-current']
357  });
358
359  function initButton(c){
360    var $btn = $(`<div class="homepage-products-button"><a href="${c.link}" class="btn btn-primary">Zobrazit všechny produkty</a></div>`);
361
362    function move(){
363      if($(window).width() < 992){
364        if(!$(c.products).next($btn).length){
365          $(c.products).after($btn);
366        }
367        $btn.addClass('mobile');
368      } else {
369        if(!$(c.heading).prev($btn).length){
370          $(c.heading).before($btn);
371        }
372        $btn.removeClass('mobile');
373      }
374    }
375
376    move();
377    $(window).on('resize', move);
378  }
379
380  initButton({ heading: '.homepage-products-heading-5', products: '#products-5', link: '#' });
381  initButton({ heading: '.homepage-products-heading-8', products: '#products-8', link: '#' });
382
383});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.