1(function ($) { 2 "use strict"; 3 4 // GLOBAL VARIABLE DECLARATION 5 const releaseNotes = $('.release-notes'), 6 introAnimationTime = 1000, 7 carouselTimer = (window.CAROUSEL_TIMER_VALUE ?? 5) * 1000; 8 let autoAdvance = true; 9 10 // INTRO ANIMATION 11 $(function () { 12 const loginScreen = $('.loginscreen'), 13 rnChildren = releaseNotes.children(); 14 15 loginScreen.addClass('slide-in'); 16 17 setTimeout(() => { 18 requestAnimationFrame(() => { 19 releaseNotes.css('transform', 'scale(1)'); 20 }); 21 }, 650); 22 23 setTimeout(() => { 24 rnChildren.css('opacity', 1); 25 }, introAnimationTime); 26 }); 27 28 // GLOBAL RELEASE NOTES STORE 29 window.ReleaseNotes = { 30 data: [], 31 get() { return this.data.slice(); } 32 }; 33 34 // LANGUAGE AND DATE 35 const APP_LANG = window.APP_LANG.toLowerCase().slice(0, 2); 36 37 const FEED_URLS = { 38 cs: 'https://www.emailcampaigns.eu/action/function/feeds/releasenotes/cz.xml', 39 sk: 'https://www.emailcampaigns.eu/action/function/feeds/releasenotes/sk.xml', 40 en: 'https://www.emailcampaigns.eu/action/function/feeds/releasenotes/en.xml', 41 hu: 'https://www.emailcampaigns.eu/action/function/feeds/releasenotes/hu.xml' 42 }; 43 44 const feedUrl = FEED_URLS[APP_LANG]; 45 46 function formatRssDate(pubDateStr) { 47 if (!pubDateStr) return ''; 48 let d = new Date(pubDateStr); 49 if (isNaN(d)) return ''; 50 let y = d.getFullYear(); 51 let m = ('0' + (d.getMonth() + 1)).slice(-2); 52 let dd = ('0' + d.getDate()).slice(-2); 53 return dd + '.' + m + '.' + y; 54 } 55 56 // FETCH 57 async function fetchReleaseNotes() { 58 try { 59 const xml = await $.ajax({ 60 url: feedUrl, 61 type: 'GET', 62 dataType: 'xml' 63 }); 64 65 const data = []; 66 $('channel > item', xml).each(function () { 67 const getText = (el, selector) => el.find(selector).first().text(); 68 const icon = getText($(this), 'ec\\:icon'), 69 iconColor = getText($(this), 'ec\\:iconColor'), 70 iconBgColor = getText($(this), 'ec\\:iconBgColor'), 71 borderColor = getText($(this), 'ec\\:borderColor'), 72 releaseDate = formatRssDate(getText($(this), 'pubDate')), 73 title = getText($(this), 'title'), 74 text = getText($(this), 'description, text'), 75 buttonText = getText($(this), 'ec\\:buttonText'), 76 buttonUrl = getText($(this), 'link'); 77 78 data.push({ 79 icon: icon, 80 iconColor: iconColor, 81 iconBgColor: iconBgColor, 82 borderColor: borderColor, 83 releaseDate: releaseDate, 84 title: title, 85 text: text, 86 buttonText: buttonText, 87 buttonUrl: buttonUrl 88 }); 89 }); 90 91 window.ReleaseNotes.data = data; 92 $(document).trigger('releaseNotes:loaded', [ data ]); 93 return data; 94 } catch (err) { 95 autoAdvance = false; 96 $('#release-notes-carousel').css('visibility', 'hidden'); 97 $('#release-notes-fallback').css('visibility', 'visible'); 98 return []; 99 } 100 } 101 102 // CAROUSEL 103 async function releaseNotesCarousel () { 104 105 window.ReleaseNotes.data = await fetchReleaseNotes(); 106 const content = window.ReleaseNotes.data, 107 $rnIconWrapper = $('.rn-main-icon'), 108 $rnIcon = $('.rn-main-icon i'), 109 $releaseDateWrapper = $('.release-date-wrapper'), 110 $releaseDate = $('.rn-release-date'), 111 $title = $('.release-notes article h2'), 112 $text = $('.release-notes article p'), 113 $button = $('.release-notes article a'), 114 $carousel = $('.carousel'); 115 let currentIndex = 0, 116 timeoutId; 117 118 if (!content.length) { 119 autoAdvance = false;
120 $('#release-notes-carousel').css('visibility', 'hidden'); 121 $('#release-notes-fallback').css('visibility', 'visible'); 122 return; 123 } else if (content.length === 1) { 124 autoAdvance = false; 125 $('#release-notes-carousel').css('visibility', 'visible'); 126 $('#release-notes-fallback').css('visibility', 'hidden'); 127 $carousel.css('visibility', 'hidden'); 128 } else { 129 $('#release-notes-carousel').css('visibility', 'visible'); 130 $('#release-notes-fallback').css('visibility', 'hidden'); 131 $carousel.empty(); 132 content.forEach(() => $carousel.append($('<span class="carousel-button"></span>'))); 133 } 134 135 const $carouselButtons = $('.carousel-button'); 136 137 function changeContent(index) { 138 $rnIcon.add($releaseDateWrapper).add($title).add($text).add($button).css({ 139 "transition": "opacity 0.25s ease", 140 "opacity": 0 141 }); 142 $carouselButtons.removeClass('opacity-1'); 143 $carouselButtons.eq(index).addClass('opacity-1'); 144 145 setTimeout(() => { 146 releaseNotes.css({"borderColor": content[index].borderColor || "#ffffff"}); 147 $rnIconWrapper.css({"color": content[index].iconColor, "backgroundColor": content[index].iconBgColor}); 148 $rnIcon.removeClass().addClass('fa-light fa-' + content[index].icon); 149 $releaseDate.text(content[index].releaseDate); 150 $title.html(content[index].title); 151 $text.html(content[index].text); 152 $button.text(content[index].buttonText).attr('href', content[index].buttonUrl); 153 $rnIcon.add($title).add($text).css('opacity', 1); 154 155 let rd = $releaseDate.text().trim(), 156 hasValidDate = rd !== '' && rd !== '0000-00-00' && rd !== '00.00.0000'; 157 158 if (hasValidDate) { 159 const parts = rd.split('.'), 160 year = parseInt(parts[2], 10); 161 if (!isNaN(year) && year < 2025) hasValidDate = false; 162 } 163 164 $releaseDateWrapper.css('opacity', hasValidDate ? 1 : 0); 165 166 let bt = $button.text().trim(); 167 if (bt === '') { 168 $button.css({ 169 "opacity": 0, 170 "pointer-events": "none" 171 }).attr("aria-hidden", "true"); 172 } else { 173 $button.css({ 174 "opacity": 1, 175 "pointer-events": "" 176 }).removeAttr("aria-hidden"); 177 } 178 }, 250); 179 // 250 ms = trvanie zmeny release note (fade-in/out) 180 } 181 182 function startCarousel() { 183 timeoutId = setTimeout(function cycle() { 184 if (!autoAdvance) return; 185 186 currentIndex = (currentIndex + 1) % content.length; 187 changeContent(currentIndex); 188 189 timeoutId = setTimeout(cycle, carouselTimer); 190 }, carouselTimer + introAnimationTime); 191 } 192 193 changeContent(currentIndex); 194 if (autoAdvance) { 195 startCarousel(); 196 } 197 198 199 function throttle(func, limit) { 200 let inThrottle = false; 201 return function () { 202 if (!inThrottle) { 203 func.apply(this, arguments); 204 inThrottle = true; 205 setTimeout(() => inThrottle = false, limit); 206 } 207 }; 208 } 209 210 const throttledClick = throttle(function (index) { 211 const prevIndex = currentIndex; 212 clearTimeout(timeoutId); 213 autoAdvance = false; 214 currentIndex = index; 215 if (index !== prevIndex) { 216 changeContent(currentIndex); 217 } 218 }, 500); 219 // umožÅuje manuálnu zmenu vykonávaÅ¥ iba raz za 0,5s aby sa animácie neprekrývali 220 221 $carouselButtons.off('click'); 222 $carouselButtons.each(function (index) { 223 $(this).on('click', function () { 224 throttledClick(index); 225 }); 226 }); 227 228 } 229 230 $(function(){ 231 releaseNotesCarousel(); 232 }); 233 234})(jQuery);
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.