PageSourceSearch

https://www.fneid.es/land/assets/scripts/canva.min.js?v=2026-10-04-0035

js fneid.es collected 2026-10-04 18:58:04 UTC 21,473 bytes, 674 lines download raw bytes

1
2// CANVA
3function extractYouTubeVideoId(input) {
4  if (!input) {
5    return '';
6  }
7
8  var value = String(input).trim();
9  if (!value) {
10    return '';
11  }
12
13  // Raw id
14  if (/^[a-zA-Z0-9_-]{11}$/.test(value)) {
15    return value;
16  }
17
18  // URL formats
19  var patterns = [
20    /[?&]v=([a-zA-Z0-9_-]{11})/,
21    /youtu\.be\/([a-zA-Z0-9_-]{11})/,
22    /youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/,
23    /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/
24  ];
25
26  for (var i = 0; i < patterns.length; i++) {
27    var match = value.match(patterns[i]);
28    if (match && match[1]) {
29      return match[1];
30    }
31  }
32
33  return '';
34}
35
36function extractVimeoVideoId(input) {
37  if (!input) {
38    return '';
39  }
40
41  var value = String(input).trim();
42  if (!value) {
43    return '';
44  }
45
46  if (/^\d+$/.test(value)) {
47    return value;
48  }
49
50  var patterns = [
51    /vimeo\.com\/(?:video\/)?(\d+)/,
52    /player\.vimeo\.com\/video\/(\d+)/,
53    /vimeo\.com\/channels\/[^/]+\/(\d+)/,
54    /vimeo\.com\/groups\/[^/]+\/videos\/(\d+)/
55  ];
56
57  for (var i = 0; i < patterns.length; i++) {
58    var match = value.match(patterns[i]);
59    if (match && match[1]) {
60      return match[1];
61    }
62  }
63
64  return '';
65}
66
67function ensureYouTubeFloatingWindow() {
68  if (document.getElementById('canva-youtube-window')) {
69    return;
70  }
71
72  var style = document.createElement('style');
73  style.setAttribute('data-canva-youtube-style', '1');
74  style.textContent = `
75    #canva-youtube-window.canva-hidden { display: none !important; }
76    #canva-youtube-window {
77      position: fixed;
78      inset: 0;
79      background: rgba(0, 0, 0, 0.9);
80      z-index: 99999;
81      justify-content: center;
82      align-items: flex-start;
83      padding: 50px 20px;
84      overflow: auto;
85    }
86    #canva-youtube-window:not(.canva-hidden) { display: flex; }
87    #canva-youtube-window .canva-youtube-content {
88      position: relative;
89      width: 80vw;
90      max-height: 80vh;
91      background: transparent;
92      padding: 0;
93    }
94    #canva-youtube-window .canva-youtube-close {
95      position: absolute;
96      right: -6px;
97      top: -40px;
98      color: #fff;
99      font-size: 36px;
100      line-height: 1;
101      cursor: pointer;
102      user-select: none;
103      z-index: 1;
104    }
105    #canva-youtube-window .canva-youtube-holder {
106      position: relative;
107      padding-bottom: 56.25%;
108      height: 0;
109      overflow: hidden;
110    }
111    #canva-youtube-window .canva-youtube-holder iframe {
112      position: absolute;
113      inset: 0;
114      width: 100%;
115      height: 100%;
116      border: 0;
117    }`;
118  document.head.appendChild(style);
119
120  var wrapper = document.createElement('div');
121  wrapper.id = 'canva-youtube-window';
122  wrapper.className = 'canva-hidden';
123  wrapper.innerHTML = `
124    <div class="canva-youtube-content">
125      <span class="canva-youtube-close" aria-label="Cerrar">&times;</span>
126      <div class="canva-youtube-holder" id="canva-youtube-holder"></div>
127    </div>`;
128  document.body.appendChild(wrapper);
129
130  function closeYouTubeFloatingWindow() {
131    var holder = document.getElementById('canva-youtube-holder');
132    if (holder) {
133      holder.innerHTML = '';
134    }
135    wrapper.classList.add('canva-hidden');
136  }
137
138  wrapper.querySelector('.canva-youtube-close').addEventListener('click', closeYouTubeFloatingWindow);
139  wrapper.addEventListener('click', function (event) {
140    if (event.target === wrapper) {
141      closeYouTubeFloatingWindow();
142    }
143  });
144  document.addEventListener('keydown', function (event) {
145    if (event.key === 'Escape' && !wrapper.classList.contains('canva-hidden')) {
146      closeYouTubeFloatingWindow();
147    }
148  });
149
150  window.closeCanvaYouTubeFloatingWindow = closeYouTubeFloatingWindow;
151}
152
153function openYouTubeFloatingWindow(videoInput) {
154  ensureYouTubeFloatingWindow();
155  var videoId = extractYouTubeVideoId(videoInput);
156  if (!videoId) {
157    return;
158  }
159
160  var wrapper = document.getElementById('canva-youtube-window');
161  var holder = document.getElementById('canva-youtube-holder');
162  if (!wrapper || !holder) {
163    return;
164  }
165
166  var videoURL = 'https://www.youtube.com/embed/' + videoId + '?autoplay=1&rel=0';
167  holder.innerHTML = '<iframe src="' + videoURL + '" allow="autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
168  wrapper.classList.remove('canva-hidden');
169}
170
171function openVimeoFloatingWindow(videoInput) {
172  ensureYouTubeFloatingWindow();
173  var videoId = extractVimeoVideoId(videoInput);
174  if (!videoId) {
175    return;
176  }
177
178  var wrapper = document.getElementById('canva-youtube-window');
179  var holder = document.getElementById('canva-youtube-holder');
180  if (!wrapper || !holder) {
181    return;
182  }
183
184  var videoURL = 'https://player.vimeo.com/video/' + videoId + '?autoplay=1&title=0&byline=0&portrait=0';
185  holder.innerHTML = '<iframe src="' + videoURL + '" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>';
186  wrapper.classList.remove('canva-hidden');
187}
188
189function enforceInlineMobileVideos() {
190  $('.canva video').each(function () {
191    var video = this;
192    video.setAttribute('playsinline', '');
193    video.setAttribute('webkit-playsinline', '');
194    if (!video.getAttribute('preload')) {
195      video.setAttribute('preload', 'metadata');
196    }
197    video.muted = true;
198    video.defaultMuted = true;
199    video.playsInline = true;
200  });
201}
202
203function syncMobileVideoPlayback() {
204  enforceInlineMobileVideos();
205
206  $('.canva video').each(function () {
207    var video = this;
208    var $video = $(video);
209    var isVisible = $video.is(':visible');
210    var isInHiddenSlide = false;
211
212    var flexItem = $video.closest('.canvasflex');
213    if (flexItem.length && !flexItem.hasClass('active')) {
214      isInHiddenSlide = true;
215    }
216
217    var carouselItem = $video.closest('.carousel .item');
218    if (carouselItem.length && !carouselItem.hasClass('active')) {
219      isInHiddenSlide = true;
220    }
221
222    var swiperSlide = $video.closest('.canva-peek-swiper .swiper-slide');
223    if (swiperSlide.length && !swiperSlide.hasClass('swiper-slide-active')) {
224      isInHiddenSlide = true;
225    }
226
227    if (!isVisible || isInHiddenSlide) {
228      video.pause();
229      return;
230    }
231
232    if (video.autoplay) {
233      var promise = video.play();
234      if (promise && typeof promise.catch === 'function') {
235        promise.catch(function () { });
236      }
237    }
238  });
239}
240
241function scheduleMobileVideoPlaybackSync() {
242  syncMobileVideoPlayback();
243  requestAnimationFrame(function () {
244    syncMobileVideoPlayback();
245  });
246  setTimeout(function () {
247    syncMobileVideoPlayback();
248  }, 120);
249  setTimeout(function () {
250    syncMobileVideoPlayback();
251  }, 320);
252}
253
254$(window).on('resize', function (e) {
255  doScale();
256  scheduleMobileVideoPlaybackSync();
257});
258$(document).ready(function () {
259  enforceInlineMobileVideos();
260  scheduleMobileVideoPlaybackSync();
261  doScale();
262  loadFonts();
263  $('body').on('click', '.layer', function (e) {
264    e.preventDefault();
265    e.stopPropagation();
266    var layer = $(this);
267    var action = layer.attr('data-action');
268    if (action && action != 'none') {
269      var target = layer.attr('data-target');
270      var link = layer.attr('data-link');
271      var info = layer.attr('data-info');
272
273      switch (action) {
274        case 'url':
275          if (target && target == 'blank') {
276            window.open(link, target).focus();
277          } else {
278            window.open(link, '_self');
279          }
280          break;
281
282        case 'section':
283          if (target && target == 'blank') {
284            window.open(link, target).focus();
285          } else if (target && target == 'modal') {
286            open_modal(link, 'ajaxmodal', '');
287          } else {
288            window.open(link, '_self');
289          }
290          break;
291
292        case 'whatsapp':
293          window.open('https://api.whatsapp.com/send?phone=' + link, target).focus();
294          break;
295
296        case 'phone':
297          window.open('tel:' + link);
298          break;
299
300        case 'email':
301          window.open('mailto:' + link);
302          break;
303
304        case 'gotoslide':
305          var slideNumber = parseInt(link, 10);
306          if (!isNaN(slideNumber) && slideNumber > 0) {
307            // 0) Swiper peek mode
308            var peekSlider = layer.closest('.canva-peek-swiper');
309            if (peekSlider.length) {
310              var targetIndex = slideNumber - 1;
311              var swiperInstance = peekSlider.data('swiper') || (peekSlider.get(0) && peekSlider.get(0).swiper);
312              if (swiperInstance) {
313                if (swiperInstance.params && swiperInstance.params.loop && typeof swiperInstance.slideToLoop === 'function') {
314                  swiperInstance.slideToLoop(targetIndex);
315                } else if (typeof swiperInstance.slideTo === 'function') {
316                  swiperInstance.slideTo(targetIndex);
317                }
318                doScale();
319                scheduleMobileVideoPlaybackSync();
320                break;
321              }
322            }
323
324            // 1) Website/keynote mode (containers with id canvawebsite{rnd}{n})
325            var container = layer.closest('[id^="canvawebsite"]');
326            if (!container.length) {
327              container = layer.closest('.canvawebsite');
328            }
329            var rnd = container.attr('data-rnd');
330            var new_container = rnd ? container.siblings('#canvawebsite' + rnd + slideNumber) : $();
331            if (new_container[0]) {
332              container.hide();
333              new_container.show();
334              doScale();
335              scheduleMobileVideoPlaybackSync();
336              break;
337            }
338
339            // 2) Bootstrap carousel mode
340            var carousel = layer.closest('.carousel');
341            if (carousel.length) {
342              var targetIndex = slideNumber - 1;
343              if (typeof carousel.carousel === 'function') {
344                carousel.carousel(targetIndex);
345              } else {
346                var items = carousel.find('.carousel-inner .item');
347                var indicators = carousel.find('.carousel-indicators li');
348                items.removeClass('active').eq(targetIndex).addClass('active');
349                indicators.removeClass('active').eq(targetIndex).addClass('active');
350              }
351              doScale();
352              scheduleMobileVideoPlaybackSync();
353              break;
354            }
355
356            // 3) Accordion/flexslider mode (data-order is 0-based)
357            var flexslider = layer.closest('.flexslider');
358            if (flexslider.length) {
359              var order = slideNumber - 1;
360              var active = flexslider.find('.canvasflex.active');
361              var next = flexslider.find('.canvasflex[data-order="' + order + '"]');
362              if (next.length) {
363                active.removeClass('active');
364                next.addClass('active');
365                doScale();
366                scheduleMobileVideoPlaybackSync();
367              }
368            }
369          }
370          break;
371
372        case 'html':
373          break;
374
375        case 'pdf':
376          break;
377
378        case 'video':
379          break;
380
381        case 'youtube':
382          openYouTubeFloatingWindow(link);
383          break;
384        case 'vimeo':
385          openVimeoFloatingWindow(link);
386          break;
387
388        case 'gmap':
389          break;
390      }
391    }
392  });
393
394  $('body').on('mouseenter', '.canvashover .flexslider li', function (e) {
395    if (!$(this).hasClass('active')) {
396      $(this).siblings().removeClass('active');
397      $(this).addClass('active');
398      scheduleMobileVideoPlaybackSync();
399    }
400  });
401
402  $('body').on('slid.bs.carousel', '.carousel', function () {
403    scheduleMobileVideoPlaybackSync();
404  });
405
406  $('body').on('transitionend webkitTransitionEnd', '.flexslider .canvasflex', function () {
407    if ($(this).hasClass('active')) {
408      scheduleMobileVideoPlaybackSync();
409    }
410  });
411});
412
413function loadFont(aval) {
414  const regex = /^custom\d+$/i;
415  const value = aval.replaceAll('"', '').replaceAll("'", "").replaceAll(', sans-serif', '').replaceAll(' !important', '');
416  var fontlink = `https://fonts.googleapis.com/css?family=${value}`;
417  if (regex.test(aval)) {
418    //Custom font
419    fontlink = server + `customfont?family=${value}`;
420  }
421  const link = document.createElement('link');
422  link.setAttribute('rel', 'stylesheet');
423  link.setAttribute('href', fontlink);
424  document.head.appendChild(link);
425}
426
427//Loads gfonts family
428function loadFonts() {
429  const loaded = [];
430  $('.layercontent').each(function () {
431    var content = $(this);
432    aval = content.css('font-family');
433    if (aval) {
434      if (!loaded.includes(aval)) {
435        loaded.push(aval);
436        loadFont(aval);
437      }
438    }
439  });
440}
441
442
443function doScale(id = '') {
444  $('.canva' + id).each(function () {
445    var canva = $(this);
446    var parent = canva.parent();
447    //Use reference to resize based on other div instead of parent size (for accordion)
448    var pwidth = parent.width();
449    var pheight = parent.height();
450
451    if (canva.attr('data-reference')) {
452      var reference = $(canva.attr('data-reference'));
453      pwidth = reference.width();
454      pheight = reference.height();
455    }
456
457    var scale = Math.min(
458      pwidth / canva.attr('width'),
459      pheight / canva.attr('height')
460    );
461    if (canva.attr('width') * scale < pwidth) {
462      scale = pwidth / canva.attr('width');
463    }
464    canva.css({
465      transformOrigin: 'top left',
466      transform: "translate(0%,0%) scale(" + scale + ")"
467    });
468    canva.css('opacity', 1);
469    var peekSlide = canva.closest('.canva-peek-swiper .swiper-slide');
470    var shouldAnimateLayers = !peekSlide.length || peekSlide.hasClass('swiper-slide-active');
471    // Restart layer animations every time the canvas is shown/scaled (initial paint,
472    // slide switch, resize), so public view reliably plays them.
473    canva.find('.layer').each(function () {
474      var layer = $(this);
475      var animationName = String(layer.attr('data-animate') || '').trim();
476      if (!animationName || animationName === 'none') {
477        return;
478      }
479      var layerStyleAttr = String(layer.attr('style') || '').toLowerCase();
480      var hasInlineDuration = /(?:^|;
480)\s*(?:-webkit-)?animation-duration\s*:/.test(layerStyleAttr);
481      var hasInlineDelay = /(?:^|;)\s*(?:-webkit-)?animation-delay\s*:/.test(layerStyleAttr);
482      var hasInlineIterations = /(?:^|;)\s*(?:-webkit-)?animation-iteration-count\s*:/.test(layerStyleAttr);
483      var hasInlineDirection = /(?:^|;)\s*(?:-webkit-)?animation-direction\s*:/.test(layerStyleAttr);
484      var hasInlineTiming = /(?:^|;)\s*(?:-webkit-)?animation-timing-function\s*:/.test(layerStyleAttr);
485      var animTarget = layer.find('.layeranim').first();
486      if (!animTarget.length) {
487        animTarget = layer.find('.layercontent').first();
488      }
489      if (!animTarget.length) {
490        return;
491      }
492      if (!shouldAnimateLayers) {
493        animTarget.removeClass('animated');
494        return;
495      }
496      var animationOverrides = {};
497      if (hasInlineDuration) {
498        var inlineDuration = String(layer.css('animation-duration') || '').trim();
499        if (inlineDuration && inlineDuration !== '0s' && inlineDuration !== '0ms') {
500          animationOverrides['animation-duration'] = inlineDuration;
501          animationOverrides['-webkit-animation-duration'] = inlineDuration;
502        }
503      }
504      if (hasInlineDelay) {
505        var inlineDelay = String(layer.css('animation-delay') || '').trim();
506        if (inlineDelay) {
507          animationOverrides['animation-delay'] = inlineDelay;
508          animationOverrides['-webkit-animation-delay'] = inlineDelay;
509        }
510      }
511      if (hasInlineIterations) {
512        var inlineIterations = String(layer.css('animation-iteration-count') || '').trim();
513        if (inlineIterations) {
514          animationOverrides['animation-iteration-count'] = inlineIterations;
515          animationOverrides['-webkit-animation-iteration-count'] = inlineIterations;
516        }
517      }
518      if (hasInlineDirection) {
519        var inlineDirection = String(layer.css('animation-direction') || '').trim();
520        if (inlineDirection) {
521          animationOverrides['animation-direction'] = inlineDirection;
522          animationOverrides['-webkit-animation-direction'] = inlineDirection;
523        }
524      }
525      if (hasInlineTiming) {
526        var inlineTiming = String(layer.css('animation-timing-function') || '').trim();
527        if (inlineTiming) {
528          animationOverrides['animation-timing-function'] = inlineTiming;
529          animationOverrides['-webkit-animation-timing-function'] = inlineTiming;
530        }
531      }
532      if (Object.keys(animationOverrides).length) {
533        animTarget.css(animationOverrides);
534      }
535      var prevAnimation = String(animTarget.attr('data-current-animation') || '').trim();
536      if (prevAnimation && prevAnimation !== animationName) {
537        animTarget.removeClass(prevAnimation);
538      }
539      animTarget.removeClass('animated');
540      animTarget.removeClass(animationName);
541      if (animTarget.get(0)) {
542        void animTarget.get(0).offsetWidth;
543      }
544      animTarget.addClass(animationName + ' animated');
545      if (!hasInlineDuration) {
546        var resolvedDuration = String(animTarget.css('animation-duration') || '').trim();
547        if (!resolvedDuration || resolvedDuration === '0s' || resolvedDuration === '0ms') {
548          animTarget.css({
549            'animation-duration': '1s',
550            '-webkit-animation-duration': '1s'
551          });
552        }
553      }
554      animTarget.attr('data-current-animation', animationName);
555    });
556
557    parent.height(canva.height() * scale);
558  });
559}
560
561
562function initializeFlexslider(canvasId, interval, loop) {
563  $(document).ready(function () {
564    var time = interval * 1000;
565    var order = 1;
566    var timerId = setInterval(function () { nextSlide(); }, time);
567    $(canvasId + ' .flexslider').on('mouseenter', function () {
568      clearInterval(timerId);
569    });
570    $(canvasId + ' .flexslider').on('mouseleave', function () {
571      timerId = setInterval(function () { nextSlide(); }, time);
572    });
573    function nextSlide() {
574      var active = $(canvasId + ' .flexslider .canvasflex.active');
575      var next = $(canvasId + ' .flexslider .canvasflex[data-order=' + order + ']');
576      if (next.length) {
577        active.removeClass('active');
578        next.addClass('active');
579        order = (order % $(canvasId + ' .flexslider .canvasflex').length) + 1;
580        scheduleMobileVideoPlaybackSync();
581      } else {
582        if (loop) {
583          order = 0;
584          $(canvasId + ' .flexslider .canvasflex').removeClass('active');
585          $(canvasId + ' .flexslider .canvasflex[data-order=0]').addClass('active');
586          scheduleMobileVideoPlaybackSync();
587        }
588      }
589    }
590  });
591}
592
593window.addEventListener('keydown', function (event) {
594  var target = event.target;
595  var isTypingContext = false;
596  if (target) {
597    var tag = (target.tagName || '').toLowerCase();
598    isTypingContext = target.isContentEditable || tag === 'input' || tag === 'textarea' || tag === 'select';
599  }
600
601  var isCmdCtrl = !!(event.metaKey || event.ctrlKey);
602  var key = String(event.key || '').toLowerCase();
603  if (!isCmdCtrl || key !== 'm' || isTypingContext) {
604    return;
605  }
606
607  event.preventDefault();
608  event.stopPropagation();
609
610  if (typeof window.toggleAddSlideTemplatePicker === 'function') {
611    window.toggleAddSlideTemplatePicker();
612    return;
613  }
614
615  var addSlideButton = document.querySelector('.add-slide-button');
616  if (addSlideButton && typeof addSlideButton.click === 'function') {
617    addSlideButton.click();
618  }
619}, true);
620
621// Canva layer tooltips (public website only): delegated, independent from Bootstrap tooltip.
622(function () {
623  function initCanvaLayerTooltipsPublic() {
624    var layerSelector = '.canva .layer[data-tooltip]';
625    var bubbleId = 'canva-layer-tooltip-bubble';
626    var bubble = document.getElementById(bubbleId);
627    if (!bubble) {
628      bubble = document.createElement('div');
629      bubble.id = bubbleId;
630      bubble.className = 'canva-layer-tooltip-bubble';
631      document.body.appendChild(bubble);
632    }
633
634    function positionBubble(clientX, clientY) {
635      if (!bubble || bubble.style.display !== 'block') {
636        return;
637      }
638      var x = Number.isFinite(clientX) ? clientX : 0;
639      var y = Number.isFinite(clientY) ? clientY : 0;
640      var maxX = window.innerWidth - bubble.offsetWidth - 8;
641      var maxY = window.innerHeight - bubble.offsetHeight - 8;
642      var finalX = Math.max(8, Math.min(maxX, x + 12));
643      var finalY = Math.max(8, Math.min(maxY, y - bubble.offsetHeight - 12));
644      bubble.style.left = finalX + 'px';
645      bubble.style.top = finalY + 'px';
646    }
647
648    $(document).off('.canvalayertooltip_public');
649    $(document).on('mouseenter.canvalayertooltip_public focusin.canvalayertooltip_public', layerSelector, function (e) {
650      var text = String($(this).attr('data-tooltip') || '').trim();
651      if (!text) {
652        bubble.style.display = 'none';
653        return;
654      }
655      bubble.textContent = text;
656      bubble.style.display = 'block';
657      if (e && Number.isFinite(e.clientX) && Number.isFinite(e.clientY)) {
658        positionBubble(e.clientX, e.clientY);
659      }
660    });
661
662    $(document).on('mousemove.canvalayertooltip_public', layerSelector, function (e) {
663      positionBubble(e.clientX, e.clientY);
664    });
665
666    $(document).on('mouseleave.canvalayertooltip_public blur.canvalayertooltip_public', layerSelector, function () {
667      bubble.style.display = 'none';
668    });
669  }
670
671  $(document).ready(function () {
672    initCanvaLayerTooltipsPublic();
673  });
674})();

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.