PageSourceSearch

https://www.entredeuxvagues.com/wp-content/plugins/eventin-pro/assets/js/etn-public.js?ver=4.1.25

js entredeuxvagues.com collected 2026-10-04 13:10:16 UTC 21,841 bytes, 638 lines download raw bytes

1"use strict";
2jQuery(document).ready(function ($) {
3  //Added active class in the eventin menu in dokan leftmenu
4  const _pathname = window.location.pathname.toString();
5  const create_event = "/eventin/create_event/";
6  const vendor_event = "/eventin/vendor_event/";
7  if (_pathname.includes(create_event) || _pathname.includes(vendor_event)) {
8    $(".dokan-dashboard-menu").find("li.eventin").addClass("active");
9  }
10
11  /*================================
12        speaker slider
13    ===================================*/
14  var $scope = $(".speaker_shortcode_slider");
15  if ($scope.length > 0) {
16    $($scope).each(function () {
17      var $this = $(this);
18      speaker_sliders_pro($, $this);
19    });
20  }
21
22  /*================================
23        speaker slider
24    ===================================*/
25  var $scope = $(".event-slider-shortcode");
26  event_sliders_pro($, $scope);
27
28  /*================================
29    Event calendar hover card
30    ===================================*/
31  etn_calendar_tooltip_placement($);
32
33  /*================================
34    Event accordion
35    ===================================*/
36
37  $(".etn-content-item > .etn-accordion-heading").on("click", function (e) {
38    e.preventDefault();
39    if ($(this).hasClass("active")) {
40      $(this).removeClass("active");
41      $(this).siblings(".etn-acccordion-contents").slideUp(200);
42      $(".etn-content-item > .etn-accordion-heading i")
43        .removeClass("etn-minus")
44        .addClass("etn-plus");
45    } else {
46      $(".etn-content-item > .etn-accordion-heading i")
47        .removeClass("etn-minus")
48        .addClass("etn-plus");
49      $(this).find("i").removeClass("etn-plus").addClass("etn-minus");
50      $(".etn-content-item > .etn-accordion-heading").removeClass("active");
51      $(this).addClass("active");
52      $(".etn-acccordion-contents").slideUp(200);
53      $(this).siblings(".etn-acccordion-contents").slideDown(200);
54    }
55  });
56
57  /*================================
58      // countdown 
59    ===================================*/
60  const main_block = $(".etn_count_down_block");
61  if (main_block.length) {
62    count_down($, main_block);
63  }
64
65  /*================================
66      // Advanced search toggle
67    ===================================*/
68  if ($(".etn-filter-icon").length > 0) {
69    $(".etn-filter-icon").on("click", function () {
70      $(this).parents().find(".etn_event_inline_form_bottom").slideToggle();
71    });
72  }
73
74  /*================================
75       // Certificate generate
76    ===================================*/
77  const certificateButton = $(".etn-certificate-download");
78  certificateButton.on("click", function (e) {
79    e.preventDefault();
80    etnCreateCertificate(certificateButton);
81  });
82
83  /*====================================================
84   * // Event bulk attendee field value update script
85   * ====================================================*/
86  $("#etn_bulk_attendee").on("change", function () {
87    const totalVariations = $(".etn-ticket-single-variation-details").length;
88    const submitButton = $(".attendee_submit");
89    const isChecked = $(this).is(":checked");
90    const checkbox = $(this);
91    checkbox.prop("checked", isChecked);
92
93    for (
94      let variationIndex = 0;
95      variationIndex < totalVariations;
96      variationIndex++
97    ) {
98      const totalTicketQuantity = checkbox.data(`total_ticket_quantity`);
99
100      for (
101        let quantityIndex = 0;
102        quantityIndex < totalTicketQuantity;
103        quantityIndex++
104      ) {
105        const element = quantityIndex + 1;
106        const nameElement = $(
107          `#ticket_${variationIndex}_attendee_name_${element}`
108        );
109        const emailElement = $(
110          `#ticket_${variationIndex}_attendee_email_${element}`
111        );
112        const phoneElement = $(
113          `#ticket_${variationIndex}_attendee_phone_${element}`
114        );
115        const fields = [nameElement, emailElement, phoneElement];
116
117        fields.forEach((field) => {
118          if (isChecked) {
119            field.removeClass("attendee_error");
120            const fieldType = field.attr("type");
121            if (fieldType === "email") {
122              emailElement.val(`attendee${element}@test.com`);
123            } else if (fieldType === "tel") {
124              field.val(`0123456789${element}`);
125            } else {
126              field.val(`Attendee ${element}`);
127            }
128          } else {
129            field.val("").addClass("attendee_error");
130          }
131        });
132      }
133    }
134    submitButton
135      .prop("disabled", !isChecked)
136      .toggleClass("attendee_submit_disable", !isChecked);
137  });
138});
139
140// etnCreateCertificate.js
141async function generateCertificateImage(element) {
142  // Wait for all images to load first
143  await Promise.all(
144    Array.from(element.querySelectorAll("img")).map((img) => {
145      if (img.complete) return Promise.resolve();
146      return new Promise((resolve) => {
147        img.onload = resolve;
148        img.onerror = resolve;
149      });
150    })
151  );
152
153  // Use html2canvas with proper config
154  const canvas = await window.html2canvas(element, {
155    useCORS: true, // Handle cross-origin images
156    allowTaint: true, // Allow loading cross-origin images
157    scrollX: 0, // Ensure proper positioning
158    scrollY: 0,
159    scale: 1.5, // Higher quality
160    logging: true, // Help debug issues
161    width: element.offsetWidth,
162    height: element.offsetHeight,
163    backgroundColor: null, // Preserve the element's own background (e.g. Elementor styles)
164    onclone: function(clonedDoc, clonedEl) {
165      // Inherit background from parent elements (e.g. Elementor section gradient)
166      // html2canvas only captures the target element's styles, so backgrounds
167      // applied to parent containers (like Elementor sections) would be lost.
168      var parent = element.parentElement;
169      while (parent && parent !== document.body) {
170        var parentStyle = window.getComputedStyle(parent);
171        var parentBgImage = parentStyle.backgroundImage;
172        var parentBgColor = parentStyle.backgroundColor;
173        var hasBgImage = parentBgImage && parentBgImage !== 'none';
174        var hasBgColor = parentBgColor &&
175                         parentBgColor !== 'rgba(0, 0, 0, 0)' &&
176                         parentBgColor !== 'transparent';
177
178        if (hasBgImage || hasBgColor) {
179          var elStyle = window.getComputedStyle(element);
180          var elBgImage = elStyle.backgroundImage;
181
182          if (hasBgImage) {
183            if (elBgImage && elBgImage !== 'none') {
184              // Layer element's background on top of parent's background
185              clonedEl.style.backgroundImage = elBgImage + ', ' + parentBgImage;
186              clonedEl.style.backgroundPosition = elStyle.backgroundPosition + ', center';
187              clonedEl.style.backgroundSize = elStyle.backgroundSize + ', cover';
188            } else {
189              clonedEl.style.backgroundImage = parentBgImage;
190            }
191          }
192
193          if (hasBgColor) {
194            clonedEl.style.backgroundColor = parentBgColor;
195          }
196
197          break;
198        }
199        parent = parent.parentElement;
200      }
201    }
202  });
203
204  return canvas.toDataURL("image/png");
205}
206
207/**
208 * Resolve the width the certificate was DESIGNED at.
209 *
210 * The certificate page is responsive (.etn-certificate-container is max-width:900px;width:100%),
211 * so the container reflows with the browser window. Because the PDF is produced by
212 * screenshotting that live layout, the same certificate yields a different PDF depen
212ding on how
213 * wide the visitor's window happens to be — text rewraps, multi-column rows stack, and the page
214 * grows taller. Capturing at the design width instead makes the output deterministic.
215 *
216 * Block templates carry the design width on the container block itself as an inline max-width
217 * (e.g. max-width:842px). The legacy template (.etn-pdf-content) has none — it is width:100%
218 * inside .etn-certificate-container, so its design width is that ancestor's max-width (900px).
219 * Walking up for the first finite max-width covers both and keeps tracking the stylesheet
220 * instead of hardcoding a number; 900 is the last resort and matches the certificate page's
221 * fixed viewport meta (see block-template-pdf-certificate.php).
222 */
223function etnCertificateDesignWidth(element) {
224  const inlineMax = parseFloat(element.style.maxWidth);
225  if (!isNaN(inlineMax) && inlineMax > 0) return Math.round(inlineMax);
226
227  for (let node = element; node && node !== document.body; node = node.parentElement) {
228    const max = parseFloat(window.getComputedStyle(node).maxWidth);
229    if (!isNaN(max) && max > 0) return Math.round(max);
230  }
231
232  return 900;
233}
234
235async function etnCreateCertificate(downloadButton) {
236  'use strict';
237
238  const jsPDF = window.jspdf.jsPDF;
239
240  if(downloadButton) downloadButton.addClass("loading");
241
242  // Try both new and legacy selectors
243  const element =
244  document.querySelector(".etn-downloadable-container") || document.querySelector(".eventin-container-block") ||
245  document.querySelector(".etn-pdf-content");
246 if (!element) {
247   throw new Error("Certificate container not found");
248 }
249
250 	// Wait for all images to load
251   await Promise.all(
252		Array.from(element.querySelectorAll('img')).map((img) => {
253			if (img.complete) return Promise.resolve();
254			return new Promise((resolve) => {
255				img.onload = resolve;
256				img.onerror = resolve;
257			});
258		})
259	);
260
261  try {
262
263    // Pin the container to its design width for the duration of the capture so the PDF does
264    // not depend on the visitor's window size. Restored immediately after rasterizing, so the
265    // on-screen certificate stays responsive. We resize the live element rather than an
266    // offscreen clone on purpose: html2canvas copies <canvas> bitmaps (the QR code) from the
267    // element it is given, and cloneNode() would hand it blank canvases.
268    const designWidth = etnCertificateDesignWidth(element);
269    const previousInlineWidth = element.style.width;
270    const previousInlineMaxWidth = element.style.maxWidth;
271
272    element.style.width = designWidth + "px";
273    element.style.maxWidth = "none";
274
275    // Let the browser lay out at the pinned width before we measure it.
276    await new Promise((resolve) =>
277      requestAnimationFrame(() => requestAnimationFrame(resolve))
278    );
279
280    let dataUrl;
281    let elementWidth;
282    let elementHeight;
283
284    try {
285      // Get dimensions from element, now that it is at its design width
286      const computedStyle = window.getComputedStyle(element);
287      elementWidth = element.offsetWidth || parseFloat(computedStyle.width);
288      elementHeight = element.offsetHeight || parseFloat(computedStyle.height);
289
290      dataUrl = await generateCertificateImage(element);
291    } finally {
292      element.style.width = previousInlineWidth;
293      element.style.maxWidth = previousInlineMaxWidth;
294    }
295
296    const img = new Image();
297
298    return new Promise((resolve) => {
299      img.onload = () => {
300      
301        const orientation = elementWidth > elementHeight ? "l" : "p";
302
303        const doc = new jsPDF({
304          orientation,
305          unit: "px",
306          format: "a4",
307        });
308
309        const pageWidth = doc.internal.pageSize.getWidth();
310        const pageHeight = doc.internal.pageSize.getHeight();
311
312        const scale = Math.min(
313          (pageWidth - 20) / elementWidth,
314          (pageHeight - 20) / elementHeight
315        );
316
317        const width = elementWidth * scale;
318        const height = elementHeight * scale;
319
320        const x = (pageWidth - width) / 2;
321        const y = (pageHeight - height) / 2;
322
323        doc.addImage(img, "PNG", x, y, width, height,undefined, "FAST");
324        const filename = `document-${new Date().toISOString().slice(0, 10)}.pdf`;
325        doc.save(filename);
326        downloadButton.removeClass("loading");
327      };
328
329      img.onerror = (error) => {
330        console.error("Certificate image generation failed:", error);
331        downloadButton.removeClass("loading");
332        resolve(false);
333      };
334
335      img.src = dataUrl;
336    });
337  } catch (error) {
338    console.error("Certificate generation failed:", error);
339    downloadButton.removeClass("loading");
340  }
341}
342
343// Event Countdown Function
344
345function count_down($, $scope) {
346  const countdownContainer = $scope.find(".etn-event-countdown-wrap");
347  if (countdownContainer.length) {
348    $scope.find(".etn-countdown-parent").countdown({
349      date: countdownContainer.data("start-date"),
350      day: countdownContainer.data("date-texts").day,
351      days: countdownContainer.data("date-texts").days,
352      hour: countdownContainer.data("date-texts").hr,
353      hours: countdownContainer.data("date-texts").hrs,
354      minute: countdownContainer.data("date-texts").min,
355      minutes: countdownContainer.data("date-texts").mins,
356      second: countdownContainer.data("date-texts").sec,
357      seconds: countdownContainer.data("date-texts").secs,
358      hideOnComplete: true,
359      offset: countdownContainer.data("date-texts").offset,
360    });
361  }
362}
363
364// print order details
365function etn_pro_pirnt_content_area(divContents) {
366  "use strict";
367  var mywindow = window.open("", "PRINT", "height=400,width=800");
368  mywindow.document.write(
369    '<style type="text/css">' +
370      ".woocommerce-column--1, .woocommerce-column--2{display:inline-block; float: none; width: 300px; vertical-align: top;}  .woocommerce-table tr th{text-align:left; width: 300px; }" +
371      "</style>"
372  );
373
374  var contentToPrint =
375    document.getElementsByClassName(divContents)[0].innerHTML;
376  contentToPrint = contentToPrint.split('<div class="extra-buttons">')[0];
377  mywindow.document.write("</head><body >");
378  mywindow.document.write(contentToPrint);
379  mywindow.document.write("</body></html>");
380  mywindow.document.close(); // necessary for IE >= 10
381  mywindow.focus(); // necessary for IE >= 10*/
382  mywindow.print();
383  return true;
384}
385
386//download pdf
387function etn_pro_download_pdf() {
388  var contentToPrint =
389    document.getElementsByClassName("woocommerce-order")[0].innerHTML;
390  var source = contentToPrint.split('<div class="extra-buttons">')[0];
391  var filename = "invoice";
392  jQuery(".woocommerce-order").html(source);
393  var divToPrint = jQuery(".woocommerce-order")[0];
394
395  // create custom canvas for a better resolution
396  var w = 1000;
397  var h = 1000;
398  var canvas = document.createElement("canvas");
399  canvas.width = w * 5;
400  canvas.height = h * 5;
401  canvas.style.width = w + "px";
402  canvas.style.height = h + "px";
403  var context = canvas.getContext("2d");
404  context.scale(5, 5);
405
406  html2canvas(divToPrint, {
407    scale: 4,
408    dpi: 288,
409    onrendered: function (canvas) {
410      var data = canvas.toDataURL("image/png", 1);
411      var docDefinition = {
412        content: [
413          {
414            image: data,
415            width: 500,
416          },
417        ],
418      };
419      pdfMake.createPdf(docDefinition).download(filename + ".pdf");
420    },
421  });
422  window.setTimeout(function () {
423    location.reload();
424  }, 500);
425}
426
427function getSwiperOption({ count, space, autoplays }) {
428  return {
429    slidesPerView: count,
430    spaceBetween: space,
431    navigation: {
432      nextEl: ".swiper-button-next",
433      prevEl: ".swiper-button-prev",
434    },
435    pagination: {
436      el: ".swiper-pagination",
437      clickable: true,
438    },
439    autoplay: autoplays,
440
441    paginationClickable: true,
442    breakpoints: {
443      320: {
444        slidesPerView: 1,
445      },
446      600: {
447        slidesPerView: 2,
448      },
449      1024: {
450        slidesPerView: count,
451      },
452    },
453  };
454}
455
456// speaker sliders pro
457function speaker_sliders_pro($, $scope) {
458  var $container = $scope.find(".etn-speaker-slider");
459  var count = $container.data("count");
460  var space = $container.data("space");
461  var autoplay = $container.data("autoplay");
462  var autoplays = autoplay == "yes" ? true : false;
463
464  if ($container.length > 0) {
465    $($container).each(function (index, element) {
466      var mySwiper = new Swiper(
467        element,
468        getSwiperOption({ count, space: 20, autoplays })
469      );
470    });
471  }
472}
473
474// Event sliders pro
475function event_sliders_pro($, $scope) {
476  var $container = $scope.find(".etn-event-slider");
477  var count = $container.data("count");
478  var autoplay = $container.data("autoplay");
479  var autoplays = autoplay == "yes" ? true : false;
480  if ($container.length > 0) {
481    $($container).each(function (index, element) {
482      var mySwiper = new Swiper(
483        element,
484        getSwiperOption({ count, space: 20, autoplays })
485      );
486    });
487  }
488}
489
490
491// Places the hover card of a calendar event next to the event it belongs to.
492//
493// The card is a child of the event element, so the stylesheet could only
494// anchor it with `bottom: calc(100% + 14px)` — always above, always centred on
495// the event. That reads correctly for a month-view chip, but a timeGrid event
496// is as tall as its duration and only ~78px wide, so the card wants to sit
497// above a 500px-tall block (off the top of the page) and centred on a column
498// narrower than itself (off the side of it). Measure per hover instead: keep
499// the card above the event where it fits, drop it against the event's top edge
500// where it does not, and slide it back inside the viewport horizontally.
501function etn_calendar_tooltip_placement($) {
502  // Matches the spacing the month view has always had between card and event.
503  var GAP = 14;
504  // Never let the card touch the edge of the screen.
505  var EDGE = 8;
506  // Keep the arrow this far from the card's own corners.
507  var ARROW_INSET = 16;
508  // The card's own `z-index: 2000` gets it nowhere: .fc-event-main is a
509  // stacking context, so the card can only order itself inside its own event.
510  // Above that FullCalendar gives every event a harness, and every column's
511  // harnesses a shared .fc-timegrid-col-events at z-index 3 — the column
512  // wrappers all tie, so they paint in DOM order and Thursday covers a card
513  // that spills out of Wednesday. Lift both levels for the hovered event.
514  var RAISE = [
515    ".fc-timegrid-event-harness",
516    ".fc-timegrid-col-events",
517    ".fc-daygrid-event-harness",
518    ".fc-daygrid-day-events",
519  ].join(",");
520  var raised = [];
521
522  function lower() {
523    raised.forEach(function (element) {
524      element.style.zIndex = element.getAttribute("data-etn-z") || "";
525      element.removeAttribute("data-etn-z");
526    });
527    raised = [];
528  }
529
530  $(document).on(
531    "mouseenter",
532    ".events_calendar_standard .has-event, .events_calendar_list .has-event",
533    function () {
534      var tooltip = this.querySelector(".calendar-tooltip");
535
536      if (!tooltip) {
537        return;
538      }
539
540      lower();
541
542      for (var node = this.parentElement; node; node = node.parentElement) {
543        if (node.classList.contains("fc")) {
544          break;
545        }
546
547        if (node.matches(RAISE)) {
548          node.setAttribute("data-etn-z", node.style.zIndex);
549          node.style.zIndex = "2000";
550          raised.push(node);
551        }
552      }
553
554      // .fc-event-main — null while the card is display:none, which is how the
555      // mobile breakpoint switches it off. Nothing to place in that case.
556      var anchor = tooltip.offsetParent;
557
558      if (!anchor) {
559        return;
560      }
561
562      // Measure against the stylesheet's own placement, not the previous
563      // hover's overrides.
564      tooltip.style.top = "";
565      tooltip.style.bottom = "";
566      tooltip.style.translate = "";
567      tooltip.style.removeProperty("--etn-tooltip-arrow-left");
568      tooltip.classList.remove("etn-tooltip-flipped");
569
570      var height = tooltip.offsetHeight;
571      var width = tooltip.offsetWidth;
572
573      if (!height || !width) {
574        return;
575      }
576
577      var event = this.getBoundingClientRect();
578      var anchorRect = anchor.getBoundingClientRect();
579      var topLimit = EDGE;
580      var bottomLimit = window.innerHeight - EDGE;
581
582      if (event.top - GAP - height >= topLimit) {
583        // Room above: the month-view look, now in pixels rather than a
584        // percentage of however tall this particular event happens to be.
585        tooltip.style.bottom = anchorRect.height + GAP + "px";
586        tooltip.style.top = "auto";
587      } else {
588        // No room above. Hang the card off the event's TOP edge rather than
589        // its bottom — an all-day timeGrid event runs the height of the grid,
590        // and a card below it would be hundreds of pixels from the label the
591        // pointer is actually on.
592        var top = Math.min(
593          Math.max(event.top + GAP, topLimit),
594          Math.max(bottomLimit - height, topLimit)
595        );
596
597        tooltip.style.top = top - anchorRect.top + "px";
598        tooltip.style.bottom = "auto";
599        tooltip.classList.add("etn-tooltip-flipped");
600      }
601
602      // The card has a 300px minimum and a week-view column is narrower than
603      // that, so centring it on the event pushes it off screen in the first
604      // and last columns. `translate` rather than `transform`: the stylesheet
605      // animates the card in on `transform`, and the two compose.
606      var placed = tooltip.getBoundingClientRect();
607      var shift = 0;
608
609      if (placed.right > window.innerWidth - EDGE) {
610        shift = window.innerWidth - EDGE - placed.right;
611      }
612
613      if (placed.left + shift < EDGE) {
614        shift = EDGE - placed.left;
615      }
616
617      if (shift) {
618        tooltip.style.translate = Math.round(shift) + "px";
619      }
620
621      // Keep the arrow over the event now that the card may have moved off it.
622      // The arrow is drawn 3px left of its `left`, hence the offset.
623      var arrow = event.left + event.width / 2 - (placed.left + shift);
624
625      arrow = Math.min(Math.max(arrow, ARROW_INSET), width - ARROW_INSET);
626      tooltip.style.setProperty(
627        "--etn-tooltip-arrow-left",
628        Math.round(arrow) + 3 + "px"
629      );
630    }
631  );
632
633  $(document).on(
634    "mouseleave",
635    ".events_calendar_standard .has-event, .events_calendar_list .has-event",
636    lower
637  );
638}

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.