/*! * CookieConsent v2.8.0 * https://www.github.com/orestbida/cookieconsent * Author Orest Bida * Released under the MIT License */ (function(){ 'use strict'; /** * @param {HTMLElement} [root] - [optional] element where the cookieconsent will be appended * @returns {Object} cookieconsent object with API */ var c_consent = function(root){ /** * CHANGE THIS FLAG FALSE TO DISABLE console.log() */ var ENABLE_LOGS = false; var _config = { 'mode': 'opt-in', // 'opt-in', 'opt-out' 'current_lang': 'en', 'auto_language': null, 'autorun': true, // run as soon as loaded 'cookie_name': 'cc_cookie', 'cookie_expiration': 182, // default: 6 months (in days) 'cookie_domain': window.location.hostname, // default: current domain 'cookie_path': '/', 'cookie_same_site': 'Lax', 'use_rfc_cookie': false, 'autoclear_cookies': true, 'revision': 0, 'branding': true, 'script_selector': 'data-cookiecategory' }; var /** * Object which holds the main methods/API (.show, .run, ...) */ _cookieconsent = {}, /** * Global user configuration object */ user_config, /** * Internal state variables */ saved_cookie_content = {}, cookie_data = null, cookie_consent_accepted = false, consent_modal_exists = false, consent_modal_visible = false, settings_modal_visible = false, clicked_inside_modal = false, current_modal_focusable, all_table_headers, all_blocks, consent_uuid, c_consent_token, // Helper callback functions // (avoid calling "user_config['onAccept']" all the time) onAccept, onChange, onFirstAction, revision_enabled = false, valid_revision = true, revision_message = '', // State variables for the autoclearCookies function changed_settings = [], reload_page = false; /** * Accept type: * - "all" * - "necessary" * - "custom" * @type {string} */ var accept_type; /** * Contains all accepted categories * @type {string[]} */ var accepted_categories = []; /** * Contains all non-accepted (rejected) categories * @type {string[]} */ var rejected_categories = []; /** * Contains all categories enabled by default * @type {string[]} */ var default_enabled_categories = []; // Don't run plugin (to avoid indexing its text content) if bot detected var is_bot = false; /** * Save reference to the last focused element on the page * (used later to restore focus when both modals are closed) */ var last_elem_before_modal; var last_consent_modal_btn_focus; /** * Both of the arrays below have the same structure: * [0] => holds reference to the FIRST focusable element inside modal * [1] => holds reference to the LAST focusable element inside modal */ var consent_modal_focusable = []; var settings_modal_focusable = []; /** * Keep track of enabled/disabled categories * @type {boolean[]} */ var toggle_states = []; /** * Stores all available categories * @type {string[]} */ var all_categories = []; /** * Keep track of readonly toggles * @type {boolean[]} */ var readonly_categories = []; /** * Pointers to main dom elements (to avoid retrieving them later using document.getElementById) */ var /** @type {HTMLElement} */ html_dom = document.documentElement, /** @type {HTMLElement} */ main_container, /** @type {HTMLElement} */ all_modals_container, /** @type {HTMLElement} */ consent_modal, /** @type {HTMLElement} */ consent_modal_title, /** @type {HTMLElement} */ consent_modal_description, /** @type {HTMLElement} */ consent_primary_btn, /** @type {HTMLElement} */ consent_secondary_btn, /** @type {HTMLElement} */ consent_buttons, /** @type {HTMLElement} */ consent_modal_inner, /** @type {HTMLElement} */ settings_container, /** @type {HTMLElement} */ settings_inner, /** @type {HTMLElement} */ settings_title, /** @type {HTMLElement} */ settings_close_btn, /** @type {HTMLElement} */ settings_blocks, /** @type {HTMLElement} */ new_settings_blocks, /** @type {HTMLElement} */ settings_buttons, /** @type {HTMLElement} */ settings_save_btn, /** @type {HTMLElement} */ settings_accept_all_btn, /** @type {HTMLElement} */ settings_reject_all_btn; /** * Update config settings * @param {Object} user_config */ var _loadScript = function(u){ var s = document.createElement("script"); s.type = "text/javascript"; s.src = u; document.head.appendChild(s); } _cookieconsent.clearCookies = function() { var arrCookies = document.cookie.split(';'), arrPaths = location.pathname.replace(/^\//, '').split('/'), // remove leading '/' and split any existing paths arrTemplate = [ 'expires=Thu, 01-Jan-1970 00:00:01 GMT', 'path={path}', 'domain=' + window.location.host, 'secure=' ]; // array of cookie settings in order tested and found most useful in establishing a "delete" for (var i in arrCookies) { var strCookie = arrCookies[i]; if (typeof strCookie == 'string' && strCookie.indexOf('=') >= 0) { var strName = strCookie.split('=')[0]; // the cookie name for (var j=1;j<=arrTemplate.length;j++) { if (document.cookie.indexOf(strName) < 0) break; // if this is true, then the cookie no longer exist else { var strValue = strName + '=; ' + arrTemplate.slice(0, j).join('; ') + ';'; // made using the temp array of settings, putting it together piece by piece as loop rolls on if (j == 1) document.cookie = strValue; else { for (var k=0;k<=arrPaths.length;k++) { if (document.cookie.indexOf(strName) < 0) break; // if this is true, then the cookie no longer exist else { var strPath = arrPaths.slice(0, k).join('/') + '/'; // builds path line strValue = strValue.replace('{path}', strPath); document.cookie = strValue; } } } } } } } _cookieconsent.show(); return true; } var _initAll = function (_conf){ const c = JSON.parse(_getCookie(_conf.cookie_name, 'one', true) || "{}"); if(Object.keys(c).length === 0){ // _cookieconsent.clearCookies(); } window.dataLayer = window.dataLayer || [], window.gtag = () => { window.dataLayer.push(arguments); }; window.gtag('js', new Date()); window.gtag('config', _conf['ga_id']); window.gtag("consent", "default", { ad_storage: "denied", analytics_storage: "denied", wait_for_update: 500 }); if(_conf['ga_id'] != undefined && _conf['ga_id'] != ""){ _loadScript('https://www.googletagmanager.com/gtag/js?id=' + _conf['ga_id']); } const _data = { ad_storage: c.level && c.level.includes("marketing") ? "granted" : "denied", analytics_storage: c.level && c.level.includes("analytics") ? "granted" : "denied" }; window.gtag('consent', 'update', _data); } var _setConfig = function(_user_config){ /** * Make user configuration globally available */ user_config = _user_config; _log("CookieConsent [CONFIG]: received_config_settings ", user_config); if(typeof user_config['c_consent_token'] === "string") c_consent_token = user_config['c_consent_token']; if(typeof user_config['cookie_expiration'] === "number") _config.cookie_expiration = user_config['cookie_expiration']; if(typeof user_config['cookie_necessary_only_expiration'] === "number") _config.cookie_necessary_only_expiration = user_config['cookie_necessary_only_expiration']; if(typeof user_config['autorun'] === "boolean") _config.autorun = user_config['autorun']; if(typeof user_config['cookie_domain'] === "string") _config.cookie_domain = user_config['cookie_domain']; if(typeof user_config['cookie_same_site'] === "string") _config.cookie_same_site = user_config['cookie_same_site']; if(typeof user_config['cookie_path'] === "string") _config.cookie_path = user_config['cookie_path']; if(typeof user_config['cookie_name'] === "string") _config.cookie_name = user_config['cookie_name']; if(typeof user_config['privacy'] === "string") _config.privacy = user_config['privacy']; if(typeof user_config['privacy_link'] === "string") _config.privacy_link = user_config['privacy_link']; if(typeof user_config['branding'] === "boolean") _config.branding = user_config['branding']; /* if(typeof user_config['onAccept'] === "function") onAccept = user_config['onAccept']; */ if(typeof user_config['onFirstAction'] === "function") onFirstAction = user_config['onFirstAction']; if(typeof user_config['onChange'] === "function") onChange = user_config['onChange']; if(user_config['mode'] === 'opt-out') _config.mode = 'opt-out'; if(typeof user_config['revision'] === "number"){ user_config['revision'] > -1 && (_config.revision = user_config['revision']); revision_enabled = true; } if(typeof user_config['autoclear_cookies'] === "boolean") _config.autoclear_cookies = user_config['autoclear_cookies']; if(user_config['use_rfc_cookie'] === true) _config.use_rfc_cookie = true; if(user_config['hide_from_bots'] === true){ is_bot = navigator && ((navigator.userAgent && /bot|crawl|spider|slurp|teoma/i.test(navigator.userAgent)) || navigator.webdriver); } _config.page_scripts = user_config['page_scripts'] === true; _config.page_scripts_order = user_config['page_scripts_order'] !== false; //[WARNING] Will be removed in v3 if (user_config['auto_language'] === 'browser' || user_config['auto_language'] === true) { _config.auto_language = 'browser'; } else if (user_config['auto_language'] === 'document') { _config.auto_language = 'document'; } _log("CookieConsent [LANG]: auto_language strategy is '" + _config.auto_language + "'"); _config.current_lang = _resolveCurrentLang(user_config.languages, user_config['current_lang']); } var _uuidv4 = function(){ return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, function(c){ return (c ^ (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) }); } /** * Add an onClick listeners to all html elements with data-cc attribute */ var _addDataButtonListeners = function(elem){ var _a = 'accept-'; var show_settings = _getElements('c-settings'); var accept_all = _getElements(_a + 'all'); var accept_necessary = _getElements(_a + 'necessary'); var accept_selection = _getElements(_a + 'selection'); for(var i=0; i} */ function _getElements(data_role){ return (elem || document).querySelectorAll('a[data-cc="' + data_role + '"], button[data-cc="' + data_role + '"]'); } /** * Helper function: accept and then hide modals * @param {PointerEvent} e source event * @param {string} [accept_type] */ function _acceptAction(e, accept_type){ e.preventDefault ? e.preventDefault() : e.returnValue = false; _cookieconsent.accept(accept_type); _cookieconsent.hideSettings(); _cookieconsent.hide(); } } /** * Get a valid language (at least 1 must be defined) * @param {string} lang - desired language * @param {Object} all_languages - all defined languages * @returns {string} validated language */ var _getValidatedLanguage = function(lang, all_languages){ if(Object.prototype.hasOwnProperty.call(all_languages, lang)){ return lang; }else if(_getKeys(all_languages).length > 0){ if(Object.prototype.hasOwnProperty.call(all_languages, _config.current_lang)){ return _config.current_lang ; }else{ return _getKeys(all_languages)[0]; } } } /** * Save reference to first and last focusable elements inside each modal * to prevent losing focus while navigating with TAB */ var _getModalFocusableData = function(){ /** * Note: any of the below focusable elements, which has the attribute tabindex="-1" AND is either * the first or last element of the modal, won't receive focus during "open/close" modal */ var allowed_focusable_types = ['[href]', 'button', 'input', 'details', '[tabindex="0"]']; function _getAllFocusableElements(modal, _array){ var focus_later=false, focus_first=false; // ie might throw exception due to complex unsupported selector => a:not([tabindex="-1"]) try{ var focusable_elems = modal.querySelectorAll(allowed_focusable_types.join(':not([tabindex="-1"]), ')); var attr, len=focusable_elems.length, i=0; while(i < len){ attr = focusable_elems[i].getAttribute('data-focus'); if(!focus_first && attr === "1"){ focus_first = focusable_elems[i]; }else if(attr === "0"){ focus_later = focusable_elems[i]; if(!focus_first && focusable_elems[i+1].getAttribute('data-focus') !== "0"){ focus_first = focusable_elems[i+1]; } } i++; } }catch(e){ return modal.querySelectorAll(allowed_focusable_types.join(', ')); } /** * Save first and last elements (used to lock/trap focus inside modal) */ _array[0] = focusable_elems[0]; _array[1] = focusable_elems[focusable_elems.length - 1]; _array[2] = focus_later; _array[3] = focus_first; } /** * Get settings modal'S all focusable elements * Save first and last elements (used to lock/trap focus inside modal) */ _getAllFocusableElements(settings_inner, settings_modal_focusable); /** * If consent modal exists, do the same */ if(consent_modal_exists){ _getAllFocusableElements(consent_modal, consent_modal_focusable); } } var _createConsentModal = function(lang){ if(user_config['force_consent'] === true) _addClass(html_dom, 'force--consent'); // Create modal if it doesn't exist if(!consent_modal){ consent_modal = _createNode('div'); var consent_modal_inner_inner = _createNode('div'); var overlay = _createNode('div'); consent_modal.id = 'cm'; consent_modal_inner_inner.id = 'c-inr-i'; overlay.id = 'cm-ov'; consent_modal.setAttribute('role', 'dialog'); consent_modal.setAttribute('aria-modal', 'true'); consent_modal.setAttribute('aria-hidden', 'false'); consent_modal.setAttribute('aria-labelledby', 'c-ttl'); consent_modal.setAttribute('aria-describedby', 'c-txt'); // Append consent modal to main container all_modals_container.appendChild(consent_modal); all_modals_container.appendChild(overlay); /** * Make modal by default hidden to prevent weird page jumps/flashes (shown only once css is loaded) */ consent_modal.style.visibility = overlay.style.visibility = "hidden"; overlay.style.opacity = 0; } // Use insertAdjacentHTML instead of innerHTML var consent_modal_title_value = user_config.languages[lang]['consent_modal']['title']; // Add title (if valid) if(consent_modal_title_value){ if(!consent_modal_title){ consent_modal_title = _createNode('div'); consent_modal_title.id = 'c-ttl'; consent_modal_title.setAttribute('role', 'heading'); consent_modal_title.setAttribute('aria-level', '2'); consent_modal_inner_inner.appendChild(consent_modal_title); } consent_modal_title.innerHTML = consent_modal_title_value; } var description = user_config.languages[lang]['consent_modal']['description']; if(revision_enabled){ if(!valid_revision){ description = description.replace("{{revision_message}}", revision_message || user_config.languages[lang]['consent_modal']['revision_message'] || ""); }else{ description = description.replace("{{revision_message}}", ""); } } if(!consent_modal_description){ consent_modal_description = _createNode('div'); consent_modal_description.id = 'c-txt'; consent_modal_inner_inner.appendChild(consent_modal_description); } if(typeof user_config['privacy'] === "string"){ var privacy_button = _createNode('a'); privacy_button.className = "cc-link-a"; privacy_button.setAttribute('href', user_config['privacy_link']); privacy_button.textContent = user_config['privacy']; consent_modal_inner_inner.appendChild(privacy_button); } if(typeof user_config['impressum'] === "string"){ var impressum_button = _createNode('a'); impressum_button.className = "cc-link-a"; impressum_button.setAttribute('href', user_config['impressum_link']); impressum_button.textContent = user_config['impressum']; consent_modal_inner_inner.appendChild(impressum_button); } // Set description content consent_modal_description.innerHTML = description; var primary_btn_data = user_config.languages[lang]['consent_modal']['primary_btn'], // accept current selection secondary_btn_data = user_config.languages[lang]['consent_modal']['secondary_btn'], branding = user_config.branding; // Add primary button if not falsy if(primary_btn_data){ if(!consent_primary_btn){ consent_primary_btn = _createNode('button'); consent_primary_btn.id = 'c-p-bn'; consent_primary_btn.className = "c-bn"; var _accept_type; if(primary_btn_data['role'] === 'accept_all') _accept_type = 'all' _addEvent(consent_primary_btn, "click", function(){ _cookieconsent.hide(); _log("CookieConsent [ACCEPT]: cookie_consent was accepted!"); _cookieconsent.accept(_accept_type); }); } consent_primary_btn.textContent = user_config.languages[lang]['consent_modal']['primary_btn']['text']; } // Add secondary button if not falsy if(secondary_btn_data){ if(!consent_secondary_btn){ consent_secondary_btn = _createNode('button'); consent_secondary_btn.id = 'c-s-bn'; consent_secondary_btn.className = "c-bn c_link"; if(secondary_btn_data['role'] === 'accept_necessary'){ consent_secondary_btn.textContent = user_config.languages[lang]['consent_modal']['secondary_btn']['text']; _addEvent(consent_secondary_btn, 'click', function(){ _cookieconsent.hide(); _cookieconsent.accept([]); // accept necessary only }); }else{ consent_secondary_btn.textContent = user_config.languages[lang]['einstellungen']; _addEvent(consent_secondary_btn, 'click', function(){ _cookieconsent.showSettings(0); }); } } } if(branding && branding == true){ var consent_homepage = _createNode('a'); consent_homepage.id = 'c-s-hp'; consent_homepage.className = "c_link"; consent_homepage.href = "https://www.cookieconsent.sk"; consent_homepage.textContent = "www.cookieconsent.sk"; } // Swap buttons var gui_options_data = user_config['gui_options']; if(!consent_modal_inner){ consent_modal_inner = _createNode('div'); consent_modal_inner.id = 'c-inr'; consent_modal_inner.appendChild(consent_modal_inner_inner); } if(!consent_buttons){ consent_buttons = _createNode('div'); consent_buttons.id = "c-bns"; if(gui_options_data && gui_options_data['consent_modal'] && gui_options_data['consent_modal']['swap_buttons'] === true){ secondary_btn_data && consent_buttons.appendChild(consent_secondary_btn); primary_btn_data && consent_buttons.appendChild(consent_primary_btn); consent_buttons.className = 'swap'; }else{ primary_btn_data && consent_buttons.appendChild(consent_primary_btn); secondary_btn_data && consent_buttons.appendChild(consent_secondary_btn); consent_homepage && consent_buttons.appendChild(consent_homepage); } (primary_btn_data || secondary_btn_data ) && consent_modal_inner.appendChild(consent_buttons); consent_modal.appendChild(consent_modal_inner); } consent_modal_exists = true; } var _createSettingsModal = function(lang){ /** * Create all consent_modal elements */ if(!settings_container){ settings_container = _createNode('div'); var settings_container_valign = _createNode('div'); var settings = _createNode('div'); var settings_container_inner = _createNode('div'); settings_inner = _createNode('div'); settings_title = _createNode('div'); var settings_header = _createNode('div'); settings_close_btn = _createNode('button'); var settings_close_btn_container = _createNode('div'); settings_blocks = _createNode('div'); var overlay = _createNode('div'); var holder = _createNode('div'); holder.className = "cc-rockmenu cc-animate"; var settings_button = _createNode('button'); settings_button.className = "rolling cc-link"; settings_button.setAttribute('data-cc', 'c-settings'); settings_button.setAttribute('href', '#'); var figure = _createNode('figure'); figure.className = "rolling_icon"; var icon = _createNode('img'); icon.src = "https://cdn.cookieconsent.sk/piktogram.svg"; icon.style.width = "52px"; icon.style.padding = "3px 3px"; var settings_text = _createNode('span'); settings_text.textContent = user_config.languages[lang]['manage_cookie_consent']; figure.appendChild(icon); settings_button.appendChild(figure); settings_button.appendChild(settings_text); holder.appendChild(settings_button); document.body.appendChild(holder); /** * Set ids */ settings_container.id = 's-cnt'; settings_container_valign.id = "c-vln"; settings_container_inner.id = "c-s-in"; settings.id = "cs"; settings_title.id = 's-ttl'; settings_inner.id = 's-inr'; settings_header.id = "s-hdr"; settings_blocks.id = 's-bl'; settings_close_btn.id = 's-c-bn'; overlay.id = 'cs-ov'; settings_close_btn_container.id = 's-c-bnc'; settings_close_btn.className = 'c-bn'; settings_container.setAttribute('role', 'dialog'); settings_container.setAttribute('aria-modal', 'true'); settings_container.setAttribute('aria-hidden', 'true'); settings_container.setAttribute('aria-labelledby', 's-ttl'); settings_title.setAttribute('role', 'heading'); settings_container.style.visibility = overlay.style.visibility = "hidden"; overlay.style.opacity = 0; settings_close_btn_container.appendChild(settings_close_btn); // If 'esc' key is pressed inside settings_container div => hide settings _addEvent(settings_container_valign, 'keydown', function(evt){ evt = evt || window.event; if (evt.keyCode === 27) { _cookieconsent.hideSettings(0); } }, true); _addEvent(settings_close_btn, 'click', function(){ _cookieconsent.hideSettings(0); }); }else{ new_settings_blocks = _createNode('div'); new_settings_blocks.id = 's-bl'; } // Add label to close button settings_close_btn.setAttribute('aria-label', user_config.languages[lang]['settings_modal']['close_btn_label'] || 'Close'); all_blocks = user_config.languages[lang]['settings_modal']['blocks']; all_table_headers = user_config.languages[lang]['settings_modal']['cookie_table_headers']; var n_blocks = all_blocks.length; // Set settings modal title settings_title.innerHTML = user_config.languages[lang]['settings_modal']['title']; // Create settings modal content (blocks) for(var i=0; i retrieve category states from cookie * Otherwise use states defined in the user_config. object */ if(cookie_consent_accepted){ if(_inArray(saved_cookie_content['level'], cookie_category) > -1){ block_switch.checked = true; !new_settings_blocks && toggle_states.push(true); }else{ !new_settings_blocks && toggle_states.push(false); } }else if(toggle_data['enabled']){ block_switch.checked = true; !new_settings_blocks && toggle_states.push(true); /** * Keep track of categories enabled by default (useful when mode=='opt-out') */ if(toggle_data['enabled']) !new_settings_blocks && default_enabled_categories.push(cookie_category); }else{ !new_settings_blocks && toggle_states.push(false); } !new_settings_blocks && all_categories.push(cookie_category); /** * Set toggle as readonly if true (disable checkbox) */ if(toggle_data['readonly']){ block_switch.disabled = true; _addClass(block_switch_span, 'c-ro'); !new_settings_blocks && readonly_categories.push(true); }else{ !new_settings_blocks && readonly_categories.push(false); } _addClass(block_table_container, 'b-acc'); _addClass(block_title_container, 'b-bn'); _addClass(block_section, 'b-ex'); block_table_container.id = accordion_id; block_table_container.setAttribute('aria-hidden', 'true'); block_switch_label.appendChild(block_switch); block_switch_label.appendChild(block_switch_span); block_switch_label.appendChild(label_text_span); block_title_container.appendChild(block_switch_label); /** * On button click handle the following :=> aria-expanded, aria-hidden and act class for current block */ isExpandable && (function(accordion, block_section, btn){ _addEvent(block_title_btn, 'click', function(){ if(!_hasClass(block_section, 'act')){ _addClass(block_section, 'act'); btn.setAttribute('aria-expanded', 'true'); accordion.setAttribute('aria-hidden', 'false'); }else{ _removeClass(block_section, 'act'); btn.setAttribute('aria-expanded', 'false'); accordion.setAttribute('aria-hidden', 'true'); } }, false); })(block_table_container, block_section, block_title_btn); }else{ /** * If block is not a button (no toggle defined), * create a simple div instead */ if(title_data){ var block_title = _createNode('div'); block_title.className = 'b-tl'; block_title.setAttribute('role', 'heading'); block_title.setAttribute('aria-level', '3'); block_title.insertAdjacentHTML('beforeend', title_data); block_title_container.appendChild(block_title); } } title_data && block_section.appendChild(block_title_container); description_data && block_table_container.appendChild(block_desc); // if cookie table found, generate table for this block if(!remove_cookie_tables && typeof cookie_table_data !== 'undefined'){ var tr_tmp_fragment = document.createDocumentFragment(); /** * Use custom table headers */ for(var p=0; p ~faster value retrieval) var curr_block = all_blocks[i]; // If current block has a toggle for opt in/out if(Object.prototype.hasOwnProperty.call(curr_block, "toggle")){ // if current block has a cookie table, an off toggle, // and its preferences were just changed => delete cookies var category_just_disabled = _inArray(changed_settings, curr_block['toggle']['value']) > -1; if( !toggle_states[++count] && Object.prototype.hasOwnProperty.call(curr_block, "cookie_table") && (clearOnFirstAction || category_just_disabled) ){ var curr_cookie_table = curr_block['cookie_table']; // Get first property name var ckey = _getKeys(all_table_headers[0])[0]; // Get number of cookies defined in cookie_table var clen = curr_cookie_table.length; // set "reload_page" to true if reload=on_disable if(curr_block['toggle']['reload'] === 'on_disable') category_just_disabled && (reload_page = true); // for each row defined in the cookie table for(var j=0; j filter cookie array if(is_regex){ for(var n=0; n -1) found_cookies.push(all_cookies_array[found_index]); } _log("CookieConsent [AUTOCLEAR]: search cookie: '" + curr_cookie_name + "', found:", found_cookies); // If cookie exists -> delete it if(found_cookies.length > 0){ _eraseCookies(found_cookies, curr_cookie_path, domains); curr_block['toggle']['reload'] === 'on_clear' && (reload_page = true); } } } } } } /** * Set toggles/checkboxes based on accepted categories and save cookie * @param {string[]} accepted_categories - Array of categories to accept */ var _saveCookiePreferences = function(accepted_categories){ changed_settings = []; // Retrieve all toggle/checkbox values var category_toggles = document.querySelectorAll('.c-tgl') || []; // If there are opt in/out toggles ... if(category_toggles.length > 0){ for(var i=0; i 0) _autoclearCookies(); if(!consent_uuid) consent_uuid = _uuidv4(); saved_cookie_content = { "level": accepted_categories, "revision": _config.revision, "data": cookie_data, "rfc_cookie": _config.use_rfc_cookie, "consent_uuid": consent_uuid } // save cookie with preferences 'level' (only if never accepted or settings were updated) if(!cookie_consent_accepted || changed_settings.length > 0 || !valid_revision){ valid_revision = true; /** * Update accept type */ accept_type = _getAcceptType(_getCurrentCategoriesState()); _setCookie(_config.cookie_name, JSON.stringify(saved_cookie_content)); _cookieconsent.logConsent(accepted_categories.includes("necessary") ? 1 : 0, accepted_categories.includes("analytics") ? 1 : 0, accepted_categories.includes("marketing") ? 1 : 0, ); _manageExistingScripts(); } if(!cookie_consent_accepted){ /** * Delete unused/"zombie" cookies the very-first time */ if(_config.autoclear_cookies) _autoclearCookies(true); if(typeof onFirstAction === 'function') onFirstAction(_cookieconsent.getUserPreferences(), saved_cookie_content); if(typeof onAccept === 'function') onAccept(saved_cookie_content); cookie_consent_accepted = true; if(_config.mode === 'opt-in') return; } // fire onChange only if settings were changed if(typeof onChange === "function" && changed_settings.length > 0) onChange(saved_cookie_content, changed_settings); /** * reload page if needed */ if(reload_page) window.location.reload(); } /** * Function to run after css load * @callback cssLoaded */ /** * Load style via ajax in background (and then show modal) * @param {string} css_path * @param {cssLoaded} callback */ var _loadCSS = function(css_path, callback){ // Enable if given path is string and non empty var enable = typeof css_path === 'string' && css_path !== ""; if(enable && !document.getElementById('cc--style')){ // Create style tag var style = _createNode('style'); // ad an id so that in SPA apps (react-like) the style doesn't get loaded multiple times when plugin is called style.id = 'cc--style'; var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if(this.readyState === 4 && this.status === 200){ // Necessary for 2 && (browser_lang = browser_lang[0]+browser_lang[1]); _log("CookieConsent [LANG]: detected_browser_lang = '"+ browser_lang + "'"); return browser_lang.toLowerCase() } /** * Trap focus inside modal and focus the first * focusable element of current active modal */ var _handleFocusTrap = function(){ var tabbedOutsideDiv = false; var tabbedInsideModal = false; _addEvent(document, 'keydown', function(e){ e = e || window.event; // If is tab key => ok if(e.key !== 'Tab') return; // If there is any modal to focus if(current_modal_focusable){ // If reached natural end of the tab sequence => restart if(e.shiftKey){ if (document.activeElement === current_modal_focusable[0]) { current_modal_focusable[1].focus(); e.preventDefault(); } }else{ if (document.activeElement === current_modal_focusable[1]) { current_modal_focusable[0].focus(); e.preventDefault(); } } // If have not yet used tab (or shift+tab) and modal is open ... // Focus the first focusable element if(!tabbedInsideModal && !clicked_inside_modal){ tabbedInsideModal = true; !tabbedOutsideDiv && e.preventDefault(); if(e.shiftKey){ if(current_modal_focusable[3]){ if(!current_modal_focusable[2]){ current_modal_focusable[0].focus(); }else{ current_modal_focusable[2].focus(); } }else{ current_modal_focusable[1].focus(); } }else{ if(current_modal_focusable[3]){ current_modal_focusable[3].focus(); }else{ current_modal_focusable[0].focus(); } } } } !tabbedInsideModal && (tabbedOutsideDiv = true); }); if(document.contains){ _addEvent(main_container, 'click', function(e){ e = e || window.event; /** * If click is on the foreground overlay (and not inside settings_modal), * hide settings modal * * Notice: click on div is not supported in IE */ if(settings_modal_visible){ if(!settings_inner.contains(e.target)){ _cookieconsent.hideSettings(0); clicked_inside_modal = false; }else{ clicked_inside_modal = true; } }else if(consent_modal_visible){ if(consent_modal.contains(e.target)){ clicked_inside_modal = true; } } }, true); } } /** * Manage each modal's layout * @param {Object} gui_options */ var _guiManager = function(gui_options, only_consent_modal){ // If gui_options is not object => exit if(typeof gui_options !== 'object') return; var consent_modal_options = gui_options['consent_modal']; var settings_modal_options = gui_options['settings_modal']; /** * Helper function which adds layout and * position classes to given modal * * @param {HTMLElement} modal * @param {string[]} allowed_layouts * @param {string[]} allowed_positions * @param {string} layout * @param {string[]} position */ function _setLayout(modal, allowed_layouts, allowed_positions, allowed_transitions, layout, position, transition){ position = (position && position.split(" ")) || []; // Check if specified layout is valid if(_inArray(allowed_layouts, layout) > -1){ // Add layout classes _addClass(modal, layout); // Add position class (if specified) if(!(layout === 'bar' && position[0] === 'middle') && _inArray(allowed_positions, position[0]) > -1){ for(var i=0; i -1) && _addClass(modal, transition); } if(consent_modal_exists && consent_modal_options){ _setLayout( consent_modal, ['box', 'bar', 'cloud'], ['top', 'middle', 'bottom'], ['zoom', 'slide'], consent_modal_options['layout'], consent_modal_options['position'], consent_modal_options['transition'] ); } if(!only_consent_modal && settings_modal_options){ _setLayout( settings_container, ['bar'], ['left', 'right'], ['zoom', 'slide'], settings_modal_options['layout'], settings_modal_options['position'], settings_modal_options['transition'] ); } } /** * Returns true if cookie category is accepted by the user * @param {string} cookie_category * @returns {boolean} */ _cookieconsent.allowedCategory = function(cookie_category){ if(cookie_consent_accepted || _config.mode === 'opt-in') var allowed_categories = JSON.parse(_getCookie(_config.cookie_name, 'one', true) || '{}')['level'] || [] else // mode is 'opt-out' var allowed_categories = default_enabled_categories; return _inArray(allowed_categories, cookie_category) > -1; } /** * "Init" method. Will run once and only if modals do not exist */ _cookieconsent.run = function(user_config){ if(!document.getElementById('cc_div')){ _initAll(user_config); // configure all parameters _setConfig(user_config); // if is bot, don't run plugin if(is_bot) return; // Retrieve cookie value (if set) saved_cookie_content = JSON.parse(_getCookie(_config.cookie_name, 'one', true) || "{}"); consent_uuid = saved_cookie_content['consent_uuid']; cookie_consent_accepted = saved_cookie_content['level'] !== undefined; /** * Immediately retrieve the 'data' field from cookie * (since this value is allowed to be accessed/used before the .run method) */ cookie_data = saved_cookie_content['data'] !== undefined ? saved_cookie_content['data'] : null; // Compare current revision with the one retrieved from cookie valid_revision = typeof user_config['revision'] === "number" ? cookie_consent_accepted ? user_config['revision'] > -1 ? saved_cookie_content['revision'] === _config.revision : true : true : true; // If invalid revision or cookie is empty => create consent modal consent_modal_exists = (!cookie_consent_accepted || !valid_revision); // Generate cookie-settings dom (& consent modal) _createCookieConsentHTML(); _loadCSS(user_config['theme_css'], function(){ _getModalFocusableData(); _guiManager(user_config['gui_options']); _addDataButtonListeners(); if(_config.autorun && consent_modal_exists){ _cookieconsent.show(user_config['delay'] || 0); } // Add class to enable animations/transitions setTimeout(function(){_addClass(main_container, 'c--anim');}, 30); // Accessibility :=> if tab pressed => trap focus inside modal setTimeout(function(){_handleFocusTrap();}, 100); }); if(cookie_consent_accepted && valid_revision){ var rfc_prop_exists = typeof saved_cookie_content['rfc_cookie'] === "boolean"; /* * Convert cookie to rfc format (if `use_rfc_cookie` is enabled) */ if(!rfc_prop_exists || (rfc_prop_exists && saved_cookie_content['rfc_cookie'] !== _config.use_rfc_cookie)){ saved_cookie_content['rfc_cookie'] = _config.use_rfc_cookie; _setCookie(_config.cookie_name, JSON.stringify(saved_cookie_content)); } /** * Update accept type */ accept_type = _getAcceptType(_getCurrentCategoriesState()); _manageExistingScripts(); if(typeof onAccept === 'function') onAccept(saved_cookie_content); }else if(_config.mode === 'opt-out'){ _log("CookieConsent [CONFIG] mode='" + _config.mode + "', default enabled categories:", default_enabled_categories); _manageExistingScripts(default_enabled_categories); } }else{ _log("CookieConsent [NOTICE]: cookie consent already attached to body!"); } } /** * Show settings modal (with optional delay) * @param {number} delay */ _cookieconsent.showSettings = function(delay){ setTimeout(function() { _addClass(html_dom, "show--settings"); settings_container.setAttribute('aria-hidden', 'false'); settings_modal_visible = true; /** * Set focus to the first focusable element inside settings modal */ setTimeout(function(){ // If there is no consent-modal, keep track of the last focused elem. if(!consent_modal_visible){ last_elem_before_modal = document.activeElement; }else{ last_consent_modal_btn_focus = document.activeElement; } if (settings_modal_focusable.length === 0) return; if(settings_modal_focusable[3]){ settings_modal_focusable[3].focus(); }else{ settings_modal_focusable[0].focus(); } current_modal_focusable = settings_modal_focusable; }, 200); _log("CookieConsent [SETTINGS]: show settings_modal"); }, delay > 0 ? delay : 0); } var onAccept = function(cookie){ if (cookie.level.includes("analytics")) { gtag('consent', 'update', { 'analytics_storage': 'granted' }); console.log("analytics"); } if (cookie.level.includes('marketing')) { gtag('consent', 'update', { 'ad_storage': 'granted' }); console.log("marketing"); if(typeof(fbq) === "function"){ fbq('consent', 'grant'); } } dataLayer.push({ event : 'cc_consent_updated' }); } var onChange = function(cookie, changed_categories){ if (cookie.level.includes('analytics')) { gtag('consent', 'update', { 'analytics_storage': 'granted' }); } if (!cookie.level.includes('analytics')) { gtag('consent', 'update', { 'analytics_storage': 'denied' }); } if (cookie.level.includes('advertising')) { gtag('consent', 'update', { 'ad_storage': 'granted' }); if(typeof(fbq) === "function"){ fbq('consent', 'grant'); } } if (!cookie.level.includes('advertising')) { gtag('consent', 'update', { 'ad_storage': 'denied' }); if(typeof(fbq) === "function"){ fbq('consent', 'revoke'); } } dataLayer.push({ event : 'cc_consent_updated' }); } /** * This function handles the loading/activation logic of the already * existing scripts based on the current accepted cookie categories * * @param {string[]} [must_enable_categories] */ var _manageExistingScripts = function(must_enable_categories){ if(!_config.page_scripts) return; // get all the scripts with "cookie-category" attribute var scripts = document.querySelectorAll('script[' + _config.script_selector + ']'); var sequential_enabled = _config.page_scripts_order; var accepted_categories = must_enable_categories || saved_cookie_content['level'] || []; _log("CookieConsent [SCRIPT_MANAGER]: sequential loading:", sequential_enabled); /** * Load scripts (sequentially), using a recursive function * which loops through the scripts array * @param {Element[]} scripts scripts to load * @param {number} index current script to load */ var _loadScripts = function(scripts, index){ if(index < scripts.length){ var curr_script = scripts[index]; var curr_script_category = curr_script.getAttribute(_config.script_selector); /** * If current script's category is on the array of categories * accepted by the user => load script */ if(_inArray(accepted_categories, curr_script_category) > -1){ curr_script.type = 'text/javascript'; curr_script.removeAttribute(_config.script_selector); // get current script data-src var src = curr_script.getAttribute('data-src'); // some scripts (like ga) might throw warning if data-src is present src && curr_script.removeAttribute('data-src'); // create fresh script (with the same code) var fresh_script = _createNode('script'); fresh_script.textContent = curr_script.innerHTML; // Copy attributes over to the new "revived" script (function(destination, source){ var attributes = source.attributes; var len = attributes.length; for(var i=0; i the next script will not be loaded // until the current's script onload event triggers if(fresh_script.readyState) { // only required for IE <9 fresh_script.onreadystatechange = function() { if (fresh_script.readyState === "loaded" || fresh_script.readyState === "complete" ) { fresh_script.onreadystatechange = null; _loadScripts(scripts, ++index); } }; }else{ // others fresh_script.onload = function(){ fresh_script.onload = null; _loadScripts(scripts, ++index); }; } }else{ // if sequential option is disabled // treat current script as inline (without onload event) src = false; } } // Replace current "sleeping" script with the new "revived" one curr_script.parentNode.replaceChild(fresh_script, curr_script); /** * If we managed to get here and scr is still set, it means that * the script is loading/loaded sequentially so don't go any further */ if(src) return; } // Go to next script right away _loadScripts(scripts, ++index); } } _loadScripts(scripts, 0); } /** * Save custom data inside cookie * @param {object|string} new_data * @param {string} [mode] * @returns {boolean} */ var _setCookieData = function(new_data, mode){ var set = false; /** * If mode is 'update': * add/update only the specified props. */ if(mode === 'update'){ cookie_data = _cookieconsent.get('data'); var same_type = typeof cookie_data === typeof new_data; if(same_type && typeof cookie_data === "object"){ !cookie_data && (cookie_data = {}); for(var prop in new_data){ if(cookie_data[prop] !== new_data[prop]){ cookie_data[prop] = new_data[prop] set = true; } } }else if((same_type || !cookie_data) && cookie_data !== new_data){ cookie_data = new_data; set = true; } }else{ cookie_data = new_data; set = true; } if(set){ saved_cookie_content['data'] = cookie_data; _setCookie(_config.cookie_name, JSON.stringify(saved_cookie_content)); } return set; } /** * Forcefully set a specific revision and show consent modal * @param {number} new_revision * @param {boolean} [prompt_consent] * @returns {boolean} */ var _setRevision = function(new_revision, prompt_consent, message){ // If plugin has been initialized and new revision is valid if( main_container && typeof new_revision === "number" && saved_cookie_content['revision'] !== new_revision ){ revision_enabled = true; revision_message = message; valid_revision = false; _config.revision = new_revision; // Show consent modal ? if(prompt_consent === true){ _createConsentModal(user_config); _guiManager(user_config['gui_options'], true); _getModalFocusableData(); _cookieconsent.show(); }else { // If revision was modified, save cookie with the new revision _cookieconsent.accept(); } return true; } return false; } /** * Helper method to set a variety of fields * @param {string} field * @param {object} data * @returns {boolean} */ _cookieconsent.set = function(field, data){ switch(field){ case 'data': return _setCookieData(data['value'], data['mode']); case 'revision': return _setRevision(data['value'], data['prompt_consent'], data['message']); //[WARNING] Will be removed in v3 default: return false; } } /** * Retrieve data from existing cookie * @param {string} field * @param {string} [cookie_name] * @returns {any} */ _cookieconsent.get = function(field, cookie_name){ var cookie = JSON.parse(_getCookie(cookie_name || _config.cookie_name, 'one', true) || "{}"); return cookie[field]; } /** * Read current configuration value * @returns {any} */ _cookieconsent.getConfig = function(field){ return _config[field] || user_config[field]; } /** * Obtain accepted and rejected categories * @returns {{accepted: string[], rejected: string[]}} */ var _getCurrentCategoriesState = function(){ // get accepted categories accepted_categories = saved_cookie_content['level'] || []; // calculate rejected categories (all_categories - accepted_categories) rejected_categories = all_categories.filter(function(category){ return (_inArray(accepted_categories, category) === -1); }); return { accepted: accepted_categories, rejected: rejected_categories } } /** * Calculate "accept type" given current categories state * @param {{accepted: string[], rejected: string[]}} currentCategoriesState * @returns {string} */ var _getAcceptType = function(currentCategoriesState){ var type = 'custom'; // number of categories marked as necessary/readonly var necessary_categories_length = readonly_categories.filter(function(readonly){ return readonly === true; }).length; // calculate accept type based on accepted/rejected categories if(currentCategoriesState.accepted.length === all_categories.length) type = 'all'; else if(currentCategoriesState.accepted.length === necessary_categories_length) type = 'necessary' return type; } /** * @typedef {object} userPreferences * @property {string} accept_type * @property {string[]} accepted_categories * @property {string[]} rejected_categories */ /** * Retrieve current user preferences (summary) * @returns {userPreferences} */ _cookieconsent.getUserPreferences = function(){ var currentCategoriesState = _getCurrentCategoriesState(); var accept_type = _getAcceptType(currentCategoriesState); return { 'accept_type': accept_type, 'accepted_categories': currentCategoriesState.accepted, 'rejected_categories': currentCategoriesState.rejected } } /** * Function which will run after script load * @callback scriptLoaded */ /** * Dynamically load script (append to head) * @param {string} src * @param {scriptLoaded} callback * @param {string[]} attrs */ _cookieconsent.loadScript = function(src, callback, attrs){ var function_defined = typeof callback === 'function'; // Load script only if not already loaded if(!document.querySelector('script[src="' + src + '"]')){ var script = _createNode('script'); // if an array is provided => add custom attributes if(attrs && attrs.length > 0){ for(var i=0; i run callback onload if(function_defined){ if(script.readyState) { // only required for IE <9 script.onreadystatechange = function() { if ( script.readyState === "loaded" || script.readyState === "complete" ) { script.onreadystatechange = null; callback(); } }; }else{ //Others script.onload = callback; } } script.src = src; /** * Append script to head */ (document.head ? document.head : document.getElementsByTagName('head')[0]).appendChild(script); }else{ function_defined && callback(); } } /** * Manage dynamically loaded scripts: https://github.com/orestbida/cookieconsent/issues/101 * If plugin has already run, call this method to enable * the newly added scripts based on currently selected preferences */ _cookieconsent.updateScripts = function(){ _manageExistingScripts(); } /** * Show cookie consent modal (with delay parameter) * @param {number} delay */ _cookieconsent.show = function(delay, force = false){ if(consent_modal_exists || force == true){ setTimeout(function() { _addClass(html_dom, "show--consent"); /** * Update attributes/internal statuses */ consent_modal.setAttribute('aria-hidden', 'false'); consent_modal_visible = true; setTimeout(function(){ last_elem_before_modal = document.activeElement; current_modal_focusable = consent_modal_focusable; }, 200); _log("CookieConsent [MODAL]: show consent_modal"); }, delay > 0 ? delay : 0); } } /** * Hide consent modal */ _cookieconsent.hide = function(){ if(consent_modal_exists){ _removeClass(html_dom, "show--consent"); consent_modal.setAttribute('aria-hidden', 'true'); consent_modal_visible = false; setTimeout(function(){ //restore focus to the last page element which had focus before modal opening last_elem_before_modal.focus(); current_modal_focusable = null; }, 200); _log("CookieConsent [MODAL]: hide"); } } /** * Hide settings modal */ _cookieconsent.hideSettings = function(){ _removeClass(html_dom, "show--settings"); settings_modal_visible = false; settings_container.setAttribute('aria-hidden', 'true'); setTimeout(function(){ /** * If consent modal is visible, focus him (instead of page document) */ if(consent_modal_visible){ last_consent_modal_btn_focus && last_consent_modal_btn_focus.focus(); current_modal_focusable = consent_modal_focusable; }else{ /** * Restore focus to last page element which had focus before modal opening */ last_elem_before_modal && last_elem_before_modal.focus(); current_modal_focusable = null; } clicked_inside_modal = false; }, 200); _log("CookieConsent [SETTINGS]: hide settings_modal"); } /** * Accept cookieconsent function API * @param {string[]|string} _categories - Categories to accept * @param {string[]} [_exclusions] - Excluded categories [optional] */ _cookieconsent.accept = function(_categories, _exclusions){ var categories = _categories || undefined; var exclusions = _exclusions || []; var to_accept = []; /** * Get all accepted categories * @returns {string[]} */ var _getCurrentPreferences = function(){ var toggles = document.querySelectorAll('.c-tgl') || []; var states = []; for(var i=0; i= 1){ for(i=0; i 0){ for(var i=0; i<_cookies.length; i++){ this.validCookie(_cookies[i]) && cookies.push(_cookies[i]); } }else{ this.validCookie(_cookies) && cookies.push(_cookies); } _eraseCookies(cookies, _path, domains); } /** * Set cookie, by specifying name and value * @param {string} name * @param {string} value */ var _setCookie = function(name, value) { var cookie_expiration = _config.cookie_expiration; if(typeof _config.cookie_necessary_only_expiration === 'number' && accept_type === 'necessary') cookie_expiration = _config.cookie_necessary_only_expiration; value = _config.use_rfc_cookie ? encodeURIComponent(value) : value; var date = new Date(); date.setTime(date.getTime() + (1000 * (cookie_expiration * 24 * 60 * 60))); var expires = "; expires=" + date.toUTCString(); var cookieStr = name + "=" + (value || "") + expires + "; Path=" + _config.cookie_path + ";"; cookieStr += " SameSite=" + _config.cookie_same_site + ";"; // assures cookie works with localhost (=> don't specify domain if on localhost) if(window.location.hostname.indexOf(".") > -1){ cookieStr += " Domain=" + _config.cookie_domain + ";"; } if(window.location.protocol === "https:") { cookieStr += " Secure;"; } document.cookie = cookieStr; _log("CookieConsent [SET_COOKIE]: cookie "+ name + "='" + value + "' was set! Expires after " + cookie_expiration + " days"); } /** * Get cookie value by name, * returns the cookie value if found (or an array * of cookies if filter provided), otherwise empty string: "" * @param {string} name * @param {string} filter - 'one' or 'all' * @param {boolean} get_value - set to true to obtain its value * @returns {string|string[]} */ var _getCookie = function(name, filter, get_value) { var found; if(filter === 'one'){ found = document.cookie.match("(^|;)\\s*" + name + "\\s*=\\s*([^;]+)"); found = found ? (get_value ? found.pop() : name) : ""; if(found && name === _config.cookie_name){ try{ found = JSON.parse(found) }catch(e){ try { found = JSON.parse(decodeURIComponent(found)) } catch (e) { // if I got here => cookie value is not a valid json string found = {}; } } found = JSON.stringify(found); } }else if(filter === 'all'){ // array of names of all existing cookies var cookies = document.cookie.split(/;\s*/); found = []; for(var i=0; i 'onclick' */ elem.attachEvent("on" + event, fn); } } /** * Get all prop. keys defined inside object * @param {Object} obj */ var _getKeys = function(obj){ if(typeof obj === "object"){ var keys = [], i = 0; for (keys[i++] in obj); return keys; } } /** * Append class to the specified dom element * @param {HTMLElement} elem * @param {string} classname */ var _addClass = function (elem, classname){ if(elem.classList) elem.classList.add(classname) else{ if(!_hasClass(elem, classname)) elem.className += ' '+classname; } } /** * Remove specified class from dom element * @param {HTMLElement} elem * @param {string} classname */ var _removeClass = function (el, className) { el.classList ? el.classList.remove(className) : el.className = el.className.replace(new RegExp('(\\s|^)' + className + '(\\s|$)'), ' '); } /** * Check if html element has class * @param {HTMLElement} el * @param {string} className */ var _hasClass = function(el, className) { if (el.classList) { return el.classList.contains(className); } return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)')); } return _cookieconsent; }; var init = 'initCookieConsent'; /** * Make CookieConsent object accessible globally */ if(typeof window[init] !== 'function'){ window[init] = c_consent } var i = document.getElementsByTagName("head")[0]; var n = document.createElement("link"); n.rel = "stylesheet"; n.type = "text/css"; n.href = "https://cdn.cookieconsent.sk/css/c_consent.css"; i.appendChild(n); })(); /* iframemanager v1.0 Author Orest Bida Released under the MIT License */ (function() { var e = { o: {}, S: [], T: [], u: null, i: null, v: null, l: null, W: function(a) { return { D: a.dataset.id, I: a.dataset.title, m: a.dataset.thumbnail, ba: a.dataset.params, K: a.hasAttribute("data-thumbnailpreload"), j: a, J: null, s: !1, R: !1, A: !0 } }, X: function(a, b) { var c = this.o[a]; a = c.length; if ("IntersectionObserver" in window) for (var d = new IntersectionObserver(function(g) { g.forEach(function(k) { k.isIntersecting && (e.O(b, c[k.target.dataset.index]), d.unobserve(k.target)) }) }), f = 0; f < a; f++) d.observe(c[f].j); else for (f = 0; f < a; f++) e.O(b, c[f]) }, acceptService: function(a) { function b(f, g) { e.F(g.cookie.name) || e.Z(g.cookie); e.N(f, g) } if ("all" === a) for (var c = this.l.length, d = 0; d < c; d++) a = this.l[d], b(a, this.v[a]); else - 1 < this.l.indexOf(a) && b(a, this.v[a]) }, rejectService: function(a) { function b(f, g) { e.F(g.cookie.name) && e.U(g.cookie); e.$(f, g) } if ("all" === a) { this.u = null; for (var c = this.l.length, d = 0; d < c; d++) a = this.l[d], b(a, this.v[a]) } else - 1 < this.l.indexOf(a) && b(a, this.v[a]) }, O: function(a, b) { function c(d) { b.J.style.backgroundImage = "url('" + d + "')"; var f = new Image; f.onload = function() { b.J.classList.add("loaded") }; f.src = d } "string" === typeof b.m ? (b.K && this.H(b.m), "" !== b.m && c(b.m)) : "function" === typeof a ? a(b.D, function(d) { e.P(d); b.K && this.H(d); c(d) }) : "string" === typeof a && (a = a.replace("{data-id}", b.D), this.P(a), b.K && this.H(a), c(a)) }, B: function(a, b) { if (!a.s) { a.h = this.g("iframe"); var c = a.ba || b.iframe && b.iframe.params, d = b.embedUrl.replace("{data-id}", a.D); a.h.loading = "lazy"; a.I && (a.h.title = a.I); b.iframe && b.iframe.allow && (a.h.allow = b.iframe.allow); c && (d = "ap:" === c.substring(0, 3) ? d + c.substring(3) : d + ("?" + c)); a.h.src = encodeURI(d); a.h.onload = function() { a.j.classList.add("c-h-b"); a.h.onload = void 0; b.iframe && "function" === typeof b.iframe.onload && b.iframe.onload(a.D, this) }; a.s = !0; a.j.appendChild(a.h) } }, Y: function(a) { a.h.parentNode.removeChild(a.h); a.s = !1 }, C: function(a) { a.A && (a.j.classList.add("c-h-n"), a.A = !1) }, aa: function(a) { a.A || (a.j.classList.remove("c-h-n", "c-h-b"), a.A = !0) }, F: function(a) { return (a = document.cookie.match("(^|;)\\s*" + a + "\\s*=\\s*([^;]+)")) ? a.pop() : "" }, Z: function(a) { var b = new Date, c = a.path || "/", d = a.sameSite || "Lax", f = a.domain || location.hostname; b.setTime(b.getTime() + 864E5 * (a.expiration || 182)); a = a.name + "=1; expires=" + b.toUTCString() + "; Path=" + c + ";"; a += " SameSite=" + d + ";"; - 1 < f.indexOf(".") && (a += " Domain=" + f + ";"); "https:" === location.protocol && (a += " Secure;"); document.cookie = a }, U: function(a) { document.cookie = a.name + "=; Path=" + (a.path || "/") + "; Domain=" + (a.domain || location.hostname) + "; Expires=Thu, 01 Jan 1970 00:00:01 GMT;" }, G: function(a) { if ("object" === typeof a) { var b = [], c = 0; for (b[c++] in a); return b } }, P: function(a) { a = a.split("://"); var b = a[0]; if (("http" == b || "https" == b) && (a = a[1] && a[1].split("/")[0] || !1) && a !== location.hostname && -1 === this.S.indexOf(a)) { var c = this.g("link"); c.rel = "preconnect"; c.href = b + "://" + a; document.head.appendChild(c); this.S.push(a) } }, H: function(a) { if (a && -1 === this.T.indexOf(a)) { var b = this.g("link"); b.rel = "preload"; b.as = "image"; b.href = a; document.head.appendChild(b); this.T.push(a) } }, g: function(a) { return document.createElement(a) }, L: function(a, b, c) { for (var d = this.o[a], f = d.length, g = 0; g < f; g++)(function(k) { var h = d[k]; if (!h.R) { k = b.languages[e.i].loadBtn; var C = b.languages[e.i].notice, D = b.languages[e.i].loadAllBtn, p = document.createDocumentFragment(), q = e.g("div"), u = e.g("span"), v = e.g("p"), l = e.g("button"), m = e.g("button"), n = e.g("span"), w = e.g("div"), z = e.g("div"), x = e.g("div"), r = e.g("div"), t = e.g("div"); l.type = m.type = "button"; n.className = "cc-text"; l.type = m.type = "button"; n.className = "cc-text"; x.className = "c-bg-i"; h.J = x; z.className = "c-ld"; if ("string" !== typeof h.m || "" !== h.m) w.className = "c-bg"; var A = h.I, B = document.createDocumentFragment(); if (A) { var y = e.g("span"); y.className = "c-tl"; y.insertAdjacentHTML("beforeend", A); B.appendChild(y) } l.textContent = k; m.textContent = D; n.appendChild(B); q && n.insertAdjacentHTML("beforeend", C || ""); u.appendChild(n); r.className = "c-t-cn"; u.className = "c-n-t"; v.className = "c-n-c"; q.className = "c-nt"; t.className = "c-n-a"; l.className = "c-l-b"; m.className = "c-la-b"; t.appendChild(l); t.appendChild(m); r.appendChild(u); r.appendChild(t); v.appendChild(r); q.appendChild(v); l.addEventListener("click", function() { e.C(h); e.B(h, b) }); m.addEventListener("click", function() { e.C(h); e.B(h, b); e.acceptService(a) }); w.appendChild(x); p.appendChild(q); (b.thumbnailUrl || h.m) && p.appendChild(w); p.appendChild(z); c && h.j.classList.add("c-h-n"); h.j.appendChild(p); h.R = !0 } })(g) }, N: function(a, b) { var c = this.o[a]; a = c.length; if ("IntersectionObserver" in window) { this.u = new IntersectionObserver(function(f) { for (var g = 0; g < f.length && null !== e.u; ++g) f[g].isIntersecting && function(k) { setTimeout(function() { var h = f[k].target.dataset.index; e.B(c[h], b); e.C(c[h]) }, 50 * k); e.u.unobserve(f[k].target) }(g) }); for (var d = 0; d < a; d++) c[d].s || this.u.observe(c[d].j) } else for (d = 0; d < a; d++)(function(f) { e.B(c[d], b); e.C(c[f]) })(d) }, $: function(a) { a = this.o[a]; for (var b = a.length, c = 0; c < b; c++) { var d = c; a[c].A || (a[c].s && e.Y(a[c]), e.aa(a[d])) } }, M: function(a, b) { if (b.hasOwnProperty(a)) return a; if (0 < this.G(b).length) return b.hasOwnProperty(this.i) ? this.i : this.G(b)[0] }, V: function() { var a = navigator.language || navigator.browserLanguage; 2 < a.length && (a = a[0] + a[1]); return a.toLowerCase() }, run: function(a) { var b = a.services; this.v = b; var c = this.G(b); this.l = c; var d = c.length; if (0 !== d) { this.i = a.currLang; var f = b[c[0]].languages; !0 === a.autoLang ? this.i = this.M(this.V(), f) : "string" === typeof a.currLang && (this.i = this.M(a.currLang, f)); for (a = 0; a < d; a++) { f = c[a]; this.o[f] = []; var g = document.querySelectorAll('div[data-service="' + f + '"]'), k = g.length; if (0 !== k) { for (var h = 0; h < k; h++) g[h].dataset.index = h, this.o[f].push(this.W(g[h])); g = b[f]; this.F(g.cookie.name) ? (this.L(f, g, !0), this.N(f, g)) : this.L(f, g, !1); this.X(f, g.thumbnailUrl) } } } } }; window.iframemanager = function() { window.iframemanager = void 0; return e } })(); function youtube_parser(url){ var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/; return (url.match(p)) ? RegExp.$1 : false ; } function meteoblue_parser(url){ var p = /^(?:https?:\/\/)?(?:www\.)?(?:meteoblue\.com\/|snow-forecast\.com\/)(?:\S+)$/; return (url.match(p)) ? true : false ; } function maps_parser(url){ var p = /^(?:https?:\/\/)?(?:www\.)?(?:maps\.google\.com\/)(?:\S+)$/; return (url.match(p)) ? true : false ; } function windy_parser(url){ var p = /^(?:https?:\/\/)?(?:www\.)?(?:embed\.windy\.com\/)(?:\S+)$/; return (url.match(p)) ? true : false ; } function iframe_parser(url){ var p = /^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^:\/\n]+)/igm; return (url.match(p)) ? RegExp.$1 : false ; } function changeIframeToDiv(){ var i, frames, to_remove = []; frames = document.getElementsByTagName("iframe"); for (i = 0; i < frames.length; ++i){ let youtube_id = youtube_parser(frames[i].src); let meteoblue = meteoblue_parser(frames[i].src); let mapsurl = maps_parser(frames[i].src); let windy = windy_parser(frames[i].src); if(youtube_id != false){ frames[i].classList.add("to_remove"); let width = frames[i].width; let height = frames[i].height; let div_youtube = document.createElement('div'); div_youtube.setAttribute('data-service', 'youtube'); div_youtube.setAttribute('data-id', youtube_id); div_youtube.setAttribute('data-autoscale', true); if((width != undefined && width != '') && (height != undefined && height != '')){ div_youtube.setAttribute('style', `width: ${width}px; height: ${height}px;`); }else{ div_youtube.setAttribute('style', frames[i].style.cssText); } frames[i].parentNode.appendChild(div_youtube); } if(meteoblue != false){ frames[i].classList.add("to_remove"); let width = frames[i].width; let height = frames[i].height; let div_meteo = document.createElement('div'); div_meteo.setAttribute('data-service', 'meteoblue'); div_meteo.setAttribute('data-id', frames[i].src); div_meteo.setAttribute('data-autoscale', true); if((width != undefined && width != '') && (height != undefined && height != '')){ div_meteo.setAttribute('style', `width: ${width}px; height: ${height}px;`); }else{ div_meteo.setAttribute('style', frames[i].style.cssText); } frames[i].parentNode.appendChild(div_meteo); } if(mapsurl != false){ frames[i].classList.add("to_remove"); let width = frames[i].width; let height = frames[i].height; let div_maps = document.createElement('div'); div_maps.setAttribute('data-service', 'google_maps'); div_maps.setAttribute('data-id', frames[i].src); div_maps.setAttribute('data-autoscale', true); if((width != undefined && width != '') && (height != undefined && height != '')){ div_maps.setAttribute('style', `width: ${width}px; height: ${height}px;`); }else{ div_maps.setAttribute('style', frames[i].style.cssText); } frames[i].parentNode.appendChild(div_maps); } if(windy != false){ frames[i].classList.add("to_remove"); let width = frames[i].width; let height = frames[i].height; let div_windy = document.createElement('div'); div_windy.setAttribute('data-service', 'windy'); div_windy.setAttribute('data-id', frames[i].src); div_windy.setAttribute('data-autoscale', true); if((width != undefined && width != '') && (height != undefined && height != '')){ div_windy.setAttribute('style', `width: ${width}px; height: ${height}px;`); }else{ div_windy.setAttribute('style', frames[i].style.cssText); } frames[i].parentNode.appendChild(div_windy); } } const frames_to_remove = document.querySelectorAll('.to_remove'); frames_to_remove.forEach(frame => { frame.remove(); }); } changeIframeToDiv();document.head.insertAdjacentHTML('beforeend', ``);document.head.insertAdjacentHTML('beforeend', ``);var mng = iframemanager();var cc = initCookieConsent();mng.run({"currLang":"en","services":{"youtube":{"embedUrl":"https:\/\/www.youtube-nocookie.com\/embed\/{data-id}","thumbnailUrl":"https:\/\/i3.ytimg.com\/vi\/{data-id}\/hqdefault.jpg","iframe":{"allow":"accelerometer; encrypted-media; gyroscope; picture-in-picture; fullscreen;"},"cookie":{"name":"cc_youtube"},"languages":{"en":{"notice":"This content is hosted by a third party. By showing the external content you accept the terms and conditions<\/a> of youtube.com.","loadBtn":"Load video","loadAllBtn":"Don't ask again"}}},"meteoblue":{"embedUrl":"{data-id}","thumbnailUrl":"","iframe":{"allow":""},"cookie":{"name":"cc_meteoblue"},"languages":{"en":{"notice":"This content is hosted by a third party. By showing the external content you accept the terms and conditions<\/a> of meteoblue.com.","loadBtn":"Load","loadAllBtn":"Don't ask again"}}},"google_maps":{"embedUrl":"{data-id}","thumbnailUrl":"","iframe":{"allow":""},"cookie":{"name":"cc_google_maps"},"languages":{"en":{"notice":"This content is hosted by a third party. By showing the external content you accept the terms and conditions<\/a> of google.maps.com.","loadBtn":"Load map","loadAllBtn":"Don't ask again"}}},"windy":{"embedUrl":"{data-id}","thumbnailUrl":"","iframe":{"allow":""},"cookie":{"name":"cc_windy"},"languages":{"en":{"notice":"This content is hosted by a third party. By showing the external content you accept the terms and conditions<\/a> of google.maps.com.","loadBtn":"Load Windy","loadAllBtn":"Don't ask again"}}},"vimeo":{"embedUrl":"https:\/\/player.vimeo.com\/video\/{data-id}","thumbnailUrl":"function(id, setThumbnail){\n \n var url = \"https:\/\/vimeo.com\/api\/v2\/video\/\" + id + \".json\";\n var xhttp = new XMLHttpRequest();\n \n xhttp.onreadystatechange = function() {\n if (this.readyState == 4 && this.status == 200) {\n var src = JSON.parse(this.response)[0].thumbnail_large;\n setThumbnail(src);\n }\n };\n\n xhttp.open(\"GET\", url, true);\n xhttp.send();\n }","iframe":{"allow":"accelerometer; encrypted-media; gyroscope; picture-in-picture; fullscreen;"},"cookie":{"name":"cc_vimeo"},"languages":{"en":{"notice":"This content is hosted by a third party. By showing the external content you accept the terms and conditions<\/a> of vimeo.com.","loadBtn":"Load video","loadAllBtn":"Don't ask again"}}}}});var cc_config = {"domain":"https:\/\/bubulakovo.dev","autorun":true,"mode":"opt-in","cookie_expiration":182,"cookie_name":"cContentCookie","cookie_path":"\/","use_rfc_cookie":false,"force_consent":false,"current_lang":"en","auto_language":null,"hide_from_bots":false,"autoclear_cookies":false,"remove_cookie_tables":false,"page_scripts":false,"branding":false,"gui_options":{"consent_modal":{"layout":"box","position_vertical":"bottom","position_horizontal":"left","transition":"zoom","position":"bottom left"},"settings_modal":{"layout":"box","position":"left","transition":"zoom"}},"c_consent_token":"8182ecf84aead179","languages":{"en":{"manage_cookie_consent":"Manage Cookie settings","consent_modal":{"title":"This site uses cookies","description":"We use cookies to personalize content and ads, to provide social media features and to analyze our traffic. We also share information about your use of our website with our social media, advertising and analytics partners, who may combine it with other information that you have provided to them or that they have collected through your use of their services. You agree to our cookies if you continue to use our website.